blob: afb88afda0f570a447160c876abe1bd4237ce760 [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) {
23 const std::vector<std::string> unsorted_logfiles = FindLogs(argc, argv);
Alexei Strots1f51ac72023-05-15 10:14:54 -070024 const LogFilesContainer log_files(SortParts(unsorted_logfiles));
25 const Configuration *config = log_files.config();
Austin Schuhb618a9b2022-01-27 18:03:21 -080026
27 // Haven't tested this on a single node log, and don't really see a need to
28 // right now. The higher layers just work.
29 CHECK(configuration::MultiNode(config));
30
31 // Now, build up all the TimestampMapper classes to read and sort the data.
32 std::vector<std::unique_ptr<TimestampMapper>> mappers;
33 TimestampMapper *node_mapper = nullptr;
34
35 for (const Node *node : configuration::GetNodes(config)) {
Alexei Strots1f51ac72023-05-15 10:14:54 -070036 const auto node_name = MaybeNodeName(node);
Austin Schuhb618a9b2022-01-27 18:03:21 -080037 // Confirm that all the parts are from the same boot if there are enough
38 // parts to not be from the same boot.
Alexei Strots1f51ac72023-05-15 10:14:54 -070039 if (log_files.ContainsPartsForNode(node_name)) {
Austin Schuhb618a9b2022-01-27 18:03:21 -080040 // Filter the parts relevant to each node when building the mapper.
41 mappers.emplace_back(
Alexei Strots1f51ac72023-05-15 10:14:54 -070042 std::make_unique<TimestampMapper>(node_name, log_files));
43 if (node_name == FLAGS_node) {
Austin Schuhb618a9b2022-01-27 18:03:21 -080044 node_mapper = mappers.back().get();
45 }
46 } else {
47 mappers.emplace_back(nullptr);
48 }
49 }
50
51 CHECK(node_mapper != nullptr) << ": Failed to find node " << FLAGS_node;
52
53 // Hook the peers up so data gets matched.
54 for (std::unique_ptr<TimestampMapper> &mapper1 : mappers) {
55 for (std::unique_ptr<TimestampMapper> &mapper2 : mappers) {
56 if (mapper1.get() != mapper2.get() && mapper1 && mapper2) {
57 mapper1->AddPeer(mapper2.get());
58 }
59 }
60 }
61
62 // Now, read all the timestamps for each node. This is simpler than the
63 // logger on purpose. It loads in *all* the timestamps in 1 go per node,
64 // ignoring memory usage.
65 const Node *node = configuration::GetNode(config, FLAGS_node);
66
67 LOG(INFO) << "Reading all data for " << node->name()->string_view();
68 const size_t node_index = configuration::GetNodeIndex(config, node);
69 TimestampMapper *timestamp_mapper = mappers[node_index].get();
70 CHECK(timestamp_mapper != nullptr);
71 CHECK_EQ(timestamp_mapper, node_mapper);
72
73 while (true) {
74 TimestampedMessage *m = timestamp_mapper->Front();
75 if (m == nullptr) {
76 break;
77 }
78 std::cout << config->nodes()
79 ->Get(configuration::GetNodeIndex(
80 config, config->channels()
81 ->Get(m->channel_index)
82 ->source_node()
83 ->string_view()))
84 ->name()
85 ->string_view()
86 << " "
87 << configuration::StrippedChannelToString(
88 config->channels()->Get(m->channel_index))
89 << " " << *m << "\n";
90 timestamp_mapper->PopFront();
91 }
92
93 return 0;
94}
95
96} // namespace aos::logger
97
98int main(int argc, char **argv) {
99 aos::InitGoogle(&argc, &argv);
100
101 return aos::logger::Main(argc, argv);
102}