feat(app): add interactive logger configuration and ownership transfer

This commit is contained in:
user
2026-07-21 15:24:00 +04:00
parent 569208c271
commit 1c109960eb
4 changed files with 250 additions and 13 deletions
+41 -2
View File
@@ -13,6 +13,9 @@ namespace app {
* LoggerWorker получает сообщения из MessageQueue и передаёт их
* в библиотеку Logger для записи в файл.
*
* Logger передаётся в worker по значению и перемещается внутрь объекта.
* LoggerWorker становится владельцем логгера.
*
* Объект Logger используется только внутри рабочего потока,
* поэтому потокобезопасность Logger не требуется.
*/
@@ -21,10 +24,12 @@ public:
/**
* @brief Создаёт worker для записи сообщений.
*
* Переданный Logger перемещается внутрь объекта LoggerWorker.
*
* @param logger Логгер, используемый для записи.
* @param queue Очередь сообщений.
*/
LoggerWorker(logger::Logger &logger, MessageQueue &queue);
LoggerWorker(logger::Logger logger, MessageQueue &queue);
/**
* @brief Останавливает поток записи.
@@ -44,11 +49,45 @@ public:
*/
LoggerWorker &operator=(const LoggerWorker &) = delete;
/**
* @brief Разрешает перемещение worker.
*
* Передаёт владение потоком записи и состоянием объекта.
*/
LoggerWorker(LoggerWorker &&) noexcept = default;
/**
* @brief Разрешает перемещающее присваивание worker.
*/
LoggerWorker &operator=(LoggerWorker &&) noexcept = default;
/**
* @brief Запускает поток записи сообщений.
*/
void start();
/**
* @brief Возвращает используемый логгер.
*
* Позволяет получить текущую конфигурацию логгера,
* например имя файла журнала или уровень логирования
* по умолчанию.
*
* @return Константная ссылка на логгер.
*/
[[nodiscard]]
const logger::Logger &getLogger() const;
/**
* @brief Устанавливает новый логгер.
*
* Новый Logger заменяет текущий.
* Переданный объект перемещается внутрь worker.
*
* @param logger Новый логгер.
*/
void setLogger(logger::Logger logger);
/**
* @brief Останавливает обработку сообщений.
*
@@ -70,7 +109,7 @@ private:
*
* Используется только рабочим потоком.
*/
logger::Logger &logger_;
logger::Logger logger_;
/**
* @brief Очередь входящих сообщений.
+9 -2
View File
@@ -1,11 +1,12 @@
#include "logger_worker.hpp"
#include <iostream>
#include <utility>
namespace app {
LoggerWorker::LoggerWorker(logger::Logger &logger, MessageQueue &queue)
: logger_(logger), queue_(queue) {}
LoggerWorker::LoggerWorker(logger::Logger logger, MessageQueue &queue)
: logger_(std::move(logger)), queue_(queue) {}
LoggerWorker::~LoggerWorker() { stop(); }
@@ -21,6 +22,12 @@ void LoggerWorker::stop() {
}
}
const logger::Logger &LoggerWorker::getLogger() const { return logger_; }
void LoggerWorker::setLogger(logger::Logger logger) {
logger_ = std::move(logger);
}
void LoggerWorker::process() {
while (auto message = queue_.pop()) {
auto status = logger_.writeMessage(message->level, message->message);
+192 -5
View File
@@ -5,22 +5,209 @@
#include "logger_worker.hpp"
#include "message_queue.hpp"
namespace {
void printMainMenu() {
std::cout << "\n*** Logger ***\n"
<< " 1: [w]rite message\n"
<< " 2: [c]onfigure\n"
<< " 3: [q]uit\n"
<< "What now> ";
}
void printConfigureMenu() {
std::cout << "\n*** Configure ***\n"
<< " 1: change [d]efault level\n"
<< " 2: change [c]urrent level\n"
<< " 3: [b]ack\n"
<< "What now> ";
}
void printWriteMenu() {
std::cout << "\n*** Write Message ***\n"
<< " 1: use [d]efault level\n"
<< " 2: use [c]urrent level\n"
<< " 3: [b]ack\n"
<< "What now> ";
}
void printLogLevelMenu(const std::string &title,
logger::LogLevel currentLevel) {
std::cout << "\n*** " << title << " ***\n"
<< "\nCurrent: " << currentLevel.toString() << "\n\n"
<< " 1: [d]ebug\n"
<< " 2: [i]nfo\n"
<< " 3: [e]rror\n"
<< " 4: [b]ack\n"
<< "Select level> ";
}
char readCommand() {
std::string command;
std::getline(std::cin, command);
return command.empty() ? '\0' : command.front();
}
} // namespace
int main() {
logger::Logger logger("app.log", logger::LogLevel::info());
app::MessageQueue queue;
app::LoggerWorker worker(logger, queue);
app::LoggerWorker worker(std::move(logger), queue);
worker.start();
std::string message;
logger::LogLevel currentLevel = logger::LogLevel::info();
bool running = true;
while (running) {
printMainMenu();
switch (readCommand()) {
case 'w': {
bool writing = true;
while (writing) {
printWriteMenu();
std::optional<logger::LogLevel> level;
switch (readCommand()) {
case 'd':
level = worker.getLogger().getLogLevel();
break;
case 'c':
level = currentLevel;
break;
case 'b':
writing = false;
continue;
default:
std::cout << "Unknown command.\n";
continue;
}
std::cout << "Message> ";
std::string message;
std::getline(std::cin, message);
queue.push({*level, message});
writing = false;
}
while (std::getline(std::cin, message)) {
if (message == "exit") {
break;
}
queue.push({logger::LogLevel::info(), message});
case 'c': {
bool configuring = true;
while (configuring) {
printConfigureMenu();
switch (readCommand()) {
case 'd': {
bool selecting = true;
while (selecting) {
printLogLevelMenu("Default Log Level",
worker.getLogger().getLogLevel());
switch (readCommand()) {
case 'd':
worker.setLogger(
worker.getLogger().withLogLevel(logger::LogLevel::debug()));
selecting = false;
break;
case 'i':
worker.setLogger(
worker.getLogger().withLogLevel(logger::LogLevel::info()));
selecting = false;
break;
case 'e':
worker.setLogger(
worker.getLogger().withLogLevel(logger::LogLevel::error()));
selecting = false;
break;
case 'b':
selecting = false;
break;
default:
std::cout << "Unknown command.\n";
break;
}
}
break;
}
case 'c': {
bool selecting = true;
while (selecting) {
printLogLevelMenu("Current Log Level", currentLevel);
switch (readCommand()) {
case 'd':
currentLevel = logger::LogLevel::debug();
selecting = false;
break;
case 'i':
currentLevel = logger::LogLevel::info();
selecting = false;
break;
case 'e':
currentLevel = logger::LogLevel::error();
selecting = false;
break;
case 'b':
selecting = false;
break;
default:
std::cout << "Unknown command.\n";
break;
}
}
break;
}
case 'b':
configuring = false;
break;
default:
std::cout << "Unknown command.\n";
break;
}
}
break;
}
case 'q':
running = false;
break;
default:
std::cout << "Unknown command.\n";
break;
}
}
worker.stop();
+8 -4
View File
@@ -49,14 +49,18 @@ public:
Logger &operator=(const Logger &) = delete;
/**
* @brief Запрещает перемещение Logger.
* @brief Разрешает перемещение Logger.
*
* Передаёт владение ресурсами новому объекту.
*/
Logger(Logger &&) = delete;
Logger(Logger &&) noexcept = default;
/**
* @brief Запрещает перемещающее присваивание.
* @brief Разрешает перемещающее присваивание.
*
* Передаёт владение ресурсами новому объекту.
*/
Logger &operator=(Logger &&) = delete;
Logger &operator=(Logger &&) noexcept = default;
/**
* @brief Записывает сообщение в журнал с указанным уровнем логирования.