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

View File

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

View File

@ -2,7 +2,6 @@
#include <webserv/log/Channel.hpp> #include <webserv/log/Channel.hpp>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <string> #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 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(const FileChannel &&other) = delete; FileChannel(FileChannel &&other) = delete;
FileChannel &operator=(const FileChannel &other) = delete; FileChannel &operator=(const FileChannel &other) = delete;
FileChannel &&operator=(const FileChannel &&other) = delete; FileChannel &operator=(FileChannel &&other) = delete;
~FileChannel(); ~FileChannel() override;
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; const std::map<std::string, std::string> &context = {}) override;
private: private:

View File

@ -5,6 +5,7 @@
#include <chrono> #include <chrono>
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#include <memory>
#include <source_location> #include <source_location>
Log::Log() Log::Log()
@ -22,7 +23,7 @@ void Log::setStdoutChannel(Log::Level logLevel)
} }
try 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) catch (const std::exception &e)
{ {
@ -39,7 +40,7 @@ void Log::setFileChannel(const std::string &filename, std::ios_base::openmode mo
} }
try 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) catch (const std::exception &e)
{ {
@ -135,12 +136,12 @@ const char *Log::logLevelToColor(Log::Level level)
return mapping.color; return mapping.color;
} }
} }
return "\033[0m"; // Default to reset return RESET_COLOR; // Default to reset
} }
std::string Log::logLevelToColoredString(Log::Level level) 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) Log::Level Log::stringToLogLevel(const std::string &level)

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
// #include <webserv/log/Channel.hpp>
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <map> #include <map>
@ -27,9 +25,9 @@ class Log
}; };
Log(const Log &other) = delete; 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=(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, void log(Level level, const std::string &message, const std::map<std::string, std::string> &context,
const std::source_location &location); const std::source_location &location);
@ -52,6 +50,7 @@ class Log
const std::source_location &location = std::source_location::current()); const std::source_location &location = std::source_location::current());
static void fatal(const std::string &message, const std::map<std::string, std::string> &context = {}, static void fatal(const std::string &message, const std::map<std::string, std::string> &context = {},
const std::source_location &location = std::source_location::current()); const std::source_location &location = std::source_location::current());
static std::string logLevelToString(Level level); static std::string logLevelToString(Level level);
static const char *logLevelToColor(Level level); static const char *logLevelToColor(Level level);
static std::string logLevelToColoredString(Level level); static std::string logLevelToColoredString(Level level);
@ -66,20 +65,20 @@ class Log
std::chrono::steady_clock::time_point start_time_; std::chrono::steady_clock::time_point start_time_;
std::unordered_map<std::string, std::unique_ptr<Channel>> channels_; std::unordered_map<std::string, std::unique_ptr<Channel>> channels_;
struct LevelMapping
struct LogLevelMapping
{ {
Log::Level level; Log::Level level;
std::string_view name; std::string_view name;
const char *color; 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::Trace, .name = "TRACE", .color = "\033[36m"},
{.level = Log::Level::Debug, .name = "DEBUG", .color = "\033[90m"}, {.level = Log::Level::Debug, .name = "DEBUG", .color = "\033[90m"},
{.level = Log::Level::Info, .name = "INFO", .color = "\033[37m"}, {.level = Log::Level::Info, .name = "INFO", .color = "\033[37m"},
{.level = Log::Level::Warn, .name = "WARN", .color = "\033[33m"}, {.level = Log::Level::Warn, .name = "WARN", .color = "\033[33m"},
{.level = Log::Level::Error, .name = "ERROR", .color = "\033[31m"}, {.level = Log::Level::Error, .name = "ERROR", .color = "\033[31m"},
{.level = Log::Level::Fatal, .name = "FATAL", .color = "\033[1;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/Channel.hpp>
#include <webserv/log/Log.hpp> #include <webserv/log/Log.hpp>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <map> #include <map>
StdoutChannel::StdoutChannel(Log::Level logLevel) : Channel(logLevel) {} StdoutChannel::StdoutChannel(Log::Level logLevel)
{
setLogLevel(logLevel);
}
StdoutChannel::~StdoutChannel() {} void StdoutChannel::log(const Log::Level &logLevel, const std::string &message,
void StdoutChannel::log(Log::Level &logLevel, const std::string &message,
const std::map<std::string, std::string> &context) const std::map<std::string, std::string> &context)
{ {
if (logLevel < logLevel_) if (logLevel < getLogLevel())
{ {
return; return;
} }
@ -25,12 +25,18 @@ void StdoutChannel::log(Log::Level &logLevel, const std::string &message,
std::cout << message; std::cout << message;
if (!context.empty()) if (!context.empty())
{ {
std::cout << " Context: {"; std::cout << "\n\t| Context: {";
bool first = true;
for (const auto &[key, value] : context) 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(Log::Level logLevel = Log::Level::Trace);
StdoutChannel(const StdoutChannel &other) = delete; 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=(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; 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::setFileChannel("webserv.log", std::ios_base::app, Log::Level::Trace);
Log::setStdoutChannel(Log::Level::Info); Log::setStdoutChannel(Log::Level::Info);
Log::info("\n======================\nStarting webserv...\n======================\n"); Log::info("\n======================\nStarting webserv...\n======================\n");
Log::warning("Testing context", {{ "key1", "value1"}, {"key2", "value2"}});
ConfigManager::getInstance().init(argv[1]); // NOLINT ConfigManager::getInstance().init(argv[1]); // NOLINT
Server server(ConfigManager::getInstance()); Server server(ConfigManager::getInstance());
server.start(); server.start();