Implement logging level support in Channel and its derived classes

- Added LogLevel parameter to Channel constructor and updated derived classes (FileChannel, StdoutChannel) to accept it.
- Modified log methods to respect the logging level, preventing lower priority logs from being processed.
- Updated Log class to set logging levels for stdout and file channels.
- Adjusted main function to initialize logging with specified levels.
This commit is contained in:
whaffman 2025-09-21 20:49:25 +02:00
parent 66e57fef59
commit bac66d2a0b
9 changed files with 65 additions and 15 deletions

View File

@ -10,6 +10,7 @@ class Channel
{
public:
Channel() = default;
Channel(LogLevel logLevel);
virtual ~Channel() = default;
Channel(const Channel &other) = delete;
@ -19,4 +20,7 @@ class Channel
virtual void log(LogLevel &logLevel, const std::string &message,
const std::map<std::string, std::string> &context = {}) = 0;
protected:
LogLevel logLevel_{LogLevel::LOGLVL_TRACE};
};

3
webserv/log/Channnel.cpp Normal file
View File

@ -0,0 +1,3 @@
#include <webserv/log/Channel.hpp>
Channel::Channel(LogLevel logLevel) : logLevel_(logLevel) {}

View File

@ -5,7 +5,8 @@
#include <chrono>
#include <iostream>
FileChannel::FileChannel(const std::string &filename) : filename_(filename), fileStream_(filename, std::ios::trunc)
FileChannel::FileChannel(const std::string &filename, LogLevel logLevel)
: Channel(logLevel), filename_(filename), fileStream_(filename, std::ios::trunc)
{
if (!fileStream_.is_open())
{
@ -23,6 +24,10 @@ FileChannel::~FileChannel()
void FileChannel::log(LogLevel &logLevel, const std::string &message, const std::map<std::string, std::string> &context)
{
if (logLevel < logLevel_)
{
return;
}
if (!fileStream_.is_open())
{
std::cerr << "Log file is not open: " << filename_ << '\n';

View File

@ -10,7 +10,7 @@
class FileChannel : public Channel
{
public:
FileChannel(const std::string &filename);
FileChannel(const std::string &filename, LogLevel logLevel = LogLevel::LOGLVL_TRACE);
FileChannel(const FileChannel &other) = delete;
FileChannel(const FileChannel &&other) = delete;

View File

@ -10,10 +10,27 @@ Log::Log()
{
// get start time
start_time_ = std::chrono::steady_clock::now();
channels_.insert({"stdout", std::unique_ptr<Channel>(new StdoutChannel())});
}
void Log::setFile(const std::string &filename)
void Log::setStdoutChannel(LogLevel logLevel)
{
Log &log = getInstance();
if (log.channels_.contains("stdout"))
{
log.channels_.erase("stdout");
}
try
{
log.channels_.insert({"stdout", std::unique_ptr<Channel>(new StdoutChannel(logLevel))});
}
catch (const std::exception &e)
{
std::cerr << "Failed to set stdout log channel: " << e.what() << '\n';
}
}
void Log::setFileChannel(const std::string &filename, LogLevel logLevel)
{
Log &log = getInstance();
if (log.channels_.contains("file"))
@ -22,7 +39,7 @@ void Log::setFile(const std::string &filename)
}
try
{
log.channels_.insert({"file", std::unique_ptr<Channel>(new FileChannel(filename))});
log.channels_.insert({"file", std::unique_ptr<Channel>(new FileChannel(filename, logLevel))});
}
catch (const std::exception &e)
{
@ -39,18 +56,16 @@ Log &Log::getInstance()
void Log::log(LogLevel level, const std::string &message, const std::string &channel,
const std::map<std::string, std::string> &context)
{
auto it = channels_.find(channel);
if (it != channels_.end())
for (auto &it : channels_)
{
it->second->log(level, message, context);
it.second->log(level, message, context);
}
}
void Log::log(LogLevel level, const std::string &message, const std::string &file, int line,
const std::string &function, const std::string &channel,
const std::map<std::string, std::string> &context)
{
auto it = channels_.find(channel);
if (it != channels_.end())
for (auto &it : channels_)
{
std::string extendedMessage;
extendedMessage += message + " | ";
@ -67,7 +82,7 @@ void Log::log(LogLevel level, const std::string &message, const std::string &fil
extendedMessage += " (" + function + ")";
}
// extendedMessage += " | " + message;
it->second->log(level, extendedMessage, context);
it.second->log(level, extendedMessage, context);
}
}

View File

@ -28,7 +28,8 @@ class Log
Log &operator=(const Log &other) = delete;
Log &&operator=(const Log &&other) = delete;
static void setFile(const std::string &filename);
static void setFileChannel(const std::string &filename, LogLevel logLevel = LogLevel::LOGLVL_TRACE);
static void setStdoutChannel(LogLevel logLevel = LogLevel::LOGLVL_TRACE);
void log(LogLevel level, const std::string &message, const std::string &channel = "stdout",
const std::map<std::string, std::string> &context = {});

View File

@ -1,12 +1,24 @@
#include <webserv/log/StdoutChannel.hpp>
#include "webserv/log/StdoutChannel.hpp"
#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() {}
void StdoutChannel::log(LogLevel &logLevel, const std::string &message,
const std::map<std::string, std::string> &context)
{
if (logLevel < logLevel_)
{
return;
}
std::cout << "[" << std::setw(3) << std::setfill('0') << Log::getElapsedTime() << "] ";
std::string prefix = "[" + logLevelToColoredString(logLevel) + "] ";
std::cout << prefix;

View File

@ -5,6 +5,15 @@
class StdoutChannel : public Channel
{
public:
StdoutChannel(LogLevel logLevel = LogLevel::LOGLVL_TRACE);
StdoutChannel(const StdoutChannel &other) = delete;
StdoutChannel(const StdoutChannel &&other) = delete;
StdoutChannel &operator=(const StdoutChannel &other) = delete;
StdoutChannel &&operator=(const StdoutChannel &&other) = delete;
~StdoutChannel();
void log(LogLevel &logLevel, const std::string &message,
const std::map<std::string, std::string> &context = {}) override;
};

View File

@ -16,7 +16,8 @@ int main(int argc, char **argv)
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n"; // NOLINT
return 1;
}
Log::setFile("webserv.log");
Log::setFileChannel("webserv.log", LogLevel::LOGLVL_WARN);
Log::setStdoutChannel(LogLevel::LOGLVL_TRACE);
ConfigManager::getInstance().init(argv[1]); // NOLINT
Server server(ConfigManager::getInstance());
server.start();