[datalog] Move all DataLog functionality to new datalog library (#7641)

Currently the major DataLog backend API (reading and writing) is split between wpiutil and glass. In the interest of allowing code that wants to use these APIs to not need to link to glass and declutter wpiutil, all of those APIs are moved to a new library named "datalog".

Signed-off-by: Jade Turner <spacey-sooty@proton.me>
Co-authored-by: Jade Turner <spacey-sooty@proton.me>
Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
This commit is contained in:
DeltaDizzy
2025-02-19 23:08:17 -06:00
committed by GitHub
parent ac1705ae2b
commit da47f06d70
99 changed files with 778 additions and 330 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,170 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stdint.h>
#include <functional>
#include <span>
#include <string>
#include <string_view>
#include <thread>
#include "wpi/DataLog.h"
#include "wpi/condition_variable.h"
#include "wpi/mutex.h"
namespace wpi {
class Logger;
} // namespace wpi
namespace wpi::log {
/**
* A data log background writer that periodically flushes the data log on a
* background thread. The data log file is created immediately upon
* construction with a temporary filename. The file may be renamed at any time
* using the SetFilename() function.
*
* The lifetime of this object must be longer than any data log entry objects
* that refer to it.
*
* The data log is periodically flushed to disk. It can also be explicitly
* flushed to disk by using the Flush() function. This operation is, however,
* non-blocking.
*/
class DataLogBackgroundWriter final : public DataLog {
public:
/**
* Construct a new Data Log. The log will be initially created with a
* temporary filename.
*
* @param dir directory to store the log
* @param filename filename to use; if none provided, a random filename is
* generated of the form "wpilog_{}.wpilog"
* @param period time between automatic flushes to disk, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
explicit DataLogBackgroundWriter(std::string_view dir = "",
std::string_view filename = "",
double period = 0.25,
std::string_view extraHeader = "");
/**
* Construct a new Data Log. The log will be initially created with a
* temporary filename.
*
* @param msglog message logger (will be called from separate thread)
* @param dir directory to store the log
* @param filename filename to use; if none provided, a random filename is
* generated of the form "wpilog_{}.wpilog"
* @param period time between automatic flushes to disk, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
explicit DataLogBackgroundWriter(wpi::Logger& msglog,
std::string_view dir = "",
std::string_view filename = "",
double period = 0.25,
std::string_view extraHeader = "");
/**
* Construct a new Data Log that passes its output to the provided function
* rather than a file. The write function will be called on a separate
* background thread and may block. The write function is called with an
* empty data array when the thread is terminating.
*
* @param write write function
* @param period time between automatic calls to write, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
explicit DataLogBackgroundWriter(
std::function<void(std::span<const uint8_t> data)> write,
double period = 0.25, std::string_view extraHeader = "");
/**
* Construct a new Data Log that passes its output to the provided function
* rather than a file. The write function will be called on a separate
* background thread and may block. The write function is called with an
* empty data array when the thread is terminating.
*
* @param msglog message logger (will be called from separate thread)
* @param write write function
* @param period time between automatic calls to write, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
explicit DataLogBackgroundWriter(
wpi::Logger& msglog,
std::function<void(std::span<const uint8_t> data)> write,
double period = 0.25, std::string_view extraHeader = "");
~DataLogBackgroundWriter() final;
DataLogBackgroundWriter(const DataLogBackgroundWriter&) = delete;
DataLogBackgroundWriter& operator=(const DataLogBackgroundWriter&) = delete;
DataLogBackgroundWriter(DataLogBackgroundWriter&&) = delete;
DataLogBackgroundWriter& operator=(const DataLogBackgroundWriter&&) = delete;
/**
* Change log filename.
*
* @param filename filename
*/
void SetFilename(std::string_view filename);
/**
* Explicitly flushes the log data to disk.
*/
void Flush() final;
/**
* Pauses appending of data records to the log. While paused, no data records
* are saved (e.g. AppendX is a no-op). Has no effect on entry starts /
* finishes / metadata changes.
*/
void Pause() final;
/**
* Resumes appending of data records to the log. If called after Stop(),
* opens a new file (with random name if SetFilename was not called after
* Stop()) and appends Start records and schema data values for all previously
* started entries and schemas.
*/
void Resume() final;
/**
* Stops appending all records to the log, and closes the log file.
*/
void Stop() final;
private:
struct WriterThreadState;
void BufferHalfFull() final;
bool BufferFull() final;
void StartLogFile(WriterThreadState& state);
void WriterThreadMain(std::string_view dir);
void WriterThreadMain(
std::function<void(std::span<const uint8_t> data)> write);
mutable wpi::mutex m_mutex;
wpi::condition_variable m_cond;
bool m_doFlush{false};
bool m_shutdown{false};
enum State {
kStart,
kActive,
kPaused,
kStopped,
} m_state = kActive;
double m_period;
std::string m_newFilename;
std::thread m_thread;
};
} // namespace wpi::log

View File

@@ -1,369 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stdint.h>
#include <iterator>
#include <memory>
#include <span>
#include <utility>
#include <vector>
#include "wpi/MemoryBuffer.h"
namespace wpi::log {
/**
* Data contained in a start control record as created by DataLog::Start() when
* writing the log. This can be read by calling DataLogRecord::GetStartData().
*/
struct StartRecordData {
/** Entry ID; this will be used for this entry in future records. */
int entry;
/** Entry name. */
std::string_view name;
/** Type of the stored data for this entry, as a string, e.g. "double". */
std::string_view type;
/** Initial metadata. */
std::string_view metadata;
};
/**
* Data contained in a set metadata control record as created by
* DataLog::SetMetadata(). This can be read by calling
* DataLogRecord::GetSetMetadataData().
*/
struct MetadataRecordData {
/** Entry ID. */
int entry;
/** New metadata for the entry. */
std::string_view metadata;
};
/**
* A record in the data log. May represent either a control record (entry == 0)
* or a data record. Used only for reading (e.g. with DataLogReader).
*/
class DataLogRecord {
public:
DataLogRecord() = default;
DataLogRecord(int entry, int64_t timestamp, std::span<const uint8_t> data)
: m_timestamp{timestamp}, m_data{data}, m_entry{entry} {}
/**
* Gets the entry ID.
*
* @return entry ID
*/
int GetEntry() const { return m_entry; }
/**
* Gets the record timestamp.
*
* @return Timestamp, in integer microseconds
*/
int64_t GetTimestamp() const { return m_timestamp; }
/**
* Gets the size of the raw data.
*
* @return size
*/
size_t GetSize() const { return m_data.size(); }
/**
* Gets the raw data. Use the GetX functions to decode based on the data type
* in the entry's start record.
*/
std::span<const uint8_t> GetRaw() const { return m_data; }
/**
* Returns true if the record is a control record.
*
* @return True if control record, false if normal data record.
*/
bool IsControl() const { return m_entry == 0; }
/**
* Returns true if the record is a start control record. Use GetStartData()
* to decode the contents.
*
* @return True if start control record, false otherwise.
*/
bool IsStart() const;
/**
* Returns true if the record is a finish control record. Use GetFinishEntry()
* to decode the contents.
*
* @return True if finish control record, false otherwise.
*/
bool IsFinish() const;
/**
* Returns true if the record is a set metadata control record. Use
* GetSetMetadataData() to decode the contents.
*
* @return True if set metadata control record, false otherwise.
*/
bool IsSetMetadata() const;
/**
* Decodes a start control record.
*
* @param[out] out start record decoded data (if successful)
* @return True on success, false on error
*/
bool GetStartData(StartRecordData* out) const;
/**
* Decodes a finish control record.
*
* @param[out] out finish record entry ID (if successful)
* @return True on success, false on error
*/
bool GetFinishEntry(int* out) const;
/**
* Decodes a set metadata control record.
*
* @param[out] out set metadata record decoded data (if successful)
* @return True on success, false on error
*/
bool GetSetMetadataData(MetadataRecordData* out) const;
/**
* Decodes a data record as a boolean. Note if the data type (as indicated in
* the corresponding start control record for this entry) is not "boolean",
* invalid results may be returned.
*
* @param[out] value boolean value (if successful)
* @return True on success, false on error
*/
bool GetBoolean(bool* value) const;
/**
* Decodes a data record as an integer. Note if the data type (as indicated in
* the corresponding start control record for this entry) is not "int64",
* invalid results may be returned.
*
* @param[out] value integer value (if successful)
* @return True on success, false on error
*/
bool GetInteger(int64_t* value) const;
/**
* Decodes a data record as a float. Note if the data type (as indicated in
* the corresponding start control record for this entry) is not "float",
* invalid results may be returned.
*
* @param[out] value float value (if successful)
* @return True on success, false on error
*/
bool GetFloat(float* value) const;
/**
* Decodes a data record as a double. Note if the data type (as indicated in
* the corresponding start control record for this entry) is not "double",
* invalid results may be returned.
*
* @param[out] value double value (if successful)
* @return True on success, false on error
*/
bool GetDouble(double* value) const;
/**
* Decodes a data record as a string. Note if the data type (as indicated in
* the corresponding start control record for this entry) is not "string",
* invalid results may be returned.
*
* @param[out] value string value
* @return True (never fails)
*/
bool GetString(std::string_view* value) const;
/**
* Decodes a data record as a boolean array. Note if the data type (as
* indicated in the corresponding start control record for this entry) is not
* "boolean[]", invalid results may be returned.
*
* @param[out] arr boolean array
* @return True (never fails)
*/
bool GetBooleanArray(std::vector<int>* arr) const;
/**
* Decodes a data record as an integer array. Note if the data type (as
* indicated in the corresponding start control record for this entry) is not
* "int64[]", invalid results may be returned.
*
* @param[out] arr integer array (if successful)
* @return True on success, false on error
*/
bool GetIntegerArray(std::vector<int64_t>* arr) const;
/**
* Decodes a data record as a float array. Note if the data type (as
* indicated in the corresponding start control record for this entry) is not
* "float[]", invalid results may be returned.
*
* @param[out] arr float array (if successful)
* @return True on success, false on error
*/
bool GetFloatArray(std::vector<float>* arr) const;
/**
* Decodes a data record as a double array. Note if the data type (as
* indicated in the corresponding start control record for this entry) is not
* "double[]", invalid results may be returned.
*
* @param[out] arr double array (if successful)
* @return True on success, false on error
*/
bool GetDoubleArray(std::vector<double>* arr) const;
/**
* Decodes a data record as a string array. Note if the data type (as
* indicated in the corresponding start control record for this entry) is not
* "string[]", invalid results may be returned.
*
* @param[out] arr string array (if successful)
* @return True on success, false on error
*/
bool GetStringArray(std::vector<std::string_view>* arr) const;
private:
int64_t m_timestamp{0};
std::span<const uint8_t> m_data;
int m_entry{-1};
};
class DataLogReader;
/** DataLogReader iterator. */
class DataLogIterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = DataLogRecord;
using pointer = const value_type*;
using reference = const value_type&;
DataLogIterator(const DataLogReader* reader, size_t pos)
: m_reader{reader}, m_pos{pos} {}
bool operator==(const DataLogIterator& oth) const {
return m_reader == oth.m_reader && m_pos == oth.m_pos;
}
bool operator!=(const DataLogIterator& oth) const {
return !this->operator==(oth);
}
bool operator<(const DataLogIterator& oth) const { return m_pos < oth.m_pos; }
bool operator>(const DataLogIterator& oth) const {
return !this->operator<(oth) && !this->operator==(oth);
}
bool operator<=(const DataLogIterator& oth) const {
return !this->operator>(oth);
}
bool operator>=(const DataLogIterator& oth) const {
return !this->operator<(oth);
}
DataLogIterator& operator++();
DataLogIterator operator++(int) {
DataLogIterator tmp = *this;
++*this;
return tmp;
}
reference operator*() const;
pointer operator->() const { return &this->operator*(); }
protected:
const DataLogReader* m_reader;
size_t m_pos;
mutable bool m_valid = false;
mutable DataLogRecord m_value;
};
/** Data log reader (reads logs written by the DataLog class). */
class DataLogReader {
friend class DataLogIterator;
public:
using iterator = DataLogIterator;
/** Constructs from a memory buffer. */
explicit DataLogReader(std::unique_ptr<MemoryBuffer> buffer);
/** Returns true if the data log is valid (e.g. has a valid header). */
explicit operator bool() const { return IsValid(); }
/** Returns true if the data log is valid (e.g. has a valid header). */
bool IsValid() const;
/**
* Gets the data log version. Returns 0 if data log is invalid.
*
* @return Version number; most significant byte is major, least significant
* is minor (so version 1.0 will be 0x0100)
*/
uint16_t GetVersion() const;
/**
* Gets the extra header data.
*
* @return Extra header data
*/
std::string_view GetExtraHeader() const;
/**
* Gets the buffer identifier, typically the filename.
*
* @return Identifier string
*/
std::string_view GetBufferIdentifier() const {
return m_buf ? m_buf->GetBufferIdentifier() : "Invalid";
}
/** Returns iterator to first record. */
iterator begin() const;
/** Returns end iterator. */
iterator end() const { return DataLogIterator{this, SIZE_MAX}; }
private:
std::unique_ptr<MemoryBuffer> m_buf;
bool GetRecord(size_t* pos, DataLogRecord* out) const;
bool GetNextRecord(size_t* pos) const;
};
inline DataLogIterator& DataLogIterator::operator++() {
if (!m_reader->GetNextRecord(&m_pos)) {
m_pos = SIZE_MAX;
}
m_valid = false;
return *this;
}
inline DataLogIterator::reference DataLogIterator::operator*() const {
if (!m_valid) {
size_t pos = m_pos;
if (m_reader->GetRecord(&pos, &m_value)) {
m_valid = true;
}
}
return m_value;
}
} // namespace wpi::log

View File

@@ -1,97 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include <string_view>
#include <system_error>
#include "wpi/DataLog.h"
namespace wpi {
class raw_ostream;
class Logger;
} // namespace wpi
namespace wpi::log {
/**
* A data log writer that flushes the data log to a file when Flush() is called.
*
* The lifetime of this object must be longer than any data log entry objects
* that refer to it.
*/
class DataLogWriter final : public DataLog {
public:
/**
* Constructs with a filename.
*
* @param filename filename to use
* @param ec error code if failed to open file (output)
* @param extraHeader extra header data
*/
explicit DataLogWriter(std::string_view filename, std::error_code& ec,
std::string_view extraHeader = "");
/**
* Construct with a filename.
*
* @param msglog message logger
* @param filename filename to use
* @param ec error code if failed to open file (output)
* @param extraHeader extra header data
*/
DataLogWriter(wpi::Logger& msglog, std::string_view filename,
std::error_code& ec, std::string_view extraHeader = "");
/**
* Constructs with an output stream.
*
* @param os output stream
* @param extraHeader extra header data
*/
explicit DataLogWriter(std::unique_ptr<wpi::raw_ostream> os,
std::string_view extraHeader = "");
/**
* Constructs with an output stream.
*
* @param msglog message logger
* @param os output stream
* @param extraHeader extra header data
*/
DataLogWriter(wpi::Logger& msglog, std::unique_ptr<wpi::raw_ostream> os,
std::string_view extraHeader = "");
~DataLogWriter() final;
DataLogWriter(const DataLogWriter&) = delete;
DataLogWriter& operator=(const DataLogWriter&) = delete;
DataLogWriter(DataLogWriter&&) = delete;
DataLogWriter& operator=(const DataLogWriter&&) = delete;
/**
* Flushes the log data to disk.
*/
void Flush() final;
/**
* Stops appending all records to the log, and closes the log file.
*/
void Stop() final;
/**
* Gets the output stream.
*
* @return output stream
*/
wpi::raw_ostream& GetStream() { return *m_os; }
private:
bool BufferFull() final;
std::unique_ptr<wpi::raw_ostream> m_os;
};
} // namespace wpi::log

View File

@@ -1,312 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stddef.h> // NOLINT
#include <stdint.h>
#include <wpi/string.h>
#ifdef __cplusplus
extern "C" {
#endif
/** C-compatible data log (opaque struct). */
struct WPI_DataLog;
/**
* Construct a new Data Log.
*
* @param filename filename to use
* @param errorCode error if file failed to open (output)
* @param extraHeader extra header data
*/
struct WPI_DataLog* WPI_DataLog_CreateWriter(
const struct WPI_String* filename, int* errorCode,
const struct WPI_String* extraHeader);
/**
* Construct a new Data Log background writer. The log will be initially
* created with a temporary filename.
*
* @param dir directory to store the log
* @param filename filename to use; if none provided, a random filename is
* generated of the form "wpilog_{}.wpilog"
* @param period time between automatic flushes to disk, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter(
const struct WPI_String* dir, const struct WPI_String* filename,
double period, const struct WPI_String* extraHeader);
/**
* Construct a new Data Log background writer that passes its output to the
* provided function rather than a file. The write function will be called on a
* separate background thread and may block. The write function is called with
* an empty data array (data=NULL, len=0) when the thread is terminating.
*
* @param write write function
* @param ptr pointer to pass to write function ptr parameter
* @param period time between automatic calls to write, in seconds;
* this is a time/storage tradeoff
* @param extraHeader extra header data
*/
struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter_Func(
void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr,
double period, const struct WPI_String* extraHeader);
/**
* Change log filename. Can only be used on background writer data logs.
*
* @param datalog data log
* @param filename filename
*/
void WPI_DataLog_SetBackgroundWriterFilename(struct WPI_DataLog* datalog,
const struct WPI_String* filename);
/**
* Releases a data log object. Closes the file and returns resources to the
* system.
*
* @param datalog data log
*/
void WPI_DataLog_Release(struct WPI_DataLog* datalog);
/**
* Explicitly flushes the log data to disk.
*
* @param datalog data log
*/
void WPI_DataLog_Flush(struct WPI_DataLog* datalog);
/**
* Pauses appending of data records to the log. While paused, no data records
* are saved (e.g. AppendX is a no-op). Has no effect on entry starts /
* finishes / metadata changes.
*
* @param datalog data log
*/
void WPI_DataLog_Pause(struct WPI_DataLog* datalog);
/**
* Resumes appending of data records to the log. If called after Stop(),
* opens a new file (with random name if SetFilename was not called after
* Stop()) and appends Start records and schema data values for all previously
* started entries and schemas.
*
* @param datalog data log
*/
void WPI_DataLog_Resume(struct WPI_DataLog* datalog);
/**
* Stops appending all records to the log, and closes the log file.
*
* @param datalog data log
*/
void WPI_DataLog_Stop(struct WPI_DataLog* datalog);
/**
* Start an entry. Duplicate names are allowed (with the same type), and
* result in the same index being returned (Start/Finish are reference
* counted). A duplicate name with a different type will result in an error
* message being printed to the console and 0 being returned (which will be
* ignored by the Append functions).
*
* @param datalog data log
* @param name Name
* @param type Data type
* @param metadata Initial metadata (e.g. data properties)
* @param timestamp Time stamp (may be 0 to indicate now)
*
* @return Entry index
*/
int WPI_DataLog_Start(struct WPI_DataLog* datalog,
const struct WPI_String* name,
const struct WPI_String* type,
const struct WPI_String* metadata, int64_t timestamp);
/**
* Finish an entry.
*
* @param datalog data log
* @param entry Entry index
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry,
int64_t timestamp);
/**
* Updates the metadata for an entry.
*
* @param datalog data log
* @param entry Entry index
* @param metadata New metadata for the entry
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry,
const struct WPI_String* metadata,
int64_t timestamp);
/**
* Appends a raw record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param data Byte array to record
* @param len Length of byte array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendRaw(struct WPI_DataLog* datalog, int entry,
const uint8_t* data, size_t len, int64_t timestamp);
/**
* Appends a boolean record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param value Boolean value to record
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendBoolean(struct WPI_DataLog* datalog, int entry,
int value, int64_t timestamp);
/**
* Appends an integer record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param value Integer value to record
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendInteger(struct WPI_DataLog* datalog, int entry,
int64_t value, int64_t timestamp);
/**
* Appends a float record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param value Float value to record
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendFloat(struct WPI_DataLog* datalog, int entry,
float value, int64_t timestamp);
/**
* Appends a double record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param value Double value to record
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry,
double value, int64_t timestamp);
/**
* Appends a string record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param value String value to record
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry,
const struct WPI_String* value,
int64_t timestamp);
/**
* Appends a boolean array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr Boolean array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendBooleanArray(struct WPI_DataLog* datalog, int entry,
const int* arr, size_t len,
int64_t timestamp);
/**
* Appends a boolean array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr Boolean array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendBooleanArrayByte(struct WPI_DataLog* datalog, int entry,
const uint8_t* arr, size_t len,
int64_t timestamp);
/**
* Appends an integer array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr Integer array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendIntegerArray(struct WPI_DataLog* datalog, int entry,
const int64_t* arr, size_t len,
int64_t timestamp);
/**
* Appends a float array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr Float array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendFloatArray(struct WPI_DataLog* datalog, int entry,
const float* arr, size_t len,
int64_t timestamp);
/**
* Appends a double array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr Double array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry,
const double* arr, size_t len,
int64_t timestamp);
/**
* Appends a string array record to the log.
*
* @param datalog data log
* @param entry Entry index, as returned by WPI_DataLog_Start()
* @param arr String array to record
* @param len Number of elements in array
* @param timestamp Time stamp (may be 0 to indicate now)
*/
void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry,
const struct WPI_String* arr, size_t len,
int64_t timestamp);
void WPI_DataLog_AddSchemaString(struct WPI_DataLog* datalog,
const struct WPI_String* name,
const struct WPI_String* type,
const struct WPI_String* schema,
int64_t timestamp);
void WPI_DataLog_AddSchema(struct WPI_DataLog* datalog,
const struct WPI_String* name,
const struct WPI_String* type, const uint8_t* schema,
size_t schema_len, int64_t timestamp);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,61 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <string_view>
#include <thread>
#include "wpi/DataLog.h"
namespace wpi {
/**
* A class version of `tail -f`, otherwise known as `tail -f` at home. Watches
* a file and puts the data somewhere else. Only works on Linux-based platforms.
*/
class FileLogger {
public:
FileLogger() = default;
/**
* Construct a FileLogger. When the specified file is modified, the callback
* will be called with the appended changes.
*
* @param file The path to the file.
* @param callback A callback that accepts the appended file data.
*/
FileLogger(std::string_view file,
std::function<void(std::string_view)> callback);
/**
* Construct a FileLogger. When the specified file is modified, appended data
* will be appended to the specified data log.
*
* @param file The path to the file.
* @param log A data log.
* @param key The log key to append data to.
*/
FileLogger(std::string_view file, log::DataLog& log, std::string_view key);
FileLogger(FileLogger&& other);
FileLogger& operator=(FileLogger&& rhs);
~FileLogger();
/**
* Creates a function that chunks incoming data into blocks of whole lines and
* stores incomplete lines to add to the next block of data.
*
* @param callback A callback that accepts the blocks of whole lines.
* @return The function.
*/
static std::function<void(std::string_view)> Buffer(
std::function<void(std::string_view)> callback);
private:
#ifdef __linux__
int m_fileHandle = -1;
int m_inotifyHandle = -1;
int m_inotifyWatchHandle = -1;
std::thread m_thread;
#endif
};
} // namespace wpi