diff --git a/app/include/logger_worker.hpp b/app/include/logger_worker.hpp index 3280e84..3466d50 100644 --- a/app/include/logger_worker.hpp +++ b/app/include/logger_worker.hpp @@ -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 Очередь входящих сообщений. diff --git a/app/src/logger_worker.cpp b/app/src/logger_worker.cpp index 85c3bf3..f63dbdd 100644 --- a/app/src/logger_worker.cpp +++ b/app/src/logger_worker.cpp @@ -1,11 +1,12 @@ #include "logger_worker.hpp" #include +#include 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); diff --git a/app/src/main.cpp b/app/src/main.cpp index 002096a..5ea9457 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -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 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(); diff --git a/logger/include/logger.hpp b/logger/include/logger.hpp index 41db5cb..841c8a8 100644 --- a/logger/include/logger.hpp +++ b/logger/include/logger.hpp @@ -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 Записывает сообщение в журнал с указанным уровнем логирования.