Implement file logging functionality with FileChannel class and update Log class to support file output
This commit is contained in:
parent
6262cda801
commit
94cd396ac1
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ build
|
||||
|
||||
|
||||
|
||||
webserv.log
|
||||
|
||||
55
webserv/log/FileChannel.cpp
Normal file
55
webserv/log/FileChannel.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "webserv/log/LogLevel.hpp"
|
||||
#include <webserv/log/FileChannel.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
FileChannel::FileChannel(const std::string &filename)
|
||||
: filename_(filename),
|
||||
fileStream_(filename, std::ios::trunc)
|
||||
{
|
||||
if (!fileStream_.is_open())
|
||||
{
|
||||
std::cerr << "Failed to open log file: " << filename << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
FileChannel::~FileChannel()
|
||||
{
|
||||
if (fileStream_.is_open())
|
||||
{
|
||||
fileStream_.close();
|
||||
}
|
||||
}
|
||||
|
||||
void FileChannel::log(LogLevel &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context)
|
||||
{
|
||||
if (!fileStream_.is_open())
|
||||
{
|
||||
std::cerr << "Log file is not open: " << filename_ << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current time
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_c = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm *tm = std::localtime(&now_c);
|
||||
|
||||
// Format the log message
|
||||
fileStream_ << "[" << std::put_time(tm, "%Y-%m-%d %H:%M:%S") << "] "
|
||||
<< "[" << logLevelToString(logLevel) << "] " << message << '\n';
|
||||
|
||||
// Log the context if it exists
|
||||
if (!context.empty())
|
||||
{
|
||||
fileStream_ << "Context:" << '\n';
|
||||
for (const auto &[key, value] : context)
|
||||
{
|
||||
fileStream_ << " " << key << ": " << value << '\n';
|
||||
}
|
||||
}
|
||||
fileStream_ << std::flush;
|
||||
}
|
||||
|
||||
27
webserv/log/FileChannel.hpp
Normal file
27
webserv/log/FileChannel.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserv/log/Channel.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
class FileChannel : public Channel
|
||||
{
|
||||
public:
|
||||
FileChannel(const std::string &filename);
|
||||
|
||||
FileChannel(const FileChannel &other) = delete;
|
||||
FileChannel(const FileChannel &&other) = delete;
|
||||
FileChannel &operator=(const FileChannel &other) = delete;
|
||||
FileChannel &&operator=(const FileChannel &&other) = delete;
|
||||
|
||||
~FileChannel();
|
||||
void log(LogLevel &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context = {}) override;
|
||||
|
||||
private:
|
||||
std::string filename_;
|
||||
std::ofstream fileStream_;
|
||||
};
|
||||
@ -1,16 +1,37 @@
|
||||
#include "webserv/log/StdoutChannel.hpp"
|
||||
#include <webserv/log/Log.hpp>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <webserv/log/FileChannel.hpp>
|
||||
#include <webserv/log/Log.hpp>
|
||||
#include <webserv/log/StdoutChannel.hpp>
|
||||
|
||||
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)
|
||||
{
|
||||
Log &log = getInstance();
|
||||
if (log.channels_.contains("file"))
|
||||
{
|
||||
log.channels_.erase("file");
|
||||
}
|
||||
try
|
||||
{
|
||||
log.channels_.insert({"file", std::unique_ptr<Channel>(new FileChannel(filename))});
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Failed to set log file: " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
Log &Log::getInstance()
|
||||
{
|
||||
static Log instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -24,7 +45,8 @@ void Log::log(LogLevel level, const std::string &message, const std::string &cha
|
||||
}
|
||||
}
|
||||
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)
|
||||
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())
|
||||
@ -47,6 +69,14 @@ std::string extendedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
int Log::getElapsedTime()
|
||||
{
|
||||
Log &log = Log::getInstance();
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - log.start_time_).count();
|
||||
return static_cast<int>(elapsed);
|
||||
}
|
||||
|
||||
void Log::static_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)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -7,8 +8,7 @@
|
||||
#include <webserv/log/Channel.hpp>
|
||||
#include <webserv/log/LogLevel.hpp>
|
||||
|
||||
#define LOG(level, message) \
|
||||
Log::static_log((level), (message), __FILE__, __LINE__, __FUNCTION__, "stdout", {})
|
||||
#define LOG(level, message) Log::static_log((level), (message), __FILE__, __LINE__, __FUNCTION__, "file", {})
|
||||
|
||||
#define LOG_TRACE(message) LOG(LogLevel::LOGLVL_TRACE, message)
|
||||
#define LOG_INFO(message) LOG(LogLevel::LOGLVL_INFO, message)
|
||||
@ -27,6 +27,8 @@ class Log
|
||||
Log &operator=(const Log &other) = delete;
|
||||
Log &&operator=(const Log &&other) = delete;
|
||||
|
||||
static void setFile(const std::string &filename);
|
||||
|
||||
void log(LogLevel level, const std::string &message, const std::string &channel = "stdout",
|
||||
const std::map<std::string, std::string> &context = {});
|
||||
|
||||
@ -34,6 +36,8 @@ class Log
|
||||
const std::string &function = "", const std::string &channel = "stdout",
|
||||
const std::map<std::string, std::string> &context = {});
|
||||
|
||||
static int getElapsedTime();
|
||||
|
||||
static void static_log(LogLevel level, const std::string &message, const std::string &file = "", int line = -1,
|
||||
const std::string &function = "", const std::string &channel = "stdout",
|
||||
const std::map<std::string, std::string> &context = {});
|
||||
@ -47,8 +51,10 @@ class Log
|
||||
|
||||
private:
|
||||
Log();
|
||||
|
||||
~Log() = default;
|
||||
static Log &getInstance();
|
||||
|
||||
std::chrono::steady_clock::time_point start_time_;
|
||||
std::unordered_map<std::string, std::unique_ptr<Channel>> channels_;
|
||||
};
|
||||
@ -1,10 +1,12 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <webserv/log/StdoutChannel.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
void StdoutChannel::log(LogLevel &logLevel, const std::string &message,
|
||||
const std::map<std::string, std::string> &context)
|
||||
{
|
||||
std::cout << "[" << std::setw(3) << std::setfill('0') << Log::getElapsedTime() << "] ";
|
||||
std::string prefix = "[" + logLevelToColoredString(logLevel) + "] ";
|
||||
std::cout << prefix;
|
||||
std::cout << message;
|
||||
|
||||
@ -15,16 +15,9 @@ int main(int argc, char **argv)
|
||||
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n"; // NOLINT
|
||||
return 1;
|
||||
}
|
||||
Log::setFile("webserv.log");
|
||||
ConfigManager::getInstance().init(argv[1]); // NOLINT
|
||||
Server server(ConfigManager::getInstance());
|
||||
LOG_TRACE("Trace message example.");
|
||||
LOG_INFO("Info message example.");
|
||||
LOG_DEBUG("Debug message example.");
|
||||
LOG_WARN("Warning message example.");
|
||||
LOG_ERROR("Error message example.");
|
||||
LOG_FATAL("Fatal message example.");
|
||||
|
||||
Log::info("test log message: server starting...", {{"port", "8080"}, {"mode", "production"}});
|
||||
server.start();
|
||||
|
||||
return 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user