blob: 4ef9237fda683de79726e98d0f2e4540549e8d32 [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");
Ravago Jones5cc9df52020-09-02 21:29:58 -070032DEFINE_bool(pretty, false,
33 "If true, pretty print the messages on multiple lines");
Austin Schuh6f3babe2020-01-26 20:34:50 -080034
Brian Silverman9891b292020-06-23 16:34:22 -070035// Print the flatbuffer out to stdout, both to remove the unnecessary cruft from
36// glog and to allow the user to readily redirect just the logged output
37// independent of any debugging information on stderr.
38void PrintMessage(const std::string_view node_name, const aos::Channel *channel,
Austin Schuh746690f2020-08-01 16:15:57 -070039 const aos::Context &context,
40 aos::FastStringBuilder *builder) {
41 builder->Reset();
Ravago Jones5cc9df52020-09-02 21:29:58 -070042 aos::FlatbufferToJson(
43 builder, channel->schema(), static_cast<const uint8_t *>(context.data),
44 {FLAGS_pretty, static_cast<size_t>(FLAGS_max_vector_size)});
Austin Schuh746690f2020-08-01 16:15:57 -070045
Austin Schuha81454b2020-05-12 19:58:36 -070046 if (context.monotonic_remote_time != context.monotonic_event_time) {
47 std::cout << node_name << context.realtime_event_time << " ("
48 << context.monotonic_event_time << ") sent "
49 << context.realtime_remote_time << " ("
50 << context.monotonic_remote_time << ") "
51 << channel->name()->c_str() << ' ' << channel->type()->c_str()
Austin Schuh746690f2020-08-01 16:15:57 -070052 << ": " << *builder << std::endl;
Austin Schuha81454b2020-05-12 19:58:36 -070053 } else {
54 std::cout << node_name << context.realtime_event_time << " ("
55 << context.monotonic_event_time << ") "
56 << channel->name()->c_str() << ' ' << channel->type()->c_str()
Austin Schuh746690f2020-08-01 16:15:57 -070057 << ": " << *builder << std::endl;
Austin Schuha81454b2020-05-12 19:58:36 -070058 }
59}
60
James Kuszmaul38735e82019-12-07 16:42:06 -080061int main(int argc, char **argv) {
62 gflags::SetUsageMessage(
Austin Schuh6f3babe2020-01-26 20:34:50 -080063 "Usage:\n"
64 " log_cat [args] logfile1 logfile2 ...\n"
65 "\n"
James Kuszmaul38735e82019-12-07 16:42:06 -080066 "This program provides a basic interface to dump data from a logfile to "
67 "stdout. Given a logfile, channel name filter, and type filter, it will "
68 "print all the messages in the logfile matching the filters. The message "
69 "filters work by taking the values of --name and --type and printing any "
70 "channel whose name contains --name as a substr and whose type contains "
71 "--type as a substr. Not specifying --name or --type leaves them free. "
72 "Calling this program without --name or --type specified prints out all "
73 "the logged data.");
74 aos::InitGoogle(&argc, &argv);
75
Austin Schuh6f3babe2020-01-26 20:34:50 -080076 if (FLAGS_raw) {
77 if (argc != 2) {
78 LOG(FATAL) << "Expected 1 logfile as an argument.";
James Kuszmaul38735e82019-12-07 16:42:06 -080079 }
Austin Schuh6f3babe2020-01-26 20:34:50 -080080 aos::logger::MessageReader reader(argv[1]);
Austin Schuh2f8fd752020-09-01 22:38:28 -070081 std::cout << aos::FlatbufferToJson(reader.log_file_header(),
82 {.multi_line = FLAGS_pretty,
83 .max_vector_size = static_cast<size_t>(
84 FLAGS_max_vector_size)})
85 << std::endl;
Austin Schuh6f3babe2020-01-26 20:34:50 -080086
87 while (true) {
88 std::optional<aos::FlatbufferVector<aos::logger::MessageHeader>> message =
89 reader.ReadMessage();
90 if (!message) {
91 break;
92 }
Austin Schuha81454b2020-05-12 19:58:36 -070093 const aos::Channel *channel =
94 reader.log_file_header()->configuration()->channels()->Get(
95 message.value().message().channel_index());
Austin Schuh6f3babe2020-01-26 20:34:50 -080096
Austin Schuha81454b2020-05-12 19:58:36 -070097 if (FLAGS_format_raw && message.value().message().data() != nullptr) {
98 std::cout << aos::configuration::StrippedChannelToString(channel) << " "
Ravago Jonescf453ab2020-05-06 21:14:53 -070099 << aos::FlatbufferToJson(
100 message.value(),
Ravago Jones5cc9df52020-09-02 21:29:58 -0700101 {.multi_line = FLAGS_pretty, .max_vector_size = 4})
Ravago Jonescf453ab2020-05-06 21:14:53 -0700102 << ": "
Austin Schuha81454b2020-05-12 19:58:36 -0700103 << aos::FlatbufferToJson(
104 channel->schema(),
105 message.value().message().data()->data(),
Ravago Jones5cc9df52020-09-02 21:29:58 -0700106 {FLAGS_pretty,
107 static_cast<size_t>(FLAGS_max_vector_size)})
Austin Schuha81454b2020-05-12 19:58:36 -0700108 << std::endl;
109 } else {
110 std::cout << aos::configuration::StrippedChannelToString(channel) << " "
Ravago Jonescf453ab2020-05-06 21:14:53 -0700111 << aos::FlatbufferToJson(
112 message.value(),
Ravago Jones5cc9df52020-09-02 21:29:58 -0700113 {FLAGS_pretty,
114 static_cast<size_t>(FLAGS_max_vector_size)})
Austin Schuha81454b2020-05-12 19:58:36 -0700115 << std::endl;
116 }
Austin Schuh6f3babe2020-01-26 20:34:50 -0800117 }
118 return 0;
James Kuszmaul38735e82019-12-07 16:42:06 -0800119 }
120
Austin Schuh6f3babe2020-01-26 20:34:50 -0800121 if (argc < 2) {
122 LOG(FATAL) << "Expected at least 1 logfile as an argument.";
123 }
124
125 std::vector<std::vector<std::string>> logfiles;
126
127 for (int i = 1; i < argc; ++i) {
128 logfiles.emplace_back(std::vector<std::string>{std::string(argv[i])});
129 }
130
131 aos::logger::LogReader reader(logfiles);
Austin Schuha81454b2020-05-12 19:58:36 -0700132
Austin Schuh746690f2020-08-01 16:15:57 -0700133 aos::FastStringBuilder builder;
134
Austin Schuha81454b2020-05-12 19:58:36 -0700135 aos::SimulatedEventLoopFactory event_loop_factory(reader.configuration());
136 reader.Register(&event_loop_factory);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800137
138 std::vector<std::unique_ptr<aos::EventLoop>> printer_event_loops;
139
140 for (const aos::Node *node : reader.Nodes()) {
141 std::unique_ptr<aos::EventLoop> printer_event_loop =
Austin Schuha81454b2020-05-12 19:58:36 -0700142 event_loop_factory.MakeEventLoop("printer", node);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800143 printer_event_loop->SkipTimingReport();
144 printer_event_loop->SkipAosLog();
145
Brian Silverman9891b292020-06-23 16:34:22 -0700146 struct MessageInfo {
147 std::string node_name;
148 std::unique_ptr<aos::RawFetcher> fetcher;
149 };
150 std::vector<MessageInfo> messages_before_start;
Austin Schuha81454b2020-05-12 19:58:36 -0700151
Austin Schuh6f3babe2020-01-26 20:34:50 -0800152 bool found_channel = false;
153 const flatbuffers::Vector<flatbuffers::Offset<aos::Channel>> *channels =
Brian Silverman9891b292020-06-23 16:34:22 -0700154 printer_event_loop->configuration()->channels();
155
Austin Schuh6f3babe2020-01-26 20:34:50 -0800156 for (flatbuffers::uoffset_t i = 0; i < channels->size(); i++) {
157 const aos::Channel *channel = channels->Get(i);
158 const flatbuffers::string_view name = channel->name()->string_view();
159 const flatbuffers::string_view type = channel->type()->string_view();
160 if (name.find(FLAGS_name) != std::string::npos &&
161 type.find(FLAGS_type) != std::string::npos) {
162 if (!aos::configuration::ChannelIsReadableOnNode(
163 channel, printer_event_loop->node())) {
164 continue;
165 }
166 VLOG(1) << "Listening on " << name << " " << type;
167
168 std::string node_name =
169 node == nullptr ? ""
170 : std::string(node->name()->string_view()) + " ";
171
172 CHECK_NOTNULL(channel->schema());
Austin Schuha81454b2020-05-12 19:58:36 -0700173
Brian Silverman9891b292020-06-23 16:34:22 -0700174 // Fetch the last message on this channel from before the log start
175 // time.
Austin Schuha81454b2020-05-12 19:58:36 -0700176 if (FLAGS_fetch) {
Austin Schuha81454b2020-05-12 19:58:36 -0700177 std::unique_ptr<aos::RawFetcher> fetcher =
178 printer_event_loop->MakeRawFetcher(channel);
179 if (fetcher->Fetch()) {
Brian Silverman9891b292020-06-23 16:34:22 -0700180 MessageInfo message{.node_name = node_name,
181 .fetcher = std::move(fetcher)};
Austin Schuha81454b2020-05-12 19:58:36 -0700182 // Insert it sorted into the vector so we can print in time order
183 // instead of channel order at the start.
184 auto it = std::lower_bound(
Brian Silverman9891b292020-06-23 16:34:22 -0700185 messages_before_start.begin(), messages_before_start.end(),
186 message, [](const MessageInfo &lhs, const MessageInfo &rhs) {
187 if (lhs.fetcher->context().monotonic_event_time <
188 rhs.fetcher->context().monotonic_event_time) {
Austin Schuha81454b2020-05-12 19:58:36 -0700189 return true;
190 }
Brian Silverman9891b292020-06-23 16:34:22 -0700191 if (lhs.fetcher->context().monotonic_event_time >
192 rhs.fetcher->context().monotonic_event_time) {
Austin Schuha81454b2020-05-12 19:58:36 -0700193 return false;
194 }
Brian Silverman9891b292020-06-23 16:34:22 -0700195 return lhs.fetcher->channel() < rhs.fetcher->channel();
Austin Schuha81454b2020-05-12 19:58:36 -0700196 });
Brian Silverman9891b292020-06-23 16:34:22 -0700197 messages_before_start.insert(it, std::move(message));
Austin Schuha81454b2020-05-12 19:58:36 -0700198 }
199 }
200
Austin Schuh6f3babe2020-01-26 20:34:50 -0800201 printer_event_loop->MakeRawWatcher(
Ravago Jones5cc9df52020-09-02 21:29:58 -0700202 channel, [channel, node_name, &builder](const aos::Context &context,
203 const void * /*message*/) {
Austin Schuh746690f2020-08-01 16:15:57 -0700204 PrintMessage(node_name, channel, context, &builder);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800205 });
206 found_channel = true;
207 }
208 }
209
210 if (!found_channel) {
211 LOG(FATAL) << "Could not find any channels";
212 }
Brian Silverman9891b292020-06-23 16:34:22 -0700213
214 // Print the messages from before the log start time.
Austin Schuha81454b2020-05-12 19:58:36 -0700215 // TODO(austin): Sort between nodes too when it becomes annoying enough.
Brian Silverman9891b292020-06-23 16:34:22 -0700216 for (const MessageInfo &message : messages_before_start) {
217 PrintMessage(message.node_name, message.fetcher->channel(),
Austin Schuh746690f2020-08-01 16:15:57 -0700218 message.fetcher->context(), &builder);
Austin Schuha81454b2020-05-12 19:58:36 -0700219 }
Austin Schuh6f3babe2020-01-26 20:34:50 -0800220 printer_event_loops.emplace_back(std::move(printer_event_loop));
Brian Silverman9891b292020-06-23 16:34:22 -0700221
222 std::cout << std::endl;
Austin Schuhee711052020-08-24 16:06:09 -0700223 std::cout << (node != nullptr ? (node->name()->str() + " ") : "")
224 << "Log starting at " << reader.realtime_start_time(node) << " ("
225 << reader.monotonic_start_time(node) << ")";
Brian Silverman9891b292020-06-23 16:34:22 -0700226 std::cout << std::endl << std::endl;
James Kuszmaul38735e82019-12-07 16:42:06 -0800227 }
228
Austin Schuha81454b2020-05-12 19:58:36 -0700229 if (FLAGS_fetch) {
230 // New line to separate fetched messages from non-fetched messages.
231 std::cout << std::endl;
232 }
233
234 event_loop_factory.Run();
James Kuszmaul38735e82019-12-07 16:42:06 -0800235
Austin Schuh51a92592020-08-09 13:17:00 -0700236 reader.Deregister();
237
James Kuszmaul38735e82019-12-07 16:42:06 -0800238 return 0;
239}