From ebb620bef645d35132ab7d24682fcf86fb5558c4 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Fri, 16 Jan 2026 20:55:55 +0300 Subject: [PATCH 01/11] feat: add optional GUI target with empty main window - Introduce BUILD_GUI option in root CMakeLists.txt to allow CLI-only builds - Add gui/CMakeLists.txt for building GUI target - Add empty main window and main.cpp placeholder for GUI - Update tests/CMakeLists.txt - Update .gitignore --- .gitignore | 4 ++++ CMakeLists.txt | 30 ++++++++++++++++-------------- gui/CMakeLists.txt | 19 +++++++++++++++++++ gui/main.cpp | 9 +++++++++ gui/main_window.cpp | 14 ++++++++++++++ gui/main_window.h | 22 ++++++++++++++++++++++ gui/main_window.ui | 37 +++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 17 ++++++++--------- 8 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 gui/main.cpp create mode 100644 gui/main_window.cpp create mode 100644 gui/main_window.ui diff --git a/.gitignore b/.gitignore index c0a5b78..d2abc30 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,7 @@ build/ !tests/test_data/*.log + +.DS_Store +.qtcreator/ +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 44c5fac..fbfba34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,22 +3,24 @@ project(LogAnalyzer VERSION 0.1.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -cmake_policy(SET CMP0079 NEW) - - -find_package(GTest QUIET) -if(NOT GTest_FOUND) - include(FetchContent) - FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 - ) - - FetchContent_MakeAvailable(googletest) -endif() + + +option(BUILD_GUI "Build GUI version" ON) add_subdirectory(core) add_subdirectory(cli) + +if(BUILD_GUI) + add_subdirectory(gui) +endif() + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 +) +FetchContent_MakeAvailable(googletest) + add_subdirectory(tests) diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index e69de29..8fb8c5c 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -0,0 +1,19 @@ +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +qt_standard_project_setup() + +qt_add_executable(log-analyzer-gui + main.cpp + main_window.h + main_window.cpp + main_window.ui +) + +target_link_libraries(log-analyzer-gui + PRIVATE Qt6::Widgets +) + +qt_finalize_executable(log-analyzer-gui) diff --git a/gui/main.cpp b/gui/main.cpp new file mode 100644 index 0000000..9b5972d --- /dev/null +++ b/gui/main.cpp @@ -0,0 +1,9 @@ +#include +#include "main_window.h" + +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + MainWindow window; + window.show(); + return app.exec(); +} diff --git a/gui/main_window.cpp b/gui/main_window.cpp new file mode 100644 index 0000000..40e8bd4 --- /dev/null +++ b/gui/main_window.cpp @@ -0,0 +1,14 @@ +#include "main_window.h" +#include "ui_main_window.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/gui/main_window.h b/gui/main_window.h index e69de29..93d4783 100644 --- a/gui/main_window.h +++ b/gui/main_window.h @@ -0,0 +1,22 @@ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAIN_WINDOW_H diff --git a/gui/main_window.ui b/gui/main_window.ui new file mode 100644 index 0000000..b12155f --- /dev/null +++ b/gui/main_window.ui @@ -0,0 +1,37 @@ + + + MainWindow + + + + 0 + 0 + 640 + 480 + + + + MainWindow + + + + + + 0 + 0 + 640 + 33 + + + + + Log-analyzer + + + + + + + + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c046de1..9d7d3fd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,19 @@ -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_data - DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) - add_executable(test-runner test_reader.cpp test_parser.cpp test_statistics.cpp test_reporter.cpp test_analyzer.cpp + tests.h ) -target_link_libraries( - test-runner +target_link_libraries(test-runner core_lib - gtest - gtest_main + GTest::gtest + GTest::gtest_main ) -add_custom_target(test DEPENDS test-runner COMMAND ./test-runner) - +add_custom_target(run-tests + COMMAND test-runner + DEPENDS test-runner +) From f0de1811f4954957cd0684b36cac4357a0e4f1cc Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Sat, 17 Jan 2026 16:15:06 +0300 Subject: [PATCH 02/11] feat: add menu window with file selection and format validation - Implemented a menu window that allows the user to select a file. - Added validation to check if the file exists and whether its format is supported. - Created an empty main window form as a placeholder for future development. --- gui/CMakeLists.txt | 3 ++ gui/main.cpp | 6 ++-- gui/main_window.cpp | 2 +- gui/main_window.h | 4 +-- gui/main_window.ui | 22 ++------------ gui/menu_window.cpp | 54 +++++++++++++++++++++++++++++++++ gui/menu_window.h | 29 ++++++++++++++++++ gui/menu_window.ui | 73 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 gui/menu_window.cpp create mode 100644 gui/menu_window.h create mode 100644 gui/menu_window.ui diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 8fb8c5c..f35d32a 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -7,6 +7,9 @@ qt_standard_project_setup() qt_add_executable(log-analyzer-gui main.cpp + menu_window.h + menu_window.cpp + menu_window.ui main_window.h main_window.cpp main_window.ui diff --git a/gui/main.cpp b/gui/main.cpp index 9b5972d..8d09149 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -1,9 +1,11 @@ #include -#include "main_window.h" +#include "menu_window.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); - MainWindow window; + app.setApplicationName("Log analyzer"); + MenuWindow window; + window.setWindowTitle("Menu"); window.show(); return app.exec(); } diff --git a/gui/main_window.cpp b/gui/main_window.cpp index 40e8bd4..fdf70f4 100644 --- a/gui/main_window.cpp +++ b/gui/main_window.cpp @@ -2,7 +2,7 @@ #include "ui_main_window.h" MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) + : QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); diff --git a/gui/main_window.h b/gui/main_window.h index 93d4783..6b63a25 100644 --- a/gui/main_window.h +++ b/gui/main_window.h @@ -1,13 +1,13 @@ #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H -#include +#include namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow +class MainWindow : public QWidget { Q_OBJECT diff --git a/gui/main_window.ui b/gui/main_window.ui index b12155f..9facd8b 100644 --- a/gui/main_window.ui +++ b/gui/main_window.ui @@ -1,7 +1,7 @@ MainWindow - + 0 @@ -11,26 +11,8 @@ - MainWindow + Form - - - - - 0 - 0 - 640 - 33 - - - - - Log-analyzer - - - - - diff --git a/gui/menu_window.cpp b/gui/menu_window.cpp new file mode 100644 index 0000000..897e28e --- /dev/null +++ b/gui/menu_window.cpp @@ -0,0 +1,54 @@ +#include "menu_window.h" +#include "main_window.h" +#include "ui_menu_window.h" + +MenuWindow::MenuWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MenuWindow) +{ + ui->setupUi(this); +} + +MenuWindow::~MenuWindow() +{ + delete ui; +} + +void MenuWindow::on_Review_clicked() +{ + QString file_path = QFileDialog::getOpenFileName ( + this, + tr("Выберите файл лога"), + QString(), + tr("Log files (*.log *.txt);;All files (*)") + ); + + if (!file_path.isEmpty()) { + ui->FilePath->setText(file_path); + } +} + + +void MenuWindow::on_Start_clicked() +{ + QString path = ui->FilePath->text(); + QFileInfo check_file(path); + + if (!check_file.exists()) { + QMessageBox::warning(this, "Ошибка", "Файл не найден!"); + return; + } + + QString suf = check_file.suffix().toLower(); + + if (suf != "txt" && suf != "log") { + QMessageBox::warning(this, "Ошибка", "Расширение файла не поддерживается!"); + return; + } + + MainWindow *main = new MainWindow; + main->setAttribute(Qt::WA_DeleteOnClose); + + main->show(); +} + diff --git a/gui/menu_window.h b/gui/menu_window.h new file mode 100644 index 0000000..b9304b0 --- /dev/null +++ b/gui/menu_window.h @@ -0,0 +1,29 @@ +#ifndef MENU_WINDOW_H +#define MENU_WINDOW_H + +#include +#include +#include + +namespace Ui { +class MenuWindow; +} + +class MenuWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MenuWindow(QWidget *parent = nullptr); + ~MenuWindow(); + +private slots: + void on_Review_clicked(); + + void on_Start_clicked(); + +private: + Ui::MenuWindow *ui; +}; + +#endif // MENU_WINDOW_H diff --git a/gui/menu_window.ui b/gui/menu_window.ui new file mode 100644 index 0000000..0e6355a --- /dev/null +++ b/gui/menu_window.ui @@ -0,0 +1,73 @@ + + + MenuWindow + + + + 0 + 0 + 535 + 158 + + + + MainWindow + + + + + + + + + Путь к лог файлу + + + + + + + Qt::LayoutDirection::LeftToRight + + + false + + + Обзор + + + + + + + + + Старт + + + + + + + + + 0 + 0 + 535 + 33 + + + + + Qt::LayoutDirection::RightToLeft + + + Log-analyzer + + + + + + + + From 8f3f986207ea8c85b5ad0f3d766e0d0d6ce86169 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Sun, 18 Jan 2026 21:47:56 +0300 Subject: [PATCH 03/11] refactor: decouple core analyzer from reporting logic - Changed Analyzer to return AnalysisResult instead of formatted text. - Moved Reporter implementation from core to CLI layer. - Removed Reporter-related tests from core test suite. --- cli/CMakeLists.txt | 2 +- cli/main.cpp | 5 +++- {core => cli}/reporter.cpp | 0 {core => cli}/reporter.h | 3 ++- core/CMakeLists.txt | 1 - core/analyzer.cpp | 5 ++-- core/analyzer.h | 4 +-- core/parser.cpp | 1 - tests/CMakeLists.txt | 1 - tests/test_analyzer.cpp | 18 ++++++------- tests/test_reporter.cpp | 53 -------------------------------------- tests/tests.h | 1 - 12 files changed, 19 insertions(+), 75 deletions(-) rename {core => cli}/reporter.cpp (100%) rename {core => cli}/reporter.h (95%) delete mode 100644 tests/test_reporter.cpp diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 2173328..9ab63a7 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(log-analyzer-cli main.cpp) +add_executable(log-analyzer-cli main.cpp reporter.cpp) target_link_libraries(log-analyzer-cli core_lib) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY EP_PREFIX ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/cli/main.cpp b/cli/main.cpp index 20cf373..2f78db0 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1,4 +1,5 @@ #include "../core/analyzer.h" +#include "reporter.h" #include int main() { @@ -7,7 +8,9 @@ int main() { std::getline(std::cin, path); Analyzer analysis; - std::string report = analysis.analyze(path); + AnalysisResult result = analysis.analyze(path); + Reporter reporter; + std::string report = reporter.GenerateTextReport(result); std::cout << report; diff --git a/core/reporter.cpp b/cli/reporter.cpp similarity index 100% rename from core/reporter.cpp rename to cli/reporter.cpp diff --git a/core/reporter.h b/cli/reporter.h similarity index 95% rename from core/reporter.h rename to cli/reporter.h index 256a6f1..09d88b2 100644 --- a/core/reporter.h +++ b/cli/reporter.h @@ -1,5 +1,6 @@ #pragma once -#include "common.h" + +#include "../core/common.h" #include diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index a72f231..ccdd931 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -2,6 +2,5 @@ add_library(core_lib reader.cpp parser.cpp statistics.cpp - reporter.cpp analyzer.cpp ) \ No newline at end of file diff --git a/core/analyzer.cpp b/core/analyzer.cpp index 3126709..6717964 100644 --- a/core/analyzer.cpp +++ b/core/analyzer.cpp @@ -1,6 +1,6 @@ #include "analyzer.h" -std::string Analyzer::analyze(std::string path) { +AnalysisResult Analyzer::analyze(std::string path) { reader_.OpenFile(path); AnalysisResult res; @@ -11,7 +11,6 @@ std::string Analyzer::analyze(std::string path) { } reader_.CloseFile(); - std::string report = reporter_.GenerateTextReport(res); - return report; + return res; } \ No newline at end of file diff --git a/core/analyzer.h b/core/analyzer.h index 470f924..b7a9486 100644 --- a/core/analyzer.h +++ b/core/analyzer.h @@ -3,17 +3,15 @@ #include "reader.h" #include "parser.h" #include "statistics.h" -#include "reporter.h" #include class Analyzer { private: Reader reader_; Parser parser_; - Reporter reporter_; Statistics statistics_; public: - std::string analyze(std::string path); + AnalysisResult analyze(std::string path); }; diff --git a/core/parser.cpp b/core/parser.cpp index 02d28f5..650ea40 100644 --- a/core/parser.cpp +++ b/core/parser.cpp @@ -1,5 +1,4 @@ #include "parser.h" -#include LogFormat Parser::DetectFormat(const std::string& line) { if (line.find("HTTP/1.0") != std::string::npos) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c046de1..99ef735 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,7 +5,6 @@ add_executable(test-runner test_reader.cpp test_parser.cpp test_statistics.cpp - test_reporter.cpp test_analyzer.cpp ) diff --git a/tests/test_analyzer.cpp b/tests/test_analyzer.cpp index 528d7b0..9a35386 100644 --- a/tests/test_analyzer.cpp +++ b/tests/test_analyzer.cpp @@ -3,20 +3,20 @@ TEST(AnalyzerTest, StandardTest) { Analyzer analyzer; fs::path path = fs::path("test_data") / "normal_test.log"; - std::string report = analyzer.analyze(path.string()); + AnalysisResult res = analyzer.analyze(path.string()); - EXPECT_TRUE(report.find("Sucсessful - 5") != std::string::npos); - EXPECT_TRUE(report.find("Failed Parsing - 8") != std::string::npos); - EXPECT_TRUE(report.find("192.168.2.145 - 4") != std::string::npos); - EXPECT_TRUE(report.find("20:00 - 2") != std::string::npos); - EXPECT_TRUE(report.find("500 - 2") != std::string::npos); - EXPECT_FALSE(report.find("402 - 1") != std::string::npos); + EXPECT_TRUE(res.successful_requests == 5); + EXPECT_TRUE(res.failed_parses == 8); + EXPECT_TRUE(res.ip["192.168.2.145"] == 4); + EXPECT_TRUE(res.time_distribution["20:00"] == 2); + EXPECT_TRUE(res.error_counts["500"] == 2); + EXPECT_FALSE(res.error_counts["402"] == 2); } TEST(AnalyzerTest, EmptyTest) { Analyzer analyzer; fs::path path = fs::path("test_data") / "empty_test.log"; - std::string report = analyzer.analyze(path.string()); + AnalysisResult res = analyzer.analyze(path.string()); - EXPECT_TRUE(report == "invalid file format or file empty"); + EXPECT_TRUE(res.total_processed == 0); } \ No newline at end of file diff --git a/tests/test_reporter.cpp b/tests/test_reporter.cpp deleted file mode 100644 index c1efa2e..0000000 --- a/tests/test_reporter.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "tests.h" - -class ReporterTest : public ::testing::Test { -protected: - AnalysisResult createSampleData() { - AnalysisResult result; - - result.total_processed = 1000; - result.successful_requests = 850; - result.error_requests = 150; - result.failed_parses = 5; - - result.ip["192.168.1.100"] = 45; - result.ip["10.0.0.25"] = 33; - result.ip["203.0.113.45"] = 22; - - result.time_distribution["14:00"] = 15; - result.time_distribution["15:00"] = 8; - - result.error_counts["404"] = 60; - result.error_counts["500"] = 25; - result.error_counts["403"] = 15; - - return result; - } - - AnalysisResult createEmptyData() { - AnalysisResult result; - return result; - } -}; - -TEST_F(ReporterTest, NormalTest) { - AnalysisResult res = createSampleData(); - Reporter reporter; - std::string report = reporter.GenerateTextReport(res); - - EXPECT_TRUE(report.find("Sucсessful - 850") != std::string::npos); - EXPECT_TRUE(report.find("Failed Parsing - 5") != std::string::npos); - EXPECT_TRUE(report.find("10.0.0.25 - 33") != std::string::npos); - EXPECT_TRUE(report.find("14:00 - 15") != std::string::npos); - EXPECT_TRUE(report.find("404 - 60") != std::string::npos); - EXPECT_FALSE(report.find("303 - 3") != std::string::npos); - -} - -TEST_F(ReporterTest, EmptyTest) { - AnalysisResult res = createEmptyData(); - Reporter reporter; - std::string report = reporter.GenerateTextReport(res); - - EXPECT_TRUE(report == "invalid file format or file empty"); -} diff --git a/tests/tests.h b/tests/tests.h index a591ed3..dbf032d 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -3,7 +3,6 @@ #include "../core/reader.h" #include "../core/parser.h" #include "../core/statistics.h" -#include "../core/reporter.h" #include "../core/analyzer.h" #include From ca289f4ba6f852ef75fc521cf0fabf01d1fe0f5f Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Mon, 19 Jan 2026 20:53:30 +0300 Subject: [PATCH 04/11] feat: add main window and initial GUI layout --- core/CMakeLists.txt | 2 +- core/analyzer.cpp | 4 +- core/analyzer.h | 2 +- gui/CMakeLists.txt | 5 +- gui/main_window.cpp | 71 ++++++++++++++++- gui/main_window.h | 10 ++- gui/main_window.ui | 187 +++++++++++++++++++++++++++++++++++++++++++- gui/menu_window.cpp | 7 +- 8 files changed, 276 insertions(+), 12 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index ccdd931..f50989a 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -3,4 +3,4 @@ add_library(core_lib parser.cpp statistics.cpp analyzer.cpp -) \ No newline at end of file +) diff --git a/core/analyzer.cpp b/core/analyzer.cpp index 6717964..9b7d921 100644 --- a/core/analyzer.cpp +++ b/core/analyzer.cpp @@ -1,6 +1,6 @@ #include "analyzer.h" -AnalysisResult Analyzer::analyze(std::string path) { +AnalysisResult Analyzer::analyze(const std::string& path) { reader_.OpenFile(path); AnalysisResult res; @@ -13,4 +13,4 @@ AnalysisResult Analyzer::analyze(std::string path) { reader_.CloseFile(); return res; -} \ No newline at end of file +} diff --git a/core/analyzer.h b/core/analyzer.h index b7a9486..17ef782 100644 --- a/core/analyzer.h +++ b/core/analyzer.h @@ -12,6 +12,6 @@ class Analyzer { Statistics statistics_; public: - AnalysisResult analyze(std::string path); + AnalysisResult analyze(const std::string& path); }; diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index f35d32a..9223fcd 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -15,8 +15,9 @@ qt_add_executable(log-analyzer-gui main_window.ui ) -target_link_libraries(log-analyzer-gui - PRIVATE Qt6::Widgets +target_link_libraries(log-analyzer-gui PRIVATE + Qt6::Widgets + core_lib ) qt_finalize_executable(log-analyzer-gui) diff --git a/gui/main_window.cpp b/gui/main_window.cpp index fdf70f4..a4ad9e4 100644 --- a/gui/main_window.cpp +++ b/gui/main_window.cpp @@ -1,14 +1,81 @@ #include "main_window.h" #include "ui_main_window.h" -MainWindow::MainWindow(QWidget *parent) - : QWidget(parent) +void MainWindow::TimeDistributionTable(std::unordered_map& time) { + ui->TimeDistributionTable->setRowCount(24); + + for(int i = 0; i < 24; ++i) { + std::string hour = std::to_string(i) + ":00"; + int count = 0; + + if (time.find(hour) != time.end()) { + count = time[hour]; + } + + ui->TimeDistributionTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(hour))); + ui->TimeDistributionTable->setItem(i, 1, new QTableWidgetItem(QString::number(count))); + } + +} + +void MainWindow::ErrorsTypeTable(const std::unordered_map& types) { + ui->ErrorsTypeTable->setRowCount(types.size()); + + int row = 0; + for(const auto& [type, count] : types) { + ui->ErrorsTypeTable->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(type))); + ui->ErrorsTypeTable->setItem(row, 1, new QTableWidgetItem(QString::number(count))); + + ++row; + } + +} + + +void MainWindow::IPTable(const std::unordered_map& Ip) { + QVector> data; + + for(const auto& [ip, count] : Ip) { + data.append({QString::fromStdString(ip), count}); + + } + + std::sort(data.begin(), data.end(), [](const auto& a, const auto& b) { + return a.second > b.second; + }); + + ui->IPTable->setRowCount(std::min(10, static_cast (data.size()))); + + for(int i = 0; i < ui->IPTable->rowCount(); ++i) { + ui->IPTable->setItem(i, 0, new QTableWidgetItem(data[i].first)); + ui->IPTable->setItem(i, 1, new QTableWidgetItem(QString::number(data[i].second))); + } + +} + +void MainWindow::UpdateGeneralStats() { + ui->total->setText(QString::number(result_.total_processed)); + ui->failed_parses->setText(QString::number(result_.failed_parses)); + ui->successful->setText(QString::number(result_.successful_requests)); + ui->errors->setText(QString::number(result_.error_requests)); + + IPTable(result_.ip); + + ErrorsTypeTable(result_.error_counts); + + TimeDistributionTable(result_.time_distribution); +} + +MainWindow::MainWindow(const AnalysisResult& res, QWidget *parent) + : result_(res), QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); + UpdateGeneralStats(); } MainWindow::~MainWindow() { delete ui; } + diff --git a/gui/main_window.h b/gui/main_window.h index 6b63a25..53558d7 100644 --- a/gui/main_window.h +++ b/gui/main_window.h @@ -3,6 +3,8 @@ #include +#include "../core/common.h" + namespace Ui { class MainWindow; } @@ -12,11 +14,17 @@ class MainWindow : public QWidget Q_OBJECT public: - explicit MainWindow(QWidget *parent = nullptr); + explicit MainWindow(const AnalysisResult& res, QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; + AnalysisResult result_; + + void UpdateGeneralStats(); + void IPTable(const std::unordered_map& ip); + void ErrorsTypeTable(const std::unordered_map& types); + void TimeDistributionTable(std::unordered_map& time); }; #endif // MAIN_WINDOW_H diff --git a/gui/main_window.ui b/gui/main_window.ui index 9facd8b..0aac289 100644 --- a/gui/main_window.ui +++ b/gui/main_window.ui @@ -6,13 +6,196 @@ 0 0 - 640 - 480 + 483 + 443 Form + + + + 260 + 0 + 248 + 461 + + + + + + + Топ ошибочных ip + + + + + 0 + 21 + 201 + 211 + + + + + IP + + + + + Count + + + + + + + + + Распределение ошибок по времени + + + + + 0 + 20 + 201 + 192 + + + + + Time + + + + + Count + + + + + + + + + + + 0 + 0 + 261 + 461 + + + + + + + Главное + + + + + 0 + 20 + 201 + 211 + + + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + TextLabel + + + + + + + Ошибка парсинга + + + + + + + TextLabel + + + + + + + Ошибочные + + + + + + + TextLabel + + + + + + + Успешные + + + + + + + TextLabel + + + + + + + Всего + + + + + + + + + + + Типы ошибок и их количество + + + + + 0 + 20 + 211 + 192 + + + + + Type + + + + + Count + + + + + + + diff --git a/gui/menu_window.cpp b/gui/menu_window.cpp index 897e28e..c3a9e29 100644 --- a/gui/menu_window.cpp +++ b/gui/menu_window.cpp @@ -1,6 +1,7 @@ #include "menu_window.h" #include "main_window.h" #include "ui_menu_window.h" +#include "../core/analyzer.h" MenuWindow::MenuWindow(QWidget *parent) : QMainWindow(parent) @@ -46,7 +47,11 @@ void MenuWindow::on_Start_clicked() return; } - MainWindow *main = new MainWindow; + Analyzer analyzer; + AnalysisResult res = analyzer.analyze(path.toStdString()); + + MainWindow *main = new MainWindow(res); + main->setWindowTitle("Analysis Result"); main->setAttribute(Qt::WA_DeleteOnClose); main->show(); From b741f82964d76161c796e451fb43dbd132f3f79d Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 11:58:14 +0300 Subject: [PATCH 05/11] feat: add CD workflow and CI test setup - Added GitHub Actions workflow for CD (build GUI + CLI and upload artifacts) - Updated CI workflow to include test-only build with BUILD_GUI=OFF --- .github/workflows/cd.yml | 59 ++++++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 4 +-- CMakeLists.txt | 2 +- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/cd.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..d2dea6c --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,59 @@ +name: CD + +on: + push: + tags: + - "v*" + workflow_dispatch: + + +jobs: + build-release: + name: Build release binaries + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y cmake build-essential qtbase5-dev + + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: | + brew update + brew install qt cmake + + - name: Configure + run: | + cmake -S . -B build \ + -DBUILD_GUI=ON \ + -DCMAKE_BUILD_TYPE=Release + + - name: Build + run: | + cmake --build build --config Release + + - name: Package artifacts + run: | + mkdir -p artifacts + + # CLI + find build -type f -name "log-analyzer-cli*" -exec cp {} artifacts/ \; + + # GUI + find build -type f -name "log-analyzer-gui*" -exec cp {} artifacts/ \; + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: log-analyzer-${{ runner.os }} + path: artifacts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e353ea..e97b78f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: push: branches: [ main, develop ] pull_request: - branches: [ main ] + branches: [ main ] jobs: Tests: @@ -25,7 +25,7 @@ jobs: sudo apt-get update && sudo apt-get install -y cmake build-essential libgtest-dev fi - cmake -B build + cmake -B build -DBUILD_GUI=OFF cmake --build build cd build/tests ./test-runner \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index fbfba34..8548e60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(LogAnalyzer VERSION 0.1.0) +project(LogAnalyzer VERSION 1.0.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) From cdf0523409bc0100662e77fa2c566756b267b321 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 15:41:16 +0300 Subject: [PATCH 06/11] fix: CD adjusted --- .github/workflows/cd.yml | 52 +++++++++++++++++++++++----------------- tests/CMakeLists.txt | 3 +++ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index d2dea6c..5dd0d5b 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -20,37 +20,45 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install dependencies (Linux) + # - name: Install Qt (macOS) + # if: runner.os == 'macOS' + # run: brew update && brew install qt + + - name: Install Qt6 (Linux) if: runner.os == 'Linux' run: | - sudo apt-get update - sudo apt-get install -y cmake build-essential qtbase5-dev + sudo apt update + sudo apt install -y qt6-base-dev qt6-base-dev-tools qt6-tools-dev build-essential cmake - - name: Install dependencies (macOS) - if: runner.os == 'macOS' - run: | - brew update - brew install qt cmake + - name: Configure CMake + run: cmake -S . -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release - - name: Configure - run: | - cmake -S . -B build \ - -DBUILD_GUI=ON \ - -DCMAKE_BUILD_TYPE=Release + - name: Build GUI + if: runner.os == 'Linux' + run: cmake --build build --target log-analyzer-gui --config Release - - name: Build - run: | - cmake --build build --config Release + - name: Build CLI + run: cmake --build build --target log-analyzer-cli --config Release + + # - name: Deploy GUI on macOS + # if: runner.os == 'macOS' + # run: | + # export PATH="/usr/local/opt/qt/bin:$PATH" + + # gui_app=$(find build -name "log-analyzer-gui.app" -type d | head -n 1) + # macdeployqt "$gui_app" - name: Package artifacts run: | - mkdir -p artifacts - - # CLI - find build -type f -name "log-analyzer-cli*" -exec cp {} artifacts/ \; + mkdir -p artifacts + + if [ "$RUNNER_OS" == "Linux" ]; then + gui_path=$(find build -type f -name "log-analyzer-gui" | head -n 1) + cp "$gui_path" artifacts/ + fi - # GUI - find build -type f -name "log-analyzer-gui*" -exec cp {} artifacts/ \; + cli_path=$(find build -type f -name "log-analyzer-cli*" | head -n 1) + cp "$cli_path" artifacts/ - name: Upload artifacts uses: actions/upload-artifact@v4 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1c087ab..3f48f33 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,6 @@ +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_data + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + add_executable(test-runner test_reader.cpp test_parser.cpp From 20c4fc3e67b6846fccbad4ecd6ba33d099229cb0 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 18:05:13 +0300 Subject: [PATCH 07/11] feat: gui off on macOS --- .github/workflows/cd.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 5dd0d5b..c834ec9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -31,7 +31,12 @@ jobs: sudo apt install -y qt6-base-dev qt6-base-dev-tools qt6-tools-dev build-essential cmake - name: Configure CMake - run: cmake -S . -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release + run: | + if [ "$RUNNER_OS" == "macOS" ]; then + cmake -S . -B build -DBUILD_GUI=OFF -DCMAKE_BUILD_TYPE=Release + else + cmake -S . -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release + fi - name: Build GUI if: runner.os == 'Linux' From 7cf407671922358125e7b6dfadb5e2e013b70698 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 18:46:27 +0300 Subject: [PATCH 08/11] docs: update readme --- README.md | 49 +++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0ba779e..d952e64 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Log Analyzer v0.2.1 +# Log Analyzer v1.0.0 ## 💻 Платформы -- ✅ macOS (clang/gcc, CMake ≥ 3.10) -- ✅ Linux (gcc, CMake ≥ 3.10) +- MacOS (cli) +- Linux (cli, gui) ## 🚀 Возможности ### 📋 Поддерживаемые форматы логов: @@ -21,39 +21,28 @@ - Язык: C++17 - Сборка: CMake - Тестирование: Google Test (gtest/gmock) -- CI: Сборка и тестирование +- CI/CD: тестирование и сборка +- Qt: графическое приложение ## 🛠️ В разработке: -- GUI +- Поддержка Windows -## 📦 Установка и сборка -- Клонирование репозитория +## 📦 Установка и запуск +### Linux +Для cli ``` -git clone https://github.com/Arkilleru/log-analyzer.git -cd log-analyzer +chmod +x log-analyzer-cli +./log-analyzer-cli ``` - -- Сборка -``` -./run.sh build -``` - -- Консольное приложение +Для gui ``` -./run.sh cli +sudo apt install qt6-base-dev +chmod +x log-analyzer-gui +./log-analyzer-gui ``` - -- Тестирование +### MacOS +Для cli ``` -./run.sh test +chmod +x log-analyzer-cli +./log-analyzer-cli ``` - -- Очистка -``` -./run.sh clean -``` - -- Очистка + Сборка + Тестирование -``` -./run.sh all -``` \ No newline at end of file From 3c472d117389e7b001249abe7dcd092e2e5e7b8b Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 18:47:29 +0300 Subject: [PATCH 09/11] refactor: delete run.sh --- run.sh | 93 ---------------------------------------------------------- 1 file changed, 93 deletions(-) delete mode 100755 run.sh diff --git a/run.sh b/run.sh deleted file mode 100755 index c952e8f..0000000 --- a/run.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -BUILD_DIR="build" -TARGET="log-analyzer-cli" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -print_info() { - echo -e "${BLUE} $1${NC}" -} - -print_success() { - echo -e "${GREEN} $1${NC}" -} - -print_warning() { - echo -e "${YELLOW} $1${NC}" -} - -print_error() { - echo -e "${RED} $1${NC}" -} - -build_project() { - print_info "Building Log Analyzer..." - mkdir -p $BUILD_DIR - cd $BUILD_DIR - cmake -DCMAKE_BUILD_TYPE=Release .. - make -j$(nproc) - cd .. - print_success "Build complete!" -} - -run_cli() { - print_info "Running Log Analyzer..." - - if [ ! -d "$BUILD_DIR" ]; then - build_project - fi - - cd $BUILD_DIR/cli - ./$TARGET -} - -run_tests() { - print_info "Running tests..." - if [ ! -d "$BUILD_DIR" ]; then - build_project - fi - cd build/tests - ./test-runner - print_success "All tests passed!" - cd ../.. -} - -clean_project() { - print_warning "Cleaning build directory..." - rm -rf $BUILD_DIR - print_success "Clean complete!" -} - -run_all() { - print_info "Starting full pipeline..." - clean_project - build_project - run_tests -} - -case "$1" in - "build") - build_project - ;; - "test") - run_tests - ;; - "clean") - clean_project - ;; - "all") - run_all - ;; - "cli") - run_cli - ;; - *) - print_error "Unknown command: $1" - exit 1 - ;; -esac \ No newline at end of file From f258f24b6d49929f43a303a3f8852d6caf1332f0 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 20:17:50 +0300 Subject: [PATCH 10/11] feat: cd release steps --- .github/workflows/cd.yml | 95 +++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index c834ec9..3b8b6be 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -6,67 +6,74 @@ on: - "v*" workflow_dispatch: +permissions: + contents: write jobs: - build-release: - name: Build release binaries - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - fail-fast: false - - runs-on: ${{ matrix.os }} + build-linux: + name: Build Linux GUI + CLI + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - # - name: Install Qt (macOS) - # if: runner.os == 'macOS' - # run: brew update && brew install qt - - - name: Install Qt6 (Linux) - if: runner.os == 'Linux' + - name: Install Qt6 run: | - sudo apt update - sudo apt install -y qt6-base-dev qt6-base-dev-tools qt6-tools-dev build-essential cmake + sudo apt update + sudo apt install -y qt6-base-dev qt6-base-dev-tools qt6-tools-dev build-essential cmake libgl1-mesa-dev libglu1-mesa-dev libx11-dev libxext-dev libxrandr-dev libxi-dev libxfixes-dev - name: Configure CMake - run: | - if [ "$RUNNER_OS" == "macOS" ]; then - cmake -S . -B build -DBUILD_GUI=OFF -DCMAKE_BUILD_TYPE=Release - else - cmake -S . -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release - fi + run: cmake -S . -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release - name: Build GUI - if: runner.os == 'Linux' run: cmake --build build --target log-analyzer-gui --config Release - name: Build CLI run: cmake --build build --target log-analyzer-cli --config Release - # - name: Deploy GUI on macOS - # if: runner.os == 'macOS' - # run: | - # export PATH="/usr/local/opt/qt/bin:$PATH" + - name: Package Linux artifacts + run: | + mkdir -p artifacts/linux + find build -type f -executable -exec cp {} artifacts/linux/ \; + tar czvf artifacts/log-analyzer-linux.tar.gz -C artifacts/linux . + + - name: Release + uses: softprops/action-gh-release@v2 + with: + files: artifacts/log-analyzer-linux.tar.gz + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # gui_app=$(find build -name "log-analyzer-gui.app" -type d | head -n 1) - # macdeployqt "$gui_app" + build-mac: + name: Build macOS CLI + runs-on: macos-latest + needs: build-linux + steps: + - uses: actions/checkout@v4 - - name: Package artifacts + - name: Install Qt + run: brew update && brew install qt + + - name: Configure CMake + run: cmake -S . -B build -DBUILD_GUI=OFF -DCMAKE_BUILD_TYPE=Release + + - name: Build CLI + run: cmake --build build --target log-analyzer-cli --config Release + + - name: Package macOS artifacts run: | - mkdir -p artifacts - - if [ "$RUNNER_OS" == "Linux" ]; then - gui_path=$(find build -type f -name "log-analyzer-gui" | head -n 1) - cp "$gui_path" artifacts/ - fi - - cli_path=$(find build -type f -name "log-analyzer-cli*" | head -n 1) - cp "$cli_path" artifacts/ - - - name: Upload artifacts - uses: actions/upload-artifact@v4 + mkdir -p artifacts/mac + find build -type f -executable -exec cp {} artifacts/mac/ \; + zip -r artifacts/log-analyzer-mac.zip artifacts/mac + + - name: Upload macOS Asset + uses: softprops/action-gh-release@v2 with: - name: log-analyzer-${{ runner.os }} - path: artifacts + files: artifacts/log-analyzer-mac.zip + tag_name: ${{ github.ref_name }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 944c6419d8c1f59107614d3c7035543ecdb84e16 Mon Sep 17 00:00:00 2001 From: Arkilleru Date: Tue, 20 Jan 2026 20:44:24 +0300 Subject: [PATCH 11/11] fix: find exec command edit --- .github/workflows/cd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3b8b6be..a5e0313 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -34,7 +34,7 @@ jobs: - name: Package Linux artifacts run: | mkdir -p artifacts/linux - find build -type f -executable -exec cp {} artifacts/linux/ \; + find build -type f \( -name "log-analyzer-gui" -o -name "log-analyzer-cli" \) -exec cp {} artifacts/linux/ \; tar czvf artifacts/log-analyzer-linux.tar.gz -C artifacts/linux . - name: Release @@ -67,7 +67,7 @@ jobs: - name: Package macOS artifacts run: | mkdir -p artifacts/mac - find build -type f -executable -exec cp {} artifacts/mac/ \; + find build -type f -name "log-analyzer-cli" -exec cp {} artifacts/mac/ \; zip -r artifacts/log-analyzer-mac.zip artifacts/mac - name: Upload macOS Asset