blob: 2a53f05b800c5e4a532cbe8bec79f30bfd945b37 [file] [log] [blame]
Austin Schuhb06f03b2021-02-17 22:00:37 -08001#include "aos/events/logging/log_writer.h"
2
Austin Schuh6bb8a822021-03-31 23:04:39 -07003#include <dirent.h>
4
Austin Schuhb06f03b2021-02-17 22:00:37 -08005#include <functional>
6#include <map>
7#include <vector>
8
9#include "aos/configuration.h"
10#include "aos/events/event_loop.h"
11#include "aos/network/message_bridge_server_generated.h"
12#include "aos/network/team_number.h"
Austin Schuh61e973f2021-02-21 21:43:56 -080013#include "aos/network/timestamp_channel.h"
Austin Schuhb06f03b2021-02-17 22:00:37 -080014
15namespace aos {
16namespace logger {
17namespace {
18using message_bridge::RemoteMessage;
Austin Schuhbd06ae42021-03-31 22:48:21 -070019namespace chrono = std::chrono;
Austin Schuhb06f03b2021-02-17 22:00:37 -080020} // namespace
21
22Logger::Logger(EventLoop *event_loop, const Configuration *configuration,
23 std::function<bool(const Channel *)> should_log)
24 : event_loop_(event_loop),
25 configuration_(configuration),
Austin Schuh5b728b72021-06-16 14:57:15 -070026 node_(configuration::GetNode(configuration_, event_loop->node())),
27 node_index_(configuration::GetNodeIndex(configuration_, node_)),
Austin Schuhb06f03b2021-02-17 22:00:37 -080028 name_(network::GetHostname()),
29 timer_handler_(event_loop_->AddTimer(
Austin Schuh30586902021-03-30 22:54:08 -070030 [this]() { DoLogData(event_loop_->monotonic_now(), true); })),
Austin Schuhb06f03b2021-02-17 22:00:37 -080031 server_statistics_fetcher_(
32 configuration::MultiNode(event_loop_->configuration())
33 ? event_loop_->MakeFetcher<message_bridge::ServerStatistics>(
34 "/aos")
35 : aos::Fetcher<message_bridge::ServerStatistics>()) {
Austin Schuh58646e22021-08-23 23:51:46 -070036 timer_handler_->set_name("channel_poll");
Austin Schuh5b728b72021-06-16 14:57:15 -070037 VLOG(1) << "Creating logger for " << FlatbufferToJson(node_);
Austin Schuhb06f03b2021-02-17 22:00:37 -080038
Austin Schuh01f3b392022-01-25 20:03:09 -080039 // When we are logging remote timestamps, we need to be able to translate from
40 // the channel index that the event loop uses to the channel index in the
41 // config in the log file.
42 event_loop_to_logged_channel_index_.resize(
43 event_loop->configuration()->channels()->size(), -1);
44 for (size_t event_loop_channel_index = 0;
45 event_loop_channel_index <
46 event_loop->configuration()->channels()->size();
47 ++event_loop_channel_index) {
48 const Channel *event_loop_channel =
49 event_loop->configuration()->channels()->Get(event_loop_channel_index);
50
51 const Channel *logged_channel = aos::configuration::GetChannel(
52 configuration_, event_loop_channel->name()->string_view(),
53 event_loop_channel->type()->string_view(), "", node_);
54
55 if (logged_channel != nullptr) {
56 event_loop_to_logged_channel_index_[event_loop_channel_index] =
57 configuration::ChannelIndex(configuration_, logged_channel);
58 }
59 }
60
61 // Map to match source channels with the timestamp logger, if the contents
62 // should be reliable, and a list of all channels logged on it to be treated
63 // as reliable.
64 std::map<const Channel *, std::tuple<const Node *, bool, std::vector<bool>>>
65 timestamp_logger_channels;
Austin Schuhb06f03b2021-02-17 22:00:37 -080066
Austin Schuh61e973f2021-02-21 21:43:56 -080067 message_bridge::ChannelTimestampFinder finder(event_loop_);
68 for (const Channel *channel : *event_loop_->configuration()->channels()) {
69 if (!configuration::ChannelIsSendableOnNode(channel, event_loop_->node())) {
Austin Schuhb06f03b2021-02-17 22:00:37 -080070 continue;
71 }
Austin Schuh61e973f2021-02-21 21:43:56 -080072 if (!channel->has_destination_nodes()) {
73 continue;
74 }
Austin Schuh01f3b392022-01-25 20:03:09 -080075 const size_t channel_index =
76 configuration::ChannelIndex(event_loop_->configuration(), channel);
77
Austin Schuh61e973f2021-02-21 21:43:56 -080078 for (const Connection *connection : *channel->destination_nodes()) {
79 if (configuration::ConnectionDeliveryTimeIsLoggedOnNode(
80 connection, event_loop_->node())) {
81 const Node *other_node = configuration::GetNode(
Austin Schuh5b728b72021-06-16 14:57:15 -070082 configuration_, connection->name()->string_view());
Austin Schuh61e973f2021-02-21 21:43:56 -080083
84 VLOG(1) << "Timestamps are logged from "
85 << FlatbufferToJson(other_node);
Austin Schuh01f3b392022-01-25 20:03:09 -080086 // True if each channel's remote timestamps are split into a separate
87 // RemoteMessage channel.
88 const bool is_split =
89 finder.SplitChannelForChannel(channel, connection) != nullptr;
90
91 const Channel *const timestamp_logger_channel =
92 finder.ForChannel(channel, connection);
93
94 auto it = timestamp_logger_channels.find(timestamp_logger_channel);
95 if (it != timestamp_logger_channels.end()) {
96 CHECK(!is_split);
97 CHECK_LT(channel_index, std::get<2>(it->second).size());
Brian Smartt796cca02022-04-12 15:07:21 -070098 std::get<2>(it->second)[channel_index] =
99 (connection->time_to_live() == 0);
Austin Schuh01f3b392022-01-25 20:03:09 -0800100 } else {
101 if (is_split) {
102 timestamp_logger_channels.insert(std::make_pair(
103 timestamp_logger_channel,
104 std::make_tuple(other_node, (connection->time_to_live() == 0),
105 std::vector<bool>())));
106 } else {
107 std::vector<bool> channel_reliable_contents(
108 event_loop->configuration()->channels()->size(), false);
109 channel_reliable_contents[channel_index] =
110 (connection->time_to_live() == 0);
111
112 timestamp_logger_channels.insert(std::make_pair(
113 timestamp_logger_channel,
114 std::make_tuple(other_node, false,
115 std::move(channel_reliable_contents))));
116 }
117 }
Austin Schuh61e973f2021-02-21 21:43:56 -0800118 }
119 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800120 }
121
Austin Schuhb06f03b2021-02-17 22:00:37 -0800122 for (size_t channel_index = 0;
123 channel_index < configuration_->channels()->size(); ++channel_index) {
124 const Channel *const config_channel =
125 configuration_->channels()->Get(channel_index);
126 // The MakeRawFetcher method needs a channel which is in the event loop
127 // configuration() object, not the configuration_ object. Go look that up
128 // from the config.
129 const Channel *channel = aos::configuration::GetChannel(
130 event_loop_->configuration(), config_channel->name()->string_view(),
131 config_channel->type()->string_view(), "", event_loop_->node());
132 CHECK(channel != nullptr)
133 << ": Failed to look up channel "
134 << aos::configuration::CleanedChannelToString(config_channel);
Austin Schuh5b728b72021-06-16 14:57:15 -0700135 if (!should_log(config_channel)) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800136 continue;
137 }
138
139 FetcherStruct fs;
140 fs.channel_index = channel_index;
141 fs.channel = channel;
142
143 const bool is_local =
Austin Schuh5b728b72021-06-16 14:57:15 -0700144 configuration::ChannelIsSendableOnNode(config_channel, node_);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800145
146 const bool is_readable =
Austin Schuh5b728b72021-06-16 14:57:15 -0700147 configuration::ChannelIsReadableOnNode(config_channel, node_);
Austin Schuh01f3b392022-01-25 20:03:09 -0800148 const bool is_logged =
149 configuration::ChannelMessageIsLoggedOnNode(config_channel, node_);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800150 const bool log_message = is_logged && is_readable;
151
152 bool log_delivery_times = false;
Austin Schuh5b728b72021-06-16 14:57:15 -0700153 if (configuration::MultiNode(configuration_)) {
Austin Schuh72211ae2021-08-05 14:02:30 -0700154 const aos::Connection *connection =
Austin Schuh5b728b72021-06-16 14:57:15 -0700155 configuration::ConnectionToNode(config_channel, node_);
Austin Schuh72211ae2021-08-05 14:02:30 -0700156
Austin Schuhb06f03b2021-02-17 22:00:37 -0800157 log_delivery_times = configuration::ConnectionDeliveryTimeIsLoggedOnNode(
Austin Schuh72211ae2021-08-05 14:02:30 -0700158 connection, event_loop_->node());
159
160 CHECK_EQ(log_delivery_times,
161 configuration::ConnectionDeliveryTimeIsLoggedOnNode(
Austin Schuh5b728b72021-06-16 14:57:15 -0700162 config_channel, node_, node_));
Austin Schuh72211ae2021-08-05 14:02:30 -0700163
164 if (connection) {
165 fs.reliable_forwarding = (connection->time_to_live() == 0);
166 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800167 }
168
Austin Schuh01f3b392022-01-25 20:03:09 -0800169 // Now, detect a RemoteMessage timestamp logger where we should just log
170 // the contents to a file directly.
Austin Schuhb06f03b2021-02-17 22:00:37 -0800171 const bool log_contents = timestamp_logger_channels.find(channel) !=
172 timestamp_logger_channels.end();
173
174 if (log_message || log_delivery_times || log_contents) {
175 fs.fetcher = event_loop->MakeRawFetcher(channel);
176 VLOG(1) << "Logging channel "
177 << configuration::CleanedChannelToString(channel);
178
179 if (log_delivery_times) {
180 VLOG(1) << " Delivery times";
181 fs.wants_timestamp_writer = true;
Austin Schuh5b728b72021-06-16 14:57:15 -0700182 fs.timestamp_node_index = static_cast<int>(node_index_);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800183 }
Austin Schuhe46492f2021-07-31 19:49:41 -0700184 // Both the timestamp and data writers want data_node_index so it knows
185 // what the source node is.
186 if (log_message || log_delivery_times) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800187 if (!is_local) {
188 const Node *source_node = configuration::GetNode(
189 configuration_, channel->source_node()->string_view());
190 fs.data_node_index =
191 configuration::GetNodeIndex(configuration_, source_node);
Austin Schuhe46492f2021-07-31 19:49:41 -0700192 }
193 }
194 if (log_message) {
195 VLOG(1) << " Data";
196 fs.wants_writer = true;
197 if (!is_local) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800198 fs.log_type = LogType::kLogRemoteMessage;
199 } else {
Austin Schuh5b728b72021-06-16 14:57:15 -0700200 fs.data_node_index = static_cast<int>(node_index_);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800201 }
202 }
203 if (log_contents) {
204 VLOG(1) << "Timestamp logger channel "
205 << configuration::CleanedChannelToString(channel);
Austin Schuh01f3b392022-01-25 20:03:09 -0800206 auto timestamp_logger_channel_info =
207 timestamp_logger_channels.find(channel);
208 CHECK(timestamp_logger_channel_info != timestamp_logger_channels.end());
209 fs.timestamp_node = std::get<0>(timestamp_logger_channel_info->second);
210 fs.reliable_contents =
211 std::get<1>(timestamp_logger_channel_info->second);
212 fs.channel_reliable_contents =
213 std::get<2>(timestamp_logger_channel_info->second);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800214 fs.wants_contents_writer = true;
215 fs.contents_node_index =
216 configuration::GetNodeIndex(configuration_, fs.timestamp_node);
217 }
218 fetchers_.emplace_back(std::move(fs));
219 }
220 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800221}
222
223Logger::~Logger() {
224 if (log_namer_) {
225 // If we are replaying a log file, or in simulation, we want to force the
226 // last bit of data to be logged. The easiest way to deal with this is to
Austin Schuh01f3b392022-01-25 20:03:09 -0800227 // poll everything as we go to destroy the class, ie, shut down the
228 // logger, and write it to disk.
Austin Schuhb06f03b2021-02-17 22:00:37 -0800229 StopLogging(event_loop_->monotonic_now());
230 }
231}
232
Austin Schuh6bb8a822021-03-31 23:04:39 -0700233bool Logger::RenameLogBase(std::string new_base_name) {
234 if (new_base_name == log_namer_->base_name()) {
235 return true;
236 }
237 std::string current_directory = std::string(log_namer_->base_name());
238 std::string new_directory = new_base_name;
239
240 auto current_path_split = current_directory.rfind("/");
241 auto new_path_split = new_directory.rfind("/");
242
243 CHECK(new_base_name.substr(new_path_split) ==
244 current_directory.substr(current_path_split))
245 << "Rename of file base from " << current_directory << " to "
246 << new_directory << " is not supported.";
247
248 current_directory.resize(current_path_split);
249 new_directory.resize(new_path_split);
250 DIR *dir = opendir(current_directory.c_str());
251 if (dir) {
252 closedir(dir);
253 const int result = rename(current_directory.c_str(), new_directory.c_str());
254 if (result != 0) {
255 PLOG(ERROR) << "Unable to rename " << current_directory << " to "
256 << new_directory;
257 return false;
258 }
259 } else {
260 // Handle if directory was already renamed.
261 dir = opendir(new_directory.c_str());
262 if (!dir) {
263 LOG(ERROR) << "Old directory " << current_directory
264 << " missing and new directory " << new_directory
265 << " not present.";
266 return false;
267 }
268 closedir(dir);
269 }
270
271 log_namer_->set_base_name(new_base_name);
272 Rotate();
273 return true;
274}
275
Brian Smartt796cca02022-04-12 15:07:21 -0700276std::string Logger::WriteConfiguration(LogNamer *log_namer) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800277 std::string config_sha256;
Brian Smartt03c00da2022-02-24 10:25:00 -0800278
Austin Schuhb06f03b2021-02-17 22:00:37 -0800279 if (separate_config_) {
280 flatbuffers::FlatBufferBuilder fbb;
281 flatbuffers::Offset<aos::Configuration> configuration_offset =
282 CopyFlatBuffer(configuration_, &fbb);
283 LogFileHeader::Builder log_file_header_builder(fbb);
284 log_file_header_builder.add_configuration(configuration_offset);
285 fbb.FinishSizePrefixed(log_file_header_builder.Finish());
286 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config_header(
287 fbb.Release());
288 config_sha256 = Sha256(config_header.span());
289 LOG(INFO) << "Config sha256 of " << config_sha256;
Brian Smartt03c00da2022-02-24 10:25:00 -0800290 log_namer->WriteConfiguration(&config_header, config_sha256);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800291 }
292
Brian Smartt03c00da2022-02-24 10:25:00 -0800293 return config_sha256;
294}
295
296void Logger::StartLogging(std::unique_ptr<LogNamer> log_namer,
297 std::optional<UUID> log_start_uuid) {
298 CHECK(!log_namer_) << ": Already logging";
299
300 VLOG(1) << "Starting logger for " << FlatbufferToJson(node_);
301
302 auto config_sha256 = WriteConfiguration(log_namer.get());
303
304 log_namer_ = std::move(log_namer);
305
Austin Schuhb06f03b2021-02-17 22:00:37 -0800306 log_event_uuid_ = UUID::Random();
307 log_start_uuid_ = log_start_uuid;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800308
309 // We want to do as much work as possible before the initial Fetch. Time
310 // between that and actually starting to log opens up the possibility of
311 // falling off the end of the queue during that time.
312
313 for (FetcherStruct &f : fetchers_) {
314 if (f.wants_writer) {
315 f.writer = log_namer_->MakeWriter(f.channel);
316 }
317 if (f.wants_timestamp_writer) {
318 f.timestamp_writer = log_namer_->MakeTimestampWriter(f.channel);
319 }
320 if (f.wants_contents_writer) {
321 f.contents_writer = log_namer_->MakeForwardedTimestampWriter(
322 f.channel, CHECK_NOTNULL(f.timestamp_node));
323 }
324 }
325
Austin Schuh73340842021-07-30 22:32:06 -0700326 log_namer_->SetHeaderTemplate(MakeHeader(config_sha256));
Austin Schuhb06f03b2021-02-17 22:00:37 -0800327
Austin Schuha42ee962021-03-31 22:49:30 -0700328 const aos::monotonic_clock::time_point beginning_time =
329 event_loop_->monotonic_now();
330
Austin Schuhb06f03b2021-02-17 22:00:37 -0800331 // Grab data from each channel right before we declare the log file started
332 // so we can capture the latest message on each channel. This lets us have
333 // non periodic messages with configuration that now get logged.
334 for (FetcherStruct &f : fetchers_) {
335 const auto start = event_loop_->monotonic_now();
336 const bool got_new = f.fetcher->Fetch();
337 const auto end = event_loop_->monotonic_now();
338 RecordFetchResult(start, end, got_new, &f);
339
340 // If there is a message, we want to write it.
341 f.written = f.fetcher->context().data == nullptr;
342 }
343
344 // Clear out any old timestamps in case we are re-starting logging.
Austin Schuh572924a2021-07-30 22:32:12 -0700345 for (size_t i = 0; i < configuration::NodesCount(configuration_); ++i) {
Austin Schuh58646e22021-08-23 23:51:46 -0700346 log_namer_->ClearStartTimes();
Austin Schuhb06f03b2021-02-17 22:00:37 -0800347 }
348
Austin Schuha42ee962021-03-31 22:49:30 -0700349 const aos::monotonic_clock::time_point fetch_time =
350 event_loop_->monotonic_now();
Austin Schuhb06f03b2021-02-17 22:00:37 -0800351 WriteHeader();
Austin Schuha42ee962021-03-31 22:49:30 -0700352 const aos::monotonic_clock::time_point header_time =
353 event_loop_->monotonic_now();
Austin Schuhb06f03b2021-02-17 22:00:37 -0800354
Brian Smartt796cca02022-04-12 15:07:21 -0700355 VLOG(1) << "Logging node as " << FlatbufferToJson(node_) << " start_time "
356 << last_synchronized_time_ << ", took "
Brian Smartt03c00da2022-02-24 10:25:00 -0800357 << chrono::duration<double>(fetch_time - beginning_time).count()
358 << " to fetch, "
359 << chrono::duration<double>(header_time - fetch_time).count()
360 << " to write headers, boot uuid " << event_loop_->boot_uuid();
Austin Schuhb06f03b2021-02-17 22:00:37 -0800361
362 // Force logging up until the start of the log file now, so the messages at
363 // the start are always ordered before the rest of the messages.
364 // Note: this ship may have already sailed, but we don't have to make it
365 // worse.
366 // TODO(austin): Test...
Austin Schuh855f8932021-03-19 22:01:32 -0700367 //
368 // This is safe to call here since we have set last_synchronized_time_ as the
369 // same time as in the header, and all the data before it should be logged
370 // without ordering concerns.
Austin Schuhb06f03b2021-02-17 22:00:37 -0800371 LogUntil(last_synchronized_time_);
372
373 timer_handler_->Setup(event_loop_->monotonic_now() + polling_period_,
374 polling_period_);
375}
376
Brian Smartt796cca02022-04-12 15:07:21 -0700377std::unique_ptr<LogNamer> Logger::RestartLogging(
378 std::unique_ptr<LogNamer> log_namer, std::optional<UUID> log_start_uuid) {
Brian Smartt03c00da2022-02-24 10:25:00 -0800379 CHECK(log_namer_) << ": Unexpected restart while not logging";
380
381 VLOG(1) << "Restarting logger for " << FlatbufferToJson(node_);
382
383 // Force out every currently pending message, pointing all fetchers at the
384 // last (currently available) records. Note that LogUntil() updates
385 // last_synchronized_time_ to the time value that it receives.
Brian Smartt796cca02022-04-12 15:07:21 -0700386 while (LogUntil(last_synchronized_time_ + polling_period_))
387 ;
Brian Smartt03c00da2022-02-24 10:25:00 -0800388
389 std::unique_ptr<LogNamer> old_log_namer = std::move(log_namer_);
390 log_namer_ = std::move(log_namer);
391
Austin Schuh41f8df92022-04-15 11:45:52 -0700392 // Now grab a representative time on both the RT and monotonic clock. Average
393 // a monotonic clock before and after to reduce the error.
Brian Smartt03c00da2022-02-24 10:25:00 -0800394 const aos::monotonic_clock::time_point beginning_time =
395 event_loop_->monotonic_now();
Austin Schuh41f8df92022-04-15 11:45:52 -0700396 const aos::realtime_clock::time_point beginning_time_rt =
397 event_loop_->realtime_now();
398 const aos::monotonic_clock::time_point beginning_time2 =
399 event_loop_->monotonic_now();
400
401 if (beginning_time > last_synchronized_time_) {
402 LOG(WARNING) << "Took over " << polling_period_.count()
403 << "ns to swap log_namer";
404 }
405
406 // Since we are going to log all in 1 big go, we need our log start time to be
407 // after the previous LogUntil call finished, but before 1 period after it.
408 // The best way to guarentee that is to pick a start time that is the earliest
409 // of the two. That covers the case where the OS puts us to sleep between
410 // when we finish LogUntil and capture beginning_time.
411 const aos::monotonic_clock::time_point monotonic_start_time =
412 std::min(last_synchronized_time_, beginning_time);
413 const aos::realtime_clock::time_point realtime_start_time =
414 (beginning_time_rt + (monotonic_start_time.time_since_epoch() -
415 ((beginning_time.time_since_epoch() +
416 beginning_time2.time_since_epoch()) /
417 2)));
Brian Smartt03c00da2022-02-24 10:25:00 -0800418
419 auto config_sha256 = WriteConfiguration(log_namer_.get());
420
421 log_event_uuid_ = UUID::Random();
422 log_start_uuid_ = log_start_uuid;
423
424 log_namer_->SetHeaderTemplate(MakeHeader(config_sha256));
425
426 // Note that WriteHeader updates last_synchronized_time_ to be the
427 // current time when it is called, which is then the "start time"
428 // of the new (restarted) log. This timestamp will be after
Austin Schuh41f8df92022-04-15 11:45:52 -0700429 // the timestamp of the last message fetched on each channel, but is carefully
430 // picked per the comment above to not violate max_out_of_order_duration.
431 WriteHeader(monotonic_start_time, realtime_start_time);
Brian Smartt03c00da2022-02-24 10:25:00 -0800432
433 const aos::monotonic_clock::time_point header_time =
434 event_loop_->monotonic_now();
435
436 // Write the transition record(s) for each channel ...
437 for (FetcherStruct &f : fetchers_) {
Brian Smartt03c00da2022-02-24 10:25:00 -0800438 // Create writers from the new namer
439 NewDataWriter *next_writer = nullptr;
440 NewDataWriter *next_timestamp_writer = nullptr;
441 NewDataWriter *next_contents_writer = nullptr;
442
443 if (f.wants_writer) {
444 next_writer = log_namer_->MakeWriter(f.channel);
445 }
446 if (f.wants_timestamp_writer) {
447 next_timestamp_writer = log_namer_->MakeTimestampWriter(f.channel);
448 }
449 if (f.wants_contents_writer) {
450 next_contents_writer = log_namer_->MakeForwardedTimestampWriter(
451 f.channel, CHECK_NOTNULL(f.timestamp_node));
452 }
453
454 if (f.fetcher->context().data != nullptr) {
Brian Smartt796cca02022-04-12 15:07:21 -0700455 // Write the last message fetched as the first of the new log of this
456 // type. The timestamps on these will all be before the new start time.
Brian Smartt03c00da2022-02-24 10:25:00 -0800457 WriteData(next_writer, f);
458 WriteTimestamps(next_timestamp_writer, f);
459 WriteContent(next_contents_writer, f);
460
Brian Smartt796cca02022-04-12 15:07:21 -0700461 // It is possible that a few more snuck in. Write them all out also,
462 // including any that should also be in the old log.
Brian Smartt03c00da2022-02-24 10:25:00 -0800463 while (true) {
Brian Smartt796cca02022-04-12 15:07:21 -0700464 // Get the next message ...
465 const auto start = event_loop_->monotonic_now();
466 const bool got_new = f.fetcher->FetchNext();
467 const auto end = event_loop_->monotonic_now();
468 RecordFetchResult(start, end, got_new, &f);
Brian Smartt03c00da2022-02-24 10:25:00 -0800469
Brian Smartt796cca02022-04-12 15:07:21 -0700470 if (got_new) {
471 if (f.fetcher->context().monotonic_event_time <=
472 last_synchronized_time_) {
473 WriteFetchedRecord(f);
Brian Smartt03c00da2022-02-24 10:25:00 -0800474 WriteData(next_writer, f);
475 WriteTimestamps(next_timestamp_writer, f);
476 WriteContent(next_contents_writer, f);
477
Brian Smartt03c00da2022-02-24 10:25:00 -0800478 } else {
Brian Smartt796cca02022-04-12 15:07:21 -0700479 f.written = false;
Brian Smartt03c00da2022-02-24 10:25:00 -0800480 break;
481 }
Brian Smartt796cca02022-04-12 15:07:21 -0700482
483 } else {
484 f.written = true;
485 break;
486 }
Brian Smartt03c00da2022-02-24 10:25:00 -0800487 }
488 }
489
490 // Switch fully over to the new writers.
491 f.writer = next_writer;
492 f.timestamp_writer = next_timestamp_writer;
493 f.contents_writer = next_contents_writer;
Brian Smartt03c00da2022-02-24 10:25:00 -0800494 }
495
496 const aos::monotonic_clock::time_point channel_time =
497 event_loop_->monotonic_now();
498
Brian Smartt796cca02022-04-12 15:07:21 -0700499 VLOG(1) << "Logging node as " << FlatbufferToJson(node_) << " restart_time "
500 << last_synchronized_time_ << ", took "
Brian Smartt03c00da2022-02-24 10:25:00 -0800501 << chrono::duration<double>(header_time - beginning_time).count()
502 << " to prepare and write header, "
503 << chrono::duration<double>(channel_time - header_time).count()
Brian Smartt796cca02022-04-12 15:07:21 -0700504 << " to write initial channel messages, boot uuid "
505 << event_loop_->boot_uuid();
Brian Smartt03c00da2022-02-24 10:25:00 -0800506
507 return old_log_namer;
508}
509
Austin Schuhb06f03b2021-02-17 22:00:37 -0800510std::unique_ptr<LogNamer> Logger::StopLogging(
511 aos::monotonic_clock::time_point end_time) {
512 CHECK(log_namer_) << ": Not logging right now";
513
514 if (end_time != aos::monotonic_clock::min_time) {
Austin Schuh30586902021-03-30 22:54:08 -0700515 // Folks like to use the on_logged_period_ callback to trigger stop and
516 // start events. We can't have those then recurse and try to stop again.
517 // Rather than making everything reentrant, let's just instead block the
518 // callback here.
519 DoLogData(end_time, false);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800520 }
521 timer_handler_->Disable();
522
523 for (FetcherStruct &f : fetchers_) {
524 f.writer = nullptr;
525 f.timestamp_writer = nullptr;
526 f.contents_writer = nullptr;
527 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800528
529 log_event_uuid_ = UUID::Zero();
Austin Schuh34f9e482021-03-31 22:54:18 -0700530 log_start_uuid_ = std::nullopt;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800531
532 return std::move(log_namer_);
533}
534
Austin Schuh41f8df92022-04-15 11:45:52 -0700535void Logger::WriteHeader(aos::monotonic_clock::time_point monotonic_start_time,
536 aos::realtime_clock::time_point realtime_start_time) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800537 if (configuration::MultiNode(configuration_)) {
538 server_statistics_fetcher_.Fetch();
539 }
540
Austin Schuh41f8df92022-04-15 11:45:52 -0700541 if (monotonic_start_time == aos::monotonic_clock::min_time) {
542 monotonic_start_time = event_loop_->monotonic_now();
543 realtime_start_time = event_loop_->realtime_now();
544 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800545
546 // We need to pick a point in time to declare the log file "started". This
547 // starts here. It needs to be after everything is fetched so that the
548 // fetchers are all pointed at the most recent message before the start
549 // time.
550 last_synchronized_time_ = monotonic_start_time;
551
552 for (const Node *node : log_namer_->nodes()) {
553 const int node_index = configuration::GetNodeIndex(configuration_, node);
554 MaybeUpdateTimestamp(node, node_index, monotonic_start_time,
555 realtime_start_time);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800556 }
557}
558
Austin Schuhb06f03b2021-02-17 22:00:37 -0800559void Logger::WriteMissingTimestamps() {
560 if (configuration::MultiNode(configuration_)) {
561 server_statistics_fetcher_.Fetch();
562 } else {
563 return;
564 }
565
566 if (server_statistics_fetcher_.get() == nullptr) {
567 return;
568 }
569
570 for (const Node *node : log_namer_->nodes()) {
571 const int node_index = configuration::GetNodeIndex(configuration_, node);
572 if (MaybeUpdateTimestamp(
573 node, node_index,
574 server_statistics_fetcher_.context().monotonic_event_time,
575 server_statistics_fetcher_.context().realtime_event_time)) {
Austin Schuh58646e22021-08-23 23:51:46 -0700576 VLOG(1) << "Timestamps changed on " << aos::FlatbufferToJson(node);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800577 }
578 }
579}
580
Austin Schuhb06f03b2021-02-17 22:00:37 -0800581bool Logger::MaybeUpdateTimestamp(
582 const Node *node, int node_index,
583 aos::monotonic_clock::time_point monotonic_start_time,
584 aos::realtime_clock::time_point realtime_start_time) {
585 // Bail early if the start times are already set.
Austin Schuh58646e22021-08-23 23:51:46 -0700586 if (node_ == node || !configuration::MultiNode(configuration_)) {
587 if (log_namer_->monotonic_start_time(node_index,
588 event_loop_->boot_uuid()) !=
589 monotonic_clock::min_time) {
590 return false;
591 }
Brian Smartt03c00da2022-02-24 10:25:00 -0800592
Austin Schuhb06f03b2021-02-17 22:00:37 -0800593 // There are no offsets to compute for ourself, so always succeed.
Austin Schuh58646e22021-08-23 23:51:46 -0700594 log_namer_->SetStartTimes(node_index, event_loop_->boot_uuid(),
595 monotonic_start_time, realtime_start_time,
596 monotonic_start_time, realtime_start_time);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800597 return true;
598 } else if (server_statistics_fetcher_.get() != nullptr) {
599 // We must be a remote node now. Look for the connection and see if it is
600 // connected.
James Kuszmaul17607fb2021-10-15 20:00:32 -0700601 CHECK(server_statistics_fetcher_->has_connections());
Austin Schuhb06f03b2021-02-17 22:00:37 -0800602
603 for (const message_bridge::ServerConnection *connection :
604 *server_statistics_fetcher_->connections()) {
605 if (connection->node()->name()->string_view() !=
606 node->name()->string_view()) {
607 continue;
608 }
609
610 if (connection->state() != message_bridge::State::CONNECTED) {
611 VLOG(1) << node->name()->string_view()
612 << " is not connected, can't start it yet.";
613 break;
614 }
615
Austin Schuhb06f03b2021-02-17 22:00:37 -0800616 if (!connection->has_monotonic_offset()) {
617 VLOG(1) << "Missing monotonic offset for setting start time for node "
618 << aos::FlatbufferToJson(node);
619 break;
620 }
621
James Kuszmaul17607fb2021-10-15 20:00:32 -0700622 CHECK(connection->has_boot_uuid());
Austin Schuh58646e22021-08-23 23:51:46 -0700623 const UUID boot_uuid =
624 UUID::FromString(connection->boot_uuid()->string_view());
625
626 if (log_namer_->monotonic_start_time(node_index, boot_uuid) !=
627 monotonic_clock::min_time) {
628 break;
629 }
630
631 VLOG(1) << "Updating start time for "
632 << aos::FlatbufferToJson(connection);
633
Austin Schuhb06f03b2021-02-17 22:00:37 -0800634 // Found it and it is connected. Compensate and go.
Austin Schuh73340842021-07-30 22:32:06 -0700635 log_namer_->SetStartTimes(
Austin Schuh58646e22021-08-23 23:51:46 -0700636 node_index, boot_uuid,
Austin Schuh73340842021-07-30 22:32:06 -0700637 monotonic_start_time +
638 std::chrono::nanoseconds(connection->monotonic_offset()),
639 realtime_start_time, monotonic_start_time, realtime_start_time);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800640 return true;
641 }
642 }
643 return false;
644}
645
646aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> Logger::MakeHeader(
Austin Schuh73340842021-07-30 22:32:06 -0700647 std::string_view config_sha256) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800648 flatbuffers::FlatBufferBuilder fbb;
649 fbb.ForceDefaults(true);
650
651 flatbuffers::Offset<aos::Configuration> configuration_offset;
652 if (!separate_config_) {
653 configuration_offset = CopyFlatBuffer(configuration_, &fbb);
654 } else {
655 CHECK(!config_sha256.empty());
656 }
657
658 const flatbuffers::Offset<flatbuffers::String> name_offset =
659 fbb.CreateString(name_);
660
661 CHECK(log_event_uuid_ != UUID::Zero());
662 const flatbuffers::Offset<flatbuffers::String> log_event_uuid_offset =
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800663 log_event_uuid_.PackString(&fbb);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800664
665 const flatbuffers::Offset<flatbuffers::String> logger_instance_uuid_offset =
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800666 logger_instance_uuid_.PackString(&fbb);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800667
668 flatbuffers::Offset<flatbuffers::String> log_start_uuid_offset;
Austin Schuh34f9e482021-03-31 22:54:18 -0700669 if (log_start_uuid_) {
670 log_start_uuid_offset = fbb.CreateString(log_start_uuid_->ToString());
Austin Schuhb06f03b2021-02-17 22:00:37 -0800671 }
672
673 flatbuffers::Offset<flatbuffers::String> config_sha256_offset;
674 if (!config_sha256.empty()) {
675 config_sha256_offset = fbb.CreateString(config_sha256);
676 }
677
678 const flatbuffers::Offset<flatbuffers::String> logger_node_boot_uuid_offset =
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800679 event_loop_->boot_uuid().PackString(&fbb);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800680
Austin Schuhb06f03b2021-02-17 22:00:37 -0800681 flatbuffers::Offset<Node> logger_node_offset;
682
683 if (configuration::MultiNode(configuration_)) {
Austin Schuh5b728b72021-06-16 14:57:15 -0700684 logger_node_offset = RecursiveCopyFlatBuffer(node_, &fbb);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800685 }
686
687 aos::logger::LogFileHeader::Builder log_file_header_builder(fbb);
688
689 log_file_header_builder.add_name(name_offset);
690
691 // Only add the node if we are running in a multinode configuration.
Austin Schuh73340842021-07-30 22:32:06 -0700692 if (configuration::MultiNode(configuration_)) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800693 log_file_header_builder.add_logger_node(logger_node_offset);
694 }
695
696 if (!configuration_offset.IsNull()) {
697 log_file_header_builder.add_configuration(configuration_offset);
698 }
699 // The worst case theoretical out of order is the polling period times 2.
700 // One message could get logged right after the boundary, but be for right
701 // before the next boundary. And the reverse could happen for another
702 // message. Report back 3x to be extra safe, and because the cost isn't
703 // huge on the read side.
704 log_file_header_builder.add_max_out_of_order_duration(
705 std::chrono::nanoseconds(3 * polling_period_).count());
706
Austin Schuhb06f03b2021-02-17 22:00:37 -0800707 log_file_header_builder.add_log_event_uuid(log_event_uuid_offset);
708 log_file_header_builder.add_logger_instance_uuid(logger_instance_uuid_offset);
709 if (!log_start_uuid_offset.IsNull()) {
710 log_file_header_builder.add_log_start_uuid(log_start_uuid_offset);
711 }
712 log_file_header_builder.add_logger_node_boot_uuid(
713 logger_node_boot_uuid_offset);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800714
715 if (!config_sha256_offset.IsNull()) {
716 log_file_header_builder.add_configuration_sha256(config_sha256_offset);
717 }
718
719 fbb.FinishSizePrefixed(log_file_header_builder.Finish());
720 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> result(
721 fbb.Release());
722
723 CHECK(result.Verify()) << ": Built a corrupted header.";
724
725 return result;
726}
727
728void Logger::ResetStatisics() {
729 max_message_fetch_time_ = std::chrono::nanoseconds::zero();
730 max_message_fetch_time_channel_ = -1;
731 max_message_fetch_time_size_ = -1;
732 total_message_fetch_time_ = std::chrono::nanoseconds::zero();
733 total_message_fetch_count_ = 0;
734 total_message_fetch_bytes_ = 0;
735 total_nop_fetch_time_ = std::chrono::nanoseconds::zero();
736 total_nop_fetch_count_ = 0;
737 max_copy_time_ = std::chrono::nanoseconds::zero();
738 max_copy_time_channel_ = -1;
739 max_copy_time_size_ = -1;
740 total_copy_time_ = std::chrono::nanoseconds::zero();
741 total_copy_count_ = 0;
742 total_copy_bytes_ = 0;
743}
744
745void Logger::Rotate() {
746 for (const Node *node : log_namer_->nodes()) {
Austin Schuh73340842021-07-30 22:32:06 -0700747 log_namer_->Rotate(node);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800748 }
749}
750
Brian Smartt03c00da2022-02-24 10:25:00 -0800751void Logger::WriteData(NewDataWriter *writer, const FetcherStruct &f) {
752 if (writer != nullptr) {
753 const UUID source_node_boot_uuid =
754 static_cast<int>(node_index_) != f.data_node_index
755 ? f.fetcher->context().source_boot_uuid
756 : event_loop_->boot_uuid();
757 // Write!
758 const auto start = event_loop_->monotonic_now();
759 flatbuffers::FlatBufferBuilder fbb(f.fetcher->context().size +
760 max_header_size_);
761 fbb.ForceDefaults(true);
762
Brian Smartt796cca02022-04-12 15:07:21 -0700763 fbb.FinishSizePrefixed(
764 PackMessage(&fbb, f.fetcher->context(), f.channel_index, f.log_type));
Brian Smartt03c00da2022-02-24 10:25:00 -0800765 const auto end = event_loop_->monotonic_now();
766 RecordCreateMessageTime(start, end, f);
767
Brian Smartt796cca02022-04-12 15:07:21 -0700768 max_header_size_ =
769 std::max(max_header_size_, fbb.GetSize() - f.fetcher->context().size);
Brian Smartt03c00da2022-02-24 10:25:00 -0800770 writer->QueueMessage(&fbb, source_node_boot_uuid, end);
771
Brian Smartt796cca02022-04-12 15:07:21 -0700772 VLOG(2) << "Wrote data as node " << FlatbufferToJson(node_)
773 << " for channel "
Brian Smartt03c00da2022-02-24 10:25:00 -0800774 << configuration::CleanedChannelToString(f.fetcher->channel())
775 << " to " << writer->filename() << " data "
Brian Smartt796cca02022-04-12 15:07:21 -0700776 << FlatbufferToJson(flatbuffers::GetSizePrefixedRoot<MessageHeader>(
777 fbb.GetBufferPointer()));
Brian Smartt03c00da2022-02-24 10:25:00 -0800778 }
779}
780
Brian Smartt796cca02022-04-12 15:07:21 -0700781void Logger::WriteTimestamps(NewDataWriter *timestamp_writer,
782 const FetcherStruct &f) {
Brian Smartt03c00da2022-02-24 10:25:00 -0800783 if (timestamp_writer != nullptr) {
784 // And now handle timestamps.
785 const auto start = event_loop_->monotonic_now();
786 flatbuffers::FlatBufferBuilder fbb;
787 fbb.ForceDefaults(true);
788
789 fbb.FinishSizePrefixed(PackMessage(&fbb, f.fetcher->context(),
790 f.channel_index,
791 LogType::kLogDeliveryTimeOnly));
792 const auto end = event_loop_->monotonic_now();
793 RecordCreateMessageTime(start, end, f);
794
795 // Tell our writer that we know something about the remote boot.
796 timestamp_writer->UpdateRemote(
797 f.data_node_index, f.fetcher->context().source_boot_uuid,
798 f.fetcher->context().monotonic_remote_time,
799 f.fetcher->context().monotonic_event_time, f.reliable_forwarding);
800 timestamp_writer->QueueMessage(&fbb, event_loop_->boot_uuid(), end);
801
Brian Smartt796cca02022-04-12 15:07:21 -0700802 VLOG(2) << "Wrote timestamps as node " << FlatbufferToJson(node_)
803 << " for channel "
Brian Smartt03c00da2022-02-24 10:25:00 -0800804 << configuration::CleanedChannelToString(f.fetcher->channel())
805 << " to " << timestamp_writer->filename() << " timestamp "
Brian Smartt796cca02022-04-12 15:07:21 -0700806 << FlatbufferToJson(flatbuffers::GetSizePrefixedRoot<MessageHeader>(
807 fbb.GetBufferPointer()));
Brian Smartt03c00da2022-02-24 10:25:00 -0800808 }
809}
810
Brian Smartt796cca02022-04-12 15:07:21 -0700811void Logger::WriteContent(NewDataWriter *contents_writer,
812 const FetcherStruct &f) {
Brian Smartt03c00da2022-02-24 10:25:00 -0800813 if (contents_writer != nullptr) {
814 const auto start = event_loop_->monotonic_now();
815 // And now handle the special message contents channel. Copy the
816 // message into a FlatBufferBuilder and save it to disk.
817 // TODO(austin): We can be more efficient here when we start to
818 // care...
819 flatbuffers::FlatBufferBuilder fbb;
820 fbb.ForceDefaults(true);
821
822 const RemoteMessage *msg =
823 flatbuffers::GetRoot<RemoteMessage>(f.fetcher->context().data);
824
825 CHECK(msg->has_boot_uuid()) << ": " << aos::FlatbufferToJson(msg);
826
827 logger::MessageHeader::Builder message_header_builder(fbb);
828
829 // TODO(austin): This needs to check the channel_index and confirm
830 // that it should be logged before squirreling away the timestamp to
831 // disk. We don't want to log irrelevant timestamps.
832
833 // Note: this must match the same order as MessageBridgeServer and
834 // PackMessage. We want identical headers to have identical
835 // on-the-wire formats to make comparing them easier.
836
837 // Translate from the channel index that the event loop uses to the
838 // channel index in the log file.
839 message_header_builder.add_channel_index(
840 event_loop_to_logged_channel_index_[msg->channel_index()]);
841
842 message_header_builder.add_queue_index(msg->queue_index());
843 message_header_builder.add_monotonic_sent_time(msg->monotonic_sent_time());
844 message_header_builder.add_realtime_sent_time(msg->realtime_sent_time());
845
846 message_header_builder.add_monotonic_remote_time(
847 msg->monotonic_remote_time());
848 message_header_builder.add_realtime_remote_time(
849 msg->realtime_remote_time());
850 message_header_builder.add_remote_queue_index(msg->remote_queue_index());
851
852 const aos::monotonic_clock::time_point monotonic_timestamp_time =
853 f.fetcher->context().monotonic_event_time;
854 message_header_builder.add_monotonic_timestamp_time(
855 monotonic_timestamp_time.time_since_epoch().count());
856
857 fbb.FinishSizePrefixed(message_header_builder.Finish());
858 const auto end = event_loop_->monotonic_now();
859 RecordCreateMessageTime(start, end, f);
860
861 // Timestamps tell us information about what happened too!
862 // Capture any reboots so UpdateRemote is properly recorded.
863 contents_writer->UpdateBoot(UUID::FromVector(msg->boot_uuid()));
864
865 // Start with recording info about the data flowing from our node to the
866 // remote.
867 const bool reliable =
868 f.channel_reliable_contents.size() != 0u
869 ? f.channel_reliable_contents[msg->channel_index()]
870 : f.reliable_contents;
871
Brian Smartt796cca02022-04-12 15:07:21 -0700872 contents_writer->UpdateRemote(
873 node_index_, event_loop_->boot_uuid(),
Brian Smartt03c00da2022-02-24 10:25:00 -0800874 monotonic_clock::time_point(
875 chrono::nanoseconds(msg->monotonic_remote_time())),
876 monotonic_clock::time_point(
877 chrono::nanoseconds(msg->monotonic_sent_time())),
878 reliable, monotonic_timestamp_time);
879
Brian Smartt796cca02022-04-12 15:07:21 -0700880 contents_writer->QueueMessage(&fbb, UUID::FromVector(msg->boot_uuid()),
881 end);
Brian Smartt03c00da2022-02-24 10:25:00 -0800882 }
883}
884
885void Logger::WriteFetchedRecord(FetcherStruct &f) {
886 WriteData(f.writer, f);
887 WriteTimestamps(f.timestamp_writer, f);
888 WriteContent(f.contents_writer, f);
889}
890
891bool Logger::LogUntil(monotonic_clock::time_point t) {
892 bool has_pending_messages = false;
893
Austin Schuhb06f03b2021-02-17 22:00:37 -0800894 // Grab the latest ServerStatistics message. This will always have the
895 // oppertunity to be >= to the current time, so it will always represent any
896 // reboots which may have happened.
897 WriteMissingTimestamps();
898
899 // Write each channel to disk, one at a time.
900 for (FetcherStruct &f : fetchers_) {
901 while (true) {
902 if (f.written) {
903 const auto start = event_loop_->monotonic_now();
904 const bool got_new = f.fetcher->FetchNext();
905 const auto end = event_loop_->monotonic_now();
906 RecordFetchResult(start, end, got_new, &f);
907 if (!got_new) {
908 VLOG(2) << "No new data on "
909 << configuration::CleanedChannelToString(
910 f.fetcher->channel());
911 break;
912 }
913 f.written = false;
914 }
915
916 // TODO(james): Write tests to exercise this logic.
917 if (f.fetcher->context().monotonic_event_time >= t) {
Brian Smartt03c00da2022-02-24 10:25:00 -0800918 has_pending_messages = true;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800919 break;
920 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800921
Brian Smartt03c00da2022-02-24 10:25:00 -0800922 WriteFetchedRecord(f);
Austin Schuhb06f03b2021-02-17 22:00:37 -0800923
924 f.written = true;
925 }
926 }
927 last_synchronized_time_ = t;
Brian Smartt03c00da2022-02-24 10:25:00 -0800928
929 return has_pending_messages;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800930}
931
Austin Schuh30586902021-03-30 22:54:08 -0700932void Logger::DoLogData(const monotonic_clock::time_point end_time,
933 bool run_on_logged) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800934 // We want to guarantee that messages aren't out of order by more than
935 // max_out_of_order_duration. To do this, we need sync points. Every write
936 // cycle should be a sync point.
937
938 do {
939 // Move the sync point up by at most polling_period. This forces one sync
940 // per iteration, even if it is small.
941 LogUntil(std::min(last_synchronized_time_ + polling_period_, end_time));
942
Austin Schuh30586902021-03-30 22:54:08 -0700943 if (run_on_logged) {
944 on_logged_period_();
945 }
Austin Schuhb06f03b2021-02-17 22:00:37 -0800946
947 // If we missed cycles, we could be pretty far behind. Spin until we are
948 // caught up.
949 } while (last_synchronized_time_ + polling_period_ < end_time);
950}
951
952void Logger::RecordFetchResult(aos::monotonic_clock::time_point start,
953 aos::monotonic_clock::time_point end,
954 bool got_new, FetcherStruct *fetcher) {
955 const auto duration = end - start;
956 if (!got_new) {
957 ++total_nop_fetch_count_;
958 total_nop_fetch_time_ += duration;
959 return;
960 }
961 ++total_message_fetch_count_;
962 total_message_fetch_bytes_ += fetcher->fetcher->context().size;
963 total_message_fetch_time_ += duration;
964 if (duration > max_message_fetch_time_) {
965 max_message_fetch_time_ = duration;
966 max_message_fetch_time_channel_ = fetcher->channel_index;
967 max_message_fetch_time_size_ = fetcher->fetcher->context().size;
968 }
969}
970
971void Logger::RecordCreateMessageTime(aos::monotonic_clock::time_point start,
972 aos::monotonic_clock::time_point end,
Brian Smartt03c00da2022-02-24 10:25:00 -0800973 const FetcherStruct &fetcher) {
Austin Schuhb06f03b2021-02-17 22:00:37 -0800974 const auto duration = end - start;
975 total_copy_time_ += duration;
976 ++total_copy_count_;
Brian Smartt03c00da2022-02-24 10:25:00 -0800977 total_copy_bytes_ += fetcher.fetcher->context().size;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800978 if (duration > max_copy_time_) {
979 max_copy_time_ = duration;
Brian Smartt03c00da2022-02-24 10:25:00 -0800980 max_copy_time_channel_ = fetcher.channel_index;
981 max_copy_time_size_ = fetcher.fetcher->context().size;
Austin Schuhb06f03b2021-02-17 22:00:37 -0800982 }
983}
984
985} // namespace logger
986} // namespace aos