blob: aee2c5e05a82bbb03cac0b804e9647dee31d189d [file] [log] [blame]
Austin Schuhb618a9b2022-01-27 18:03:21 -08001#include <iostream>
2#include <string>
3#include <vector>
4
Philipp Schrader790cb542023-07-05 21:06:52 -07005#include "gflags/gflags.h"
6
Austin Schuhb618a9b2022-01-27 18:03:21 -08007#include "aos/events/logging/logfile_sorting.h"
8#include "aos/events/logging/logfile_utils.h"
9#include "aos/init.h"
10#include "aos/network/multinode_timestamp_filter.h"
Austin Schuhb618a9b2022-01-27 18:03:21 -080011
12// This is a simple application to match up data with timestamps for a node in a
13// log. It doesn't solve the timestamp problem, but is still quite useful for
14// debugging what happened in a log.
15
16DEFINE_string(node, "", "The node to dump sorted messages for");
17
18namespace aos::logger {
19
20namespace chrono = std::chrono;
21
Austin Schuhb618a9b2022-01-27 18:03:21 -080022int Main(int argc, char **argv) {
Austin Schuh95460cc2023-06-26 11:53:10 -070023 const LogFilesContainer log_files(SortParts(FindLogs(argc, argv)));
Alexei Strots1f51ac72023-05-15 10:14:54 -070024 const Configuration *config = log_files.config();
Austin Schuhb618a9b2022-01-27 18:03:21 -080025
26 // Haven't tested this on a single node log, and don't really see a need to
27 // right now. The higher layers just work.
28 CHECK(configuration::MultiNode(config));
29
30 // Now, build up all the TimestampMapper classes to read and sort the data.
31 std::vector<std::unique_ptr<TimestampMapper>> mappers;
32 TimestampMapper *node_mapper = nullptr;
33
34 for (const Node *node : configuration::GetNodes(config)) {
Alexei Strots1f51ac72023-05-15 10:14:54 -070035 const auto node_name = MaybeNodeName(node);
Austin Schuhb618a9b2022-01-27 18:03:21 -080036 // Confirm that all the parts are from the same boot if there are enough
37 // parts to not be from the same boot.
Alexei Strots1f51ac72023-05-15 10:14:54 -070038 if (log_files.ContainsPartsForNode(node_name)) {
Austin Schuhb618a9b2022-01-27 18:03:21 -080039 // Filter the parts relevant to each node when building the mapper.
40 mappers.emplace_back(
Alexei Strots1f51ac72023-05-15 10:14:54 -070041 std::make_unique<TimestampMapper>(node_name, log_files));
42 if (node_name == FLAGS_node) {
Austin Schuhb618a9b2022-01-27 18:03:21 -080043 node_mapper = mappers.back().get();
44 }
45 } else {
46 mappers.emplace_back(nullptr);
47 }
48 }
49
50 CHECK(node_mapper != nullptr) << ": Failed to find node " << FLAGS_node;
51
52 // Hook the peers up so data gets matched.
53 for (std::unique_ptr<TimestampMapper> &mapper1 : mappers) {
54 for (std::unique_ptr<TimestampMapper> &mapper2 : mappers) {
55 if (mapper1.get() != mapper2.get() && mapper1 && mapper2) {
56 mapper1->AddPeer(mapper2.get());
57 }
58 }
59 }
60
61 // Now, read all the timestamps for each node. This is simpler than the
62 // logger on purpose. It loads in *all* the timestamps in 1 go per node,
63 // ignoring memory usage.
64 const Node *node = configuration::GetNode(config, FLAGS_node);
65
66 LOG(INFO) << "Reading all data for " << node->name()->string_view();
67 const size_t node_index = configuration::GetNodeIndex(config, node);
68 TimestampMapper *timestamp_mapper = mappers[node_index].get();
69 CHECK(timestamp_mapper != nullptr);
70 CHECK_EQ(timestamp_mapper, node_mapper);
71
72 while (true) {
73 TimestampedMessage *m = timestamp_mapper->Front();
74 if (m == nullptr) {
75 break;
76 }
77 std::cout << config->nodes()
78 ->Get(configuration::GetNodeIndex(
79 config, config->channels()
80 ->Get(m->channel_index)
81 ->source_node()
82 ->string_view()))
83 ->name()
84 ->string_view()
85 << " "
86 << configuration::StrippedChannelToString(
87 config->channels()->Get(m->channel_index))
88 << " " << *m << "\n";
89 timestamp_mapper->PopFront();
90 }
91
92 return 0;
93}
94
95} // namespace aos::logger
96
97int main(int argc, char **argv) {
98 aos::InitGoogle(&argc, &argv);
99
100 return aos::logger::Main(argc, argv);
101}