blob: 2d4c23e8c0a2b8dd6b4553ae44c98dd1d33c62fc [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"
12#include "aos/events/logging/uuid.h"
13#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
26 // Writes the header to all log files for a specific node. This function
27 // needs to be called after all the writers are created.
28 //
29 // Modifies header to contain the uuid and part number for each writer as it
30 // writes it. Since this is done unconditionally, it does not restore the
31 // previous value at the end.
32 virtual void WriteHeader(
33 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
34 const Node *node) = 0;
35
Brian Silverman87ac0402020-09-17 14:47:01 -070036 // Returns a writer for writing data from messages on this channel (on the
37 // primary node).
38 //
39 // The returned pointer will stay valid across rotations, but the object it
40 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070041 virtual DetachedBufferWriter *MakeWriter(const Channel *channel) = 0;
42
Brian Silverman87ac0402020-09-17 14:47:01 -070043 // Returns a writer for writing timestamps from messages on this channel (on
44 // the primary node).
45 //
46 // The returned pointer will stay valid across rotations, but the object it
47 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070048 virtual DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) = 0;
49
50 // Returns a writer for writing timestamps delivered over the special
51 // /aos/remote_timestamps/* channels. node is the node that the timestamps
Brian Silverman87ac0402020-09-17 14:47:01 -070052 // are forwarded back from (to the primary node).
53 //
54 // The returned pointer will stay valid across rotations, but the object it
55 // points to will be assigned to.
Austin Schuhcb5601b2020-09-10 15:29:59 -070056 virtual DetachedBufferWriter *MakeForwardedTimestampWriter(
57 const Channel *channel, const Node *node) = 0;
58
59 // Rotates all log files for the provided node. The provided header will be
60 // modified and written per WriteHeader above.
61 virtual void Rotate(
62 const Node *node,
63 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) = 0;
64
Austin Schuh315b96b2020-12-11 21:21:12 -080065 // Reboots all log files for the provided node. The provided header will be
66 // modified and written per WriteHeader above. Resets any parts UUIDs.
67 virtual void Reboot(
68 const Node *node,
69 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header) = 0;
70
Austin Schuhcb5601b2020-09-10 15:29:59 -070071 // Returns all the nodes that data is being written for.
72 const std::vector<const Node *> &nodes() const { return nodes_; }
73
74 // Returns the node the logger is running on.
75 const Node *node() const { return node_; }
76
Austin Schuh8c399962020-12-25 21:51:45 -080077 // Writes out the nested Configuration object to the config file location.
78 virtual void WriteConfiguration(
79 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
80 std::string_view config_sha256) = 0;
81
Austin Schuhcb5601b2020-09-10 15:29:59 -070082 protected:
83 // Modifies the header to have the provided UUID and part id.
84 void UpdateHeader(
85 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
86 const UUID &uuid, int part_id) const;
87
88 const Node *const node_;
89 std::vector<const Node *> nodes_;
90};
91
92// Local log namer is a simple version which only names things
93// "base_name.part#.bfbs" and increments the part number. It doesn't support
94// any other log type.
95class LocalLogNamer : public LogNamer {
96 public:
97 LocalLogNamer(std::string_view base_name, const Node *node)
98 : LogNamer(node),
99 base_name_(base_name),
100 uuid_(UUID::Random()),
101 data_writer_(OpenDataWriter()) {}
Brian Silverman0465fcf2020-09-24 00:29:18 -0700102 ~LocalLogNamer() override = default;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700103
104 void WriteHeader(
105 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
106 const Node *node) override;
107
108 DetachedBufferWriter *MakeWriter(const Channel *channel) override;
109
110 void Rotate(const Node *node,
111 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
112 override;
113
Austin Schuh315b96b2020-12-11 21:21:12 -0800114 void Reboot(const Node *node,
115 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
116 override;
117
Austin Schuhcb5601b2020-09-10 15:29:59 -0700118 DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) override;
119
120 DetachedBufferWriter *MakeForwardedTimestampWriter(
121 const Channel * /*channel*/, const Node * /*node*/) override;
122
Austin Schuh8c399962020-12-25 21:51:45 -0800123 void WriteConfiguration(
124 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
125 std::string_view config_sha256) override;
126
Austin Schuhcb5601b2020-09-10 15:29:59 -0700127 private:
128 // Creates a new data writer with the new part number.
129 std::unique_ptr<DetachedBufferWriter> OpenDataWriter() {
130 return std::make_unique<DetachedBufferWriter>(
Brian Silvermanf51499a2020-09-21 12:49:08 -0700131 absl::StrCat(base_name_, ".part", part_number_, ".bfbs"),
132 std::make_unique<aos::logger::DummyEncoder>());
Austin Schuhcb5601b2020-09-10 15:29:59 -0700133 }
134
135 const std::string base_name_;
136 const UUID uuid_;
137 size_t part_number_ = 0;
138 std::unique_ptr<DetachedBufferWriter> data_writer_;
139};
140
141// Log namer which uses a config and a base name to name a bunch of files.
142class MultiNodeLogNamer : public LogNamer {
143 public:
Brian Silvermancb805822020-10-06 17:43:35 -0700144 MultiNodeLogNamer(std::string_view base_name,
145 const Configuration *configuration, const Node *node);
146 ~MultiNodeLogNamer() override;
147
148 std::string_view base_name() const { return base_name_; }
149
Brian Silverman48deab12020-09-30 18:39:28 -0700150 // If temp_suffix is set, then this will write files under names beginning
151 // with the specified suffix, and then rename them to the desired name after
152 // they are fully written.
153 //
154 // This is useful to enable incremental copying of the log files.
155 //
156 // Defaults to writing directly to the final filename.
Brian Silvermancb805822020-10-06 17:43:35 -0700157 void set_temp_suffix(std::string_view temp_suffix) {
158 temp_suffix_ = temp_suffix;
159 }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700160
Brian Silvermancb805822020-10-06 17:43:35 -0700161 // Sets the function for creating encoders.
162 //
163 // Defaults to just creating DummyEncoders.
164 void set_encoder_factory(
165 std::function<std::unique_ptr<DetachedBufferEncoder>()> encoder_factory) {
166 encoder_factory_ = std::move(encoder_factory);
167 }
168
169 // Sets an additional file extension.
170 //
171 // Defaults to nothing.
172 void set_extension(std::string_view extension) { extension_ = extension; }
Brian Silverman1f345222020-09-24 21:14:48 -0700173
Brian Silvermana621f522020-09-30 16:52:43 -0700174 // A list of all the filenames we've written.
175 //
176 // This only includes the part after base_name().
177 const std::vector<std::string> &all_filenames() const {
178 return all_filenames_;
179 }
180
Austin Schuhcb5601b2020-09-10 15:29:59 -0700181 void WriteHeader(
182 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
183 const Node *node) override;
184
185 void Rotate(const Node *node,
186 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
187 override;
188
Austin Schuh315b96b2020-12-11 21:21:12 -0800189 void Reboot(const Node *node,
190 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header)
191 override;
192
Austin Schuh8c399962020-12-25 21:51:45 -0800193 void WriteConfiguration(
194 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
195 std::string_view config_sha256) override;
196
Austin Schuhcb5601b2020-09-10 15:29:59 -0700197 DetachedBufferWriter *MakeWriter(const Channel *channel) override;
198
Brian Silvermand90905f2020-09-23 14:42:56 -0700199 DetachedBufferWriter *MakeForwardedTimestampWriter(const Channel *channel,
200 const Node *node) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700201
202 DetachedBufferWriter *MakeTimestampWriter(const Channel *channel) override;
203
Brian Silverman0465fcf2020-09-24 00:29:18 -0700204 // Indicates that at least one file ran out of space. Once this happens, we
205 // stop trying to open new files, to avoid writing any files with holes from
206 // previous parts.
207 //
208 // Besides this function, this object will silently stop logging data when
209 // this occurs. If you want to ensure log files are complete, you must call
210 // this method.
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700211 bool ran_out_of_space() const {
212 return accumulate_data_writers<bool>(
213 ran_out_of_space_, [](bool x, const DataWriter &data_writer) {
214 return x ||
215 (data_writer.writer && data_writer.writer->ran_out_of_space());
216 });
217 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700218
Brian Silverman1f345222020-09-24 21:14:48 -0700219 // Returns the maximum total_bytes() value for all existing
220 // DetachedBufferWriters.
221 //
222 // Returns 0 if no files are open.
223 size_t maximum_total_bytes() const {
Brian Silvermancb805822020-10-06 17:43:35 -0700224 return accumulate_data_writers<size_t>(
225 0, [](size_t x, const DataWriter &data_writer) {
226 return std::max(x, data_writer.writer->total_bytes());
227 });
Brian Silverman1f345222020-09-24 21:14:48 -0700228 }
229
Brian Silverman0465fcf2020-09-24 00:29:18 -0700230 // Closes all existing log files. No more data may be written after this.
231 //
232 // This may set ran_out_of_space().
233 void Close();
234
Brian Silvermancb805822020-10-06 17:43:35 -0700235 // Accessors for various statistics. See the identically-named methods in
236 // DetachedBufferWriter for documentation. These are aggregated across all
237 // past and present DetachedBufferWriters.
238 std::chrono::nanoseconds max_write_time() const {
239 return accumulate_data_writers(
240 max_write_time_,
241 [](std::chrono::nanoseconds x, const DataWriter &data_writer) {
242 return std::max(x, data_writer.writer->max_write_time());
243 });
244 }
245 int max_write_time_bytes() const {
246 return std::get<0>(accumulate_data_writers(
247 std::make_tuple(max_write_time_bytes_, max_write_time_),
248 [](std::tuple<int, std::chrono::nanoseconds> x,
249 const DataWriter &data_writer) {
250 if (data_writer.writer->max_write_time() > std::get<1>(x)) {
251 return std::make_tuple(data_writer.writer->max_write_time_bytes(),
252 data_writer.writer->max_write_time());
253 }
254 return x;
255 }));
256 }
257 int max_write_time_messages() const {
258 return std::get<0>(accumulate_data_writers(
259 std::make_tuple(max_write_time_messages_, max_write_time_),
260 [](std::tuple<int, std::chrono::nanoseconds> x,
261 const DataWriter &data_writer) {
262 if (data_writer.writer->max_write_time() > std::get<1>(x)) {
263 return std::make_tuple(
264 data_writer.writer->max_write_time_messages(),
265 data_writer.writer->max_write_time());
266 }
267 return x;
268 }));
269 }
270 std::chrono::nanoseconds total_write_time() const {
271 return accumulate_data_writers(
272 total_write_time_,
273 [](std::chrono::nanoseconds x, const DataWriter &data_writer) {
274 return x + data_writer.writer->total_write_time();
275 });
276 }
277 int total_write_count() const {
278 return accumulate_data_writers(
279 total_write_count_, [](int x, const DataWriter &data_writer) {
280 return x + data_writer.writer->total_write_count();
281 });
282 }
283 int total_write_messages() const {
284 return accumulate_data_writers(
285 total_write_messages_, [](int x, const DataWriter &data_writer) {
286 return x + data_writer.writer->total_write_messages();
287 });
288 }
289 int total_write_bytes() const {
290 return accumulate_data_writers(
291 total_write_bytes_, [](int x, const DataWriter &data_writer) {
292 return x + data_writer.writer->total_write_bytes();
293 });
294 }
295
296 void ResetStatistics();
297
Austin Schuhcb5601b2020-09-10 15:29:59 -0700298 private:
299 // Files to write remote data to. We want one per channel. Maps the channel
300 // to the writer, Node, and part number.
301 struct DataWriter {
302 std::unique_ptr<DetachedBufferWriter> writer = nullptr;
303 const Node *node;
304 size_t part_number = 0;
Austin Schuh315b96b2020-12-11 21:21:12 -0800305 UUID uuid = UUID::Random();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700306 std::function<void(const Channel *, DataWriter *)> rotate;
307 };
308
Austin Schuh315b96b2020-12-11 21:21:12 -0800309 // Implements Rotate and Reboot, controlled by the 'reboot' flag. The only
310 // difference between the two is if DataWriter::uuid is reset or not.
311 void DoRotate(
312 const Node *node,
313 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
314 bool reboot);
315
Austin Schuhcb5601b2020-09-10 15:29:59 -0700316 // Opens up a writer for timestamps forwarded back.
317 void OpenForwardedTimestampWriter(const Channel *channel,
318 DataWriter *data_writer);
319
320 // Opens up a writer for remote data.
321 void OpenWriter(const Channel *channel, DataWriter *data_writer);
322
323 // Opens the main data writer file for this node responsible for data_writer_.
Brian Silvermana621f522020-09-30 16:52:43 -0700324 void OpenDataWriter();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700325
Brian Silvermana621f522020-09-30 16:52:43 -0700326 void CreateBufferWriter(std::string_view path,
Brian Silverman0465fcf2020-09-24 00:29:18 -0700327 std::unique_ptr<DetachedBufferWriter> *destination);
328
Brian Silverman48deab12020-09-30 18:39:28 -0700329 void RenameTempFile(DetachedBufferWriter *destination);
330
Brian Silvermancb805822020-10-06 17:43:35 -0700331 void CloseWriter(std::unique_ptr<DetachedBufferWriter> *writer_pointer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700332
Brian Silvermancb805822020-10-06 17:43:35 -0700333 // A version of std::accumulate which operates over all of our DataWriters.
334 template <typename T, typename BinaryOperation>
335 T accumulate_data_writers(T t, BinaryOperation op) const {
336 for (const std::pair<const Channel *const, DataWriter> &data_writer :
337 data_writers_) {
Austin Schuhad0cfc32020-12-21 12:34:26 -0800338 if (!data_writer.second.writer) continue;
Brian Silvermancb805822020-10-06 17:43:35 -0700339 t = op(std::move(t), data_writer.second);
340 }
341 if (data_writer_.writer) {
342 t = op(std::move(t), data_writer_);
343 }
344 return t;
345 }
346
347 const std::string base_name_;
348 const Configuration *const configuration_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700349
Brian Silverman0465fcf2020-09-24 00:29:18 -0700350 bool ran_out_of_space_ = false;
Brian Silvermana621f522020-09-30 16:52:43 -0700351 std::vector<std::string> all_filenames_;
Brian Silverman0465fcf2020-09-24 00:29:18 -0700352
Brian Silvermancb805822020-10-06 17:43:35 -0700353 std::string temp_suffix_;
354 std::function<std::unique_ptr<DetachedBufferEncoder>()> encoder_factory_ =
355 []() { return std::make_unique<DummyEncoder>(); };
356 std::string extension_;
357
358 // Storage for statistics from previously-rotated DetachedBufferWriters.
359 std::chrono::nanoseconds max_write_time_ = std::chrono::nanoseconds::zero();
360 int max_write_time_bytes_ = -1;
361 int max_write_time_messages_ = -1;
362 std::chrono::nanoseconds total_write_time_ = std::chrono::nanoseconds::zero();
363 int total_write_count_ = 0;
364 int total_write_messages_ = 0;
365 int total_write_bytes_ = 0;
366
Austin Schuhcb5601b2020-09-10 15:29:59 -0700367 // File to write both delivery timestamps and local data to.
Brian Silvermancb805822020-10-06 17:43:35 -0700368 DataWriter data_writer_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700369
370 std::map<const Channel *, DataWriter> data_writers_;
371};
372
373} // namespace logger
374} // namespace aos
375
376#endif // AOS_EVENTS_LOGGING_LOG_NAMER_H_