blob: 3b2c83c8d8718dd21457ea5d0e070072c2a601df [file] [log] [blame]
Austin Schuhcb5601b2020-09-10 15:29:59 -07001#ifndef AOS_EVENTS_LOGGING_LOG_NAMER_H_
2#define AOS_EVENTS_LOGGING_LOG_NAMER_H_
3
4#include <functional>
5#include <map>
6#include <memory>
7#include <string_view>
8#include <vector>
9
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
15namespace aos {
16namespace logger {
17
18// Interface describing how to name, track, and add headers to log file parts.
19class LogNamer {
20 public:
21 // Constructs a LogNamer with the primary node (ie the one the logger runs on)
22 // being node.
23 LogNamer(const Node *node) : node_(node) { nodes_.emplace_back(node_); }
24 virtual ~LogNamer() {}
25
Austin Schuh6bb8a822021-03-31 23:04:39 -070026 virtual std::string_view base_name() const = 0;
27
28 // Rotate should be called at least once in between calls to set_base_name.
29 // Otherwise temporary files will not be recoverable.
30 // Rotate is called by Logger::RenameLogBase, which is currently the only user
31 // of this method.
32 // Only renaming the folder is supported, not the file base name.
33 virtual void set_base_name(std::string_view base_name) = 0;
34
Austin Schuhcb5601b2020-09-10 15:29:59 -070035 // Writes the header to all log files for a specific node. This function
36 // needs to be called after all the writers are created.
37 //
38 // Modifies header to contain the uuid and part number for each writer as it
39 // writes it. Since this is done unconditionally, it does not restore the
40 // previous value at the end.
41 virtual void WriteHeader(
42 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
43 const Node *node) = 0;
44
Brian Silverman87ac0402020-09-17 14:47:01 -070045 // Returns a writer for writing data from messages on this channel (on the
46 // primary node).
47 //
48 // The returned pointer will stay valid across rotations, but the object it
49 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070050 virtual DetachedBufferWriter *MakeWriter(const Channel *channel) = 0;
51
Brian Silverman87ac0402020-09-17 14:47:01 -070052 // Returns a writer for writing timestamps from messages on this channel (on
53 // the primary node).
54 //
55 // The returned pointer will stay valid across rotations, but the object it
56 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070057 virtual DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) = 0;
58
59 // Returns a writer for writing timestamps delivered over the special
60 // /aos/remote_timestamps/* channels. node is the node that the timestamps
Brian Silverman87ac0402020-09-17 14:47:01 -070061 // are forwarded back from (to the primary node).
62 //
63 // The returned pointer will stay valid across rotations, but the object it
64 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070065 virtual DetachedBufferWriter *MakeForwardedTimestampWriter(
66 const Channel *channel, const Node *node) = 0;
67
68 // Rotates all log files for the provided node. The provided header will be
69 // modified and written per WriteHeader above.
70 virtual void Rotate(
71 const Node *node,
72 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) = 0;
73
Austin Schuh315b96b2020-12-11 21:21:12 -080074 // Reboots all log files for the provided node. The provided header will be
75 // modified and written per WriteHeader above. Resets any parts UUIDs.
76 virtual void Reboot(
77 const Node *node,
78 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) = 0;
79
Austin Schuhcb5601b2020-09-10 15:29:59 -070080 // Returns all the nodes that data is being written for.
81 const std::vector<const Node *> &nodes() const { return nodes_; }
82
83 // Returns the node the logger is running on.
84 const Node *node() const { return node_; }
85
Austin Schuh8c399962020-12-25 21:51:45 -080086 // Writes out the nested Configuration object to the config file location.
87 virtual void WriteConfiguration(
88 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
89 std::string_view config_sha256) = 0;
90
Austin Schuhcb5601b2020-09-10 15:29:59 -070091 protected:
92 // Modifies the header to have the provided UUID and part id.
93 void UpdateHeader(
94 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
95 const UUID &uuid, int part_id) const;
96
97 const Node *const node_;
98 std::vector<const Node *> nodes_;
99};
100
101// Local log namer is a simple version which only names things
102// "base_name.part#.bfbs" and increments the part number. It doesn't support
103// any other log type.
104class LocalLogNamer : public LogNamer {
105 public:
106 LocalLogNamer(std::string_view base_name, const Node *node)
107 : LogNamer(node),
108 base_name_(base_name),
109 uuid_(UUID::Random()),
110 data_writer_(OpenDataWriter()) {}
Brian Silverman0465fcf2020-09-24 00:29:18 -0700111 ~LocalLogNamer() override = default;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700112
Austin Schuh6bb8a822021-03-31 23:04:39 -0700113 std::string_view base_name() const final { return base_name_; }
114
115 void set_base_name(std::string_view base_name) final {
116 base_name_ = base_name;
117 }
118
Austin Schuhcb5601b2020-09-10 15:29:59 -0700119 void WriteHeader(
120 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
121 const Node *node) override;
122
123 DetachedBufferWriter *MakeWriter(const Channel *channel) override;
124
125 void Rotate(const Node *node,
126 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
127 override;
128
Austin Schuh315b96b2020-12-11 21:21:12 -0800129 void Reboot(const Node *node,
130 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
131 override;
132
Austin Schuhcb5601b2020-09-10 15:29:59 -0700133 DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) override;
134
135 DetachedBufferWriter *MakeForwardedTimestampWriter(
136 const Channel * /*channel*/, const Node * /*node*/) override;
137
Austin Schuh8c399962020-12-25 21:51:45 -0800138 void WriteConfiguration(
139 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
140 std::string_view config_sha256) override;
141
Austin Schuhcb5601b2020-09-10 15:29:59 -0700142 private:
143 // Creates a new data writer with the new part number.
144 std::unique_ptr<DetachedBufferWriter> OpenDataWriter() {
145 return std::make_unique<DetachedBufferWriter>(
Brian Silvermanf51499a2020-09-21 12:49:08 -0700146 absl::StrCat(base_name_, ".part", part_number_, ".bfbs"),
147 std::make_unique<aos::logger::DummyEncoder>());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700148 }
149
Austin Schuh6bb8a822021-03-31 23:04:39 -0700150 std::string base_name_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700151 const UUID uuid_;
152 size_t part_number_ = 0;
153 std::unique_ptr<DetachedBufferWriter> data_writer_;
154};
155
156// Log namer which uses a config and a base name to name a bunch of files.
157class MultiNodeLogNamer : public LogNamer {
158 public:
Brian Silvermancb805822020-10-06 17:43:35 -0700159 MultiNodeLogNamer(std::string_view base_name,
160 const Configuration *configuration, const Node *node);
161 ~MultiNodeLogNamer() override;
162
Austin Schuh6bb8a822021-03-31 23:04:39 -0700163 std::string_view base_name() const final { return base_name_; }
164
165 void set_base_name(std::string_view base_name) final {
166 old_base_name_ = base_name_;
167 base_name_ = base_name;
168 }
Brian Silvermancb805822020-10-06 17:43:35 -0700169
Brian Silverman48deab12020-09-30 18:39:28 -0700170 // If temp_suffix is set, then this will write files under names beginning
171 // with the specified suffix, and then rename them to the desired name after
172 // they are fully written.
173 //
174 // This is useful to enable incremental copying of the log files.
175 //
176 // Defaults to writing directly to the final filename.
Brian Silvermancb805822020-10-06 17:43:35 -0700177 void set_temp_suffix(std::string_view temp_suffix) {
178 temp_suffix_ = temp_suffix;
179 }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700180
Brian Silvermancb805822020-10-06 17:43:35 -0700181 // Sets the function for creating encoders.
182 //
183 // Defaults to just creating DummyEncoders.
184 void set_encoder_factory(
185 std::function<std::unique_ptr<DetachedBufferEncoder>()> encoder_factory) {
186 encoder_factory_ = std::move(encoder_factory);
187 }
188
189 // Sets an additional file extension.
190 //
191 // Defaults to nothing.
192 void set_extension(std::string_view extension) { extension_ = extension; }
Brian Silverman1f345222020-09-24 21:14:48 -0700193
Brian Silvermana621f522020-09-30 16:52:43 -0700194 // A list of all the filenames we've written.
195 //
196 // This only includes the part after base_name().
197 const std::vector<std::string> &all_filenames() const {
198 return all_filenames_;
199 }
200
Austin Schuhcb5601b2020-09-10 15:29:59 -0700201 void WriteHeader(
202 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
203 const Node *node) override;
204
205 void Rotate(const Node *node,
206 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
207 override;
208
Austin Schuh315b96b2020-12-11 21:21:12 -0800209 void Reboot(const Node *node,
210 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
211 override;
212
Austin Schuh8c399962020-12-25 21:51:45 -0800213 void WriteConfiguration(
214 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
215 std::string_view config_sha256) override;
216
Austin Schuhcb5601b2020-09-10 15:29:59 -0700217 DetachedBufferWriter *MakeWriter(const Channel *channel) override;
218
Brian Silvermand90905f2020-09-23 14:42:56 -0700219 DetachedBufferWriter *MakeForwardedTimestampWriter(const Channel *channel,
220 const Node *node) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700221
222 DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) override;
223
Brian Silverman0465fcf2020-09-24 00:29:18 -0700224 // Indicates that at least one file ran out of space. Once this happens, we
225 // stop trying to open new files, to avoid writing any files with holes from
226 // previous parts.
227 //
228 // Besides this function, this object will silently stop logging data when
229 // this occurs. If you want to ensure log files are complete, you must call
230 // this method.
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700231 bool ran_out_of_space() const {
232 return accumulate_data_writers<bool>(
233 ran_out_of_space_, [](bool x, const DataWriter &data_writer) {
234 return x ||
235 (data_writer.writer && data_writer.writer->ran_out_of_space());
236 });
237 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700238
Brian Silverman1f345222020-09-24 21:14:48 -0700239 // Returns the maximum total_bytes() value for all existing
240 // DetachedBufferWriters.
241 //
242 // Returns 0 if no files are open.
243 size_t maximum_total_bytes() const {
Brian Silvermancb805822020-10-06 17:43:35 -0700244 return accumulate_data_writers<size_t>(
245 0, [](size_t x, const DataWriter &data_writer) {
246 return std::max(x, data_writer.writer->total_bytes());
247 });
Brian Silverman1f345222020-09-24 21:14:48 -0700248 }
249
Brian Silverman0465fcf2020-09-24 00:29:18 -0700250 // Closes all existing log files. No more data may be written after this.
251 //
252 // This may set ran_out_of_space().
253 void Close();
254
Brian Silvermancb805822020-10-06 17:43:35 -0700255 // Accessors for various statistics. See the identically-named methods in
256 // DetachedBufferWriter for documentation. These are aggregated across all
257 // past and present DetachedBufferWriters.
258 std::chrono::nanoseconds max_write_time() const {
259 return accumulate_data_writers(
260 max_write_time_,
261 [](std::chrono::nanoseconds x, const DataWriter &data_writer) {
262 return std::max(x, data_writer.writer->max_write_time());
263 });
264 }
265 int max_write_time_bytes() const {
266 return std::get<0>(accumulate_data_writers(
267 std::make_tuple(max_write_time_bytes_, max_write_time_),
268 [](std::tuple<int, std::chrono::nanoseconds> x,
269 const DataWriter &data_writer) {
270 if (data_writer.writer->max_write_time() > std::get<1>(x)) {
271 return std::make_tuple(data_writer.writer->max_write_time_bytes(),
272 data_writer.writer->max_write_time());
273 }
274 return x;
275 }));
276 }
277 int max_write_time_messages() const {
278 return std::get<0>(accumulate_data_writers(
279 std::make_tuple(max_write_time_messages_, max_write_time_),
280 [](std::tuple<int, std::chrono::nanoseconds> x,
281 const DataWriter &data_writer) {
282 if (data_writer.writer->max_write_time() > std::get<1>(x)) {
283 return std::make_tuple(
284 data_writer.writer->max_write_time_messages(),
285 data_writer.writer->max_write_time());
286 }
287 return x;
288 }));
289 }
290 std::chrono::nanoseconds total_write_time() const {
291 return accumulate_data_writers(
292 total_write_time_,
293 [](std::chrono::nanoseconds x, const DataWriter &data_writer) {
294 return x + data_writer.writer->total_write_time();
295 });
296 }
297 int total_write_count() const {
298 return accumulate_data_writers(
299 total_write_count_, [](int x, const DataWriter &data_writer) {
300 return x + data_writer.writer->total_write_count();
301 });
302 }
303 int total_write_messages() const {
304 return accumulate_data_writers(
305 total_write_messages_, [](int x, const DataWriter &data_writer) {
306 return x + data_writer.writer->total_write_messages();
307 });
308 }
309 int total_write_bytes() const {
310 return accumulate_data_writers(
311 total_write_bytes_, [](int x, const DataWriter &data_writer) {
312 return x + data_writer.writer->total_write_bytes();
313 });
314 }
315
316 void ResetStatistics();
317
Austin Schuhcb5601b2020-09-10 15:29:59 -0700318 private:
319 // Files to write remote data to. We want one per channel. Maps the channel
320 // to the writer, Node, and part number.
321 struct DataWriter {
322 std::unique_ptr<DetachedBufferWriter> writer = nullptr;
323 const Node *node;
324 size_t part_number = 0;
Austin Schuh315b96b2020-12-11 21:21:12 -0800325 UUID uuid = UUID::Random();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700326 std::function<void(const Channel *, DataWriter *)> rotate;
327 };
328
Austin Schuh315b96b2020-12-11 21:21:12 -0800329 // Implements Rotate and Reboot, controlled by the 'reboot' flag. The only
330 // difference between the two is if DataWriter::uuid is reset or not.
331 void DoRotate(
332 const Node *node,
333 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
334 bool reboot);
335
Austin Schuhcb5601b2020-09-10 15:29:59 -0700336 // Opens up a writer for timestamps forwarded back.
337 void OpenForwardedTimestampWriter(const Channel *channel,
338 DataWriter *data_writer);
339
340 // Opens up a writer for remote data.
341 void OpenWriter(const Channel *channel, DataWriter *data_writer);
342
343 // Opens the main data writer file for this node responsible for data_writer_.
Brian Silvermana621f522020-09-30 16:52:43 -0700344 void OpenDataWriter();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700345
Brian Silvermana621f522020-09-30 16:52:43 -0700346 void CreateBufferWriter(std::string_view path,
Brian Silverman0465fcf2020-09-24 00:29:18 -0700347 std::unique_ptr<DetachedBufferWriter> *destination);
348
Brian Silverman48deab12020-09-30 18:39:28 -0700349 void RenameTempFile(DetachedBufferWriter *destination);
350
Brian Silvermancb805822020-10-06 17:43:35 -0700351 void CloseWriter(std::unique_ptr<DetachedBufferWriter> *writer_pointer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700352
Brian Silvermancb805822020-10-06 17:43:35 -0700353 // A version of std::accumulate which operates over all of our DataWriters.
354 template <typename T, typename BinaryOperation>
355 T accumulate_data_writers(T t, BinaryOperation op) const {
356 for (const std::pair<const Channel *const, DataWriter> &data_writer :
357 data_writers_) {
Austin Schuhad0cfc32020-12-21 12:34:26 -0800358 if (!data_writer.second.writer) continue;
Brian Silvermancb805822020-10-06 17:43:35 -0700359 t = op(std::move(t), data_writer.second);
360 }
361 if (data_writer_.writer) {
362 t = op(std::move(t), data_writer_);
363 }
364 return t;
365 }
366
Austin Schuh6bb8a822021-03-31 23:04:39 -0700367 std::string base_name_;
368 std::string old_base_name_;
Brian Silvermancb805822020-10-06 17:43:35 -0700369 const Configuration *const configuration_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700370
Brian Silverman0465fcf2020-09-24 00:29:18 -0700371 bool ran_out_of_space_ = false;
Brian Silvermana621f522020-09-30 16:52:43 -0700372 std::vector<std::string> all_filenames_;
Brian Silverman0465fcf2020-09-24 00:29:18 -0700373
Brian Silvermancb805822020-10-06 17:43:35 -0700374 std::string temp_suffix_;
375 std::function<std::unique_ptr<DetachedBufferEncoder>()> encoder_factory_ =
376 []() { return std::make_unique<DummyEncoder>(); };
377 std::string extension_;
378
379 // Storage for statistics from previously-rotated DetachedBufferWriters.
380 std::chrono::nanoseconds max_write_time_ = std::chrono::nanoseconds::zero();
381 int max_write_time_bytes_ = -1;
382 int max_write_time_messages_ = -1;
383 std::chrono::nanoseconds total_write_time_ = std::chrono::nanoseconds::zero();
384 int total_write_count_ = 0;
385 int total_write_messages_ = 0;
386 int total_write_bytes_ = 0;
387
Austin Schuhcb5601b2020-09-10 15:29:59 -0700388 // File to write both delivery timestamps and local data to.
Brian Silvermancb805822020-10-06 17:43:35 -0700389 DataWriter data_writer_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700390
391 std::map<const Channel *, DataWriter> data_writers_;
392};
393
394} // namespace logger
395} // namespace aos
396
397#endif // AOS_EVENTS_LOGGING_LOG_NAMER_H_