From c0228b0c12df4dce38540516790e272645e99a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=93=D0=BB=D0=B0=D0=B7=D1=83?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Jan 2026 00:23:04 +0300 Subject: [PATCH] logger added --- .gitignore | 3 ++ CMakeLists.txt | 1 + config.ini | 2 ++ src/config.cpp | 17 +++++++++++ src/config.hpp | 4 +++ src/logger.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/logger.hpp | 36 +++++++++++++++++++++++ src/main.cpp | 7 ++++- src/server.cpp | 25 ++++++++++------ src/utils.cpp | 23 ++++++++++++--- src/utils.hpp | 2 +- 11 files changed, 182 insertions(+), 15 deletions(-) create mode 100644 src/logger.cpp create mode 100644 src/logger.hpp diff --git a/.gitignore b/.gitignore index 55912ec..0fda8b5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ install_strip_local_manifest.txt .venv/ my_own_redis + + +*.log \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f40c703..06958dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES src/config.cpp src/server.cpp src/net_util.cpp + src/logger.cpp ) add_executable(my_own_redis ${SOURCES}) diff --git a/config.ini b/config.ini index 081e2d6..eeacd07 100644 --- a/config.ini +++ b/config.ini @@ -1,2 +1,4 @@ port 6379 address 127.0.0.1 +log_level INFO +log_file not_redis.log diff --git a/src/config.cpp b/src/config.cpp index 61ab4f6..11b8f0f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -18,6 +18,8 @@ void Config::load_from_file(const std::string& filename) { std::cout << "Using default parameters: 127.0.0.1:6379\n"; address = "127.0.0.1"; port = 6379; + log_level = "INFO"; + log_file = ""; return; } @@ -27,12 +29,19 @@ void Config::load_from_file(const std::string& filename) { file >> address; } else if (key == "port") { file >> port; + } else if (key == "log_level") { + file >> log_level; + } else if (key == "log_file") { + file >> log_file; } else { std::cerr << "Unknown key: " << key << "\n"; continue; } } + // Set defaults if not provided + if (log_level.empty()) log_level = "INFO"; + file.close(); } @@ -44,6 +53,14 @@ int Config::get_port() const { return port; } +std::string Config::get_log_level() const { + return log_level; +} + +std::string Config::get_log_file() const { + return log_file; +} + void Config::check_required_keys() const { if (address.empty()) { std::cerr << "Address is not set\n"; diff --git a/src/config.hpp b/src/config.hpp index 5c5ebfb..3b592ad 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -11,12 +11,16 @@ public: // Геттеры std::string get_address() const; int get_port() const; + std::string get_log_level() const; + std::string get_log_file() const; void check_required_keys() const; private: std::string address; int port; + std::string log_level; + std::string log_file; void load_from_file(const std::string& filename); }; diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..6c17ae4 --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,77 @@ +#include "logger.hpp" +#include +#include +#include +#include + +LogLevel Logger::current_level = LogLevel::INFO; +std::ofstream Logger::log_file; +std::mutex Logger::log_mutex; +bool Logger::to_file = false; + +void Logger::init(const std::string& level, const std::string& file_path) { + std::lock_guard lock(log_mutex); + current_level = string_to_level(level); + + if (!file_path.empty()) { + log_file.open(file_path, std::ios::app); + if (log_file.is_open()) { + to_file = true; + } else { + std::cerr << "Failed to open log file: " << file_path << ". Logging to console only.\n"; + } + } +} + +void Logger::log(LogLevel level, const std::string& msg) { + if (level < current_level) return; + + std::lock_guard lock(log_mutex); + std::string timestamp = get_timestamp(); + std::string level_str = level_to_string(level); + + std::ostream& out = (level == LogLevel::ERROR) ? std::cerr : std::cout; + + std::string full_msg = "[" + timestamp + "] [" + level_str + "] " + msg + "\n"; + + out << full_msg; + if (to_file) { + log_file << full_msg; + log_file.flush(); + } +} + +void Logger::log_info(const std::string& msg) { log(LogLevel::INFO, msg); } +void Logger::log_error(const std::string& msg) { log(LogLevel::ERROR, msg); } +void Logger::log_warning(const std::string& msg) { log(LogLevel::WARNING, msg); } +void Logger::log_debug(const std::string& msg) { log(LogLevel::DEBUG, msg); } + +LogLevel Logger::string_to_level(const std::string& level) { + std::string upper_level = level; + std::transform(upper_level.begin(), upper_level.end(), upper_level.begin(), ::toupper); + + if (upper_level == "DEBUG") return LogLevel::DEBUG; + if (upper_level == "INFO") return LogLevel::INFO; + if (upper_level == "WARNING") return LogLevel::WARNING; + if (upper_level == "ERROR") return LogLevel::ERROR; + + return LogLevel::INFO; +} + +std::string Logger::level_to_string(LogLevel level) { + switch (level) { + case LogLevel::DEBUG: return "DEBUG"; + case LogLevel::INFO: return "INFO"; + case LogLevel::WARNING: return "WARNING"; + case LogLevel::ERROR: return "ERROR"; + default: return "UNKNOWN"; + } +} + +std::string Logger::get_timestamp() { + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S"); + return ss.str(); +} diff --git a/src/logger.hpp b/src/logger.hpp new file mode 100644 index 0000000..a0e2ef9 --- /dev/null +++ b/src/logger.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + +enum class LogLevel { + DEBUG, + INFO, + WARNING, + ERROR +}; + +class Logger { +public: + static void init(const std::string& level, const std::string& file_path = ""); + + static void log(LogLevel level, const std::string& msg); + static void log_info(const std::string& msg); + static void log_error(const std::string& msg); + static void log_warning(const std::string& msg); + static void log_debug(const std::string& msg); + +private: + Logger() = default; + + static LogLevel string_to_level(const std::string& level); + static std::string level_to_string(LogLevel level); + static std::string get_timestamp(); + + static LogLevel current_level; + static std::ofstream log_file; + static std::mutex log_mutex; + static bool to_file; +}; diff --git a/src/main.cpp b/src/main.cpp index c4efaf8..9e90f90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "config.hpp" #include "server.hpp" #include "utils.hpp" +#include "logger.hpp" int main() { std::signal(SIGINT, stop_program); @@ -11,10 +12,14 @@ int main() { Config config("config.ini"); config.check_required_keys(); + Logger::init(config.get_log_level(), config.get_log_file()); + Logger::log_info("Logger initialized"); + Server server(config); + print_logo(); server.run(); } catch (const std::exception& e) { - std::cerr << "Fatal error: " << e.what() << "\n"; + Logger::log_error("Fatal error: " + std::string(e.what())); return EXIT_FAILURE; } diff --git a/src/server.cpp b/src/server.cpp index c89648b..31e3d41 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -14,6 +14,7 @@ #include "net_util.hpp" #include "constants.hpp" #include "utils.hpp" +#include "logger.hpp" Server::Server(const Config& config) @@ -51,36 +52,39 @@ void Server::setup() { throw std::runtime_error("Error listening for connections"); } - std::cout << "Server started on " << address << ":" << port << "\n"; + Logger::log_info("Server started on " + address + ":" + std::to_string(port)); } int32_t Server::handle_connection(int connectionfd) { - std::cout << "Waiting for data from " << connectionfd << "\n"; + Logger::log_debug("Waiting for data from fd=" + std::to_string(connectionfd)); uint32_t len_net = 0; errno = 0; if (read_full(connectionfd, &len_net, sizeof(len_net)) != 0) { - print_error(errno == 0 ? "EOF from client" : "Error reading length"); + if (errno == 0) { + Logger::log_info("Client disconnected (EOF) from fd=" + std::to_string(connectionfd)); + } else { + Logger::log_error("Error reading length from fd=" + std::to_string(connectionfd) + ": " + std::strerror(errno)); + } return -1; } uint32_t len = ntohl(len_net); if (len > k_max_message_size) { - print_error("Message length is too long"); - std::cerr << len << " > " << k_max_message_size << "\n"; + Logger::log_error("Message length is too long: " + std::to_string(len) + " (max: " + std::to_string(k_max_message_size) + ")"); return -1; } std::string message(len, '\0'); if (len > 0) { if (read_full(connectionfd, message.data(), len) != 0) { - print_error("Error reading payload"); + Logger::log_error("Error reading payload from fd=" + std::to_string(connectionfd)); return -1; } } - std::cout << "Client says: " << message << "\n"; + Logger::log_info("Client (fd=" + std::to_string(connectionfd) + ") says: " + message); const std::string reply = "world"; uint32_t reply_len_net = htonl(static_cast(reply.size())); @@ -99,16 +103,19 @@ void Server::run() { socklen_t addrlen = sizeof(client_addr); int connectionfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen); if (connectionfd < 0) { + Logger::log_error("accept() error: " + std::string(std::strerror(errno))); continue; } - std::cout << "Accepted connection from " << connectionfd << "\n"; + + Logger::log_info("Accepted connection from " + std::string(inet_ntoa(client_addr.sin_addr)) + ":" + std::to_string(ntohs(client_addr.sin_port)) + " (fd=" + std::to_string(connectionfd) + ")"); + while (true) { int32_t err = handle_connection(connectionfd); if (err) { break; } } - std::cout << "Closing connection from " << connectionfd << "\n"; + Logger::log_info("Closing connection from " + std::to_string(connectionfd)); close(connectionfd); } } diff --git a/src/utils.cpp b/src/utils.cpp index 64421ff..a5feb31 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,13 +1,28 @@ #include #include #include +#include +#include "logger.hpp" void stop_program(int signum) { - std::cout << "\nInterrupt signal (" << signum << ") received.\n"; - std::cout << "Exiting program...\n"; - exit(signum); + Logger::log_info("Interrupt signal (" + std::to_string(signum) + ") received. Shutting down..."); + exit(signum); } void print_error(const std::string& msg) { - std::cerr << msg << ": " << std::strerror(errno) << "\n"; + Logger::log_error(msg + ": " + std::strerror(errno)); } + + +void print_logo() { + std::cout << R"( +╔════════════════════════════════════════════════════════════╗ +║ _ _____ ______ _____ _____ _____ ║ +║ | | | __ \| ____| __ \_ _|/ ____|║ +║ _ __ ___ | |_ __ _ | |__) | |__ | | | || | | (___ ║ +║| '_ \ / _ \| __| / _` | | _ /| __| | | | || | \___ \ ║ +║| | | | (_) | |_ | (_| | | | \ \| |____| |__| || |_ ____) |║ +║|_| |_|\___/ \__| \__,_| |_| \_\______|_____/_____|_____/ ║ +╚════════════════════════════════════════════════════════════╝ +)" << std::endl; +} \ No newline at end of file diff --git a/src/utils.hpp b/src/utils.hpp index 6c81c7d..46697d4 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -5,4 +5,4 @@ void stop_program(int signum); void print_error(const std::string& msg); - +void print_logo();