Refactor logging system: replace LogLevel with Log::Level across multiple files for improved consistency and clarity
This commit is contained in:
parent
358b48e407
commit
6803524989
@ -1,4 +1,3 @@
|
||||
#include "webserv/log/LogLevel.hpp"
|
||||
#include "webserv/socket/Socket.hpp"
|
||||
|
||||
#include <webserv/client/Client.hpp>
|
||||
|
||||
4
webserv/log/Channel.cpp
Normal file
4
webserv/log/Channel.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include <webserv/log/Channel.hpp>
|
||||
|
||||
|
||||
Channel::Channel(Log::Level logLevel) : logLevel_(logLevel) {}
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserv/log/Log.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -10,7 +10,7 @@ class Channel
|
||||
{
|
||||
public:
|
||||
Channel() = default;
|
||||
Channel(LogLevel logLevel);
|
||||
Channel(Log::Level logLevel);
|
||||
virtual ~Channel() = default;
|
||||
|
||||
Channel(const Channel &other) = delete;
|
||||
@ -18,9 +18,9 @@ class Channel
|
||||
Channel &operator=(const Channel &other) = delete;
|
||||
Channel &&operator=(const Channel &&other) = delete;
|
||||
|
||||
virtual void log(LogLevel &logLevel, const std::string &message,
|
||||
virtual void log(Log::Level &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context = {}) = 0;
|
||||
|
||||
protected:
|
||||
LogLevel logLevel_{LogLevel::LOGLVL_TRACE};
|
||||
Log::Level logLevel_{Log::Level::Trace};
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
#include <webserv/log/Channel.hpp>
|
||||
|
||||
Channel::Channel(LogLevel logLevel) : logLevel_(logLevel) {}
|
||||
@ -1,12 +1,13 @@
|
||||
#include "webserv/log/LogLevel.hpp"
|
||||
|
||||
|
||||
#include <webserv/log/FileChannel.hpp>
|
||||
#include <webserv/log/Log.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
|
||||
FileChannel::FileChannel(const std::string &filename, std::ios_base::openmode mode, LogLevel logLevel)
|
||||
FileChannel::FileChannel(const std::string &filename, std::ios_base::openmode mode, Log::Level logLevel)
|
||||
: Channel(logLevel), filename_(filename), fileStream_(filename, mode)
|
||||
{
|
||||
if (!fileStream_.is_open())
|
||||
@ -23,7 +24,7 @@ FileChannel::~FileChannel()
|
||||
}
|
||||
}
|
||||
|
||||
void FileChannel::log(LogLevel &logLevel, const std::string &message, const std::map<std::string, std::string> &context)
|
||||
void FileChannel::log(Log::Level &logLevel, const std::string &message, const std::map<std::string, std::string> &context)
|
||||
{
|
||||
if (logLevel < logLevel_)
|
||||
{
|
||||
@ -42,7 +43,7 @@ void FileChannel::log(LogLevel &logLevel, const std::string &message, const std:
|
||||
|
||||
// Format the log message
|
||||
fileStream_ << "[" << std::put_time(tm, "%Y-%m-%d %H:%M:%S") << "] "
|
||||
<< "[" << logLevelToString(logLevel) << "] " << message << '\n';
|
||||
<< "[" << Log::logLevelToString(logLevel) << "] " << message << '\n';
|
||||
|
||||
// Log the context if it exists
|
||||
if (!context.empty())
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserv/log/Channel.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
@ -10,7 +10,7 @@
|
||||
class FileChannel : public Channel
|
||||
{
|
||||
public:
|
||||
FileChannel(const std::string &filename, std::ios_base::openmode mode, LogLevel logLevel = LogLevel::LOGLVL_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;
|
||||
@ -18,7 +18,7 @@ class FileChannel : public Channel
|
||||
FileChannel &&operator=(const FileChannel &&other) = delete;
|
||||
|
||||
~FileChannel();
|
||||
void log(LogLevel &logLevel, const std::string &message,
|
||||
void log(Log::Level &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context = {}) override;
|
||||
|
||||
private:
|
||||
|
||||
@ -13,7 +13,7 @@ Log::Log()
|
||||
start_time_ = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void Log::setStdoutChannel(LogLevel logLevel)
|
||||
void Log::setStdoutChannel(Log::Level logLevel)
|
||||
{
|
||||
Log &log = getInstance();
|
||||
if (log.channels_.contains("stdout"))
|
||||
@ -30,7 +30,7 @@ void Log::setStdoutChannel(LogLevel logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
void Log::setFileChannel(const std::string &filename, std::ios_base::openmode mode, LogLevel logLevel)
|
||||
void Log::setFileChannel(const std::string &filename, std::ios_base::openmode mode, Log::Level logLevel)
|
||||
{
|
||||
Log &log = getInstance();
|
||||
if (log.channels_.contains("file"))
|
||||
@ -53,7 +53,7 @@ Log &Log::getInstance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Log::log(LogLevel level, const std::string &message, const std::map<std::string, std::string> &context,
|
||||
void Log::log(Log::Level level, const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
for (auto &it : channels_)
|
||||
@ -81,35 +81,76 @@ int Log::getElapsedTime()
|
||||
void Log::trace(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_TRACE, message, context, location);
|
||||
getInstance().log(Log::Level::Trace, message, context, location);
|
||||
}
|
||||
|
||||
void Log::debug(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_DEBUG, message, context, location);
|
||||
getInstance().log(Log::Level::Debug, message, context, location);
|
||||
}
|
||||
|
||||
void Log::info(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_INFO, message, context, location);
|
||||
getInstance().log(Log::Level::Info, message, context, location);
|
||||
}
|
||||
|
||||
void Log::warning(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_WARN, message, context, location);
|
||||
getInstance().log(Log::Level::Warn, message, context, location);
|
||||
}
|
||||
|
||||
void Log::error(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_ERROR, message, context, location);
|
||||
getInstance().log(Log::Level::Error, message, context, location);
|
||||
}
|
||||
|
||||
void Log::fatal(const std::string &message, const std::map<std::string, std::string> &context,
|
||||
const std::source_location &location)
|
||||
{
|
||||
getInstance().log(LogLevel::LOGLVL_FATAL, message, context, location);
|
||||
getInstance().log(Log::Level::Fatal, message, context, location);
|
||||
}
|
||||
|
||||
std::string Log::logLevelToString(Log::Level level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.level == level)
|
||||
{
|
||||
return std::string(mapping.name);
|
||||
}
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *Log::logLevelToColor(Log::Level level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.level == level)
|
||||
{
|
||||
return mapping.color;
|
||||
}
|
||||
}
|
||||
return "\033[0m"; // Default to reset
|
||||
}
|
||||
|
||||
std::string Log::logLevelToColoredString(Log::Level level)
|
||||
{
|
||||
return std::string(Log::logLevelToColor(level)) + Log::logLevelToString(level) + "\033[0m";
|
||||
}
|
||||
|
||||
Log::Level Log::stringToLogLevel(const std::string &level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.name == level)
|
||||
{
|
||||
return mapping.level;
|
||||
}
|
||||
}
|
||||
return Log::Level::Info; // Default fallback
|
||||
}
|
||||
@ -1,45 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserv/log/Channel.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
// #include <webserv/log/Channel.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <source_location>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
/*
|
||||
TODO ACTUALLY WE USE C++20 SO WE CAN USE std::source_location TO AUTOMATICALLY CAPTURE FILE, LINE, FUNCTION
|
||||
|
||||
#include <source_location>
|
||||
|
||||
void log(LogLevel level, const std::string& message,
|
||||
std::source_location location = std::source_location::current()) {
|
||||
std::cout << "File: " << location.file_name() << std::endl;
|
||||
std::cout << "Line: " << location.line() << std::endl;
|
||||
std::cout << "Function: " << location.function_name() << std::endl;
|
||||
}
|
||||
|
||||
No macros needed!!!!
|
||||
*/
|
||||
|
||||
class Channel; // Forward declaration
|
||||
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
enum class Level : uint8_t
|
||||
{
|
||||
Trace = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Fatal = 5
|
||||
};
|
||||
|
||||
Log(const Log &other) = delete;
|
||||
Log(const Log &&other) = delete;
|
||||
Log &operator=(const Log &other) = delete;
|
||||
Log &&operator=(const Log &&other) = delete;
|
||||
|
||||
void log(LogLevel 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);
|
||||
|
||||
static void setFileChannel(const std::string &filename, std::ios_base::openmode mode = std::ios_base::app,
|
||||
LogLevel logLevel = LogLevel::LOGLVL_TRACE);
|
||||
static void setStdoutChannel(LogLevel logLevel = LogLevel::LOGLVL_TRACE);
|
||||
Level logLevel = Level::Trace);
|
||||
static void setStdoutChannel(Level logLevel = Level::Trace);
|
||||
|
||||
static int getElapsedTime();
|
||||
|
||||
@ -55,6 +52,10 @@ 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);
|
||||
static Log::Level stringToLogLevel(const std::string &level);
|
||||
|
||||
private:
|
||||
Log();
|
||||
@ -64,4 +65,21 @@ class Log
|
||||
|
||||
std::chrono::steady_clock::time_point start_time_;
|
||||
std::unordered_map<std::string, std::unique_ptr<Channel>> channels_;
|
||||
|
||||
|
||||
|
||||
struct LogLevelMapping
|
||||
{
|
||||
Log::Level level;
|
||||
std::string_view name;
|
||||
const char *color;
|
||||
};
|
||||
|
||||
constexpr static std::array<LogLevelMapping, 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"}}};
|
||||
};
|
||||
@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
// TODO LOG_LEVEL_MAP should not be in the global namespace, but i do think this is the nice way? lets refactor this to
|
||||
// the log class or use a seperate namespace or put everything in a log namespace except for the class, then everything
|
||||
// has Log::
|
||||
|
||||
enum class LogLevel : uint8_t
|
||||
{
|
||||
LOGLVL_TRACE = 0,
|
||||
LOGLVL_DEBUG = 1,
|
||||
LOGLVL_INFO = 2,
|
||||
LOGLVL_WARN = 3,
|
||||
LOGLVL_ERROR = 4,
|
||||
LOGLVL_FATAL = 5
|
||||
};
|
||||
|
||||
// ANSI color codes
|
||||
namespace LogColors
|
||||
{
|
||||
constexpr const char *RESET = "\033[0m";
|
||||
constexpr const char *TRACE_COLOR = "\033[36m"; // Cyan
|
||||
constexpr const char *DEBUG_COLOR = "\033[90m"; // Bright black (gray)
|
||||
constexpr const char *INFO_COLOR = "\033[37m"; // White
|
||||
constexpr const char *WARN_COLOR = "\033[33m"; // Yellow
|
||||
constexpr const char *ERROR_COLOR = "\033[31m"; // Red
|
||||
constexpr const char *FATAL_COLOR = "\033[1;31m"; // Bold red
|
||||
} // namespace LogColors
|
||||
|
||||
// Constexpr bidirectional mapping
|
||||
struct LogLevelMapping
|
||||
{
|
||||
LogLevel level;
|
||||
std::string_view name;
|
||||
const char *color;
|
||||
};
|
||||
|
||||
constexpr std::array<LogLevelMapping, 6> LOG_LEVEL_MAP = {
|
||||
{{.level = LogLevel::LOGLVL_TRACE, .name = "TRACE", .color = LogColors::TRACE_COLOR},
|
||||
{.level = LogLevel::LOGLVL_DEBUG, .name = "DEBUG", .color = LogColors::DEBUG_COLOR},
|
||||
{.level = LogLevel::LOGLVL_INFO, .name = "INFO", .color = LogColors::INFO_COLOR},
|
||||
{.level = LogLevel::LOGLVL_WARN, .name = "WARN", .color = LogColors::WARN_COLOR},
|
||||
{.level = LogLevel::LOGLVL_ERROR, .name = "ERROR", .color = LogColors::ERROR_COLOR},
|
||||
{.level = LogLevel::LOGLVL_FATAL, .name = "FATAL", .color = LogColors::FATAL_COLOR}}};
|
||||
|
||||
inline std::string logLevelToString(LogLevel level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.level == level)
|
||||
{
|
||||
return std::string(mapping.name);
|
||||
}
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
inline const char *logLevelToColor(LogLevel level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.level == level)
|
||||
{
|
||||
return mapping.color;
|
||||
}
|
||||
}
|
||||
return LogColors::RESET;
|
||||
}
|
||||
|
||||
inline std::string logLevelToColoredString(LogLevel level)
|
||||
{
|
||||
return std::string(logLevelToColor(level)) + logLevelToString(level) + LogColors::RESET;
|
||||
}
|
||||
|
||||
inline LogLevel stringToLogLevel(const std::string &level)
|
||||
{
|
||||
for (const auto &mapping : LOG_LEVEL_MAP)
|
||||
{
|
||||
if (mapping.name == level)
|
||||
{
|
||||
return mapping.level;
|
||||
}
|
||||
}
|
||||
return LogLevel::LOGLVL_INFO; // Default fallback
|
||||
}
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
#include <webserv/log/Channel.hpp>
|
||||
#include <webserv/log/Log.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
StdoutChannel::StdoutChannel(LogLevel logLevel) : Channel(logLevel) {}
|
||||
StdoutChannel::StdoutChannel(Log::Level logLevel) : Channel(logLevel) {}
|
||||
|
||||
StdoutChannel::~StdoutChannel() {}
|
||||
|
||||
void StdoutChannel::log(LogLevel &logLevel, const std::string &message,
|
||||
void StdoutChannel::log(Log::Level &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context)
|
||||
{
|
||||
if (logLevel < logLevel_)
|
||||
@ -20,7 +20,7 @@ void StdoutChannel::log(LogLevel &logLevel, const std::string &message,
|
||||
return;
|
||||
}
|
||||
std::cout << "[" << std::setw(3) << std::setfill('0') << Log::getElapsedTime() << "] ";
|
||||
std::string prefix = "[" + logLevelToColoredString(logLevel) + "] ";
|
||||
std::string prefix = "[" + Log::logLevelToColoredString(logLevel) + "] ";
|
||||
std::cout << prefix;
|
||||
std::cout << message;
|
||||
if (!context.empty())
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
class StdoutChannel : public Channel
|
||||
{
|
||||
public:
|
||||
StdoutChannel(LogLevel logLevel = LogLevel::LOGLVL_TRACE);
|
||||
StdoutChannel(Log::Level logLevel = Log::Level::Trace);
|
||||
|
||||
StdoutChannel(const StdoutChannel &other) = delete;
|
||||
StdoutChannel(const StdoutChannel &&other) = delete;
|
||||
@ -14,6 +14,6 @@ class StdoutChannel : public Channel
|
||||
|
||||
~StdoutChannel();
|
||||
|
||||
void log(LogLevel &logLevel, const std::string &message,
|
||||
void log(Log::Level &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context = {}) override;
|
||||
};
|
||||
@ -2,7 +2,6 @@
|
||||
#include <webserv/config/LocationConfig.hpp>
|
||||
#include <webserv/config/ServerConfig.hpp>
|
||||
#include <webserv/log/Log.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
#include <webserv/server/Server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
@ -16,8 +15,8 @@ int main(int argc, char **argv)
|
||||
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n"; // NOLINT
|
||||
return 1;
|
||||
}
|
||||
Log::setFileChannel("webserv.log", std::ios_base::app, LogLevel::LOGLVL_TRACE);
|
||||
Log::setStdoutChannel(LogLevel::LOGLVL_INFO);
|
||||
Log::setFileChannel("webserv.log", std::ios_base::app, Log::Level::Trace);
|
||||
Log::setStdoutChannel(Log::Level::Info);
|
||||
Log::info("\n======================\nStarting webserv...\n======================\n");
|
||||
ConfigManager::getInstance().init(argv[1]); // NOLINT
|
||||
Server server(ConfigManager::getInstance());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user