Compare commits

...

2 Commits

Author SHA1 Message Date
user 86153e967b docs(logger): document thread safety limitations 2026-07-19 22:58:05 +04:00
user 223afbea40 feat(logger): add timestamp support to log messages 2026-07-19 22:57:14 +04:00
7 changed files with 72 additions and 4 deletions
+3 -2
View File
@@ -16,7 +16,8 @@ BUILD_DIR := $(ROOT_DIR)/build
TARGET := $(BUILD_DIR)/liblogger.so
SRC := src/logger.cpp
SRC := src/logger.cpp \
src/time_utils.cpp
.PHONY: all clean
@@ -31,7 +32,7 @@ $(TARGET): $(SRC)
$(CC) \
$(CXXFLAGS) \
-shared \
$< \
$^ \
-o $@ \
$(LDFLAGS)
+10
View File
@@ -65,6 +65,11 @@ public:
* При ошибке открытия файла или записи возвращается Status
* с описанием ошибки.
*
* @warning Класс Logger не является потокобезопасным.
* Одновременный вызов данного метода из нескольких потоков
* для одного и того же экземпляра Logger или одного файла журнала
* может привести к неопределённому порядку записей.
*
* @param level Уровень логирования сообщения.
* @param message Текст сообщения.
*
@@ -81,6 +86,11 @@ public:
* writeMessage(getLogLevel(), message);
* @endcode
*
* @warning Класс Logger не является потокобезопасным.
* Одновременный вызов данного метода из нескольких потоков
* для одного и того же экземпляра Logger или одного файла журнала
* может привести к неопределённому порядку записей.
*
* @param message Текст сообщения.
*
* @return Статус выполнения операции.
+6 -1
View File
@@ -2,6 +2,8 @@
#include <fstream>
#include "time_utils.hpp"
namespace logger {
Logger::Logger(const std::string &fileName, LogLevel defaultLevel)
@@ -10,13 +12,16 @@ Logger::Logger(const std::string &fileName, LogLevel defaultLevel)
Logger::~Logger() = default;
core::Status Logger::writeMessage(LogLevel level, const std::string &message) {
// std::ios::app — режим добавления в конец файла
// без удаления уже существующих записей.
std::ofstream stream(fileName_, std::ios::app);
if (!stream.is_open()) {
return core::Status::Failure("Unable to open log file: " + fileName_);
}
stream << "[" << level.toString() << "] " << message << '\n';
stream << '[' << time::getCurrentTimestamp() << "] [" << level.toString()
<< "] " << message << '\n';
if (!stream.good()) {
return core::Status::Failure("Failed to write to log file: " + fileName_);
+29
View File
@@ -0,0 +1,29 @@
#include "time_utils.hpp"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
namespace logger::time {
std::string getCurrentTimestamp() {
const auto now = std::chrono::system_clock::now();
const std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::tm localTime{};
#if defined(_WIN32)
localtime_s(&localTime, &currentTime);
#else
localtime_r(&currentTime, &localTime);
#endif
std::ostringstream stream;
stream << std::put_time(&localTime, "%Y-%m-%d %H:%M:%S");
return stream.str();
}
} // namespace logger::time
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <string>
namespace logger::time {
/**
* @brief Возвращает текущее локальное время.
*
* Время возвращается в формате:
*
* @code
* YYYY-MM-DD HH:MM:SS
* @endcode
*
* @return Текущее локальное время в виде строки.
*/
std::string getCurrentTimestamp();
} // namespace logger::time
+2 -1
View File
@@ -25,7 +25,8 @@ LOGGER_TEST_SRC := core/logger_test.cpp
SCOPED_FILE_TEST_SRC := helpers/scoped_file_test.cpp
LOGGER_SRC := $(ROOT_DIR)/logger/src/logger.cpp
LOGGER_SRC := $(ROOT_DIR)/logger/src/logger.cpp \
$(ROOT_DIR)/logger/src/time_utils.cpp
.PHONY: all test clean
+2
View File
@@ -85,6 +85,8 @@ void testMultipleWrites() {
Logger logger(file.getFileName(), LogLevel::info());
// NOTE: Ресурс файла был автоматически освобождён после первого вызова,
// поэтому следующий вызов может повторно открыть файл для записи
auto first = logger.writeMessage(LogLevel::info(), "first message");
auto second = logger.writeMessage(LogLevel::error(), "second message");