Implement pipeline logging with bounded channels and orchestrator integration

This commit is contained in:
Aaron Po
2026-05-14 21:08:17 -04:00
parent f93b14897b
commit 74f11b57e2
16 changed files with 361 additions and 61 deletions

View File

@@ -0,0 +1,37 @@
/**
* @file services/logging/channel_logger.h
* @brief Channel-backed implementation of the Logger interface.
*
* ChannelLogger constructs LogEntry values and forwards them to a
* BoundedChannel<LogEntry> for asynchronous consumption by LogConsumer.
* The channel is injected by reference; ChannelLogger does not own it.
*/
#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 final : public ILogger {
public:
explicit ChannelLogger(BoundedChannel<LogEntry>& channel);
ChannelLogger(const ChannelLogger&) = delete;
ChannelLogger& operator=(const ChannelLogger&) = delete;
ChannelLogger(ChannelLogger&&) = delete;
ChannelLogger& operator=(ChannelLogger&&) = delete;
~ChannelLogger() override = default;
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

@@ -0,0 +1,44 @@
/**
* @file services/logging/log_consumer.h
* @brief Dedicated log drain worker for the pipeline logging channel.
*
* LogConsumer runs on its own thread, draining LogEntry items from a
* BoundedChannel<LogEntry> and forwarding them to spdlog. Exits cleanly
* when the channel is closed.
*/
#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 {
public:
explicit LogConsumer(BoundedChannel<LogEntry>& channel);
LogConsumer(const LogConsumer&) = delete;
LogConsumer& operator=(const LogConsumer&) = delete;
LogConsumer(LogConsumer&&) = delete;
LogConsumer& operator=(LogConsumer&&) = delete;
/**
* @brief Drains the channel until it is closed.
*
* Intended to be run on a dedicated std::thread. Exits when:
* - The channel is closed and the queue is fully drained.
*/
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,41 @@
/**
* @file services/logging/log_entry.h
* @brief POD struct representing a single log event in the pipeline.
*
* LogEntry is produced by PipelineLogger and consumed by LogWorker via
* BoundedChannel<LogEntry>. All fields are value types so entries are
* safely movable across the channel without shared ownership.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_
#include <chrono>
#include <string>
enum class LogLevel {
Debug,
Info,
Warn,
Error,
};
enum class PipelinePhase {
Startup,
UserGeneration,
BreweryAndBeerGeneration,
CheckinGeneration,
RatingGeneration,
FollowGeneration,
Teardown,
};
struct LogEntry {
std::chrono::system_clock::time_point timestamp =
std::chrono::system_clock::now();
LogLevel level;
PipelinePhase phase;
std::string message;
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOG_ENTRY_H_

View File

@@ -0,0 +1,31 @@
/**
* @file services/logging/logger.h
* @brief Abstract interface for pipeline logging.
*
* Kept intentionally narrow. Components that need to log depend on Logger,
* not on PipelineLogger or any channel type.
*/
#ifndef BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOGGER_H_
#define BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOGGER_H_
#include <optional>
#include <string>
#include <string_view>
#include "services/logging/log_entry.h"
class ILogger {
public:
ILogger() = default;
ILogger(const ILogger&) = delete;
ILogger& operator=(const ILogger&) = delete;
ILogger(ILogger&&) = delete;
ILogger& operator=(ILogger&&) = delete;
virtual ~ILogger() = default;
virtual void Log(LogLevel level, PipelinePhase phase,
std::string_view message) = 0;
};
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_LOGGING_LOGGER_H_