Skip to content

Commit

Permalink
refactor: uls reader into header and source file
Browse files Browse the repository at this point in the history
  • Loading branch information
jr0me committed Jan 10, 2025
1 parent 4cc16c6 commit 40b41c6
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 120 deletions.
139 changes: 139 additions & 0 deletions src/modules/logcollector/src/uls_reader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include "uls_reader.hpp"

#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

namespace logcollector
{

ULSReader::ULSReader(Logcollector& logcollector, const std::string& logLevel, const std::string& query, const std::vector<std::string>& logTypes)
: IReader(logcollector)
, m_logLevel(OSLogStoreWrapper::LogLevel::Undefined)
, m_startTime(std::chrono::system_clock::now().time_since_epoch())
, m_lastLogEntryTimeInSecondsSince1970(m_startTime.count())
{
SetLogLevel(logLevel);
SetQuery(query, logTypes);

try
{
m_osLogIterator = m_osLogStoreWrapper.Begin(m_startTime.count(), m_query, m_logLevel);
}
catch(const std::exception& e)
{
LogError("Failed to create OSLogStore iterator: {}", e.what());
}
}

Awaitable ULSReader::Run()
{
m_keepRunning.store(true);

while (m_keepRunning.load())
{
if (m_osLogIterator != m_osLogStoreWrapper.End())
{
constexpr double increment = 0.000001;

const auto log = *m_osLogIterator;
const auto slightlyBigger = log.dateInSeconds + increment;
m_lastLogEntryTimeInSecondsSince1970 = slightlyBigger;

const auto logAndDate = log.date + " " + log.log;
m_logcollector.SendMessage("ULSReader", logAndDate, "uls");

++m_osLogIterator;
}
else
{
// if we've reached the end of the log, we need to restart the iterator,
// but from the last log entry time
m_osLogIterator = m_osLogStoreWrapper.Begin(m_lastLogEntryTimeInSecondsSince1970, m_query, m_logLevel);
auto executor = co_await boost::asio::this_coro::executor;
auto timer = boost::asio::steady_timer(executor);
timer.expires_after(std::chrono::seconds(10)); // NOLINT(cppcoreguidelines-avoid-magic-numbers)
co_await timer.async_wait(boost::asio::use_awaitable);
}
}
co_return;
}

void ULSReader::Stop()
{
m_keepRunning.store(false);
}

void ULSReader::SetLogLevel(const std::string& logLevel)
{
if (logLevel == "debug")
{
m_logLevel = OSLogStoreWrapper::LogLevel::Debug;
}
else if (logLevel == "info")
{
m_logLevel = OSLogStoreWrapper::LogLevel::Info;
}
else if (logLevel == "notice")
{
m_logLevel = OSLogStoreWrapper::LogLevel::Notice;
}
else if (logLevel == "error")
{
m_logLevel = OSLogStoreWrapper::LogLevel::Error;
}
else if (logLevel == "fault")
{
m_logLevel = OSLogStoreWrapper::LogLevel::Fault;
}
else
{
m_logLevel = OSLogStoreWrapper::LogLevel::Undefined;
}
}

void ULSReader::SetQuery(const std::string& query, const std::vector<std::string>& logTypes)
{
const auto logTypesPredicate = [&logTypes] () -> std::string
{
if (logTypes.empty())
{
return "";
}

std::vector<std::string> predicates;

for (const auto& type : logTypes)
{
if (type == "trace")
{
predicates.emplace_back("eventType == traceEvent");
}
else if (type == "log")
{
predicates.emplace_back("eventType == logEvent");
}
else if (type == "activity")
{
predicates.emplace_back("eventType == activityCreateEvent OR eventType == activityTransitionEvent OR eventType == userActionEvent");
}
}
return fmt::format("{}", fmt::join(predicates, " OR "));
}();

if (query.empty())
{
m_query = fmt::format("{}", logTypesPredicate);
}
else if (logTypesPredicate.empty())
{
m_query = fmt::format("{}", query);
}
else
{
m_query = fmt::format("({}) AND ({})", query, logTypesPredicate);
}
}

} // namespace logcollector
126 changes: 6 additions & 120 deletions src/modules/logcollector/src/uls_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
#include <logcollector.hpp>
#include <oslogstore_wrapper.hpp>

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/steady_timer.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

#include <atomic>
#include <chrono>
Expand All @@ -24,132 +20,22 @@ class ULSReader : public IReader
public:
/// @brief Constructor
/// @param logcollector Logcollector instance
ULSReader(Logcollector& logcollector, std::string logLevel = "", std::string query = "", std::vector<std::string> logTypes = {})
: IReader(logcollector)
, m_startTime(std::chrono::system_clock::now().time_since_epoch())
, m_lastLogEntryTimeInSecondsSince1970(m_startTime.count())
{
m_logLevel = [logLevel]
{
if (logLevel == "debug")
{
return OSLogStoreWrapper::LogLevel::Debug;
}
if (logLevel == "info")
{
return OSLogStoreWrapper::LogLevel::Info;
}
if (logLevel == "notice")
{
return OSLogStoreWrapper::LogLevel::Notice;
}
if (logLevel == "error")
{
return OSLogStoreWrapper::LogLevel::Error;
}
if (logLevel == "fault")
{
return OSLogStoreWrapper::LogLevel::Fault;
}
return OSLogStoreWrapper::LogLevel::Undefined;
}();

// Join all predicates with " OR " to form the compound predicate
const auto logTypesPredicate = [&logTypes] () -> std::string
{
if (logTypes.empty())
{
return "";
}

std::vector<std::string> predicates;

for (const auto& type : logTypes)
{
if (type == "trace")
{
predicates.push_back("eventType == traceEvent");
}
else if (type == "log")
{
predicates.push_back("eventType == logEvent");
}
else if (type == "activity")
{
predicates.push_back("eventType == activityCreateEvent OR eventType == activityTransitionEvent OR eventType == userActionEvent");
}
}
return fmt::format("{}", fmt::join(predicates, " OR "));
}();

if (query.empty())
{
m_query = fmt::format("{}", logTypesPredicate);
}
else if (logTypesPredicate.empty())
{
m_query = fmt::format("{}", query);
}
else
{
m_query = fmt::format("({}) AND ({})", query, logTypesPredicate);
}

try
{
m_osLogIterator = m_osLogStoreWrapper.Begin(m_startTime.count(), m_query, m_logLevel);
}
catch(const std::exception& e)
{
LogError("Failed to create OSLogStore iterator: {}", e.what());
}
}
ULSReader(Logcollector& logcollector, const std::string& logLevel = "", const std::string& query = "", const std::vector<std::string>& logTypes = {});

/// @brief Destructor
~ULSReader() override = default;

/// @brief Runs the log reader
/// @return Awaitable result
Awaitable Run() override
{
m_keepRunning.store(true);

while (m_keepRunning.load())
{
if (m_osLogIterator != m_osLogStoreWrapper.End())
{
constexpr double increment = 0.000001;

const auto log = *m_osLogIterator;
const auto slightlyBigger = log.dateInSeconds + increment;
m_lastLogEntryTimeInSecondsSince1970 = slightlyBigger;

const auto logAndDate = log.date + " " + log.log;
m_logcollector.SendMessage("ULSReader", logAndDate, "uls");

++m_osLogIterator;
}
else
{
// if we've reached the end of the log, we need to restart the iterator,
// but from the last log entry time
m_osLogIterator = m_osLogStoreWrapper.Begin(m_lastLogEntryTimeInSecondsSince1970, m_query, m_logLevel);
auto executor = co_await boost::asio::this_coro::executor;
auto timer = boost::asio::steady_timer(executor);
timer.expires_after(std::chrono::seconds(10)); // NOLINT(cppcoreguidelines-avoid-magic-numbers)
co_await timer.async_wait(boost::asio::use_awaitable);
}
}
co_return;
}
Awaitable Run() override;

/// @brief Stops the log reader
void Stop() override
{
m_keepRunning.store(false);
}
void Stop() override;

private:
void SetLogLevel(const std::string& logLevel);
void SetQuery(const std::string& query, const std::vector<std::string>& logTypes);

std::atomic<bool> m_keepRunning = false;
OSLogStoreWrapper m_osLogStoreWrapper;
OSLogStoreWrapper::Iterator m_osLogIterator;
Expand Down

0 comments on commit 40b41c6

Please sign in to comment.