blob: 2067bdc10924e6eed3e49c1c327c07f376f338de [file] [log] [blame]
Austin Schuhcb5601b2020-09-10 15:29:59 -07001#include "aos/events/logging/log_namer.h"
2
3#include <functional>
4#include <map>
5#include <memory>
6#include <string_view>
7#include <vector>
8
9#include "absl/strings/str_cat.h"
10#include "aos/events/logging/logfile_utils.h"
11#include "aos/events/logging/logger_generated.h"
Austin Schuh4385b142021-03-14 21:31:13 -070012#include "aos/uuid.h"
Austin Schuhcb5601b2020-09-10 15:29:59 -070013#include "flatbuffers/flatbuffers.h"
14#include "glog/logging.h"
15
16namespace aos {
17namespace logger {
18
19void LogNamer::UpdateHeader(
20 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
21 const UUID &uuid, int parts_index) const {
22 header->mutable_message()->mutate_parts_index(parts_index);
Austin Schuh5e2bfb82021-03-13 22:46:55 -080023 CHECK_EQ(UUID::kStringSize,
Austin Schuhcb5601b2020-09-10 15:29:59 -070024 header->mutable_message()->mutable_parts_uuid()->size());
Austin Schuh5e2bfb82021-03-13 22:46:55 -080025 uuid.CopyTo(reinterpret_cast<char *>(
26 header->mutable_message()->mutable_parts_uuid()->Data()));
Austin Schuhcb5601b2020-09-10 15:29:59 -070027}
28
29void LocalLogNamer::WriteHeader(
30 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
31 const Node *node) {
32 CHECK_EQ(node, this->node());
33 UpdateHeader(header, uuid_, part_number_);
Austin Schuhadd6eb32020-11-09 21:24:26 -080034 data_writer_->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -070035}
36
37DetachedBufferWriter *LocalLogNamer::MakeWriter(const Channel *channel) {
Austin Schuhdf576472020-10-19 09:39:37 -070038 CHECK(configuration::ChannelIsSendableOnNode(channel, node()))
39 << ": " << configuration::CleanedChannelToString(channel);
Austin Schuhcb5601b2020-09-10 15:29:59 -070040 return data_writer_.get();
41}
42
43void LocalLogNamer::Rotate(
44 const Node *node,
45 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) {
46 CHECK(node == this->node());
47 ++part_number_;
48 *data_writer_ = std::move(*OpenDataWriter());
49 UpdateHeader(header, uuid_, part_number_);
Austin Schuhadd6eb32020-11-09 21:24:26 -080050 data_writer_->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -070051}
Austin Schuh8c399962020-12-25 21:51:45 -080052
53void LocalLogNamer::WriteConfiguration(
54 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
55 std::string_view config_sha256) {
56 const std::string filename = absl::StrCat(base_name_, config_sha256, ".bfbs");
57
58 std::unique_ptr<DetachedBufferWriter> writer =
59 std::make_unique<DetachedBufferWriter>(
60 filename, std::make_unique<aos::logger::DummyEncoder>());
61 writer->QueueSizedFlatbuffer(header->Release());
62}
63
Austin Schuh315b96b2020-12-11 21:21:12 -080064void LocalLogNamer::Reboot(
65 const Node * /*node*/,
66 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> * /*header*/) {
67 LOG(FATAL) << "Can't reboot a single node.";
68}
Austin Schuhcb5601b2020-09-10 15:29:59 -070069
70DetachedBufferWriter *LocalLogNamer::MakeTimestampWriter(
71 const Channel *channel) {
72 CHECK(configuration::ChannelIsReadableOnNode(channel, node_))
73 << ": Message is not delivered to this node.";
74 CHECK(node_ != nullptr) << ": Can't log timestamps in a single node world";
75 CHECK(configuration::ConnectionDeliveryTimeIsLoggedOnNode(channel, node_,
76 node_))
77 << ": Delivery times aren't logged for this channel on this node.";
78 return data_writer_.get();
79}
80
81DetachedBufferWriter *LocalLogNamer::MakeForwardedTimestampWriter(
82 const Channel * /*channel*/, const Node * /*node*/) {
83 LOG(FATAL) << "Can't log forwarded timestamps in a singe log file.";
84 return nullptr;
85}
86
87MultiNodeLogNamer::MultiNodeLogNamer(std::string_view base_name,
88 const Configuration *configuration,
Brian Silvermancb805822020-10-06 17:43:35 -070089 const Node *node)
90 : LogNamer(node), base_name_(base_name), configuration_(configuration) {}
Austin Schuhcb5601b2020-09-10 15:29:59 -070091
Brian Silverman48deab12020-09-30 18:39:28 -070092MultiNodeLogNamer::~MultiNodeLogNamer() {
93 if (!ran_out_of_space_) {
94 // This handles renaming temporary files etc.
95 Close();
96 }
97}
98
Austin Schuhcb5601b2020-09-10 15:29:59 -070099void MultiNodeLogNamer::WriteHeader(
100 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
101 const Node *node) {
102 if (node == this->node()) {
Brian Silvermancb805822020-10-06 17:43:35 -0700103 if (!data_writer_.writer) {
104 OpenDataWriter();
105 }
106 UpdateHeader(header, data_writer_.uuid, data_writer_.part_number);
Austin Schuhadd6eb32020-11-09 21:24:26 -0800107 data_writer_.writer->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700108 } else {
109 for (std::pair<const Channel *const, DataWriter> &data_writer :
110 data_writers_) {
111 if (node == data_writer.second.node) {
112 UpdateHeader(header, data_writer.second.uuid,
113 data_writer.second.part_number);
Austin Schuhadd6eb32020-11-09 21:24:26 -0800114 data_writer.second.writer->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700115 }
116 }
117 }
118}
119
120void MultiNodeLogNamer::Rotate(
121 const Node *node,
122 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800123 DoRotate(node, header, false);
124}
125
126void MultiNodeLogNamer::Reboot(
127 const Node *node,
128 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) {
129 DoRotate(node, header, true);
130}
131
132void MultiNodeLogNamer::DoRotate(
133 const Node *node,
Austin Schuh8c399962020-12-25 21:51:45 -0800134 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
135 bool reboot) {
Austin Schuhcb5601b2020-09-10 15:29:59 -0700136 if (node == this->node()) {
Brian Silvermancb805822020-10-06 17:43:35 -0700137 if (data_writer_.writer) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800138 if (reboot) {
139 data_writer_.uuid = UUID::Random();
140 }
Brian Silvermancb805822020-10-06 17:43:35 -0700141 ++data_writer_.part_number;
142 }
Brian Silvermana621f522020-09-30 16:52:43 -0700143 OpenDataWriter();
Brian Silvermancb805822020-10-06 17:43:35 -0700144 UpdateHeader(header, data_writer_.uuid, data_writer_.part_number);
Austin Schuhadd6eb32020-11-09 21:24:26 -0800145 data_writer_.writer->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700146 } else {
147 for (std::pair<const Channel *const, DataWriter> &data_writer :
148 data_writers_) {
149 if (node == data_writer.second.node) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800150 if (reboot) {
151 data_writer.second.uuid = UUID::Random();
152 }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700153 ++data_writer.second.part_number;
154 data_writer.second.rotate(data_writer.first, &data_writer.second);
155 UpdateHeader(header, data_writer.second.uuid,
156 data_writer.second.part_number);
Austin Schuhadd6eb32020-11-09 21:24:26 -0800157 data_writer.second.writer->QueueSpan(header->span());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700158 }
159 }
160 }
161}
162
Austin Schuh8c399962020-12-25 21:51:45 -0800163void MultiNodeLogNamer::WriteConfiguration(
164 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
165 std::string_view config_sha256) {
166 if (ran_out_of_space_) {
167 return;
168 }
169
170 const std::string_view separator = base_name_.back() == '/' ? "" : "_";
171 const std::string filename = absl::StrCat(
172 base_name_, separator, config_sha256, ".bfbs", extension_, temp_suffix_);
173
174 std::unique_ptr<DetachedBufferWriter> writer =
175 std::make_unique<DetachedBufferWriter>(filename, encoder_factory_());
176
177 writer->QueueSizedFlatbuffer(header->Release());
178
179 if (!writer->ran_out_of_space()) {
180 all_filenames_.emplace_back(filename);
181 }
182 CloseWriter(&writer);
183}
184
Austin Schuhcb5601b2020-09-10 15:29:59 -0700185DetachedBufferWriter *MultiNodeLogNamer::MakeWriter(const Channel *channel) {
186 // See if we can read the data on this node at all.
187 const bool is_readable =
188 configuration::ChannelIsReadableOnNode(channel, this->node());
189 if (!is_readable) {
190 return nullptr;
191 }
192
193 // Then, see if we are supposed to log the data here.
194 const bool log_message =
195 configuration::ChannelMessageIsLoggedOnNode(channel, this->node());
196
197 if (!log_message) {
198 return nullptr;
199 }
200
201 // Now, sort out if this is data generated on this node, or not. It is
202 // generated if it is sendable on this node.
203 if (configuration::ChannelIsSendableOnNode(channel, this->node())) {
Brian Silvermancb805822020-10-06 17:43:35 -0700204 if (!data_writer_.writer) {
205 OpenDataWriter();
206 }
207 return data_writer_.writer.get();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700208 }
209
210 // Ok, we have data that is being forwarded to us that we are supposed to
211 // log. It needs to be logged with send timestamps, but be sorted enough
212 // to be able to be processed.
213 CHECK(data_writers_.find(channel) == data_writers_.end());
214
215 // Track that this node is being logged.
216 const Node *source_node = configuration::GetNode(
217 configuration_, channel->source_node()->string_view());
218
219 if (std::find(nodes_.begin(), nodes_.end(), source_node) == nodes_.end()) {
220 nodes_.emplace_back(source_node);
221 }
222
223 DataWriter data_writer;
224 data_writer.node = source_node;
225 data_writer.rotate = [this](const Channel *channel, DataWriter *data_writer) {
226 OpenWriter(channel, data_writer);
227 };
228 data_writer.rotate(channel, &data_writer);
229
230 return data_writers_.insert(std::make_pair(channel, std::move(data_writer)))
231 .first->second.writer.get();
232}
233
234DetachedBufferWriter *MultiNodeLogNamer::MakeForwardedTimestampWriter(
235 const Channel *channel, const Node *node) {
236 // See if we can read the data on this node at all.
237 const bool is_readable =
238 configuration::ChannelIsReadableOnNode(channel, this->node());
239 CHECK(is_readable) << ": " << configuration::CleanedChannelToString(channel);
240
241 CHECK(data_writers_.find(channel) == data_writers_.end());
242
243 if (std::find(nodes_.begin(), nodes_.end(), node) == nodes_.end()) {
244 nodes_.emplace_back(node);
245 }
246
247 DataWriter data_writer;
248 data_writer.node = node;
249 data_writer.rotate = [this](const Channel *channel, DataWriter *data_writer) {
250 OpenForwardedTimestampWriter(channel, data_writer);
251 };
252 data_writer.rotate(channel, &data_writer);
253
254 return data_writers_.insert(std::make_pair(channel, std::move(data_writer)))
255 .first->second.writer.get();
256}
257
258DetachedBufferWriter *MultiNodeLogNamer::MakeTimestampWriter(
259 const Channel *channel) {
Brian Silverman0465fcf2020-09-24 00:29:18 -0700260 bool log_delivery_times = false;
261 if (this->node() != nullptr) {
262 log_delivery_times = configuration::ConnectionDeliveryTimeIsLoggedOnNode(
263 channel, this->node(), this->node());
264 }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700265 if (!log_delivery_times) {
266 return nullptr;
267 }
268
Brian Silvermancb805822020-10-06 17:43:35 -0700269 if (!data_writer_.writer) {
270 OpenDataWriter();
271 }
272 return data_writer_.writer.get();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700273}
274
Brian Silverman0465fcf2020-09-24 00:29:18 -0700275void MultiNodeLogNamer::Close() {
276 for (std::pair<const Channel *const, DataWriter> &data_writer :
277 data_writers_) {
Brian Silvermancb805822020-10-06 17:43:35 -0700278 CloseWriter(&data_writer.second.writer);
279 data_writer.second.writer.reset();
Brian Silverman0465fcf2020-09-24 00:29:18 -0700280 }
Brian Silvermancb805822020-10-06 17:43:35 -0700281 CloseWriter(&data_writer_.writer);
282 data_writer_.writer.reset();
283}
284
285void MultiNodeLogNamer::ResetStatistics() {
286 for (std::pair<const Channel *const, DataWriter> &data_writer :
287 data_writers_) {
Austin Schuhad0cfc32020-12-21 12:34:26 -0800288 if (!data_writer.second.writer) continue;
Brian Silvermancb805822020-10-06 17:43:35 -0700289 data_writer.second.writer->ResetStatistics();
Brian Silverman0465fcf2020-09-24 00:29:18 -0700290 }
Brian Silvermancb805822020-10-06 17:43:35 -0700291 if (data_writer_.writer) {
292 data_writer_.writer->ResetStatistics();
293 }
294 max_write_time_ = std::chrono::nanoseconds::zero();
295 max_write_time_bytes_ = -1;
296 max_write_time_messages_ = -1;
297 total_write_time_ = std::chrono::nanoseconds::zero();
298 total_write_count_ = 0;
299 total_write_messages_ = 0;
300 total_write_bytes_ = 0;
Brian Silverman0465fcf2020-09-24 00:29:18 -0700301}
302
Austin Schuhcb5601b2020-09-10 15:29:59 -0700303void MultiNodeLogNamer::OpenForwardedTimestampWriter(const Channel *channel,
304 DataWriter *data_writer) {
305 std::string filename =
Austin Schuhe715eae2020-10-10 15:39:30 -0700306 absl::StrCat("timestamps", channel->name()->string_view(), "/",
Brian Silvermana621f522020-09-30 16:52:43 -0700307 channel->type()->string_view(), ".part",
Brian Silverman1b071eb2020-10-09 12:24:10 -0700308 data_writer->part_number, ".bfbs", extension_);
Brian Silverman0465fcf2020-09-24 00:29:18 -0700309 CreateBufferWriter(filename, &data_writer->writer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700310}
311
312void MultiNodeLogNamer::OpenWriter(const Channel *channel,
313 DataWriter *data_writer) {
314 const std::string filename = absl::StrCat(
Austin Schuhe715eae2020-10-10 15:39:30 -0700315 CHECK_NOTNULL(channel->source_node())->string_view(), "_data",
Brian Silvermana621f522020-09-30 16:52:43 -0700316 channel->name()->string_view(), "/", channel->type()->string_view(),
Brian Silvermancb805822020-10-06 17:43:35 -0700317 ".part", data_writer->part_number, ".bfbs", extension_);
Brian Silverman0465fcf2020-09-24 00:29:18 -0700318 CreateBufferWriter(filename, &data_writer->writer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700319}
320
Brian Silvermana621f522020-09-30 16:52:43 -0700321void MultiNodeLogNamer::OpenDataWriter() {
322 std::string name;
Brian Silverman7af8c902020-09-29 16:14:04 -0700323 if (node() != nullptr) {
Austin Schuhe715eae2020-10-10 15:39:30 -0700324 name = absl::StrCat(name, node()->name()->string_view(), "_");
Brian Silverman7af8c902020-09-29 16:14:04 -0700325 }
Austin Schuhe715eae2020-10-10 15:39:30 -0700326 absl::StrAppend(&name, "data.part", data_writer_.part_number, ".bfbs",
Brian Silvermancb805822020-10-06 17:43:35 -0700327 extension_);
328 CreateBufferWriter(name, &data_writer_.writer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700329}
330
Brian Silverman0465fcf2020-09-24 00:29:18 -0700331void MultiNodeLogNamer::CreateBufferWriter(
Brian Silvermana621f522020-09-30 16:52:43 -0700332 std::string_view path, std::unique_ptr<DetachedBufferWriter> *destination) {
Brian Silverman0465fcf2020-09-24 00:29:18 -0700333 if (ran_out_of_space_) {
334 // Refuse to open any new files, which might skip data. Any existing files
335 // are in the same folder, which means they're on the same filesystem, which
336 // means they're probably going to run out of space and get stuck too.
Austin Schuha426f1f2021-03-31 22:27:41 -0700337 if (!destination->get()) {
338 // But avoid leaving a nullptr writer if we're out of space when
339 // attempting to open the first file.
340 *destination = std::make_unique<DetachedBufferWriter>(
341 DetachedBufferWriter::already_out_of_space_t());
342 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700343 return;
344 }
Austin Schuhe715eae2020-10-10 15:39:30 -0700345 const std::string_view separator = base_name_.back() == '/' ? "" : "_";
346 const std::string filename =
347 absl::StrCat(base_name_, separator, path, temp_suffix_);
Brian Silverman0465fcf2020-09-24 00:29:18 -0700348 if (!destination->get()) {
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700349 if (ran_out_of_space_) {
350 *destination = std::make_unique<DetachedBufferWriter>(
351 DetachedBufferWriter::already_out_of_space_t());
352 return;
353 }
Brian Silvermancb805822020-10-06 17:43:35 -0700354 *destination =
355 std::make_unique<DetachedBufferWriter>(filename, encoder_factory_());
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700356 if (!destination->get()->ran_out_of_space()) {
357 all_filenames_.emplace_back(path);
358 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700359 return;
360 }
Brian Silvermancb805822020-10-06 17:43:35 -0700361
362 CloseWriter(destination);
363 if (ran_out_of_space_) {
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700364 *destination->get() =
365 DetachedBufferWriter(DetachedBufferWriter::already_out_of_space_t());
Brian Silverman0465fcf2020-09-24 00:29:18 -0700366 return;
367 }
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700368
Brian Silvermancb805822020-10-06 17:43:35 -0700369 *destination->get() = DetachedBufferWriter(filename, encoder_factory_());
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700370 if (!destination->get()->ran_out_of_space()) {
371 all_filenames_.emplace_back(path);
372 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700373}
374
Brian Silverman48deab12020-09-30 18:39:28 -0700375void MultiNodeLogNamer::RenameTempFile(DetachedBufferWriter *destination) {
376 if (temp_suffix_.empty()) {
377 return;
378 }
379 const std::string current_filename = std::string(destination->filename());
380 CHECK(current_filename.size() > temp_suffix_.size());
381 const std::string final_filename =
382 current_filename.substr(0, current_filename.size() - temp_suffix_.size());
383 const int result = rename(current_filename.c_str(), final_filename.c_str());
384 if (result != 0) {
385 if (errno == ENOSPC) {
386 ran_out_of_space_ = true;
387 return;
388 } else {
389 PLOG(FATAL) << "Renaming " << current_filename << " to " << final_filename
390 << " failed";
391 }
392 }
393}
394
Brian Silvermancb805822020-10-06 17:43:35 -0700395void MultiNodeLogNamer::CloseWriter(
396 std::unique_ptr<DetachedBufferWriter> *writer_pointer) {
397 DetachedBufferWriter *const writer = writer_pointer->get();
398 if (!writer) {
399 return;
400 }
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700401 const bool was_open = writer->is_open();
Brian Silvermancb805822020-10-06 17:43:35 -0700402 writer->Close();
403
404 if (writer->max_write_time() > max_write_time_) {
405 max_write_time_ = writer->max_write_time();
406 max_write_time_bytes_ = writer->max_write_time_bytes();
407 max_write_time_messages_ = writer->max_write_time_messages();
408 }
409 total_write_time_ += writer->total_write_time();
410 total_write_count_ += writer->total_write_count();
411 total_write_messages_ += writer->total_write_messages();
412 total_write_bytes_ += writer->total_write_bytes();
413
414 if (writer->ran_out_of_space()) {
415 ran_out_of_space_ = true;
416 writer->acknowledge_out_of_space();
417 }
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700418 if (was_open) {
419 RenameTempFile(writer);
420 } else {
421 CHECK(access(std::string(writer->filename()).c_str(), F_OK) == -1)
422 << ": File should not exist: " << writer->filename();
423 }
Brian Silvermancb805822020-10-06 17:43:35 -0700424}
425
Austin Schuhcb5601b2020-09-10 15:29:59 -0700426} // namespace logger
427} // namespace aos