Make logger and timesamp_logger config lists

We want to log messages on both the roboRIO, and on the laptop/logger
pi.  This means that we want lists of loggers instead of a single
logger.

We are lucky and there are no known log files with loggers in them which
we care to preserve.  This lets us reuse the field without worying about
compatability.

Change-Id: I452994fbca78909d6320da3d02ad51fe45a0354b
diff --git a/aos/configuration.cc b/aos/configuration.cc
index d6d276e..f250c93 100644
--- a/aos/configuration.cc
+++ b/aos/configuration.cc
@@ -383,18 +383,20 @@
           switch (connection->timestamp_logger()) {
             case LoggerConfig::LOCAL_LOGGER:
             case LoggerConfig::NOT_LOGGED:
-              CHECK(!connection->has_timestamp_logger_node());
+              CHECK(!connection->has_timestamp_logger_nodes());
               break;
             case LoggerConfig::REMOTE_LOGGER:
             case LoggerConfig::LOCAL_AND_REMOTE_LOGGER:
-              CHECK(connection->has_timestamp_logger_node());
-              CHECK(
-                  GetNode(&result.message(),
-                          connection->timestamp_logger_node()->string_view()) !=
-                  nullptr)
-                  << ": Channel " << FlatbufferToJson(c)
-                  << " has an unknown \"timestamp_logger_node\""
-                  << connection->name()->string_view();
+              CHECK(connection->has_timestamp_logger_nodes());
+              CHECK_GT(connection->timestamp_logger_nodes()->size(), 0u);
+              for (const flatbuffers::String *timestamp_logger_node :
+                   *connection->timestamp_logger_nodes()) {
+                CHECK(GetNode(&result.message(),
+                              timestamp_logger_node->string_view()) != nullptr)
+                    << ": Channel " << FlatbufferToJson(c)
+                    << " has an unknown \"timestamp_logger_node\""
+                    << connection->name()->string_view();
+              }
               break;
           }
 
@@ -778,20 +780,24 @@
       }
       return channel->source_node()->string_view() ==
              node->name()->string_view();
-    case LoggerConfig::REMOTE_LOGGER:
-      CHECK(channel->has_logger_node());
-
-      return channel->logger_node()->string_view() ==
-             CHECK_NOTNULL(node)->name()->string_view();
     case LoggerConfig::LOCAL_AND_REMOTE_LOGGER:
-      CHECK(channel->has_logger_node());
+      CHECK(channel->has_logger_nodes());
+      CHECK_GT(channel->logger_nodes()->size(), 0u);
 
       if (channel->source_node()->string_view() ==
           CHECK_NOTNULL(node)->name()->string_view()) {
         return true;
       }
-      if (channel->logger_node()->string_view() == node->name()->string_view()) {
-        return true;
+
+      [[fallthrough]];
+    case LoggerConfig::REMOTE_LOGGER:
+      CHECK(channel->has_logger_nodes());
+      CHECK_GT(channel->logger_nodes()->size(), 0u);
+      for (const flatbuffers::String *logger_node : *channel->logger_nodes()) {
+        if (logger_node->string_view() ==
+            CHECK_NOTNULL(node)->name()->string_view()) {
+          return true;
+        }
       }
 
       return false;
@@ -828,24 +834,27 @@
                                           const Node *node) {
   switch (connection->timestamp_logger()) {
     case LoggerConfig::LOCAL_AND_REMOTE_LOGGER:
-      CHECK(connection->has_timestamp_logger_node());
+      CHECK(connection->has_timestamp_logger_nodes());
+      CHECK_GT(connection->timestamp_logger_nodes()->size(), 0u);
       if (connection->name()->string_view() == node->name()->string_view()) {
         return true;
       }
 
-      if (connection->timestamp_logger_node()->string_view() ==
-          node->name()->string_view()) {
-        return true;
+      [[fallthrough]];
+    case LoggerConfig::REMOTE_LOGGER:
+      CHECK(connection->has_timestamp_logger_nodes());
+      CHECK_GT(connection->timestamp_logger_nodes()->size(), 0u);
+      for (const flatbuffers::String *timestamp_logger_node :
+           *connection->timestamp_logger_nodes()) {
+        if (timestamp_logger_node->string_view() ==
+            node->name()->string_view()) {
+          return true;
+        }
       }
 
       return false;
     case LoggerConfig::LOCAL_LOGGER:
       return connection->name()->string_view() == node->name()->string_view();
-    case LoggerConfig::REMOTE_LOGGER:
-      CHECK(connection->has_timestamp_logger_node());
-
-      return connection->timestamp_logger_node()->string_view() ==
-             node->name()->string_view();
     case LoggerConfig::NOT_LOGGED:
       return false;
   }
diff --git a/aos/configuration.fbs b/aos/configuration.fbs
index 576616e..c66da06 100644
--- a/aos/configuration.fbs
+++ b/aos/configuration.fbs
@@ -29,7 +29,7 @@
   // remotely, which node should be responsible for logging the data.  Note:
   // for now, this can only be the source node.  Empty implies the node this
   // connection is connecting to (i.e. name).
-  timestamp_logger_node:string;
+  timestamp_logger_nodes:[string];
 
   // Priority to forward data with.
   priority:ushort = 100;
@@ -77,7 +77,7 @@
   // logging the data.  Note: this requires that the data is forwarded to the
   // node responsible for logging it.  Empty implies the node this connection
   // is connecting to (i.e. name).
-  logger_node:string;
+  logger_nodes:[string];
 }
 
 // Table to support renaming channel names.
diff --git a/aos/configuration_test.cc b/aos/configuration_test.cc
index f069277..0be7a46 100644
--- a/aos/configuration_test.cc
+++ b/aos/configuration_test.cc
@@ -354,7 +354,7 @@
   "type": "aos.examples.Ping",
   "source_node": "bar",
   "logger": "REMOTE_LOGGER",
-  "logger_node": "baz",
+  "logger_nodes": ["baz"],
   "destination_nodes": [
     {
       "name": "baz"
@@ -370,7 +370,7 @@
   "type": "aos.examples.Ping",
   "source_node": "bar",
   "logger": "REMOTE_LOGGER",
-  "logger_node": "foo",
+  "logger_nodes": ["foo"],
   "destination_nodes": [
     {
       "name": "baz"
@@ -386,7 +386,7 @@
   "type": "aos.examples.Ping",
   "source_node": "bar",
   "logger": "LOCAL_AND_REMOTE_LOGGER",
-  "logger_node": "baz",
+  "logger_nodes": ["baz"],
   "destination_nodes": [
     {
       "name": "baz"
@@ -462,7 +462,7 @@
   "type": "aos.examples.Ping",
   "source_node": "bar",
   "logger": "REMOTE_LOGGER",
-  "logger_node": "baz",
+  "logger_nodes": ["baz"],
   "destination_nodes": [
     {
       "name": "baz"
@@ -495,7 +495,7 @@
     {
       "name": "baz",
       "timestamp_logger": "REMOTE_LOGGER",
-      "timestamp_logger_node": "bar"
+      "timestamp_logger_nodes": ["bar"]
     }
   ]
 })channel",
@@ -508,12 +508,12 @@
   "type": "aos.examples.Ping",
   "source_node": "bar",
   "logger": "REMOTE_LOGGER",
-  "logger_node": "foo",
+  "logger_nodes": ["foo"],
   "destination_nodes": [
     {
       "name": "baz",
       "timestamp_logger": "REMOTE_LOGGER",
-      "timestamp_logger_node": "foo"
+      "timestamp_logger_nodes": ["foo"]
     }
   ]
 })channel",
@@ -529,7 +529,7 @@
     {
       "name": "baz",
       "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-      "timestamp_logger_node": "bar"
+      "timestamp_logger_nodes": ["bar"]
     }
   ]
 })channel",
diff --git a/aos/events/logging/multinode_pingpong.json b/aos/events/logging/multinode_pingpong.json
index 957cc2b..f1bcc54 100644
--- a/aos/events/logging/multinode_pingpong.json
+++ b/aos/events/logging/multinode_pingpong.json
@@ -43,7 +43,7 @@
           "name": "pi2",
           "priority": 1,
           "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-          "timestamp_logger_node": "pi1",
+          "timestamp_logger_nodes": ["pi1"],
           "time_to_live": 5000000
         }
       ]
@@ -59,7 +59,7 @@
       "type": "aos.examples.Pong",
       "source_node": "pi2",
       "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_node": "pi1",
+      "logger_nodes": ["pi1"],
       "destination_nodes": [
         {
           "name": "pi1",
diff --git a/aos/network/message_bridge_test_common.json b/aos/network/message_bridge_test_common.json
index 1e5dfce..1767c4c 100644
--- a/aos/network/message_bridge_test_common.json
+++ b/aos/network/message_bridge_test_common.json
@@ -105,7 +105,7 @@
           "name": "pi2",
           "priority": 1,
           "timestamp_logger": "REMOTE_LOGGER",
-          "timestamp_logger_node": "pi1"
+          "timestamp_logger_nodes": ["pi1"]
         }
       ]
     },
@@ -119,13 +119,13 @@
       "type": "aos.examples.Pong",
       "source_node": "pi2",
       "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_node": "pi1",
+      "logger_nodes": ["pi1"],
       "destination_nodes": [
         {
           "name": "pi1",
           "priority": 1,
           "timestamp_logger": "REMOTE_LOGGER",
-          "timestamp_logger_node": "pi1"
+          "timestamp_logger_nodes": ["pi1"]
         }
       ]
     }
diff --git a/y2020/y2020_pi1.json b/y2020/y2020_pi1.json
index f14996c..93d3ba9 100644
--- a/y2020/y2020_pi1.json
+++ b/y2020/y2020_pi1.json
@@ -58,7 +58,7 @@
       "type": "frc971.vision.sift.ImageMatchResult",
       "source_node": "pi1",
       "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_node": "roborio",
+      "logger_nodes": ["roborio"],
       "frequency": 25,
       "max_size": 10000,
       "destination_nodes": [
diff --git a/y2020/y2020_pi2.json b/y2020/y2020_pi2.json
index 82a2bc9..2046666 100644
--- a/y2020/y2020_pi2.json
+++ b/y2020/y2020_pi2.json
@@ -58,7 +58,7 @@
       "type": "frc971.vision.sift.ImageMatchResult",
       "source_node": "pi2",
       "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_node": "roborio",
+      "logger_nodes": ["roborio"],
       "frequency": 25,
       "max_size": 10000,
       "destination_nodes": [
diff --git a/y2020/y2020_pi3.json b/y2020/y2020_pi3.json
index 727e41d..fe8f980 100644
--- a/y2020/y2020_pi3.json
+++ b/y2020/y2020_pi3.json
@@ -58,7 +58,7 @@
       "type": "frc971.vision.sift.ImageMatchResult",
       "source_node": "pi3",
       "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_node": "roborio",
+      "logger_nodes": ["roborio"],
       "frequency": 25,
       "max_size": 10000,
       "destination_nodes": [