blob: 9383fdd025a5da8291f51111488b03351c870472 [file] [log] [blame]
Stephan Massaltf84cf812019-12-31 14:14:50 -08001#include <iomanip>
2#include <iostream>
3
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 "aos/time/time.h"
9#include "gflags/gflags.h"
10
11DEFINE_string(logfile, "/tmp/logfile.bfbs",
12 "Name and path of the logfile to read from.");
13DEFINE_string(
14 name, "",
15 "Name to match for printing out channels. Empty means no name filter.");
16
17// define struct to hold all information
18struct ChannelStats {
19 // pointer to the channel for which stats are collected
20 const aos::Channel *channel;
21 aos::realtime_clock::time_point channel_end_time =
22 aos::realtime_clock::min_time;
23 aos::monotonic_clock::time_point first_message_time =
24 // needs to be higher than time in the logfile!
25 aos::monotonic_clock::max_time;
26 aos::monotonic_clock::time_point current_message_time =
27 aos::monotonic_clock::min_time;
28 // channel stats to collect per channel
29 int total_num_messages = 0;
30 size_t max_message_size = 0;
31 size_t total_message_size = 0;
32 double avg_messages_sec = 0.0; // TODO in Lambda, now in stats overview.
33 double max_messages_sec = 0.0; // TODO in Lambda
34};
35
36struct LogfileStats {
37 // All relevant stats on to logfile level
38 size_t logfile_length = 0;
39 int total_log_messages = 0;
40 aos::realtime_clock::time_point logfile_end_time =
41 aos::realtime_clock::min_time;
42};
43
44int main(int argc, char **argv) {
45 gflags::SetUsageMessage(
46 "This program provides statistics on a given log file. Supported "
47 "statistics are:\n"
48 " - Logfile start time;\n"
49 " - Total messages per channel/type;\n"
50 " - Max message size per channel/type;\n"
51 " - Frequency of messages per second;\n"
52 " - Total logfile size and number of messages.\n"
53 "Use --logfile flag to select a logfile (path/filename) and use --name "
54 "flag to specify a channel to listen on.");
55
56 aos::InitGoogle(&argc, &argv);
57
58 LogfileStats logfile_stats;
59 std::vector<ChannelStats> channel_stats;
60
61 // Open LogFile
62 aos::logger::LogReader reader(FLAGS_logfile);
63 aos::SimulatedEventLoopFactory log_reader_factory(reader.configuration());
64 reader.Register(&log_reader_factory);
65
66 // Make an eventloop for retrieving stats
67 std::unique_ptr<aos::EventLoop> stats_event_loop =
68 log_reader_factory.MakeEventLoop("logstats");
69 stats_event_loop->SkipTimingReport();
70
71 // Read channel info and store in vector
72 bool found_channel = false;
73 const flatbuffers::Vector<flatbuffers::Offset<aos::Channel>> *channels =
74 reader.configuration()->channels();
75
76 int it = 0; // iterate through the channel_stats
77 for (flatbuffers::uoffset_t i = 0; i < channels->size(); i++) {
78 const aos::Channel *channel = channels->Get(i);
79 if (channel->name()->string_view().find(FLAGS_name) != std::string::npos) {
80 // Add a record to the stats vector.
81 channel_stats.push_back({channel});
82 it++;
83 // Lambda to read messages and parse for information
84 stats_event_loop->MakeRawWatcher(
85 channel,
86 [&logfile_stats, &channel_stats, it](const aos::Context &context,
87 const void * /* message */) {
88 channel_stats[it].max_message_size =
89 std::max(channel_stats[it].max_message_size, context.size);
90 channel_stats[it].total_message_size += context.size;
91 channel_stats[it].total_num_messages++;
92 // asume messages are send in sequence per channel
93 channel_stats[it].channel_end_time = context.realtime_event_time;
94 channel_stats[it].first_message_time =
95 std::min(channel_stats[it].first_message_time,
96 context.monotonic_event_time);
97 channel_stats[it].current_message_time =
98 context.monotonic_event_time;
99 // update the overall logfile statistics
100 logfile_stats.logfile_length += context.size;
101 });
102 // TODO (Stephan): Frequency of messages per second
103 // - Sliding window
104 // - Max / Deviation
105 found_channel = true;
106 }
107 }
108 if (!found_channel) {
109 LOG(FATAL) << "Could not find any channels";
110 }
111
112 log_reader_factory.Run();
113
114 // Print out the stats per channel and for the logfile
115 for (size_t i = 0; i != channel_stats.size(); i++) {
116 if (channel_stats[i].total_num_messages > 0) {
117 double sec_active =
118 aos::time::DurationInSeconds(channel_stats[i].current_message_time -
119 channel_stats[i].first_message_time);
120 channel_stats[i].avg_messages_sec =
121 (channel_stats[i].total_num_messages / sec_active);
122 logfile_stats.total_log_messages += channel_stats[i].total_num_messages;
123 logfile_stats.logfile_end_time = std::max(
124 logfile_stats.logfile_end_time, channel_stats[i].channel_end_time);
125 std::cout << "Channel name: "
126 << channel_stats[i].channel->name()->string_view()
127 << "\tMsg type: "
128 << channel_stats[i].channel->type()->string_view() << "\n"
129 << "Number of msg: " << channel_stats[i].total_num_messages
130 << std::setprecision(3) << std::fixed
131 << "\tAvg msg per sec: " << channel_stats[i].avg_messages_sec
132 << "\tSet max msg frequency: "
133 << channel_stats[i].channel->frequency() << "\n"
134 << "Avg msg size: "
135 << (channel_stats[i].total_message_size /
136 channel_stats[i].total_num_messages)
137 << "\tMax msg size: " << channel_stats[i].max_message_size
138 << "\tSet max msg size: "
139 << channel_stats[i].channel->max_size() << "\n"
140 << "First msg time: " << channel_stats[i].first_message_time
141 << "\tLast msg time: " << channel_stats[i].current_message_time
142 << "\tSeconds active: " << sec_active << "sec\n";
143 } else {
144 std::cout << "Channel name: "
145 << channel_stats[i].channel->name()->string_view() << "\t"
146 << "Msg type: "
147 << channel_stats[i].channel->type()->string_view() << "\n"
148 << "Set max msg frequency: "
149 << channel_stats[i].channel->frequency() << "\t"
150 << "Set max msg size: " << channel_stats[i].channel->max_size()
151 << "\n--- No messages in channel ---"
152 << "\n";
153 }
154 }
155 std::cout << std::setfill('-') << std::setw(80) << "-"
156 << "\nLogfile statistics for: " << FLAGS_logfile << "\n"
157 << "Log starts at:\t" << reader.realtime_start_time() << "\n"
158 << "Log ends at:\t" << logfile_stats.logfile_end_time << "\n"
159 << "Log file size:\t" << logfile_stats.logfile_length << "\n"
160 << "Total messages:\t" << logfile_stats.total_log_messages << "\n";
161
162 // Cleanup the created processes
163 reader.Deregister();
164 aos::Cleanup();
165 return 0;
166}