blob: a1696eb6f3263cd8061706ea92b9f8166a1cb999 [file] [log] [blame]
Brian Silverman9891b292020-06-23 16:34:22 -07001#include <algorithm>
James Kuszmaul38735e82019-12-07 16:42:06 -08002#include <iostream>
Brian Silverman9891b292020-06-23 16:34:22 -07003#include <memory>
4#include <optional>
5#include <string>
6#include <string_view>
7#include <vector>
James Kuszmaul38735e82019-12-07 16:42:06 -08008
9#include "aos/configuration.h"
10#include "aos/events/logging/logger.h"
11#include "aos/events/simulated_event_loop.h"
12#include "aos/init.h"
13#include "aos/json_to_flatbuffer.h"
14#include "gflags/gflags.h"
15
James Kuszmaul38735e82019-12-07 16:42:06 -080016DEFINE_string(
17 name, "",
18 "Name to match for printing out channels. Empty means no name filter.");
19DEFINE_string(type, "",
20 "Channel type to match for printing out channels. Empty means no "
21 "type filter.");
Austin Schuha81454b2020-05-12 19:58:36 -070022DEFINE_bool(fetch, false,
23 "If true, also print out the messages from before the start of the "
24 "log file");
Austin Schuh6f3babe2020-01-26 20:34:50 -080025DEFINE_bool(raw, false,
26 "If true, just print the data out unsorted and unparsed");
Austin Schuha81454b2020-05-12 19:58:36 -070027DEFINE_bool(format_raw, true,
28 "If true and --raw is specified, print out raw data, but use the "
29 "schema to format the data.");
Austin Schuhae46f362020-04-11 19:52:56 -070030DEFINE_int32(max_vector_size, 100,
31 "If positive, vectors longer than this will not be printed");
Austin Schuh6f3babe2020-01-26 20:34:50 -080032
Brian Silverman9891b292020-06-23 16:34:22 -070033// Print the flatbuffer out to stdout, both to remove the unnecessary cruft from
34// glog and to allow the user to readily redirect just the logged output
35// independent of any debugging information on stderr.
36void PrintMessage(const std::string_view node_name, const aos::Channel *channel,
37 const aos::Context &context) {
Austin Schuha81454b2020-05-12 19:58:36 -070038 if (context.monotonic_remote_time != context.monotonic_event_time) {
39 std::cout << node_name << context.realtime_event_time << " ("
40 << context.monotonic_event_time << ") sent "
41 << context.realtime_remote_time << " ("
42 << context.monotonic_remote_time << ") "
43 << channel->name()->c_str() << ' ' << channel->type()->c_str()
44 << ": "
45 << aos::FlatbufferToJson(
46 channel->schema(),
47 static_cast<const uint8_t *>(context.data),
48 FLAGS_max_vector_size)
49 << std::endl;
50 } else {
51 std::cout << node_name << context.realtime_event_time << " ("
52 << context.monotonic_event_time << ") "
53 << channel->name()->c_str() << ' ' << channel->type()->c_str()
54 << ": "
55 << aos::FlatbufferToJson(
56 channel->schema(),
57 static_cast<const uint8_t *>(context.data),
58 FLAGS_max_vector_size)
59 << std::endl;
60 }
61}
62
James Kuszmaul38735e82019-12-07 16:42:06 -080063int main(int argc, char **argv) {
64 gflags::SetUsageMessage(
Austin Schuh6f3babe2020-01-26 20:34:50 -080065 "Usage:\n"
66 " log_cat [args] logfile1 logfile2 ...\n"
67 "\n"
James Kuszmaul38735e82019-12-07 16:42:06 -080068 "This program provides a basic interface to dump data from a logfile to "
69 "stdout. Given a logfile, channel name filter, and type filter, it will "
70 "print all the messages in the logfile matching the filters. The message "
71 "filters work by taking the values of --name and --type and printing any "
72 "channel whose name contains --name as a substr and whose type contains "
73 "--type as a substr. Not specifying --name or --type leaves them free. "
74 "Calling this program without --name or --type specified prints out all "
75 "the logged data.");
76 aos::InitGoogle(&argc, &argv);
77
Austin Schuh6f3babe2020-01-26 20:34:50 -080078 if (FLAGS_raw) {
79 if (argc != 2) {
80 LOG(FATAL) << "Expected 1 logfile as an argument.";
James Kuszmaul38735e82019-12-07 16:42:06 -080081 }
Austin Schuh6f3babe2020-01-26 20:34:50 -080082 aos::logger::MessageReader reader(argv[1]);
83
84 while (true) {
85 std::optional<aos::FlatbufferVector<aos::logger::MessageHeader>> message =
86 reader.ReadMessage();
87 if (!message) {
88 break;
89 }
Austin Schuha81454b2020-05-12 19:58:36 -070090 const aos::Channel *channel =
91 reader.log_file_header()->configuration()->channels()->Get(
92 message.value().message().channel_index());
Austin Schuh6f3babe2020-01-26 20:34:50 -080093
Austin Schuha81454b2020-05-12 19:58:36 -070094 if (FLAGS_format_raw && message.value().message().data() != nullptr) {
95 std::cout << aos::configuration::StrippedChannelToString(channel) << " "
96 << aos::FlatbufferToJson(message.value(), false, 4) << ": "
97 << aos::FlatbufferToJson(
98 channel->schema(),
99 message.value().message().data()->data(),
100 FLAGS_max_vector_size)
101 << std::endl;
102 } else {
103 std::cout << aos::configuration::StrippedChannelToString(channel) << " "
104 << aos::FlatbufferToJson(message.value(), false,
105 FLAGS_max_vector_size)
106 << std::endl;
107 }
Austin Schuh6f3babe2020-01-26 20:34:50 -0800108 }
109 return 0;
James Kuszmaul38735e82019-12-07 16:42:06 -0800110 }
111
Austin Schuh6f3babe2020-01-26 20:34:50 -0800112 if (argc < 2) {
113 LOG(FATAL) << "Expected at least 1 logfile as an argument.";
114 }
115
116 std::vector<std::vector<std::string>> logfiles;
117
118 for (int i = 1; i < argc; ++i) {
119 logfiles.emplace_back(std::vector<std::string>{std::string(argv[i])});
120 }
121
122 aos::logger::LogReader reader(logfiles);
Austin Schuha81454b2020-05-12 19:58:36 -0700123
124 aos::SimulatedEventLoopFactory event_loop_factory(reader.configuration());
125 reader.Register(&event_loop_factory);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800126
127 std::vector<std::unique_ptr<aos::EventLoop>> printer_event_loops;
128
129 for (const aos::Node *node : reader.Nodes()) {
130 std::unique_ptr<aos::EventLoop> printer_event_loop =
Austin Schuha81454b2020-05-12 19:58:36 -0700131 event_loop_factory.MakeEventLoop("printer", node);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800132 printer_event_loop->SkipTimingReport();
133 printer_event_loop->SkipAosLog();
134
Brian Silverman9891b292020-06-23 16:34:22 -0700135 struct MessageInfo {
136 std::string node_name;
137 std::unique_ptr<aos::RawFetcher> fetcher;
138 };
139 std::vector<MessageInfo> messages_before_start;
Austin Schuha81454b2020-05-12 19:58:36 -0700140
Austin Schuh6f3babe2020-01-26 20:34:50 -0800141 bool found_channel = false;
142 const flatbuffers::Vector<flatbuffers::Offset<aos::Channel>> *channels =
Brian Silverman9891b292020-06-23 16:34:22 -0700143 printer_event_loop->configuration()->channels();
144
Austin Schuh6f3babe2020-01-26 20:34:50 -0800145 for (flatbuffers::uoffset_t i = 0; i < channels->size(); i++) {
146 const aos::Channel *channel = channels->Get(i);
147 const flatbuffers::string_view name = channel->name()->string_view();
148 const flatbuffers::string_view type = channel->type()->string_view();
149 if (name.find(FLAGS_name) != std::string::npos &&
150 type.find(FLAGS_type) != std::string::npos) {
151 if (!aos::configuration::ChannelIsReadableOnNode(
152 channel, printer_event_loop->node())) {
153 continue;
154 }
155 VLOG(1) << "Listening on " << name << " " << type;
156
157 std::string node_name =
158 node == nullptr ? ""
159 : std::string(node->name()->string_view()) + " ";
160
161 CHECK_NOTNULL(channel->schema());
Austin Schuha81454b2020-05-12 19:58:36 -0700162
Brian Silverman9891b292020-06-23 16:34:22 -0700163 // Fetch the last message on this channel from before the log start
164 // time.
Austin Schuha81454b2020-05-12 19:58:36 -0700165 if (FLAGS_fetch) {
Austin Schuha81454b2020-05-12 19:58:36 -0700166 std::unique_ptr<aos::RawFetcher> fetcher =
167 printer_event_loop->MakeRawFetcher(channel);
168 if (fetcher->Fetch()) {
Brian Silverman9891b292020-06-23 16:34:22 -0700169 MessageInfo message{.node_name = node_name,
170 .fetcher = std::move(fetcher)};
Austin Schuha81454b2020-05-12 19:58:36 -0700171 // Insert it sorted into the vector so we can print in time order
172 // instead of channel order at the start.
173 auto it = std::lower_bound(
Brian Silverman9891b292020-06-23 16:34:22 -0700174 messages_before_start.begin(), messages_before_start.end(),
175 message, [](const MessageInfo &lhs, const MessageInfo &rhs) {
176 if (lhs.fetcher->context().monotonic_event_time <
177 rhs.fetcher->context().monotonic_event_time) {
Austin Schuha81454b2020-05-12 19:58:36 -0700178 return true;
179 }
Brian Silverman9891b292020-06-23 16:34:22 -0700180 if (lhs.fetcher->context().monotonic_event_time >
181 rhs.fetcher->context().monotonic_event_time) {
Austin Schuha81454b2020-05-12 19:58:36 -0700182 return false;
183 }
Brian Silverman9891b292020-06-23 16:34:22 -0700184 return lhs.fetcher->channel() < rhs.fetcher->channel();
Austin Schuha81454b2020-05-12 19:58:36 -0700185 });
Brian Silverman9891b292020-06-23 16:34:22 -0700186 messages_before_start.insert(it, std::move(message));
Austin Schuha81454b2020-05-12 19:58:36 -0700187 }
188 }
189
Austin Schuh6f3babe2020-01-26 20:34:50 -0800190 printer_event_loop->MakeRawWatcher(
191 channel, [channel, node_name](const aos::Context &context,
Austin Schuha81454b2020-05-12 19:58:36 -0700192 const void * /*message*/) {
Brian Silverman9891b292020-06-23 16:34:22 -0700193 PrintMessage(node_name, channel, context);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800194 });
195 found_channel = true;
196 }
197 }
198
199 if (!found_channel) {
200 LOG(FATAL) << "Could not find any channels";
201 }
Brian Silverman9891b292020-06-23 16:34:22 -0700202
203 // Print the messages from before the log start time.
Austin Schuha81454b2020-05-12 19:58:36 -0700204 // TODO(austin): Sort between nodes too when it becomes annoying enough.
Brian Silverman9891b292020-06-23 16:34:22 -0700205 for (const MessageInfo &message : messages_before_start) {
206 PrintMessage(message.node_name, message.fetcher->channel(),
207 message.fetcher->context());
Austin Schuha81454b2020-05-12 19:58:36 -0700208 }
Austin Schuh6f3babe2020-01-26 20:34:50 -0800209 printer_event_loops.emplace_back(std::move(printer_event_loop));
Brian Silverman9891b292020-06-23 16:34:22 -0700210
211 std::cout << std::endl;
212 std::cout << "Log starting at " << reader.realtime_start_time() << " ("
213 << reader.monotonic_start_time() << ")";
214 std::cout << std::endl << std::endl;
James Kuszmaul38735e82019-12-07 16:42:06 -0800215 }
216
Austin Schuha81454b2020-05-12 19:58:36 -0700217 if (FLAGS_fetch) {
218 // New line to separate fetched messages from non-fetched messages.
219 std::cout << std::endl;
220 }
221
222 event_loop_factory.Run();
James Kuszmaul38735e82019-12-07 16:42:06 -0800223
224 aos::Cleanup();
225 return 0;
226}