Integrate logging channel system

update logging to use logger channel

updates
This commit is contained in:
Aaron Po
2026-05-15 01:13:53 -04:00
parent 29972f54d1
commit 54a46458a3
35 changed files with 586 additions and 440 deletions

View File

@@ -1,54 +0,0 @@
/**
* @file services/logging/channel_logger.h
* @brief Channel-backed producer for asynchronous pipeline logging.
*
* Intent: Decouple logging from synchronous I/O by forwarding entries to a
* bounded channel. LogConsumer drains the channel on a dedicated thread.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_
#include <string_view>
#include "concurrency/bounded_channel.h"
#include "services/logging/log_entry.h"
#include "services/logging/logger.h"
/**
* @class ChannelLogger
* @brief ILogger implementation that sends entries to a BoundedChannel.
*
* Non-copyable, non-movable. Holds a non-owning reference to the channel.
*/
class ChannelLogger final : public ILogger {
public:
/**
* @brief Construct a channel-backed logger.
*
* @param channel Reference to bounded channel for log entry transfer.
* Channel must outlive this logger instance.
*/
explicit ChannelLogger(BoundedChannel<LogEntry>& channel);
ChannelLogger(const ChannelLogger&) = delete;
ChannelLogger& operator=(const ChannelLogger&) = delete;
ChannelLogger(ChannelLogger&&) = delete;
ChannelLogger& operator=(ChannelLogger&&) = delete;
~ChannelLogger() override = default;
/**
* @brief Queue a log entry for asynchronous processing.
*
* Blocks if the channel is full (backpressure). Returns immediately
* if the channel is closed.
*/
void Log(LogLevel level, PipelinePhase phase,
std::string_view message) override;
private:
BoundedChannel<LogEntry>& channel_;
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_

View File

@@ -1,59 +0,0 @@
/**
* @file services/logging/log_consumer.h
* @brief Dedicated log consumer/drain for asynchronous pipeline logging.
*
* Intent: Dequeue LogEntry values from a BoundedChannel on a dedicated thread
* and forward them to spdlog for I/O and formatting. Decouples application
* logic from logging latency.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_
#include <spdlog/spdlog.h>
#include <string>
#include "concurrency/bounded_channel.h"
#include "services/logging/log_entry.h"
/**
* @class LogConsumer
* @brief Consumes log entries from channel and forwards to spdlog.
*
* Non-copyable, non-movable. Designed to run on its own dedicated std::thread.
* Drains the channel until closure, then exits cleanly.
*/
class LogConsumer {
public:
/**
* @brief Construct a log consumer.
*
* @param channel Reference to bounded channel for log entry retrieval.
* Channel must outlive this consumer instance.
*/
explicit LogConsumer(BoundedChannel<LogEntry>& channel);
LogConsumer(const LogConsumer&) = delete;
LogConsumer& operator=(const LogConsumer&) = delete;
LogConsumer(LogConsumer&&) = delete;
LogConsumer& operator=(LogConsumer&&) = delete;
/**
* @brief Main loop: drain channel and forward entries to spdlog.
*
* Intended to be called once on a dedicated thread. Returns when:
* - Channel is closed AND all queued entries are drained.
*
* Thread-safe for use from multiple ChannelLogger instances on other threads.
*/
void Run();
private:
BoundedChannel<LogEntry>& channel_;
static spdlog::level::level_enum ToSpdlogLevel(LogLevel level);
static std::string ToString(PipelinePhase phase);
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_

View File

@@ -0,0 +1,53 @@
/**
* @file services/logging/log_dispatcher.h
* @brief Dedicated log dispatcher for asynchronous pipeline logging.
*
* The dispatcher drains LogEntry values from a bounded channel and forwards
* them to spdlog on a dedicated thread.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_
#include <spdlog/spdlog.h>
#include "concurrency/bounded_channel.h"
#include "services/logging/log_entry.h"
/**
* @class LogDispatcher
* @brief Consumes log entries from a channel and forwards them to spdlog.
*
* Non-copyable and non-movable. Intended to run on its own dedicated thread
* and exit once the channel has been closed and drained.
*/
class LogDispatcher {
public:
/**
* @brief Construct a log dispatcher.
*
* @param channel Reference to the bounded channel used for log retrieval.
*/
explicit LogDispatcher(BoundedChannel<LogEntry>& channel);
LogDispatcher(const LogDispatcher&) = delete;
LogDispatcher& operator=(const LogDispatcher&) = delete;
LogDispatcher(LogDispatcher&&) = delete;
LogDispatcher& operator=(LogDispatcher&&) = delete;
~LogDispatcher() = default;
/**
* @brief Drain the channel and forward entries to spdlog.
*
* Intended to be called once on a dedicated thread. The loop returns after
* the channel has been closed and all queued entries have been processed.
*/
void Run();
private:
BoundedChannel<LogEntry>& channel_;
static spdlog::level::level_enum ToSpdlogLevel(LogLevel level);
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_CONSUMER_H_

View File

@@ -1,65 +1,68 @@
/**
* @file services/logging/log_entry.h
* @brief POD log entry structure for asynchronous pipeline logging.
* @brief Structured log record shared by the pipeline logging infra.
*
* Intent: Lightweight, move-safe data transfer between logging producer
* (ChannelLogger) and consumer (LogConsumer) via BoundedChannel<LogEntry>.
* LogEntry is a lightweight value type that can be passed safely between the
* logging producer and dispatcher through BoundedChannel<LogEntry>.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_
#include <chrono>
#include <thread>
#include <string>
/**
* @enum LogLevel
* @brief Severity levels for log entries.
* @brief Severity levels supported by the logging infra.
*/
enum class LogLevel {
Debug, ///< Development/debugging information.
Info, ///< General informational messages.
Warn, ///< Warning conditions.
Error, ///< Error conditions.
Debug, ///< Development/debugging information.
Info, ///< General informational messages.
Warn, ///< Warning conditions.
Error, ///< Error conditions.
};
/**
* @enum PipelinePhase
* @brief Execution phases for contextual logging.
* @brief Pipeline execution phases used to tag log records.
*
* Used to tag log entries by their processing stage, enabling phase-specific
* analysis and filtering of the execution timeline.
* The phase tag makes it easier to correlate log output with the part of the
* pipeline that emitted it.
*/
enum class PipelinePhase {
Startup, ///< Initialization and validation.
UserGeneration, ///< User profile generation.
BreweryAndBeerGeneration, ///< Brewery and beer data generation.
CheckinGeneration, ///< Checkin (visit) record generation.
RatingGeneration, ///< Rating and review generation.
FollowGeneration, ///< Follow relationship generation.
Teardown, ///< Finalization and cleanup.
Startup, ///< Initialization and validation.
UserGeneration, ///< User profile generation.
BreweryAndBeerGeneration, ///< Brewery and beer data generation.
CheckinGeneration, ///< Checkin (visit) record generation.
RatingGeneration, ///< Rating and review generation.
FollowGeneration, ///< Follow relationship generation.
Teardown, ///< Finalization and cleanup.
};
/**
* @struct LogEntry
* @brief Single log event for asynchronous processing.
* @brief Single structured log event.
*
* All fields are value types, allowing safe move semantics across
* BoundedChannel without shared ownership or synchronization overhead.
* All fields are value types, which keeps transfer across the bounded channel
* simple and avoids shared ownership.
*/
struct LogEntry {
/// @brief Timestamp when entry was created.
std::chrono::system_clock::time_point timestamp =
std::chrono::system_clock::now();
/// @brief Timestamp when the entry was created.
std::chrono::system_clock::time_point timestamp =
std::chrono::system_clock::now();
/// @brief Severity level of this entry.
LogLevel level;
/// @brief Pipeline phase when entry was logged.
PipelinePhase phase;
/// @brief Severity level of this entry.
LogLevel level;
/// @brief Pipeline phase associated with the entry.
PipelinePhase phase;
/// @brief Log message text.
std::string message;
/// @brief Log message text.
std::string message;
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_

View File

@@ -0,0 +1,53 @@
/**
* @file services/logging/log_producer.h
* @brief Channel-backed log producer for asynchronous pipeline logging.
*
* The producer captures log records from application code and forwards them to
* a bounded channel for later processing by the dispatcher.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_
#include <string_view>
#include "concurrency/bounded_channel.h"
#include "services/logging/log_entry.h"
#include "services/logging/logger.h"
/**
* @class LogProducer
* @brief ILogger implementation that forwards entries to a bounded channel.
*
* Non-copyable and non-movable. The channel reference is non-owning and must
* remain valid for the lifetime of the producer.
*/
class LogProducer final : public ILogger {
public:
/**
* @brief Construct a channel-backed producer.
*
* @param channel Reference to the bounded channel used for log transfer.
*/
explicit LogProducer(BoundedChannel<LogEntry>& channel);
LogProducer(const LogProducer&) = delete;
LogProducer& operator=(const LogProducer&) = delete;
LogProducer(LogProducer&&) = delete;
LogProducer& operator=(LogProducer&&) = delete;
~LogProducer() override = default;
/**
* @brief Queue a log message for asynchronous processing.
*
* Blocks while the channel applies backpressure.
*/
void Log(LogLevel level, PipelinePhase phase,
std::string_view message) override;
private:
BoundedChannel<LogEntry>& channel_;
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_CHANNEL_LOGGER_H_

View File

@@ -1,9 +1,9 @@
/**
* @file services/logging/logger.h
* @brief Abstract logging interface for pipeline components.
* @brief Abstract logging interface used by pipeline components.
*
* Intent: Decouple logging from channel/worker implementation details.
* All pipeline components depend on ILogger, enabling swappable backends.
* The interface keeps application code independent from the concrete logging
* transport, buffering, and formatting implementation.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOGGER_H_
@@ -17,10 +17,10 @@
/**
* @class ILogger
* @brief Minimal interface for submitting log entries.
* @brief Minimal interface for submitting structured log messages.
*
* Non-copyable and non-movable. Implementations are typically short-lived,
* created and owned by the composition root.
* Implementations are non-copyable and non-movable. They are typically owned
* by the composition root and injected into services that emit diagnostics.
*/
class ILogger {
public:
@@ -32,11 +32,11 @@ class ILogger {
virtual ~ILogger() = default;
/**
* @brief Submit a log entry to the logging subsystem.
* @brief Submit a log message to the logging subsystem.
*
* @param level Log level (Debug, Info, Warn, Error).
* @param phase Pipeline execution phase (Startup, Generation, Teardown, etc.).
* @param message Log message text.
* @param level Severity of the message.
* @param phase Pipeline execution phase associated with the message.
* @param message Log message text.
*/
virtual void Log(LogLevel level, PipelinePhase phase,
std::string_view message) = 0;