diff --git a/.gitignore b/.gitignore index e455c7f..0256658 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ front-generator/main-*.html # логи сервера в релизной версии http_server_*.log + +# папка с логами, используется для разработки +logs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index a7c928b..d8677d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,9 @@ add_compile_options(-Wall -Wextra -Wsign-conversion -DPROJECT_GIT_REVISION="${PR # максимальный размер тела запроса 200mb add_definitions(-DHTTP_MAX_PAYLOAD=200000000) +if(MANAGER_LOGS_DIR) + add_definitions(-DMANAGER_LOGS_DIR="${MANAGER_LOGS_DIR}") +endif() include_directories(src/) diff --git a/src/api-driver/structs.cpp b/src/api-driver/structs.cpp index bb0a92c..c3925f5 100644 --- a/src/api-driver/structs.cpp +++ b/src/api-driver/structs.cpp @@ -2,6 +2,7 @@ #include "api-driver/proxy.h" #include "common/nlohmann/json.hpp" #include +#include #include #include #include "terminal_api_driver.h" @@ -970,6 +971,98 @@ nlohmann::json api_driver::obj::TerminalRxTxSettings::asJson() const { api_driver::obj::TerminalRxTxSettings::~TerminalRxTxSettings() = default; +// Вспомогательная функция для получения отсортированного списка файлов логов +std::vector getLogFilesSorted(const std::string& path) { + std::vector files; + constexpr const char* logRegex = "manager_orlik_(\\d+)\\.log"; + std::regex pattern(logRegex); + + for (const auto& entry : std::filesystem::directory_iterator(path)) { + std::string filename = entry.path().filename().string(); + std::smatch match; + if (std::regex_match(filename, match, pattern)) { + files.push_back(filename); + } + } + + std::sort(files.begin(), files.end(), [](const std::string& a, const std::string& b) { + std::smatch matchA, matchB; + std::regex_match(a, matchA, std::regex(logRegex)); + std::regex_match(b, matchB, std::regex(logRegex)); + return std::stoi(matchA[1]) < std::stoi(matchB[1]); + }); + + return files; +} +api_driver::obj::TerminalManagerLogs::TerminalManagerLogs(const std::string& path): logsFileDir(path) {} + +std::string api_driver::obj::TerminalManagerLogs::loadPreview() { + auto logFiles = getLogFilesSorted(logsFileDir); + if (logFiles.empty()) return "No log files found..."; + + // Читаем файлы в обратном порядке (от новых к старым) + std::vector lines; + lines.reserve(1000); + + for (auto it = logFiles.rbegin(); it != logFiles.rend() && lines.size() < 1000; ++it) { + std::ifstream file(logsFileDir + *it, std::ios::binary); + if (!file) continue; + + // Читаем файл с конца для эффективности + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + std::string content(size, '\0'); + file.seekg(0); + file.read(&content[0], size); + + // Обрабатываем строки с конца файла + size_t pos = content.size(); + while (pos > 0 && lines.size() < 1000) { + size_t prev_pos = content.rfind('\n', pos - 1); + if (prev_pos == std::string::npos) { + lines.push_back(content.substr(0, pos)); + break; + } + lines.push_back(content.substr(prev_pos + 1, pos - prev_pos - 1)); + pos = prev_pos; + } + } + + // Собираем результат в правильном порядке + std::string result; + result.reserve(lines.size() * 100); // Предполагаемая средняя длина строки + for (auto it = lines.rbegin(); it != lines.rend(); ++it) { + result += *it; + result += '\n'; + } + + return result; +} + +std::string api_driver::obj::TerminalManagerLogs::loadPreviewWithFilter(const std::string& logLevel) { + return "Logs filtering not supported yet..."; +} + +void api_driver::obj::TerminalManagerLogs::loadFullLog(std::vector& destData) { + destData.clear(); + auto logFiles = getLogFilesSorted(logsFileDir); + + for (const auto& file : logFiles) { + std::ifstream stream(logsFileDir + file, std::ios::binary | std::ios::ate); + if (!stream) continue; + + std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + size_t currentSize = destData.size(); + destData.resize(currentSize + size); + stream.read(destData.data() + currentSize, size); + } +} + +api_driver::obj::TerminalManagerLogs::~TerminalManagerLogs() = default; + + diff --git a/src/api-driver/structs.h b/src/api-driver/structs.h index 48ae754..bc29cca 100644 --- a/src/api-driver/structs.h +++ b/src/api-driver/structs.h @@ -255,6 +255,23 @@ namespace api_driver::obj { ~TerminalRxTxSettings(); }; + +#ifdef API_OBJECT_MANAGER_LOGS_ENABLE + class TerminalManagerLogs { + public: + const std::string logsFileDir; + + TerminalManagerLogs(const std::string& path); + + std::string loadPreview(); + + std::string loadPreviewWithFilter(const std::string& logLevel); + + void loadFullLog(std::vector& destData); + + ~TerminalManagerLogs(); + }; +#endif // API_OBJECT_MANAGER_LOGS_ENABLE } #endif //STRUCTS_H diff --git a/src/auth/resources.h b/src/auth/resources.h index 5238b43..62af93a 100644 --- a/src/auth/resources.h +++ b/src/auth/resources.h @@ -47,11 +47,12 @@ namespace http::auth { static constexpr uint32_t SUPERUSER = 0x0001; static constexpr uint32_t WATCH_STATISTICS = 0x0002; // мониторинг модема static constexpr uint32_t RESET_PACKET_STATISTICS = 0x0004; // сброс статистики пакетов - static constexpr uint32_t WATCH_SETTINGS = 0x0008; // просмотр настроек , если недоступно, то вкладки с настройками не будет + static constexpr uint32_t WATCH_SETTINGS = 0x0008; // просмотр настроек, если недоступно, то вкладки с настройками не будет static constexpr uint32_t EDIT_SETTINGS = 0x0010; // редактирование настроек, установка параметров модулятора/демодулятора/dma/cinc static constexpr uint32_t UPDATE_FIRMWARE = 0x0020; // обновление прошивки static constexpr uint32_t SETUP_QOS = 0x0040; // управление профилем QoS static constexpr uint32_t DEVELOPER = 0x0080; // использование функций для разработчиков + static constexpr uint32_t VIEW_LOGS = 0x0100; // просмотр логов /** * Проверить, что у пользователя есть нужное право. Если это суперпользователь, то у него по умолчанию все права есть. diff --git a/src/main.cpp b/src/main.cpp index 96eed32..2ac5956 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -134,7 +134,8 @@ public: http::auth::User::WATCH_SETTINGS | http::auth::User::EDIT_SETTINGS | http::auth::User::UPDATE_FIRMWARE | - http::auth::User::SETUP_QOS)); + http::auth::User::SETUP_QOS | + http::auth::User::VIEW_LOGS)); // пароль fuckyou123 auth.users.emplace_back(std::make_shared("developer", "10628cfc434fb87f31d675d37e0402c2d824cfe8393aff7a61ee57aaa7d909c3", http::auth::User::SUPERUSER)); @@ -669,6 +670,35 @@ public: http::resource::loadFile("/tmp/weblog-statistics.csv", rep.content); })); #endif + +#ifdef API_OBJECT_MANAGER_LOGS_ENABLE + s.resources.emplace_back(std::make_unique("/api/get/manager.log", this->auth, http::auth::User::VIEW_LOGS, [this](const http::server::Request& req, auto& rep) { + if (req.method != "GET") { + http::server::stockReply(http::server::bad_request, rep); + return; + } + + bool isPreview = false; + if (req.url->params.find("preview") != req.url->params.end()) { + isPreview = true; + } + + std::string logLevelFilter; + if (req.url->params.find("level") != req.url->params.end()) { + logLevelFilter = req.url->params["level"]; + } + + rep.status = http::server::ok; + rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)}); + rep.content.clear(); + if (isPreview) { + auto result = logLevelFilter.empty() ? this->api->logs.loadPreview() : this->api->logs.loadPreviewWithFilter(logLevelFilter); + rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); + } else { + this->api->logs.loadFullLog(rep.content); + } + })); +#endif } ~ServerResources() = default; diff --git a/src/terminal_api_driver.cpp b/src/terminal_api_driver.cpp index 88565b9..3dfa2c9 100644 --- a/src/terminal_api_driver.cpp +++ b/src/terminal_api_driver.cpp @@ -8,13 +8,15 @@ #include #include #include + +#include "version.h" #include "common/nlohmann/json.hpp" #include "api-driver/daemon.h" typedef boost::property_tree::ptree::path_type json_path; -api_driver::ApiDriver::ApiDriver() = default; +api_driver::ApiDriver::ApiDriver(): logs(MANAGER_LOGS_DIR) {}; void api_driver::ApiDriver::startDaemon() { if (daemon == nullptr) { diff --git a/src/terminal_api_driver.h b/src/terminal_api_driver.h index 23fbaf5..59d317f 100644 --- a/src/terminal_api_driver.h +++ b/src/terminal_api_driver.h @@ -6,6 +6,7 @@ #include #include +#include "api-driver/structs.h" #include "common/nlohmann/json.hpp" namespace api_driver { @@ -96,6 +97,10 @@ namespace api_driver { std::string getOtaFileLocation() const; #endif +#ifdef API_OBJECT_MANAGER_LOGS_ENABLE + obj::TerminalManagerLogs logs; +#endif + ~ApiDriver(); private: diff --git a/src/version.h b/src/version.h index 9cdc0ca..061abba 100644 --- a/src/version.h +++ b/src/version.h @@ -9,4 +9,8 @@ #define PROJECT_BUILD_TIME __TIMESTAMP__ " compiler version " __VERSION__ +#ifndef MANAGER_LOGS_DIR +#define MANAGER_LOGS_DIR "/root/" +#endif + #endif //VERSION_H