WPILibC++ 2025.0.0-alpha-1-10-g1ccd8d1
DataLog.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <stdint.h>
8
9#include <concepts>
10#include <initializer_list>
11#include <ranges>
12#include <span>
13#include <string>
14#include <string_view>
15#include <tuple>
16#include <utility>
17#include <vector>
18#include <version>
19
20#include "wpi/DataLog_c.h"
21#include "wpi/DenseMap.h"
22#include "wpi/SmallVector.h"
23#include "wpi/StringMap.h"
24#include "wpi/mutex.h"
26#include "wpi/string.h"
27#include "wpi/struct/Struct.h"
28#include "wpi/timestamp.h"
29
30namespace wpi {
31class Logger;
32} // namespace wpi
33
34namespace wpi::log {
35
36namespace impl {
37
42};
43
44} // namespace impl
45
46/**
47 * A data log for high-speed writing of data values.
48 *
49 * The lifetime of the data log object must be longer than any data log entry
50 * objects that refer to it.
51 *
52 * Finish() is needed only to indicate in the log that a particular entry is
53 * no longer being used (it releases the name to ID mapping). Finish() is not
54 * required to be called for data to be flushed to disk; entries in the log
55 * are written as Append() calls are being made. In fact, Finish() does not
56 * need to be called at all; this is helpful to avoid shutdown races where the
57 * DataLog object might be destroyed before other objects. It's often not a
58 * good idea to call Finish() from destructors for this reason.
59 *
60 * DataLog calls are thread safe. DataLog uses a typical multiple-supplier,
61 * single-consumer setup. Writes to the log are atomic, but there is no
62 * guaranteed order in the log when multiple threads are writing to it;
63 * whichever thread grabs the write mutex first will get written first.
64 * For this reason (as well as the fact that timestamps can be set to
65 * arbitrary values), records in the log are not guaranteed to be sorted by
66 * timestamp.
67 */
68class DataLog {
69 public:
70 virtual ~DataLog() = default;
71
72 DataLog(const DataLog&) = delete;
73 DataLog& operator=(const DataLog&) = delete;
74 DataLog(DataLog&&) = delete;
75 DataLog& operator=(const DataLog&&) = delete;
76
77 /**
78 * Explicitly flushes the log data to disk.
79 */
80 virtual void Flush() = 0;
81
82 /**
83 * Pauses appending of data records to the log. While paused, no data records
84 * are saved (e.g. AppendX is a no-op). Has no effect on entry starts /
85 * finishes / metadata changes.
86 */
87 virtual void Pause();
88
89 /**
90 * Resumes appending of data records to the log.
91 */
92 virtual void Resume();
93
94 /**
95 * Stops appending start/metadata/schema records to the log.
96 */
97 virtual void Stop();
98
99 /**
100 * Returns whether there is a data schema already registered with the given
101 * name.
102 *
103 * @param name Name (the string passed as the data type for records using this
104 * schema)
105 * @return True if schema already registered
106 */
107 bool HasSchema(std::string_view name) const;
108
109 /**
110 * Registers a data schema. Data schemas provide information for how a
111 * certain data type string can be decoded. The type string of a data schema
112 * indicates the type of the schema itself (e.g. "protobuf" for protobuf
113 * schemas, "struct" for struct schemas, etc). In the data log, schemas are
114 * saved just like normal records, with the name being generated from the
115 * provided name: "/.schema/<name>". Duplicate calls to this function with
116 * the same name are silently ignored.
117 *
118 * @param name Name (the string passed as the data type for records using this
119 * schema)
120 * @param type Type of schema (e.g. "protobuf", "struct", etc)
121 * @param schema Schema data
122 * @param timestamp Time stamp (may be 0 to indicate now)
123 */
125 std::span<const uint8_t> schema, int64_t timestamp = 0);
126
127 /**
128 * Registers a data schema. Data schemas provide information for how a
129 * certain data type string can be decoded. The type string of a data schema
130 * indicates the type of the schema itself (e.g. "protobuf" for protobuf
131 * schemas, "struct" for struct schemas, etc). In the data log, schemas are
132 * saved just like normal records, with the name being generated from the
133 * provided name: "/.schema/<name>". Duplicate calls to this function with
134 * the same name are silently ignored.
135 *
136 * @param name Name (the string passed as the data type for records using this
137 * schema)
138 * @param type Type of schema (e.g. "protobuf", "struct", etc)
139 * @param schema Schema data
140 * @param timestamp Time stamp (may be 0 to indicate now)
141 */
143 std::string_view schema, int64_t timestamp = 0) {
144 AddSchema(
145 name, type,
146 std::span<const uint8_t>{
147 reinterpret_cast<const uint8_t*>(schema.data()), schema.size()},
148 timestamp);
149 }
150
151 /**
152 * Registers a protobuf schema. Duplicate calls to this function with the same
153 * name are silently ignored.
154 *
155 * @tparam T protobuf serializable type
156 * @param msg protobuf message
157 * @param timestamp Time stamp (0 to indicate now)
158 */
159 template <ProtobufSerializable T>
160 void AddProtobufSchema(ProtobufMessage<T>& msg, int64_t timestamp = 0) {
161 if (timestamp == 0) {
162 timestamp = Now();
163 }
165 [this](auto typeString) { return HasSchema(typeString); },
166 [this, timestamp](auto typeString, auto schema) {
167 AddSchema(typeString, "proto:FileDescriptorProto", schema, timestamp);
168 });
169 }
170
171 /**
172 * Registers a struct schema. Duplicate calls to this function with the same
173 * name are silently ignored.
174 *
175 * @tparam T struct serializable type
176 * @param info optional struct type info
177 * @param timestamp Time stamp (0 to indicate now)
178 */
179 template <typename T, typename... I>
180 requires StructSerializable<T, I...>
181 void AddStructSchema(const I&... info, int64_t timestamp = 0) {
182 if (timestamp == 0) {
183 timestamp = Now();
184 }
185 ForEachStructSchema<T>(
186 [this, timestamp](auto typeString, auto schema) {
187 this->AddSchema(typeString, "structschema", schema, timestamp);
188 },
189 info...);
190 }
191
192 /**
193 * Start an entry. Duplicate names are allowed (with the same type), and
194 * result in the same index being returned (Start/Finish are reference
195 * counted). A duplicate name with a different type will result in an error
196 * message being printed to the console and 0 being returned (which will be
197 * ignored by the Append functions).
198 *
199 * @param name Name
200 * @param type Data type
201 * @param metadata Initial metadata (e.g. data properties)
202 * @param timestamp Time stamp (may be 0 to indicate now)
203 *
204 * @return Entry index
205 */
207 std::string_view metadata = {}, int64_t timestamp = 0);
208
209 /**
210 * Finish an entry.
211 *
212 * @param entry Entry index
213 * @param timestamp Time stamp (may be 0 to indicate now)
214 */
215 void Finish(int entry, int64_t timestamp = 0);
216
217 /**
218 * Updates the metadata for an entry.
219 *
220 * @param entry Entry index
221 * @param metadata New metadata for the entry
222 * @param timestamp Time stamp (may be 0 to indicate now)
223 */
224 void SetMetadata(int entry, std::string_view metadata, int64_t timestamp = 0);
225
226 /**
227 * Appends a raw record to the log.
228 *
229 * @param entry Entry index, as returned by Start()
230 * @param data Byte array to record
231 * @param timestamp Time stamp (may be 0 to indicate now)
232 */
233 void AppendRaw(int entry, std::span<const uint8_t> data, int64_t timestamp);
234
235 /**
236 * Appends a raw record to the log.
237 *
238 * @param entry Entry index, as returned by Start()
239 * @param data Byte array to record
240 * @param timestamp Time stamp (may be 0 to indicate now)
241 */
242 void AppendRaw2(int entry, std::span<const std::span<const uint8_t>> data,
243 int64_t timestamp);
244
245 /**
246 * Appends a boolean record to the log.
247 *
248 * @param entry Entry index, as returned by Start()
249 * @param value Boolean value to record
250 * @param timestamp Time stamp (may be 0 to indicate now)
251 */
252 void AppendBoolean(int entry, bool value, int64_t timestamp);
253
254 /**
255 * Appends an integer record to the log.
256 *
257 * @param entry Entry index, as returned by Start()
258 * @param value Integer value to record
259 * @param timestamp Time stamp (may be 0 to indicate now)
260 */
261 void AppendInteger(int entry, int64_t value, int64_t timestamp);
262
263 /**
264 * Appends a float record to the log.
265 *
266 * @param entry Entry index, as returned by Start()
267 * @param value Float value to record
268 * @param timestamp Time stamp (may be 0 to indicate now)
269 */
270 void AppendFloat(int entry, float value, int64_t timestamp);
271
272 /**
273 * Appends a double record to the log.
274 *
275 * @param entry Entry index, as returned by Start()
276 * @param value Double value to record
277 * @param timestamp Time stamp (may be 0 to indicate now)
278 */
279 void AppendDouble(int entry, double value, int64_t timestamp);
280
281 /**
282 * Appends a string record to the log.
283 *
284 * @param entry Entry index, as returned by Start()
285 * @param value String value to record
286 * @param timestamp Time stamp (may be 0 to indicate now)
287 */
288 void AppendString(int entry, std::string_view value, int64_t timestamp);
289
290 /**
291 * Appends a boolean array record to the log.
292 *
293 * @param entry Entry index, as returned by Start()
294 * @param arr Boolean array to record
295 * @param timestamp Time stamp (may be 0 to indicate now)
296 */
297 void AppendBooleanArray(int entry, std::span<const bool> arr,
298 int64_t timestamp);
299
300 /**
301 * Appends a boolean array record to the log.
302 *
303 * @param entry Entry index, as returned by Start()
304 * @param arr Boolean array to record
305 * @param timestamp Time stamp (may be 0 to indicate now)
306 */
307 void AppendBooleanArray(int entry, std::span<const int> arr,
308 int64_t timestamp);
309
310 /**
311 * Appends a boolean array record to the log.
312 *
313 * @param entry Entry index, as returned by Start()
314 * @param arr Boolean array to record
315 * @param timestamp Time stamp (may be 0 to indicate now)
316 */
317 void AppendBooleanArray(int entry, std::span<const uint8_t> arr,
318 int64_t timestamp);
319
320 /**
321 * Appends an integer array record to the log.
322 *
323 * @param entry Entry index, as returned by Start()
324 * @param arr Integer array to record
325 * @param timestamp Time stamp (may be 0 to indicate now)
326 */
327 void AppendIntegerArray(int entry, std::span<const int64_t> arr,
328 int64_t timestamp);
329
330 /**
331 * Appends a float array record to the log.
332 *
333 * @param entry Entry index, as returned by Start()
334 * @param arr Float array to record
335 * @param timestamp Time stamp (may be 0 to indicate now)
336 */
337 void AppendFloatArray(int entry, std::span<const float> arr,
338 int64_t timestamp);
339
340 /**
341 * Appends a double array record to the log.
342 *
343 * @param entry Entry index, as returned by Start()
344 * @param arr Double array to record
345 * @param timestamp Time stamp (may be 0 to indicate now)
346 */
347 void AppendDoubleArray(int entry, std::span<const double> arr,
348 int64_t timestamp);
349
350 /**
351 * Appends a string array record to the log.
352 *
353 * @param entry Entry index, as returned by Start()
354 * @param arr String array to record
355 * @param timestamp Time stamp (may be 0 to indicate now)
356 */
357 void AppendStringArray(int entry, std::span<const std::string> arr,
358 int64_t timestamp);
359
360 /**
361 * Appends a string array record to the log.
362 *
363 * @param entry Entry index, as returned by Start()
364 * @param arr String array to record
365 * @param timestamp Time stamp (may be 0 to indicate now)
366 */
367 void AppendStringArray(int entry, std::span<const std::string_view> arr,
368 int64_t timestamp);
369
370 /**
371 * Appends a string array record to the log.
372 *
373 * @param entry Entry index, as returned by Start()
374 * @param arr String array to record
375 * @param timestamp Time stamp (may be 0 to indicate now)
376 */
377 void AppendStringArray(int entry, std::span<const struct WPI_String> arr,
378 int64_t timestamp);
379
380 protected:
381 static constexpr size_t kBlockSize = 16 * 1024;
383
384 class Buffer {
385 public:
386 explicit Buffer(size_t alloc = kBlockSize)
387 : m_buf{new uint8_t[alloc]}, m_maxLen{alloc} {}
388 ~Buffer() { delete[] m_buf; }
389
390 Buffer(const Buffer&) = delete;
391 Buffer& operator=(const Buffer&) = delete;
392
394 : m_buf{oth.m_buf}, m_len{oth.m_len}, m_maxLen{oth.m_maxLen} {
395 oth.m_buf = nullptr;
396 oth.m_len = 0;
397 oth.m_maxLen = 0;
398 }
399
401 if (m_buf) {
402 delete[] m_buf;
403 }
404 m_buf = oth.m_buf;
405 m_len = oth.m_len;
406 m_maxLen = oth.m_maxLen;
407 oth.m_buf = nullptr;
408 oth.m_len = 0;
409 oth.m_maxLen = 0;
410 return *this;
411 }
412
413 uint8_t* Reserve(size_t size) {
414 assert(size <= GetRemaining());
415 uint8_t* rv = m_buf + m_len;
416 m_len += size;
417 return rv;
418 }
419
420 void Unreserve(size_t size) { m_len -= size; }
421
422 void Clear() { m_len = 0; }
423
424 size_t GetRemaining() const { return m_maxLen - m_len; }
425
426 std::span<uint8_t> GetData() { return {m_buf, m_len}; }
427 std::span<const uint8_t> GetData() const { return {m_buf, m_len}; }
428
429 private:
430 uint8_t* m_buf;
431 size_t m_len = 0;
432 size_t m_maxLen;
433 };
434
435 /**
436 * Constructs the log. StartFile() must be called to actually start the
437 * file output.
438 *
439 * @param msglog message logger (will be called from separate thread)
440 * @param extraHeader extra header metadata
441 */
442 explicit DataLog(wpi::Logger& msglog, std::string_view extraHeader = "")
443 : m_msglog{msglog}, m_extraHeader{extraHeader} {}
444
445 /**
446 * Starts the log. Appends file header and Start records and schema data
447 * values for all previously started entries and schemas. No effect unless
448 * the data log is currently stopped.
449 */
450 void StartFile();
451
452 /**
453 * Provides complete set of all buffers that need to be written.
454 *
455 * Any existing contents of writeBufs will be released as if ReleaseBufs()
456 * was called prior to this call.
457 *
458 * Returned buffers should provided back via ReleaseBufs() after the write is
459 * complete.
460 *
461 * @param writeBufs buffers to be written (output)
462 */
463 void FlushBufs(std::vector<Buffer>* writeBufs);
464
465 /**
466 * Releases memory for a set of buffers back to the internal buffer pool.
467 *
468 * @param bufs buffers; empty on return
469 */
470 void ReleaseBufs(std::vector<Buffer>* bufs);
471
472 /**
473 * Called when internal buffers are half the maximum count. Called with
474 * internal mutex held; do not call any other DataLog functions from this
475 * function.
476 */
477 virtual void BufferHalfFull();
478
479 /**
480 * Called when internal buffers reach the maximum count. Called with internal
481 * mutex held; do not call any other DataLog functions from this function.
482 *
483 * @return true if log should be paused (don't call PauseLog)
484 */
485 virtual bool BufferFull() = 0;
486
487 private:
488 static constexpr size_t kMaxBufferCount = 1024 * 1024 / kBlockSize;
489 static constexpr size_t kMaxFreeCount = 256 * 1024 / kBlockSize;
490
491 // must be called with m_mutex held
492 int StartImpl(std::string_view name, std::string_view type,
493 std::string_view metadata, int64_t timestamp);
494 uint8_t* StartRecord(uint32_t entry, uint64_t timestamp, uint32_t payloadSize,
495 size_t reserveSize);
496 uint8_t* Reserve(size_t size);
497 void AppendImpl(std::span<const uint8_t> data);
498 void AppendStringImpl(std::string_view str);
499 void AppendStartRecord(int id, std::string_view name, std::string_view type,
500 std::string_view metadata, int64_t timestamp);
501 void DoReleaseBufs(std::vector<Buffer>* bufs);
502
503 protected:
505
506 private:
507 mutable wpi::mutex m_mutex;
508 bool m_active = false;
509 bool m_paused = false;
510 std::string m_extraHeader;
511 std::vector<Buffer> m_free;
512 std::vector<Buffer> m_outgoing;
513 struct EntryInfo {
514 std::string type;
515 std::vector<uint8_t> schemaData; // only set for schema entries
516 int id{0};
517 };
519 struct EntryInfo2 {
520 std::string metadata;
521 unsigned int count;
522 };
524 int m_lastId = 0;
525};
526
527/**
528 * Log entry base class.
529 */
531 protected:
532 DataLogEntry() = default;
534 std::string_view metadata = {}, int64_t timestamp = 0)
535 : m_log{&log}, m_entry{log.Start(name, type, metadata, timestamp)} {}
536
537 public:
538 DataLogEntry(const DataLogEntry&) = delete;
540
542 rhs.m_log = nullptr;
543 }
545 if (m_log) {
547 }
548 m_log = rhs.m_log;
549 rhs.m_log = nullptr;
550 m_entry = rhs.m_entry;
551 return *this;
552 }
553
554 explicit operator bool() const { return m_log != nullptr; }
555
556 /**
557 * Updates the metadata for the entry.
558 *
559 * @param metadata New metadata for the entry
560 * @param timestamp Time stamp (may be 0 to indicate now)
561 */
562 void SetMetadata(std::string_view metadata, int64_t timestamp = 0) {
563 m_log->SetMetadata(m_entry, metadata, timestamp);
564 }
565
566 /**
567 * Finishes the entry.
568 *
569 * @param timestamp Time stamp (may be 0 to indicate now)
570 */
571 void Finish(int64_t timestamp = 0) { m_log->Finish(m_entry, timestamp); }
572
573 protected:
574 DataLog* m_log = nullptr;
575 int m_entry = 0;
576};
577
578/**
579 * Log arbitrary byte data.
580 */
581class RawLogEntry : public DataLogEntry {
582 public:
583 static constexpr std::string_view kDataType = "raw";
584
585 RawLogEntry() = default;
586 RawLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
587 : RawLogEntry{log, name, {}, kDataType, timestamp} {}
589 int64_t timestamp = 0)
590 : RawLogEntry{log, name, metadata, kDataType, timestamp} {}
592 std::string_view type, int64_t timestamp = 0)
593 : DataLogEntry{log, name, type, metadata, timestamp} {}
594
595 /**
596 * Appends a record to the log.
597 *
598 * @param data Data to record
599 * @param timestamp Time stamp (may be 0 to indicate now)
600 */
601 void Append(std::span<const uint8_t> data, int64_t timestamp = 0) {
602 m_log->AppendRaw(m_entry, data, timestamp);
603 }
604};
605
606/**
607 * Log boolean values.
608 */
610 public:
611 static constexpr std::string_view kDataType = "boolean";
612
613 BooleanLogEntry() = default;
615 : BooleanLogEntry{log, name, {}, timestamp} {}
617 std::string_view metadata, int64_t timestamp = 0)
618 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
619
620 /**
621 * Appends a record to the log.
622 *
623 * @param value Value to record
624 * @param timestamp Time stamp (may be 0 to indicate now)
625 */
626 void Append(bool value, int64_t timestamp = 0) {
627 m_log->AppendBoolean(m_entry, value, timestamp);
628 }
629};
630
631/**
632 * Log integer values.
633 */
635 public:
636 static constexpr std::string_view kDataType = "int64";
637
638 IntegerLogEntry() = default;
640 : IntegerLogEntry{log, name, {}, timestamp} {}
642 std::string_view metadata, int64_t timestamp = 0)
643 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
644
645 /**
646 * Appends a record to the log.
647 *
648 * @param value Value to record
649 * @param timestamp Time stamp (may be 0 to indicate now)
650 */
651 void Append(int64_t value, int64_t timestamp = 0) {
652 m_log->AppendInteger(m_entry, value, timestamp);
653 }
654};
655
656/**
657 * Log float values.
658 */
660 public:
661 static constexpr std::string_view kDataType = "float";
662
663 FloatLogEntry() = default;
665 : FloatLogEntry{log, name, {}, timestamp} {}
667 int64_t timestamp = 0)
668 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
669
670 /**
671 * Appends a record to the log.
672 *
673 * @param value Value to record
674 * @param timestamp Time stamp (may be 0 to indicate now)
675 */
676 void Append(float value, int64_t timestamp = 0) {
677 m_log->AppendFloat(m_entry, value, timestamp);
678 }
679};
680
681/**
682 * Log double values.
683 */
685 public:
686 static constexpr std::string_view kDataType = "double";
687
688 DoubleLogEntry() = default;
690 : DoubleLogEntry{log, name, {}, timestamp} {}
692 int64_t timestamp = 0)
693 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
694
695 /**
696 * Appends a record to the log.
697 *
698 * @param value Value to record
699 * @param timestamp Time stamp (may be 0 to indicate now)
700 */
701 void Append(double value, int64_t timestamp = 0) {
702 m_log->AppendDouble(m_entry, value, timestamp);
703 }
704};
705
706/**
707 * Log string values.
708 */
710 public:
711 static constexpr const char* kDataType = "string";
712
713 StringLogEntry() = default;
715 : StringLogEntry{log, name, {}, kDataType, timestamp} {}
717 int64_t timestamp = 0)
718 : StringLogEntry{log, name, metadata, kDataType, timestamp} {}
720 std::string_view type, int64_t timestamp = 0)
721 : DataLogEntry{log, name, type, metadata, timestamp} {}
722
723 /**
724 * Appends a record to the log.
725 *
726 * @param value Value to record
727 * @param timestamp Time stamp (may be 0 to indicate now)
728 */
729 void Append(std::string_view value, int64_t timestamp = 0) {
730 m_log->AppendString(m_entry, value, timestamp);
731 }
732};
733
734/**
735 * Log array of boolean values.
736 */
738 public:
739 static constexpr const char* kDataType = "boolean[]";
740
743 int64_t timestamp = 0)
744 : BooleanArrayLogEntry{log, name, {}, timestamp} {}
746 std::string_view metadata, int64_t timestamp = 0)
747 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
748
749 /**
750 * Appends a record to the log. For find functions to work, timestamp
751 * must be monotonically increasing.
752 *
753 * @param arr Values to record
754 * @param timestamp Time stamp (may be 0 to indicate now)
755 */
756 void Append(std::span<const bool> arr, int64_t timestamp = 0) {
757 m_log->AppendBooleanArray(m_entry, arr, timestamp);
758 }
759
760 /**
761 * Appends a record to the log.
762 *
763 * @param arr Values to record
764 * @param timestamp Time stamp (may be 0 to indicate now)
765 */
766 void Append(std::initializer_list<bool> arr, int64_t timestamp = 0) {
767 Append(std::span{arr.begin(), arr.end()}, timestamp);
768 }
769
770 /**
771 * Appends a record to the log.
772 *
773 * @param arr Values to record
774 * @param timestamp Time stamp (may be 0 to indicate now)
775 */
776 void Append(std::span<const int> arr, int64_t timestamp = 0) {
777 m_log->AppendBooleanArray(m_entry, arr, timestamp);
778 }
779
780 /**
781 * Appends a record to the log.
782 *
783 * @param arr Values to record
784 * @param timestamp Time stamp (may be 0 to indicate now)
785 */
786 void Append(std::initializer_list<int> arr, int64_t timestamp = 0) {
787 Append(std::span{arr.begin(), arr.end()}, timestamp);
788 }
789
790 /**
791 * Appends a record to the log.
792 *
793 * @param arr Values to record
794 * @param timestamp Time stamp (may be 0 to indicate now)
795 */
796 void Append(std::span<const uint8_t> arr, int64_t timestamp = 0) {
797 m_log->AppendBooleanArray(m_entry, arr, timestamp);
798 }
799};
800
801/**
802 * Log array of integer values.
803 */
805 public:
806 static constexpr const char* kDataType = "int64[]";
807
810 int64_t timestamp = 0)
811 : IntegerArrayLogEntry{log, name, {}, timestamp} {}
813 std::string_view metadata, int64_t timestamp = 0)
814 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
815
816 /**
817 * Appends a record to the log.
818 *
819 * @param arr Values to record
820 * @param timestamp Time stamp (may be 0 to indicate now)
821 */
822 void Append(std::span<const int64_t> arr, int64_t timestamp = 0) {
823 m_log->AppendIntegerArray(m_entry, arr, timestamp);
824 }
825
826 /**
827 * Appends a record to the log.
828 *
829 * @param arr Values to record
830 * @param timestamp Time stamp (may be 0 to indicate now)
831 */
832 void Append(std::initializer_list<int64_t> arr, int64_t timestamp = 0) {
833 Append({arr.begin(), arr.end()}, timestamp);
834 }
835};
836
837/**
838 * Log array of float values.
839 */
841 public:
842 static constexpr const char* kDataType = "float[]";
843
846 : FloatArrayLogEntry{log, name, {}, timestamp} {}
848 std::string_view metadata, int64_t timestamp = 0)
849 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
850
851 /**
852 * Appends a record to the log.
853 *
854 * @param arr Values to record
855 * @param timestamp Time stamp (may be 0 to indicate now)
856 */
857 void Append(std::span<const float> arr, int64_t timestamp = 0) {
858 m_log->AppendFloatArray(m_entry, arr, timestamp);
859 }
860
861 /**
862 * Appends a record to the log.
863 *
864 * @param arr Values to record
865 * @param timestamp Time stamp (may be 0 to indicate now)
866 */
867 void Append(std::initializer_list<float> arr, int64_t timestamp = 0) {
868 Append({arr.begin(), arr.end()}, timestamp);
869 }
870};
871
872/**
873 * Log array of double values.
874 */
876 public:
877 static constexpr const char* kDataType = "double[]";
878
881 int64_t timestamp = 0)
882 : DoubleArrayLogEntry{log, name, {}, timestamp} {}
884 std::string_view metadata, int64_t timestamp = 0)
885 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
886
887 /**
888 * Appends a record to the log.
889 *
890 * @param arr Values to record
891 * @param timestamp Time stamp (may be 0 to indicate now)
892 */
893 void Append(std::span<const double> arr, int64_t timestamp = 0) {
894 m_log->AppendDoubleArray(m_entry, arr, timestamp);
895 }
896
897 /**
898 * Appends a record to the log.
899 *
900 * @param arr Values to record
901 * @param timestamp Time stamp (may be 0 to indicate now)
902 */
903 void Append(std::initializer_list<double> arr, int64_t timestamp = 0) {
904 Append({arr.begin(), arr.end()}, timestamp);
905 }
906};
907
908/**
909 * Log array of string values.
910 */
912 public:
913 static constexpr const char* kDataType = "string[]";
914
917 int64_t timestamp = 0)
918 : StringArrayLogEntry{log, name, {}, timestamp} {}
920 std::string_view metadata, int64_t timestamp = 0)
921 : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
922
923 /**
924 * Appends a record to the log.
925 *
926 * @param arr Values to record
927 * @param timestamp Time stamp (may be 0 to indicate now)
928 */
929 void Append(std::span<const std::string> arr, int64_t timestamp = 0) {
930 m_log->AppendStringArray(m_entry, arr, timestamp);
931 }
932
933 /**
934 * Appends a record to the log.
935 *
936 * @param arr Values to record
937 * @param timestamp Time stamp (may be 0 to indicate now)
938 */
939 void Append(std::span<const std::string_view> arr, int64_t timestamp = 0) {
940 m_log->AppendStringArray(m_entry, arr, timestamp);
941 }
942
943 /**
944 * Appends a record to the log.
945 *
946 * @param arr Values to record
947 * @param timestamp Time stamp (may be 0 to indicate now)
948 */
949 void Append(std::initializer_list<std::string_view> arr,
950 int64_t timestamp = 0) {
951 Append(std::span<const std::string_view>{arr.begin(), arr.end()},
952 timestamp);
953 }
954};
955
956/**
957 * Log raw struct serializable objects.
958 */
959template <typename T, typename... I>
960 requires StructSerializable<T, I...>
962 using S = Struct<T, I...>;
963
964 public:
965 StructLogEntry() = default;
967 int64_t timestamp = 0)
968 : StructLogEntry{log, name, {}, std::move(info)..., timestamp} {}
970 I... info, int64_t timestamp = 0)
971 : m_info{std::move(info)...} {
972 m_log = &log;
973 log.AddStructSchema<T, I...>(info..., timestamp);
974 m_entry = log.Start(name, S::GetTypeString(info...), metadata, timestamp);
975 }
976
977 /**
978 * Appends a record to the log.
979 *
980 * @param data Data to record
981 * @param timestamp Time stamp (may be 0 to indicate now)
982 */
983 void Append(const T& data, int64_t timestamp = 0) {
984 if constexpr (sizeof...(I) == 0) {
985 if constexpr (wpi::is_constexpr([] { S::GetSize(); })) {
986 uint8_t buf[S::GetSize()];
987 S::Pack(buf, data);
988 m_log->AppendRaw(m_entry, buf, timestamp);
989 return;
990 }
991 }
993 buf.resize_for_overwrite(std::apply(S::GetSize, m_info));
994 std::apply([&](const I&... info) { S::Pack(buf, data, info...); }, m_info);
995 m_log->AppendRaw(m_entry, buf, timestamp);
996 }
997
998 private:
999 [[no_unique_address]]
1000 std::tuple<I...> m_info;
1001};
1002
1003/**
1004 * Log raw struct serializable array of objects.
1005 */
1006template <typename T, typename... I>
1007 requires StructSerializable<T, I...>
1009 using S = Struct<T, I...>;
1010
1011 public:
1014 int64_t timestamp = 0)
1015 : StructArrayLogEntry{log, name, {}, std::move(info)..., timestamp} {}
1017 std::string_view metadata, I... info,
1018 int64_t timestamp = 0)
1019 : m_info{std::move(info)...} {
1020 m_log = &log;
1021 log.AddStructSchema<T, I...>(info..., timestamp);
1022 m_entry = log.Start(
1023 name, MakeStructArrayTypeString<T, std::dynamic_extent>(info...),
1024 metadata, timestamp);
1025 }
1026
1027 /**
1028 * Appends a record to the log.
1029 *
1030 * @param data Data to record
1031 * @param timestamp Time stamp (may be 0 to indicate now)
1032 */
1033 template <typename U>
1034#if __cpp_lib_ranges >= 201911L
1035 requires std::ranges::range<U> &&
1036 std::convertible_to<std::ranges::range_value_t<U>, T>
1037#endif
1038 void Append(U&& data, int64_t timestamp = 0) {
1039 std::apply(
1040 [&](const I&... info) {
1041 m_buf.Write(
1042 std::forward<U>(data),
1043 [&](auto bytes) { m_log->AppendRaw(m_entry, bytes, timestamp); },
1044 info...);
1045 },
1046 m_info);
1047 }
1048
1049 /**
1050 * Appends a record to the log.
1051 *
1052 * @param data Data to record
1053 * @param timestamp Time stamp (may be 0 to indicate now)
1054 */
1055 void Append(std::span<const T> data, int64_t timestamp = 0) {
1056 std::apply(
1057 [&](const I&... info) {
1058 m_buf.Write(
1059 data,
1060 [&](auto bytes) { m_log->AppendRaw(m_entry, bytes, timestamp); },
1061 info...);
1062 },
1063 m_info);
1064 }
1065
1066 private:
1067 StructArrayBuffer<T, I...> m_buf;
1068 [[no_unique_address]]
1069 std::tuple<I...> m_info;
1070};
1071
1072/**
1073 * Log protobuf serializable objects.
1074 */
1075template <ProtobufSerializable T>
1077 using P = Protobuf<T>;
1078
1079 public:
1080 ProtobufLogEntry() = default;
1082 : ProtobufLogEntry{log, name, {}, timestamp} {}
1084 std::string_view metadata, int64_t timestamp = 0) {
1085 m_log = &log;
1086 log.AddProtobufSchema<T>(m_msg, timestamp);
1087 m_entry = log.Start(name, m_msg.GetTypeString(), metadata, timestamp);
1088 }
1089
1090 /**
1091 * Appends a record to the log.
1092 *
1093 * @param data Data to record
1094 * @param timestamp Time stamp (may be 0 to indicate now)
1095 */
1096 void Append(const T& data, int64_t timestamp = 0) {
1098 {
1099 std::scoped_lock lock{m_mutex};
1100 m_msg.Pack(buf, data);
1101 }
1102 m_log->AppendRaw(m_entry, buf, timestamp);
1103 }
1104
1105 private:
1106 wpi::mutex m_mutex;
1107 ProtobufMessage<T> m_msg;
1108};
1109
1110} // namespace wpi::log
This file defines the DenseMap class.
This file defines the SmallVector class.
This file defines the StringMap class.
Definition: format.h:4108
Definition: Logger.h:27
Owning wrapper (ala std::unique_ptr) for google::protobuf::Message* that does not require the protobu...
Definition: Protobuf.h:158
void ForEachProtobufDescriptor(function_ref< bool(std::string_view filename)> exists, function_ref< void(std::string_view filename, std::span< const uint8_t > descriptor)> fn)
Loops over all protobuf descriptors including nested/referenced descriptors.
Definition: Protobuf.h:248
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1211
void resize_for_overwrite(size_type N)
Like resize, but T is POD, the new values won't be initialized.
Definition: SmallVector.h:656
Definition: Struct.h:344
Log array of boolean values.
Definition: DataLog.h:737
void Append(std::span< const uint8_t > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:796
void Append(std::initializer_list< bool > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:766
BooleanArrayLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:742
void Append(std::initializer_list< int > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:786
void Append(std::span< const int > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:776
void Append(std::span< const bool > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:756
BooleanArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:745
BooleanArrayLogEntry()=default
Log boolean values.
Definition: DataLog.h:609
BooleanLogEntry()=default
BooleanLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:616
void Append(bool value, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:626
BooleanLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:614
Definition: DataLog.h:384
std::span< uint8_t > GetData()
Definition: DataLog.h:426
Buffer(size_t alloc=kBlockSize)
Definition: DataLog.h:386
Buffer(Buffer &&oth)
Definition: DataLog.h:393
Buffer & operator=(Buffer &&oth)
Definition: DataLog.h:400
~Buffer()
Definition: DataLog.h:388
std::span< const uint8_t > GetData() const
Definition: DataLog.h:427
void Clear()
Definition: DataLog.h:422
Buffer(const Buffer &)=delete
size_t GetRemaining() const
Definition: DataLog.h:424
void Unreserve(size_t size)
Definition: DataLog.h:420
Buffer & operator=(const Buffer &)=delete
uint8_t * Reserve(size_t size)
Definition: DataLog.h:413
Log entry base class.
Definition: DataLog.h:530
DataLogEntry(DataLogEntry &&rhs)
Definition: DataLog.h:541
DataLogEntry(const DataLogEntry &)=delete
void Finish(int64_t timestamp=0)
Finishes the entry.
Definition: DataLog.h:571
DataLog * m_log
Definition: DataLog.h:574
DataLogEntry(DataLog &log, std::string_view name, std::string_view type, std::string_view metadata={}, int64_t timestamp=0)
Definition: DataLog.h:533
DataLogEntry()=default
DataLogEntry & operator=(const DataLogEntry &)=delete
int m_entry
Definition: DataLog.h:575
DataLogEntry & operator=(DataLogEntry &&rhs)
Definition: DataLog.h:544
void SetMetadata(std::string_view metadata, int64_t timestamp=0)
Updates the metadata for the entry.
Definition: DataLog.h:562
A data log for high-speed writing of data values.
Definition: DataLog.h:68
void AppendBooleanArray(int entry, std::span< const bool > arr, int64_t timestamp)
Appends a boolean array record to the log.
void AppendBooleanArray(int entry, std::span< const int > arr, int64_t timestamp)
Appends a boolean array record to the log.
void SetMetadata(int entry, std::string_view metadata, int64_t timestamp=0)
Updates the metadata for an entry.
void AppendStringArray(int entry, std::span< const std::string > arr, int64_t timestamp)
Appends a string array record to the log.
virtual void Stop()
Stops appending start/metadata/schema records to the log.
int Start(std::string_view name, std::string_view type, std::string_view metadata={}, int64_t timestamp=0)
Start an entry.
DataLog & operator=(const DataLog &)=delete
void AppendRaw(int entry, std::span< const uint8_t > data, int64_t timestamp)
Appends a raw record to the log.
void AppendIntegerArray(int entry, std::span< const int64_t > arr, int64_t timestamp)
Appends an integer array record to the log.
void AddStructSchema(const I &... info, int64_t timestamp=0)
Registers a struct schema.
Definition: DataLog.h:181
DataLog(const DataLog &)=delete
void ReleaseBufs(std::vector< Buffer > *bufs)
Releases memory for a set of buffers back to the internal buffer pool.
DataLog(wpi::Logger &msglog, std::string_view extraHeader="")
Constructs the log.
Definition: DataLog.h:442
void AppendStringArray(int entry, std::span< const struct WPI_String > arr, int64_t timestamp)
Appends a string array record to the log.
static wpi::Logger s_defaultMessageLog
Definition: DataLog.h:382
void AddSchema(std::string_view name, std::string_view type, std::string_view schema, int64_t timestamp=0)
Registers a data schema.
Definition: DataLog.h:142
void AppendBooleanArray(int entry, std::span< const uint8_t > arr, int64_t timestamp)
Appends a boolean array record to the log.
void AppendDouble(int entry, double value, int64_t timestamp)
Appends a double record to the log.
void AppendFloat(int entry, float value, int64_t timestamp)
Appends a float record to the log.
DataLog & operator=(const DataLog &&)=delete
wpi::Logger & m_msglog
Definition: DataLog.h:504
void AppendFloatArray(int entry, std::span< const float > arr, int64_t timestamp)
Appends a float array record to the log.
virtual void Resume()
Resumes appending of data records to the log.
void AppendString(int entry, std::string_view value, int64_t timestamp)
Appends a string record to the log.
void AddSchema(std::string_view name, std::string_view type, std::span< const uint8_t > schema, int64_t timestamp=0)
Registers a data schema.
DataLog(DataLog &&)=delete
virtual ~DataLog()=default
static constexpr size_t kBlockSize
Definition: DataLog.h:381
virtual void Pause()
Pauses appending of data records to the log.
void AppendStringArray(int entry, std::span< const std::string_view > arr, int64_t timestamp)
Appends a string array record to the log.
bool HasSchema(std::string_view name) const
Returns whether there is a data schema already registered with the given name.
virtual bool BufferFull()=0
Called when internal buffers reach the maximum count.
void StartFile()
Starts the log.
void AppendRaw2(int entry, std::span< const std::span< const uint8_t > > data, int64_t timestamp)
Appends a raw record to the log.
void Finish(int entry, int64_t timestamp=0)
Finish an entry.
void AppendDoubleArray(int entry, std::span< const double > arr, int64_t timestamp)
Appends a double array record to the log.
virtual void Flush()=0
Explicitly flushes the log data to disk.
void AppendInteger(int entry, int64_t value, int64_t timestamp)
Appends an integer record to the log.
void FlushBufs(std::vector< Buffer > *writeBufs)
Provides complete set of all buffers that need to be written.
virtual void BufferHalfFull()
Called when internal buffers are half the maximum count.
void AddProtobufSchema(ProtobufMessage< T > &msg, int64_t timestamp=0)
Registers a protobuf schema.
Definition: DataLog.h:160
void AppendBoolean(int entry, bool value, int64_t timestamp)
Appends a boolean record to the log.
Log array of double values.
Definition: DataLog.h:875
DoubleArrayLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:880
void Append(std::span< const double > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:893
void Append(std::initializer_list< double > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:903
DoubleArrayLogEntry()=default
DoubleArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:883
Log double values.
Definition: DataLog.h:684
DoubleLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:691
void Append(double value, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:701
DoubleLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:689
DoubleLogEntry()=default
Log array of float values.
Definition: DataLog.h:840
FloatArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:847
void Append(std::span< const float > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:857
void Append(std::initializer_list< float > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:867
FloatArrayLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:845
FloatArrayLogEntry()=default
Log float values.
Definition: DataLog.h:659
FloatLogEntry()=default
FloatLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:664
FloatLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:666
void Append(float value, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:676
Log array of integer values.
Definition: DataLog.h:804
IntegerArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:812
void Append(std::span< const int64_t > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:822
IntegerArrayLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:809
void Append(std::initializer_list< int64_t > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:832
IntegerArrayLogEntry()=default
Log integer values.
Definition: DataLog.h:634
IntegerLogEntry()=default
IntegerLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:641
IntegerLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:639
void Append(int64_t value, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:651
Log protobuf serializable objects.
Definition: DataLog.h:1076
ProtobufLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:1081
void Append(const T &data, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:1096
ProtobufLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:1083
ProtobufLogEntry()=default
Log arbitrary byte data.
Definition: DataLog.h:581
RawLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:588
RawLogEntry(DataLog &log, std::string_view name, std::string_view metadata, std::string_view type, int64_t timestamp=0)
Definition: DataLog.h:591
static constexpr std::string_view kDataType
Definition: DataLog.h:583
RawLogEntry()=default
void Append(std::span< const uint8_t > data, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:601
RawLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:586
Log array of string values.
Definition: DataLog.h:911
void Append(std::initializer_list< std::string_view > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:949
StringArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:919
void Append(std::span< const std::string > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:929
void Append(std::span< const std::string_view > arr, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:939
StringArrayLogEntry()=default
StringArrayLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:916
Log string values.
Definition: DataLog.h:709
StringLogEntry(DataLog &log, std::string_view name, std::string_view metadata, int64_t timestamp=0)
Definition: DataLog.h:716
void Append(std::string_view value, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:729
StringLogEntry(DataLog &log, std::string_view name, std::string_view metadata, std::string_view type, int64_t timestamp=0)
Definition: DataLog.h:719
StringLogEntry()=default
StringLogEntry(DataLog &log, std::string_view name, int64_t timestamp=0)
Definition: DataLog.h:714
Log raw struct serializable array of objects.
Definition: DataLog.h:1008
StructArrayLogEntry(DataLog &log, std::string_view name, I... info, int64_t timestamp=0)
Definition: DataLog.h:1013
void Append(U &&data, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:1038
StructArrayLogEntry()=default
void Append(std::span< const T > data, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:1055
StructArrayLogEntry(DataLog &log, std::string_view name, std::string_view metadata, I... info, int64_t timestamp=0)
Definition: DataLog.h:1016
Log raw struct serializable objects.
Definition: DataLog.h:961
StructLogEntry()=default
StructLogEntry(DataLog &log, std::string_view name, I... info, int64_t timestamp=0)
Definition: DataLog.h:966
void Append(const T &data, int64_t timestamp=0)
Appends a record to the log.
Definition: DataLog.h:983
StructLogEntry(DataLog &log, std::string_view name, std::string_view metadata, I... info, int64_t timestamp=0)
Definition: DataLog.h:969
Specifies that a type is capable of raw struct serialization and deserialization.
Definition: Struct.h:68
basic_string_view< char > string_view
Definition: core.h:518
constexpr dimensionless::scalar_t log(const ScalarUnit x) noexcept
Compute natural logarithm.
Definition: math.h:351
constexpr auto count() -> size_t
Definition: core.h:1222
type
Definition: core.h:573
Implement std::hash so that hash_code can be used in STL containers.
Definition: array.h:89
constexpr const char * name(const T &)
std::string GetTypeString(const google::protobuf::Message &msg)
ControlRecordType
Definition: DataLog.h:38
@ kControlFinish
Definition: DataLog.h:40
@ kControlStart
Definition: DataLog.h:39
@ kControlSetMetadata
Definition: DataLog.h:41
Definition: ntcore_cpp.h:31
Definition: ntcore_cpp.h:26
constexpr bool is_constexpr(Lambda)
Definition: type_traits.h:81
uint64_t Now()
Return a value representing the current time in microseconds.
Protobuf serialization template.
Definition: Protobuf.h:37
Struct serialization template.
Definition: Struct.h:38
::std::mutex mutex
Definition: mutex.h:17