2024-09-13 01:13:06 -04:00
|
|
|
// 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.
|
|
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/datalog/FileLogger.hpp"
|
2025-03-02 10:47:48 -08:00
|
|
|
|
2024-09-13 01:13:06 -04:00
|
|
|
#ifdef __linux__
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/inotify.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-10-08 14:55:16 -04:00
|
|
|
#include <chrono>
|
2024-09-13 01:13:06 -04:00
|
|
|
#include <string>
|
|
|
|
|
#include <string_view>
|
2024-10-08 14:55:16 -04:00
|
|
|
#include <thread>
|
2024-09-13 01:13:06 -04:00
|
|
|
#include <tuple>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2024-10-08 14:55:16 -04:00
|
|
|
#include <fmt/format.h>
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/util/StringExtras.hpp"
|
2024-10-08 14:55:16 -04:00
|
|
|
|
2025-02-19 23:08:17 -06:00
|
|
|
namespace wpi::log {
|
2024-09-13 01:13:06 -04:00
|
|
|
FileLogger::FileLogger(std::string_view file,
|
|
|
|
|
std::function<void(std::string_view)> callback)
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
: m_fileHandle{open(file.data(), O_RDONLY)},
|
|
|
|
|
m_inotifyHandle{inotify_init()},
|
|
|
|
|
m_inotifyWatchHandle{
|
|
|
|
|
inotify_add_watch(m_inotifyHandle, file.data(), IN_MODIFY)},
|
|
|
|
|
m_thread{[=, this] {
|
2024-10-08 14:55:16 -04:00
|
|
|
char buf[8000];
|
|
|
|
|
char eventBuf[sizeof(struct inotify_event) + NAME_MAX + 1];
|
2024-09-13 01:13:06 -04:00
|
|
|
lseek(m_fileHandle, 0, SEEK_END);
|
2024-10-08 14:55:16 -04:00
|
|
|
while (read(m_inotifyHandle, eventBuf, sizeof(eventBuf)) > 0) {
|
2024-09-13 01:13:06 -04:00
|
|
|
int bufLen = 0;
|
2024-10-08 14:55:16 -04:00
|
|
|
if ((bufLen = read(m_fileHandle, buf, sizeof(buf))) > 0) {
|
2024-09-13 01:13:06 -04:00
|
|
|
callback(std::string_view{buf, static_cast<size_t>(bufLen)});
|
|
|
|
|
}
|
2024-10-08 14:55:16 -04:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
2024-09-13 01:13:06 -04:00
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
FileLogger::FileLogger(std::string_view file, log::DataLog& log,
|
|
|
|
|
std::string_view key)
|
2024-10-08 14:55:16 -04:00
|
|
|
: FileLogger(file, Buffer([entry = log.Start(key, "string"),
|
|
|
|
|
&log](std::string_view line) {
|
2024-09-13 01:13:06 -04:00
|
|
|
log.AppendString(entry, line, 0);
|
|
|
|
|
})) {}
|
|
|
|
|
FileLogger::FileLogger(FileLogger&& other)
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
: m_fileHandle{std::exchange(other.m_fileHandle, -1)},
|
|
|
|
|
m_inotifyHandle{std::exchange(other.m_inotifyHandle, -1)},
|
|
|
|
|
m_inotifyWatchHandle{std::exchange(other.m_inotifyWatchHandle, -1)},
|
|
|
|
|
m_thread{std::move(other.m_thread)}
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
FileLogger& FileLogger::operator=(FileLogger&& rhs) {
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
std::swap(m_fileHandle, rhs.m_fileHandle);
|
|
|
|
|
std::swap(m_inotifyHandle, rhs.m_inotifyHandle);
|
|
|
|
|
std::swap(m_inotifyWatchHandle, rhs.m_inotifyWatchHandle);
|
|
|
|
|
m_thread = std::move(rhs.m_thread);
|
|
|
|
|
#endif
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
FileLogger::~FileLogger() {
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
if (m_inotifyWatchHandle != -1) {
|
|
|
|
|
inotify_rm_watch(m_inotifyHandle, m_inotifyWatchHandle);
|
|
|
|
|
}
|
|
|
|
|
if (m_inotifyHandle != -1) {
|
|
|
|
|
close(m_inotifyHandle);
|
|
|
|
|
}
|
|
|
|
|
if (m_fileHandle != -1) {
|
|
|
|
|
close(m_fileHandle);
|
|
|
|
|
}
|
|
|
|
|
if (m_thread.joinable()) {
|
|
|
|
|
m_thread.join();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2024-10-08 14:55:16 -04:00
|
|
|
|
|
|
|
|
std::function<void(std::string_view)> FileLogger::Buffer(
|
2024-09-13 01:13:06 -04:00
|
|
|
std::function<void(std::string_view)> callback) {
|
|
|
|
|
return [callback,
|
2024-10-08 14:55:16 -04:00
|
|
|
buf = wpi::SmallVector<char, 64>{}](std::string_view data) mutable {
|
|
|
|
|
buf.append(data.begin(), data.end());
|
|
|
|
|
if (!wpi::contains({data.data(), data.size()}, "\n")) {
|
2024-09-13 01:13:06 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2024-10-08 14:55:16 -04:00
|
|
|
auto [wholeData, extra] = wpi::rsplit({buf.data(), buf.size()}, "\n");
|
|
|
|
|
std::string leftover{extra};
|
2024-09-13 01:13:06 -04:00
|
|
|
|
2024-10-08 14:55:16 -04:00
|
|
|
callback(wholeData);
|
2024-09-13 01:13:06 -04:00
|
|
|
buf.clear();
|
2024-10-08 14:55:16 -04:00
|
|
|
buf.append(leftover.begin(), leftover.end());
|
2024-09-13 01:13:06 -04:00
|
|
|
};
|
|
|
|
|
}
|
2025-02-19 23:08:17 -06:00
|
|
|
} // namespace wpi::log
|