diff --git a/webserv/log/Channel.hpp b/webserv/log/Channel.hpp new file mode 100644 index 0000000..e3d8299 --- /dev/null +++ b/webserv/log/Channel.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include +#include + +class Channel +{ + public: + Channel() = default; + virtual ~Channel() = default; + + Channel(const Channel &other) = delete; + Channel(const Channel &&other) = delete; + Channel &operator=(const Channel &other) = delete; + Channel &&operator=(const Channel &&other) = delete; + + virtual void log(LogLevel &logLevel, const std::string &message, + const std::map &context = {}) = 0; +}; \ No newline at end of file diff --git a/webserv/log/Log.cpp b/webserv/log/Log.cpp new file mode 100644 index 0000000..90fa947 --- /dev/null +++ b/webserv/log/Log.cpp @@ -0,0 +1,44 @@ +#include "webserv/log/StdoutChannel.hpp" +#include + +Log::Log() +{ + channels_.insert({"stdout", std::unique_ptr(new StdoutChannel())}); +} + +Log &Log::getInstance() +{ + static Log instance; + + return instance; +} + +void Log::log(LogLevel level, const std::string &message, const std::string &channel, + const std::map &context) +{ + auto it = channels_.find(channel); + if (it != channels_.end()) + { + it->second->log(level, message, context); + } +} + +void Log::debug(const std::string &message, const std::map &context) +{ + getInstance().log(LogLevel::DEBUG, message, "stdout", context); +} + +void Log::info(const std::string &message, const std::map &context) +{ + getInstance().log(LogLevel::INFO, message, "stdout", context); +} + +void Log::warning(const std::string &message, const std::map &context) +{ + getInstance().log(LogLevel::WARN, message, "stdout", context); +} + +void Log::error(const std::string &message, const std::map &context) +{ + getInstance().log(LogLevel::ERROR, message, "stdout", context); +} \ No newline at end of file diff --git a/webserv/log/Log.hpp b/webserv/log/Log.hpp new file mode 100644 index 0000000..47e8e41 --- /dev/null +++ b/webserv/log/Log.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "webserv/log/Channel.hpp" +#include +#include +#include +#include +#include + +class Channel; // Forward declaration + +class Log +{ + public: + 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::string &channel = "stdout", + const std::map &context = {}); + + static void debug(const std::string &message, const std::map &context = {}); + static void info(const std::string &message, const std::map &context = {}); + static void warning(const std::string &message, const std::map &context = {}); + static void error(const std::string &message, const std::map &context = {}); + + private: + Log(); + ~Log() = default; + static Log &getInstance(); + + std::unordered_map> channels_; +}; \ No newline at end of file diff --git a/webserv/log/LogLevel.hpp b/webserv/log/LogLevel.hpp new file mode 100644 index 0000000..9314c4d --- /dev/null +++ b/webserv/log/LogLevel.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +enum class LogLevel : uint8_t +{ + DEBUG, + INFO, + WARN, + ERROR +}; + +inline std::string logLevelToString(LogLevel level) +{ + switch (level) + { + case LogLevel::DEBUG: + return "DEBUG"; + case LogLevel::INFO: + return "INFO"; + case LogLevel::WARN: + return "WARN"; + case LogLevel::ERROR: + return "ERROR"; + } + return "UNKNOWN"; // Fallback to silence warnings +} \ No newline at end of file diff --git a/webserv/log/StdoutChannel.cpp b/webserv/log/StdoutChannel.cpp new file mode 100644 index 0000000..592e2c4 --- /dev/null +++ b/webserv/log/StdoutChannel.cpp @@ -0,0 +1,21 @@ +#include +#include +#include + +void StdoutChannel::log(LogLevel &logLevel, const std::string &message, + const std::map &context) +{ + std::string prefix = "[" + logLevelToString(logLevel) + "] "; + std::cout << prefix; + std::cout << message; + if (!context.empty()) + { + std::cout << " Context: {"; + for (const auto &[key, value] : context) + { + std::cout << key << ": " << value << ", "; + } + std::cout << "}"; + } + std::cout << "\n"; +} \ No newline at end of file diff --git a/webserv/log/StdoutChannel.hpp b/webserv/log/StdoutChannel.hpp new file mode 100644 index 0000000..bb63b85 --- /dev/null +++ b/webserv/log/StdoutChannel.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +class StdoutChannel : public Channel +{ + public: + void log(LogLevel &logLevel, const std::string &message, + const std::map &context = {}) override; +}; \ No newline at end of file diff --git a/webserv/main.cpp b/webserv/main.cpp index 1f6270d..514e0fd 100644 --- a/webserv/main.cpp +++ b/webserv/main.cpp @@ -1,3 +1,4 @@ +#include "webserv/log/Log.hpp" #include #include #include @@ -16,6 +17,8 @@ int main(int argc, char **argv) } ConfigManager::getInstance().init(argv[1]); // NOLINT Server server(ConfigManager::getInstance()); + + Log::info("test log message: server starting...", {{"port", "8080"}, {"mode", "production"}}); server.start(); return 0;