blob: a938367432da3d6e4867d823e50aae8e492aa480 [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");
Austin Schuhae46f362020-04-11 19:52:56 -070018DEFINE_int32(max_vector_size, 100,
19 "If positive, vectors longer than this will not be printed");
Austin Schuh6f3babe2020-01-26 20:34:50 -080020
James Kuszmaul38735e82019-12-07 16:42:06 -080021int main(int argc, char **argv) {
22 gflags::SetUsageMessage(
Austin Schuh6f3babe2020-01-26 20:34:50 -080023 "Usage:\n"
24 " log_cat [args] logfile1 logfile2 ...\n"
25 "\n"
James Kuszmaul38735e82019-12-07 16:42:06 -080026 "This program provides a basic interface to dump data from a logfile to "
27 "stdout. Given a logfile, channel name filter, and type filter, it will "
28 "print all the messages in the logfile matching the filters. The message "
29 "filters work by taking the values of --name and --type and printing any "
30 "channel whose name contains --name as a substr and whose type contains "
31 "--type as a substr. Not specifying --name or --type leaves them free. "
32 "Calling this program without --name or --type specified prints out all "
33 "the logged data.");
34 aos::InitGoogle(&argc, &argv);
35
Austin Schuh6f3babe2020-01-26 20:34:50 -080036 if (FLAGS_raw) {
37 if (argc != 2) {
38 LOG(FATAL) << "Expected 1 logfile as an argument.";
James Kuszmaul38735e82019-12-07 16:42:06 -080039 }
Austin Schuh6f3babe2020-01-26 20:34:50 -080040 aos::logger::MessageReader reader(argv[1]);
41
42 while (true) {
43 std::optional<aos::FlatbufferVector<aos::logger::MessageHeader>> message =
44 reader.ReadMessage();
45 if (!message) {
46 break;
47 }
48
Austin Schuhae46f362020-04-11 19:52:56 -070049 std::cout << aos::FlatbufferToJson(message.value(), FLAGS_max_vector_size)
50 << std::endl;
Austin Schuh6f3babe2020-01-26 20:34:50 -080051 }
52 return 0;
James Kuszmaul38735e82019-12-07 16:42:06 -080053 }
54
Austin Schuh6f3babe2020-01-26 20:34:50 -080055 if (argc < 2) {
56 LOG(FATAL) << "Expected at least 1 logfile as an argument.";
57 }
58
59 std::vector<std::vector<std::string>> logfiles;
60
61 for (int i = 1; i < argc; ++i) {
62 logfiles.emplace_back(std::vector<std::string>{std::string(argv[i])});
63 }
64
65 aos::logger::LogReader reader(logfiles);
66 reader.Register();
67
68 std::vector<std::unique_ptr<aos::EventLoop>> printer_event_loops;
69
70 for (const aos::Node *node : reader.Nodes()) {
71 std::unique_ptr<aos::EventLoop> printer_event_loop =
72 reader.event_loop_factory()->MakeEventLoop("printer", node);
73 printer_event_loop->SkipTimingReport();
74 printer_event_loop->SkipAosLog();
75
76 bool found_channel = false;
77 const flatbuffers::Vector<flatbuffers::Offset<aos::Channel>> *channels =
78 reader.configuration()->channels();
79 for (flatbuffers::uoffset_t i = 0; i < channels->size(); i++) {
80 const aos::Channel *channel = channels->Get(i);
81 const flatbuffers::string_view name = channel->name()->string_view();
82 const flatbuffers::string_view type = channel->type()->string_view();
83 if (name.find(FLAGS_name) != std::string::npos &&
84 type.find(FLAGS_type) != std::string::npos) {
85 if (!aos::configuration::ChannelIsReadableOnNode(
86 channel, printer_event_loop->node())) {
87 continue;
88 }
89 VLOG(1) << "Listening on " << name << " " << type;
90
91 std::string node_name =
92 node == nullptr ? ""
93 : std::string(node->name()->string_view()) + " ";
94
95 CHECK_NOTNULL(channel->schema());
96 printer_event_loop->MakeRawWatcher(
97 channel, [channel, node_name](const aos::Context &context,
98 const void *message) {
99 // Print the flatbuffer out to stdout, both to remove the
100 // unnecessary cruft from glog and to allow the user to readily
101 // redirect just the logged output independent of any debugging
102 // information on stderr.
103 if (context.monotonic_remote_time !=
104 context.monotonic_event_time) {
105 std::cout << node_name << context.realtime_event_time << " ("
106 << context.monotonic_event_time << ") sent "
107 << context.realtime_remote_time << " ("
108 << context.monotonic_remote_time << ") "
109 << channel->name()->c_str() << ' '
110 << channel->type()->c_str() << ": "
111 << aos::FlatbufferToJson(
112 channel->schema(),
Austin Schuhae46f362020-04-11 19:52:56 -0700113 static_cast<const uint8_t *>(message),
114 FLAGS_max_vector_size)
Austin Schuh6f3babe2020-01-26 20:34:50 -0800115 << std::endl;
116 } else {
117 std::cout << node_name << context.realtime_event_time << " ("
118 << context.monotonic_event_time << ") "
119 << channel->name()->c_str() << ' '
120 << channel->type()->c_str() << ": "
121 << aos::FlatbufferToJson(
122 channel->schema(),
Austin Schuhae46f362020-04-11 19:52:56 -0700123 static_cast<const uint8_t *>(message),
124 FLAGS_max_vector_size)
Austin Schuh6f3babe2020-01-26 20:34:50 -0800125 << std::endl;
126 }
127 });
128 found_channel = true;
129 }
130 }
131
132 if (!found_channel) {
133 LOG(FATAL) << "Could not find any channels";
134 }
135 printer_event_loops.emplace_back(std::move(printer_event_loop));
James Kuszmaul38735e82019-12-07 16:42:06 -0800136 }
137
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800138 reader.event_loop_factory()->Run();
James Kuszmaul38735e82019-12-07 16:42:06 -0800139
140 aos::Cleanup();
141 return 0;
142}