blob: 7fb23780ed96513198e26153a95f191b298c6cf8 [file] [log] [blame]
James Kuszmaul38735e82019-12-07 16:42:06 -08001#include <iostream>
2
3#include "aos/configuration.h"
4#include "aos/events/logging/logger.h"
5#include "aos/events/simulated_event_loop.h"
6#include "aos/init.h"
7#include "aos/json_to_flatbuffer.h"
8#include "gflags/gflags.h"
9
James Kuszmaul38735e82019-12-07 16:42:06 -080010DEFINE_string(
11 name, "",
12 "Name to match for printing out channels. Empty means no name filter.");
13DEFINE_string(type, "",
14 "Channel type to match for printing out channels. Empty means no "
15 "type filter.");
Austin Schuh6f3babe2020-01-26 20:34:50 -080016DEFINE_bool(raw, false,
17 "If true, just print the data out unsorted and unparsed");
18
James Kuszmaul38735e82019-12-07 16:42:06 -080019int main(int argc, char **argv) {
20 gflags::SetUsageMessage(
Austin Schuh6f3babe2020-01-26 20:34:50 -080021 "Usage:\n"
22 " log_cat [args] logfile1 logfile2 ...\n"
23 "\n"
James Kuszmaul38735e82019-12-07 16:42:06 -080024 "This program provides a basic interface to dump data from a logfile to "
25 "stdout. Given a logfile, channel name filter, and type filter, it will "
26 "print all the messages in the logfile matching the filters. The message "
27 "filters work by taking the values of --name and --type and printing any "
28 "channel whose name contains --name as a substr and whose type contains "
29 "--type as a substr. Not specifying --name or --type leaves them free. "
30 "Calling this program without --name or --type specified prints out all "
31 "the logged data.");
32 aos::InitGoogle(&argc, &argv);
33
Austin Schuh6f3babe2020-01-26 20:34:50 -080034 if (FLAGS_raw) {
35 if (argc != 2) {
36 LOG(FATAL) << "Expected 1 logfile as an argument.";
James Kuszmaul38735e82019-12-07 16:42:06 -080037 }
Austin Schuh6f3babe2020-01-26 20:34:50 -080038 aos::logger::MessageReader reader(argv[1]);
39
40 while (true) {
41 std::optional<aos::FlatbufferVector<aos::logger::MessageHeader>> message =
42 reader.ReadMessage();
43 if (!message) {
44 break;
45 }
46
47 std::cout << aos::FlatbufferToJson(message.value()) << std::endl;
48 }
49 return 0;
James Kuszmaul38735e82019-12-07 16:42:06 -080050 }
51
Austin Schuh6f3babe2020-01-26 20:34:50 -080052 if (argc < 2) {
53 LOG(FATAL) << "Expected at least 1 logfile as an argument.";
54 }
55
56 std::vector<std::vector<std::string>> logfiles;
57
58 for (int i = 1; i < argc; ++i) {
59 logfiles.emplace_back(std::vector<std::string>{std::string(argv[i])});
60 }
61
62 aos::logger::LogReader reader(logfiles);
63 reader.Register();
64
65 std::vector<std::unique_ptr<aos::EventLoop>> printer_event_loops;
66
67 for (const aos::Node *node : reader.Nodes()) {
68 std::unique_ptr<aos::EventLoop> printer_event_loop =
69 reader.event_loop_factory()->MakeEventLoop("printer", node);
70 printer_event_loop->SkipTimingReport();
71 printer_event_loop->SkipAosLog();
72
73 bool found_channel = false;
74 const flatbuffers::Vector<flatbuffers::Offset<aos::Channel>> *channels =
75 reader.configuration()->channels();
76 for (flatbuffers::uoffset_t i = 0; i < channels->size(); i++) {
77 const aos::Channel *channel = channels->Get(i);
78 const flatbuffers::string_view name = channel->name()->string_view();
79 const flatbuffers::string_view type = channel->type()->string_view();
80 if (name.find(FLAGS_name) != std::string::npos &&
81 type.find(FLAGS_type) != std::string::npos) {
82 if (!aos::configuration::ChannelIsReadableOnNode(
83 channel, printer_event_loop->node())) {
84 continue;
85 }
86 VLOG(1) << "Listening on " << name << " " << type;
87
88 std::string node_name =
89 node == nullptr ? ""
90 : std::string(node->name()->string_view()) + " ";
91
92 CHECK_NOTNULL(channel->schema());
93 printer_event_loop->MakeRawWatcher(
94 channel, [channel, node_name](const aos::Context &context,
95 const void *message) {
96 // Print the flatbuffer out to stdout, both to remove the
97 // unnecessary cruft from glog and to allow the user to readily
98 // redirect just the logged output independent of any debugging
99 // information on stderr.
100 if (context.monotonic_remote_time !=
101 context.monotonic_event_time) {
102 std::cout << node_name << context.realtime_event_time << " ("
103 << context.monotonic_event_time << ") sent "
104 << context.realtime_remote_time << " ("
105 << context.monotonic_remote_time << ") "
106 << channel->name()->c_str() << ' '
107 << channel->type()->c_str() << ": "
108 << aos::FlatbufferToJson(
109 channel->schema(),
110 static_cast<const uint8_t *>(message))
111 << std::endl;
112 } else {
113 std::cout << node_name << context.realtime_event_time << " ("
114 << context.monotonic_event_time << ") "
115 << channel->name()->c_str() << ' '
116 << channel->type()->c_str() << ": "
117 << aos::FlatbufferToJson(
118 channel->schema(),
119 static_cast<const uint8_t *>(message))
120 << std::endl;
121 }
122 });
123 found_channel = true;
124 }
125 }
126
127 if (!found_channel) {
128 LOG(FATAL) << "Could not find any channels";
129 }
130 printer_event_loops.emplace_back(std::move(printer_event_loop));
James Kuszmaul38735e82019-12-07 16:42:06 -0800131 }
132
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800133 reader.event_loop_factory()->Run();
James Kuszmaul38735e82019-12-07 16:42:06 -0800134
135 aos::Cleanup();
136 return 0;
137}