Refactor logging system: enhance Channel and FileChannel classes to use getter/setter for log level, improve log context formatting in StdoutChannel, and update main to test logging context

This commit is contained in:
whaffman 2025-09-22 13:13:29 +02:00
parent 6803524989
commit 6b85be65b8
9 changed files with 66 additions and 44 deletions

View File

@ -1,4 +1,11 @@
#include <webserv/log/Channel.hpp>
Log::Level Channel::getLogLevel() const
{
return logLevel_;
}
Channel::Channel(Log::Level logLevel) : logLevel_(logLevel) {}
void Channel::setLogLevel(Log::Level level)
{
logLevel_ = level;
}

View File

@ -2,7 +2,6 @@
#include <webserv/log/Log.hpp>
#include <map>
#include <string>
@ -10,17 +9,18 @@ class Channel
{
public:
Channel() = default;
Channel(Log::Level logLevel);
virtual ~Channel() = default;
Channel(const Channel &other) = delete;
Channel(const Channel &&other) = delete;
Channel(Channel &&other) = delete;
Channel &operator=(const Channel &other) = delete;
Channel &&operator=(const Channel &&other) = delete;
virtual void log(Log::Level &logLevel, const std::string &message,
Channel &operator=(Channel &&other) = delete;
virtual void log(const Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context = {}) = 0;
protected:
[[nodiscard]] Log::Level getLogLevel() const;
void setLogLevel(Log::Level level);
private:
Log::Level logLevel_{Log::Level::Trace};
};

View File

@ -8,8 +8,9 @@
#include <iostream>
FileChannel::FileChannel(const std::string &filename, std::ios_base::openmode mode, Log::Level logLevel)
: Channel(logLevel), filename_(filename), fileStream_(filename, mode)
: filename_(filename), fileStream_(filename, mode)
{
setLogLevel(logLevel);
if (!fileStream_.is_open())
{
std::cerr << "Failed to open log file: " << filename << '\n';
@ -24,9 +25,10 @@ FileChannel::~FileChannel()
}
}
void FileChannel::log(Log::Level &logLevel, const std::string &message, const std::map<std::string, std::string> &context)
void FileChannel::log(const Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context)
{
if (logLevel < logLevel_)
if (logLevel < getLogLevel())
{
return;
}
@ -48,11 +50,18 @@ void FileChannel::log(Log::Level &logLevel, const std::string &message, const st
// Log the context if it exists
if (!context.empty())
{
fileStream_ << "Context:" << '\n';
fileStream_ << "\n\t| Context: {";
bool first = true;
for (const auto &[key, value] : context)
{
fileStream_ << " " << key << ": " << value << '\n';
if (!first)
{
fileStream_ << ", ";
}
fileStream_ << key << ": " << value;
first = false;
}
fileStream_ << "}\n";
}
fileStream_ << std::flush;
}

View File

@ -2,7 +2,6 @@
#include <webserv/log/Channel.hpp>
#include <fstream>
#include <map>
#include <string>
@ -13,12 +12,12 @@ class FileChannel : public Channel
FileChannel(const std::string &filename, std::ios_base::openmode mode, Log::Level logLevel = Log::Level::Trace);
FileChannel(const FileChannel &other) = delete;
FileChannel(const FileChannel &&other) = delete;
FileChannel(FileChannel &&other) = delete;
FileChannel &operator=(const FileChannel &other) = delete;
FileChannel &&operator=(const FileChannel &&other) = delete;
FileChannel &operator=(FileChannel &&other) = delete;
~FileChannel();
void log(Log::Level &logLevel, const std::string &message,
~FileChannel() override;
void log(const Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context = {}) override;
private:

View File

@ -5,6 +5,7 @@
#include <chrono>
#include <filesystem>
#include <iostream>
#include <memory>
#include <source_location>
Log::Log()
@ -22,7 +23,7 @@ void Log::setStdoutChannel(Log::Level logLevel)
}
try
{
log.channels_.insert({"stdout", std::unique_ptr<Channel>(new StdoutChannel(logLevel))});
log.channels_["stdout"] = std::make_unique<StdoutChannel>(logLevel);
}
catch (const std::exception &e)
{
@ -39,7 +40,7 @@ void Log::setFileChannel(const std::string &filename, std::ios_base::openmode mo
}
try
{
log.channels_.insert({"file", std::unique_ptr<Channel>(new FileChannel(filename, mode, logLevel))});
log.channels_["file"] = std::make_unique<FileChannel>(filename, mode, logLevel);
}
catch (const std::exception &e)
{
@ -135,12 +136,12 @@ const char *Log::logLevelToColor(Log::Level level)
return mapping.color;
}
}
return "\033[0m"; // Default to reset
return RESET_COLOR; // Default to reset
}
std::string Log::logLevelToColoredString(Log::Level level)
{
return std::string(Log::logLevelToColor(level)) + Log::logLevelToString(level) + "\033[0m";
return std::string(Log::logLevelToColor(level)) + Log::logLevelToString(level) + RESET_COLOR;
}
Log::Level Log::stringToLogLevel(const std::string &level)

View File

@ -1,7 +1,5 @@
#pragma once
// #include <webserv/log/Channel.hpp>
#include <array>
#include <chrono>
#include <map>
@ -27,9 +25,9 @@ class Log
};
Log(const Log &other) = delete;
Log(const Log &&other) = delete;
Log(Log &&other) = delete;
Log &operator=(const Log &other) = delete;
Log &&operator=(const Log &&other) = delete;
Log &operator=(Log &&other) = delete;
void log(Level level, const std::string &message, const std::map<std::string, std::string> &context,
const std::source_location &location);
@ -52,6 +50,7 @@ class Log
const std::source_location &location = std::source_location::current());
static void fatal(const std::string &message, const std::map<std::string, std::string> &context = {},
const std::source_location &location = std::source_location::current());
static std::string logLevelToString(Level level);
static const char *logLevelToColor(Level level);
static std::string logLevelToColoredString(Level level);
@ -66,20 +65,20 @@ class Log
std::chrono::steady_clock::time_point start_time_;
std::unordered_map<std::string, std::unique_ptr<Channel>> channels_;
struct LogLevelMapping
struct LevelMapping
{
Log::Level level;
std::string_view name;
const char *color;
};
constexpr static std::array<LogLevelMapping, 6> LOG_LEVEL_MAP = {
constexpr static std::array<LevelMapping, 6> LOG_LEVEL_MAP = {
{{.level = Log::Level::Trace, .name = "TRACE", .color = "\033[36m"},
{.level = Log::Level::Debug, .name = "DEBUG", .color = "\033[90m"},
{.level = Log::Level::Info, .name = "INFO", .color = "\033[37m"},
{.level = Log::Level::Warn, .name = "WARN", .color = "\033[33m"},
{.level = Log::Level::Error, .name = "ERROR", .color = "\033[31m"},
{.level = Log::Level::Fatal, .name = "FATAL", .color = "\033[1;31m"}}};
constexpr static const char* RESET_COLOR = "\033[0m";
};

View File

@ -3,19 +3,19 @@
#include <webserv/log/Channel.hpp>
#include <webserv/log/Log.hpp>
#include <iomanip>
#include <iostream>
#include <map>
StdoutChannel::StdoutChannel(Log::Level logLevel) : Channel(logLevel) {}
StdoutChannel::StdoutChannel(Log::Level logLevel)
{
setLogLevel(logLevel);
}
StdoutChannel::~StdoutChannel() {}
void StdoutChannel::log(Log::Level &logLevel, const std::string &message,
void StdoutChannel::log(const Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context)
{
if (logLevel < logLevel_)
if (logLevel < getLogLevel())
{
return;
}
@ -25,12 +25,18 @@ void StdoutChannel::log(Log::Level &logLevel, const std::string &message,
std::cout << message;
if (!context.empty())
{
std::cout << " Context: {";
std::cout << "\n\t| Context: {";
bool first = true;
for (const auto &[key, value] : context)
{
std::cout << key << ": " << value << ", ";
if (!first)
{
std::cout << ", ";
}
std::cout << "}";
std::cout << key << ": " << value;
first = false;
}
std::cout << "\n";
std::cout << "}\n";
}
std::cout << "\n" << std::flush;
}

View File

@ -8,12 +8,12 @@ class StdoutChannel : public Channel
StdoutChannel(Log::Level logLevel = Log::Level::Trace);
StdoutChannel(const StdoutChannel &other) = delete;
StdoutChannel(const StdoutChannel &&other) = delete;
StdoutChannel(StdoutChannel &&other) = delete;
StdoutChannel &operator=(const StdoutChannel &other) = delete;
StdoutChannel &&operator=(const StdoutChannel &&other) = delete;
StdoutChannel &operator=(StdoutChannel &&other) = delete;
~StdoutChannel();
~StdoutChannel() override = default;
void log(Log::Level &logLevel, const std::string &message,
void log(const Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context = {}) override;
};

View File

@ -18,6 +18,7 @@ int main(int argc, char **argv)
Log::setFileChannel("webserv.log", std::ios_base::app, Log::Level::Trace);
Log::setStdoutChannel(Log::Level::Info);
Log::info("\n======================\nStarting webserv...\n======================\n");
Log::warning("Testing context", {{ "key1", "value1"}, {"key2", "value2"}});
ConfigManager::getInstance().init(argv[1]); // NOLINT
Server server(ConfigManager::getInstance());
server.start();