logger added

This commit is contained in:
Илья Глазунов 2026-01-11 00:23:04 +03:00
parent 4819674833
commit c0228b0c12
11 changed files with 182 additions and 15 deletions

3
.gitignore vendored
View File

@ -14,3 +14,6 @@ install_strip_local_manifest.txt
.venv/
my_own_redis
*.log

View File

@ -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})

View File

@ -1,2 +1,4 @@
port 6379
address 127.0.0.1
log_level INFO
log_file not_redis.log

View File

@ -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";

View File

@ -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);
};

77
src/logger.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "logger.hpp"
#include <chrono>
#include <iomanip>
#include <algorithm>
#include <sstream>
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<std::mutex> 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<std::mutex> 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();
}

36
src/logger.hpp Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <mutex>
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;
};

View File

@ -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;
}

View File

@ -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<uint32_t>(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);
}
}

View File

@ -1,13 +1,28 @@
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include "logger.hpp"
void stop_program(int signum) {
std::cout << "\nInterrupt signal (" << signum << ") received.\n";
std::cout << "Exiting program...\n";
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;
}

View File

@ -5,4 +5,4 @@
void stop_program(int signum);
void print_error(const std::string& msg);
void print_logo();