From 32cf1e681fc04f5e5d61009fdecbc6a13fa51fd9 Mon Sep 17 00:00:00 2001 From: Denis Sumin <denis.smolov@demlabs.net> Date: Thu, 17 Aug 2023 09:37:41 +0000 Subject: [PATCH] Features 9364 --- .gitignore | 1 + .gitlab-ci.yml | 6 +- CMakeLists.txt | 15 +- diagtool/AbstractDiagnostic.cpp | 223 +++++++++++++++++++++++++- diagtool/AbstractDiagnostic.h | 14 ++ diagtool/CMakeLists.txt | 41 ++++- diagtool/DiagnosticWorker.cpp | 10 +- diagtool/DiagnosticWorker.h | 9 +- diagtool/LinuxDiagnostic.cpp | 208 +----------------------- diagtool/LinuxDiagnostic.h | 15 +- diagtool/MacDiagnostic.cpp | 243 ++++++++++++++++++++++++++++ diagtool/MacDiagnostic.h | 36 +++++ diagtool/NodeDiagnostic.pro | 30 +++- diagtool/WinDiagnostic.cpp | 274 ++++++++++++++++++++++++++++++++ diagtool/WinDiagnostic.h | 38 +++++ diagtool/main.cpp | 1 + version.mk | 2 +- 17 files changed, 920 insertions(+), 246 deletions(-) create mode 100644 diagtool/MacDiagnostic.cpp create mode 100644 diagtool/MacDiagnostic.h create mode 100644 diagtool/WinDiagnostic.cpp create mode 100644 diagtool/WinDiagnostic.h diff --git a/.gitignore b/.gitignore index 6a60feef0..5223da1bb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ test/build *.txt.user *.txt.user.* *.autosave +*.user .vscode/ # Object files *.o diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b05a1e422..d5efcdf77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,17 +42,17 @@ stages: windows-amd64: extends: .build - image: demlabs/amd64/debian-bullseye:windowsbuilder + image: demlabs/amd64/debian-bullseye:windowsbuilder before_script: /opt/buildtools/prepare_environment.sh amd64-linux script: - - ./prod_build/build.sh --target windows release + - ./prod_build/build.sh --target windows release -DBUILD_DIAGTOOL=ON macos-amd64: extends: .build image: demlabs/amd64/debian-bullseye:osxbuilder before_script: /opt/buildtools/prepare_environment.sh amd64-osx script: - - ./prod_build/build.sh --target osx release + - ./prod_build/build.sh --target osx release -DBUILD_DIAGTOOL=ON - ./prod_build/pack.sh --target osx release --sign /opt/buildtools/sign/macos/demlabs.sh artifacts: paths: diff --git a/CMakeLists.txt b/CMakeLists.txt index b8998a0a3..24e844e0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,10 @@ endif() target_link_libraries(${NODE_TARGET} ${NODE_LIBRARIES} crc32c_adler ) target_link_libraries(${NODE_TOOL_TARGET} ${NODE_TOOL_LIBRARIES} crc32c_adler ) +if(BUILD_DIAGTOOL) + message("[*] Diagtool build on") + add_subdirectory(diagtool) +endif() if(UNIX AND NOT WIN32) message ("[*] Unix library set") @@ -237,11 +241,6 @@ if(UNIX AND NOT WIN32) set(NODE_CLI_LIBRARIES m cellframe-sdk) set(NODE_TOOL_LIBRARIES m cellframe-sdk) - - if(BUILD_DIAGTOOL) - message("[*] Diagtool build on") - add_subdirectory(diagtool) - endif() if (SUPPORT_PYTHON_PLUGINS) message("[+] Build with python plugins support") @@ -369,7 +368,11 @@ else() INSTALL(TARGETS ${NODE_TOOL_TARGET} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) if (BUILD_DIAGTOOL) - INSTALL(TARGETS cellframe-diagtool DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + if(WIN32) + INSTALL(TARGETS cellframe-diagtool.exe DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + else() + INSTALL(TARGETS cellframe-diagtool DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + endif() endif() if(NOT ANDROID) diff --git a/diagtool/AbstractDiagnostic.cpp b/diagtool/AbstractDiagnostic.cpp index b175b29ed..fdb51df4a 100644 --- a/diagtool/AbstractDiagnostic.cpp +++ b/diagtool/AbstractDiagnostic.cpp @@ -1,8 +1,23 @@ #include "AbstractDiagnostic.h" +#ifdef Q_OS_LINUX + +#elif defined(Q_OS_WIN) +#include "registry.h" +#elif defined(Q_OS_MACOS) +#include "dap_common.h" +#endif + AbstractDiagnostic::AbstractDiagnostic(QObject *parent) :QObject(parent) { +#ifdef Q_OS_LINUX + s_nodeDataPath = "/opt/cellframe-node"; +#elif defined(Q_OS_WIN) + s_nodeDataPath = QString("%1/cellframe-node").arg(regGetUsrPath()); +#elif defined(Q_OS_MACOS) + s_nodeDataPath = QString("/Users/%1/Applications/Cellframe.app/Contents/Resources/").arg(getenv("USER")); +#endif s_timer_update = new QTimer(); s_mac = get_mac(); } @@ -127,7 +142,7 @@ QJsonObject AbstractDiagnostic::roles_processing() { QJsonObject rolesObject; - QDir currentFolder("/opt/cellframe-node/etc/network"); + QDir currentFolder(s_nodeDataPath + "/etc/network"); currentFolder.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks ); currentFolder.setSorting( QDir::Name ); @@ -148,3 +163,209 @@ QJsonObject AbstractDiagnostic::roles_processing() return rolesObject; } + +/// --------------------------------------------------------------- +/// Cli info +/// --------------------------------------------------------------- +QJsonObject AbstractDiagnostic::get_cli_info() +{ + QStringList networks = get_networks(); + + QJsonObject netObj; + + for(QString net : networks) + { + QJsonObject dataObj; + + dataObj.insert("net_info", get_net_info(net)); + dataObj.insert("mempool" , get_mempool_count(net)); +// dataObj.insert("ledger" , get_ledger_count(net)); + dataObj.insert("blocks" , get_blocks_count(net)); + dataObj.insert("events" , get_events_count(net)); + dataObj.insert("nodelist" , get_nodelist(net)); + + netObj.insert(net, dataObj); + } + + return netObj; +} + +QStringList AbstractDiagnostic::get_networks() +{ + QProcess proc; + proc.start(QString(CLI_PATH), QStringList()<<"net"<<"list"); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QStringList listNetworks; + result.remove(' '); + result.remove("\r"); + result.remove("\n"); + result.remove("Networks:"); + if(!(result.isEmpty() || result.isNull() || result.contains('\'') || result.contains("error") || result.contains("Error") || result.contains("err"))) + { + listNetworks = result.split("\t", QString::SkipEmptyParts); + } + + return listNetworks; +} + +QJsonObject AbstractDiagnostic::get_net_info(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"net"<<"-net"<<QString(net)<<"get"<<"status"); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + // ---------- State & TargetState ---------------- + + QRegularExpression rx(R"***(^Network "(\S+)" has state (\S+) \(target state (\S*)\), .*cur node address ([A-F0-9]{4}::[A-F0-9]{4}::[A-F0-9]{4}::[A-F0-9]{4}))***"); + QRegularExpressionMatch match = rx.match(result); + if (!match.hasMatch()) { + return {}; + } + + QJsonObject resultObj({ + {"state" , match.captured(2)}, + {"target_state" , match.captured(3)}, + {"node_address" , match.captured(4)} + }); + + // ---------- Links count ---------------- + QRegularExpression rxLinks(R"(\), active links (\d+) from (\d+),)"); + match = rxLinks.match(result); + if (!match.hasMatch()) { + return resultObj; + } + + resultObj.insert("active_links_count", match.captured(1)); + resultObj.insert("links_count" , match.captured(2)); + resultObj.insert("balancer", get_balancer_links(net)); + + return resultObj; +} + +QJsonObject AbstractDiagnostic::get_mempool_count(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"mempool_list"<<"-net"<<QString(net)); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QRegularExpression rx(R"(\.(.+): Total (.+) records)"); + + ///TODO: bug in requests. Always returns both chains +// QRegularExpressionMatch match = rx.match(result); +// if (!match.hasMatch()) { +// return {}; +// } + +// proc.start(QString(CLI_PATH), +// QStringList()<<"mempool_list"<<"-net"<<QString(net)<<"-chain"<<"zero"); +// proc.waitForFinished(5000); +// result = proc.readAll(); + + QJsonObject resultObj; + + QRegularExpressionMatchIterator matchItr = rx.globalMatch(result); + + while (matchItr.hasNext()) + { + QRegularExpressionMatch match = matchItr.next(); + resultObj.insert(match.captured(1), match.captured(2)); + } + + return resultObj; +} + +QJsonObject AbstractDiagnostic::get_ledger_count(QString net) +{ + //TODO: legder tx -all -net NOT WORKING + return {}; +} + +QJsonObject AbstractDiagnostic::get_blocks_count(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"block"<<"list"<<"-net"<<QString(net) <<"-chain" << "main"); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QRegularExpression rx(R"(\.(.+): Have (.+) blocks)"); + QRegularExpressionMatch match = rx.match(result); + if (!match.hasMatch()) { + return {}; + } + + QJsonObject resultObj; + resultObj.insert(match.captured(1), match.captured(2)); + + return resultObj; + +} + +QJsonObject AbstractDiagnostic::get_events_count(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"dag"<<"event"<<"list"<<"-net"<<QString(net) <<"-chain" << "zerochain"); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QRegularExpression rx(R"(\.(.+) have total (.+) events)"); + QRegularExpressionMatch match = rx.match(result); + if (!match.hasMatch()) { + return {}; + } + + QJsonObject resultObj; + resultObj.insert(match.captured(1), match.captured(2)); + + return resultObj; +} + + +QJsonArray AbstractDiagnostic::get_nodelist(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"node"<<"dump"<<"-net"<<QString(net)); + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QJsonArray res; + for (auto l : result.split("\n")) + res.push_back(QJsonValue(l)); + + return res; +} + +QJsonObject AbstractDiagnostic::get_balancer_links(QString net) +{ + QProcess proc; + proc.start(QString(CLI_PATH), + QStringList()<<"node"<<"connections"<<"-net"<<QString(net)); + + + proc.waitForFinished(5000); + QString result = proc.readAll(); + + QJsonObject resultObj; + for (auto line : result.split("\n")) + { + if (line.split(":").length() < 2) + continue; + + if(line.startsWith("Uplinks:")) + resultObj.insert("uplinks", line.split(":")[1].trimmed()); + if(line.startsWith("Downlinks:")) + resultObj.insert("downlinks", line.split(":")[1].trimmed()); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/diagtool/AbstractDiagnostic.h b/diagtool/AbstractDiagnostic.h index 197b44613..b00068f51 100644 --- a/diagtool/AbstractDiagnostic.h +++ b/diagtool/AbstractDiagnostic.h @@ -39,11 +39,25 @@ public: QJsonObject roles_processing(); + //CLI + QJsonObject get_cli_info(); + + QStringList get_networks(); + QJsonObject get_net_info(QString net); + QJsonObject get_mempool_count(QString net); + QJsonObject get_ledger_count(QString net); + QJsonObject get_blocks_count(QString net); + QJsonObject get_events_count(QString net); + QJsonArray get_nodelist(QString net); + QJsonObject get_balancer_links(QString net); + public: QTimer * s_timer_update; int s_timeout{1000}; QJsonDocument s_full_info; QJsonValue s_mac; + bool s_node_status{false}; + QString s_nodeDataPath{""}; signals: void data_updated(QJsonDocument); diff --git a/diagtool/CMakeLists.txt b/diagtool/CMakeLists.txt index 76aea6192..ad329d3a5 100644 --- a/diagtool/CMakeLists.txt +++ b/diagtool/CMakeLists.txt @@ -9,12 +9,41 @@ find_package(Qt5 5.15 REQUIRED COMPONENTS set(CMAKE_AUTOMOC ON) -add_executable(${PROJECT_NAME} - main.cpp - DiagnosticWorker.cpp - AbstractDiagnostic.cpp - LinuxDiagnostic.cpp -) + + +if(UNIX) + if(DARWIN) + add_definitions(-DCLI_PATH="./cellframe-node-cli") + add_executable(${PROJECT_NAME} + main.cpp + DiagnosticWorker.cpp + AbstractDiagnostic.cpp + MacDiagnostic.cpp + ) + endif() + + if(LINUX) + add_definitions(-DCLI_PATH="/opt/cellframe-node/bin/cellframe-node-cli") + add_executable(${PROJECT_NAME} + main.cpp + DiagnosticWorker.cpp + AbstractDiagnostic.cpp + LinuxDiagnostic.cpp + ) + endif() + +endif() + +if(WIN32) + add_definitions(-DCLI_PATH="cellframe-node-cli.exe") + add_executable(${PROJECT_NAME} + main.cpp + DiagnosticWorker.cpp + AbstractDiagnostic.cpp + WinDiagnostic.cpp + ) +endif() + target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Network diff --git a/diagtool/DiagnosticWorker.cpp b/diagtool/DiagnosticWorker.cpp index be0c71a3c..0768437f2 100644 --- a/diagtool/DiagnosticWorker.cpp +++ b/diagtool/DiagnosticWorker.cpp @@ -17,14 +17,20 @@ DiagnosticWorker::DiagnosticWorker(QObject * parent) s_elapsed_timer = new QElapsedTimer(); s_elapsed_timer->start(); +#ifdef Q_OS_LINUX m_diagnostic = new LinuxDiagnostic(); +#elif defined Q_OS_WIN + m_diagnostic = new WinDiagnostic(); +#elif defined Q_OS_MAC + m_diagnostic = new MacDiagnostic(); +#endif connect(m_diagnostic, &AbstractDiagnostic::data_updated, this, &DiagnosticWorker::slot_diagnostic_data, Qt::QueuedConnection); m_diagnostic->start_diagnostic(); - m_diagnostic->set_timeout(30000); //3minutes + m_diagnostic->set_timeout(30000); //30 sec } DiagnosticWorker::~DiagnosticWorker() { @@ -52,7 +58,7 @@ void DiagnosticWorker::slot_diagnostic_data(QJsonDocument data) if(m_node_version.isEmpty()) { QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), QStringList()<<"version"); + proc.start(QString(CLI_PATH), QStringList()<<"version"); proc.waitForFinished(5000); QString result = proc.readAll(); if(result.contains("version")) diff --git a/diagtool/DiagnosticWorker.h b/diagtool/DiagnosticWorker.h index 01341f29c..2216d1cfe 100644 --- a/diagtool/DiagnosticWorker.h +++ b/diagtool/DiagnosticWorker.h @@ -10,7 +10,14 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include "LinuxDiagnostic.h" + +#ifdef Q_OS_LINUX + #include "LinuxDiagnostic.h" +#elif defined Q_OS_WIN + #include "WinDiagnostic.h" +#elif defined Q_OS_MAC + #include "MacDiagnostic.h" +#endif class DiagnosticWorker : public QObject diff --git a/diagtool/LinuxDiagnostic.cpp b/diagtool/LinuxDiagnostic.cpp index 455e3aec8..f302ad8ca 100644 --- a/diagtool/LinuxDiagnostic.cpp +++ b/diagtool/LinuxDiagnostic.cpp @@ -29,7 +29,8 @@ void LinuxDiagnostic::info_update(){ sys_info.insert("mac", s_mac); sys_info.insert("disk", get_disk_info()); - QFile file("/opt/cellframe-node/etc/diagdata.json"); + QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath); + QFile file(jsonFilePath); if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QJsonParseError err; @@ -344,208 +345,3 @@ QJsonObject LinuxDiagnostic::get_process_info(long proc_id, int totalRam) return process_info; } - -/// --------------------------------------------------------------- -/// Cli info -/// --------------------------------------------------------------- -QJsonObject LinuxDiagnostic::get_cli_info() -{ - QStringList networks = get_networks(); - - QJsonObject netObj; - - for(QString net : networks) - { - QJsonObject dataObj; - - dataObj.insert("net_info", get_net_info(net)); - dataObj.insert("mempool" , get_mempool_count(net)); -// dataObj.insert("ledger" , get_ledger_count(net)); - dataObj.insert("blocks" , get_blocks_count(net)); - dataObj.insert("events" , get_events_count(net)); - dataObj.insert("nodelist" , get_nodelist(net)); - - netObj.insert(net, dataObj); - } - - return netObj; -} - -QStringList LinuxDiagnostic::get_networks() -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), QStringList()<<"net"<<"list"); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QStringList listNetworks; - result.remove(' '); - result.remove("\r"); - result.remove("\n"); - result.remove("Networks:"); - if(!(result.isEmpty() || result.isNull() || result.contains('\'') || result.contains("error") || result.contains("Error") || result.contains("err"))) - { - listNetworks = result.split("\t", QString::SkipEmptyParts); - } - - return listNetworks; -} - -QJsonObject LinuxDiagnostic::get_net_info(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"net"<<"-net"<<QString(net)<<"get"<<"status"); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - // ---------- State & TargetState ---------------- - - QRegularExpression rx(R"***(^Network "(\S+)" has state (\S+) \(target state (\S*)\), .*cur node address ([A-F0-9]{4}::[A-F0-9]{4}::[A-F0-9]{4}::[A-F0-9]{4}))***"); - QRegularExpressionMatch match = rx.match(result); - if (!match.hasMatch()) { - return {}; - } - - QJsonObject resultObj({ - {"state" , match.captured(2)}, - {"target_state" , match.captured(3)}, - {"node_address" , match.captured(4)} - }); - - // ---------- Links count ---------------- - QRegularExpression rxLinks(R"(\), active links (\d+) from (\d+),)"); - match = rxLinks.match(result); - if (!match.hasMatch()) { - return resultObj; - } - - resultObj.insert("active_links_count", match.captured(1)); - resultObj.insert("links_count" , match.captured(2)); - resultObj.insert("balancer", get_balancer_links(net)); - - return resultObj; -} - -QJsonObject LinuxDiagnostic::get_mempool_count(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"mempool_list"<<"-net"<<QString(net)); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QRegularExpression rx(R"(\.(.+): Total (.+) records)"); - - ///TODO: bug in requests. Always returns both chains -// QRegularExpressionMatch match = rx.match(result); -// if (!match.hasMatch()) { -// return {}; -// } - -// proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), -// QStringList()<<"mempool_list"<<"-net"<<QString(net)<<"-chain"<<"zero"); -// proc.waitForFinished(5000); -// result = proc.readAll(); - - QJsonObject resultObj; - - QRegularExpressionMatchIterator matchItr = rx.globalMatch(result); - - while (matchItr.hasNext()) - { - QRegularExpressionMatch match = matchItr.next(); - resultObj.insert(match.captured(1), match.captured(2)); - } - - return resultObj; -} - -QJsonObject LinuxDiagnostic::get_ledger_count(QString net) -{ - //TODO: legder tx -all -net NOT WORKING - return {}; -} - -QJsonObject LinuxDiagnostic::get_blocks_count(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"block"<<"list"<<"-net"<<QString(net) <<"-chain" << "main"); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QRegularExpression rx(R"(\.(.+): Have (.+) blocks)"); - QRegularExpressionMatch match = rx.match(result); - if (!match.hasMatch()) { - return {}; - } - - QJsonObject resultObj; - resultObj.insert(match.captured(1), match.captured(2)); - - return resultObj; - -} - -QJsonObject LinuxDiagnostic::get_events_count(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"dag"<<"event"<<"list"<<"-net"<<QString(net) <<"-chain" << "zerochain"); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QRegularExpression rx(R"(\.(.+) have total (.+) events)"); - QRegularExpressionMatch match = rx.match(result); - if (!match.hasMatch()) { - return {}; - } - - QJsonObject resultObj; - resultObj.insert(match.captured(1), match.captured(2)); - - return resultObj; -} - - -QJsonArray LinuxDiagnostic::get_nodelist(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"node"<<"dump"<<"-net"<<QString(net)); - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QJsonArray res; - for (auto l : result.split("\n")) - res.push_back(QJsonValue(l)); - - return res; -} - -QJsonObject LinuxDiagnostic::get_balancer_links(QString net) -{ - QProcess proc; - proc.start(QString("/opt/cellframe-node/bin/cellframe-node-cli"), - QStringList()<<"node"<<"connections"<<"-net"<<QString(net)); - - proc.waitForFinished(5000); - QString result = proc.readAll(); - - QJsonObject resultObj; - for (auto line : result.split("\n")) - { - if (line.split(":").length() < 2) - continue; - - if(line.startsWith("Uplinks:")) - resultObj.insert("uplinks", line.split(":")[1].trimmed()); - if(line.startsWith("Downlinks:")) - resultObj.insert("downlinks", line.split(":")[1].trimmed()); - } - - qDebug() << resultObj; - - return resultObj; -} \ No newline at end of file diff --git a/diagtool/LinuxDiagnostic.h b/diagtool/LinuxDiagnostic.h index a5e02d7a1..37d89f52a 100644 --- a/diagtool/LinuxDiagnostic.h +++ b/diagtool/LinuxDiagnostic.h @@ -39,19 +39,6 @@ private: QString get_proc_path(long pid); QJsonObject get_process_info(long pid, int totalRam); QJsonObject get_disk_info(); - QJsonObject get_cli_info(); - - - //CLI - - QStringList get_networks(); - QJsonObject get_net_info(QString net); - QJsonObject get_mempool_count(QString net); - QJsonObject get_ledger_count(QString net); - QJsonObject get_blocks_count(QString net); - QJsonObject get_events_count(QString net); - QJsonArray get_nodelist(QString net); - QJsonObject get_balancer_links(QString net); private slots: @@ -59,7 +46,7 @@ private slots: private: size_t previous_idle_time{0}, previous_total_time{0}; - bool s_node_status{false}; + }; diff --git a/diagtool/MacDiagnostic.cpp b/diagtool/MacDiagnostic.cpp new file mode 100644 index 000000000..08674958d --- /dev/null +++ b/diagtool/MacDiagnostic.cpp @@ -0,0 +1,243 @@ +#include "MacDiagnostic.h" + +static unsigned long long _previousTotalTicks = 0; +static unsigned long long _previousIdleTicks = 0; + +MacDiagnostic::MacDiagnostic(AbstractDiagnostic *parent) + : AbstractDiagnostic{parent} +{ + connect(s_timer_update, &QTimer::timeout, + this, &MacDiagnostic::info_update, + Qt::QueuedConnection); +} + +void MacDiagnostic::info_update() +{ +// qInfo()<<"MacDiagnostic::info_update "; + + QJsonObject proc_info; + QJsonObject sys_info; + QJsonObject cli_info; + QJsonObject full_info; + + + sys_info = get_sys_info(); + sys_info.insert("mac", s_mac); + + QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath); + QFile file(jsonFilePath); + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err); + file.close(); + + if(err.error == QJsonParseError::NoError && !doc.isEmpty()) + sys_info.insert("data", doc.object()); + else + qWarning()<<err.errorString(); + } + + QJsonObject obj = sys_info["memory"].toObject(); + int mem = obj["total"].toString().toUInt();; + + proc_info = get_process_info(mem); + proc_info.insert("roles", roles_processing()); + + if(s_node_status) + { + cli_info = get_cli_info(); + full_info.insert("cli_data", cli_info); + } + + full_info.insert("system", sys_info); + full_info.insert("process", proc_info); + + s_full_info.setObject(full_info); + + emit data_updated(s_full_info); +} + +QJsonObject MacDiagnostic::get_sys_info() +{ +// qInfo()<<"MacDiagnostic::get_sys_info "; + QJsonObject obj_sys_data, obj_cpu, obj_memory; + + //get memory data + //total mem + int mib[2]; + int64_t physical_memory; + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + size_t length = sizeof(int64_t); + sysctl(mib, 2, &physical_memory, &length, NULL, 0); + + + + //use mem + + vm_size_t page_size; + mach_port_t mach_port; + mach_msg_type_number_t count; + vm_statistics64_data_t vm_stats; + long long free_memory = 0; +// long long used_memory = 0; + + mach_port = mach_host_self(); + count = sizeof(vm_stats) / sizeof(natural_t); + if (KERN_SUCCESS == host_page_size(mach_port, &page_size) && + KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, + (host_info64_t)&vm_stats, &count)) + { + free_memory = (int64_t)vm_stats.free_count * (int64_t)page_size; + +// used_memory = ((int64_t)vm_stats.active_count + +// (int64_t)vm_stats.inactive_count + +// (int64_t)vm_stats.wire_count) * (int64_t)page_size; + } + + QString memtotal = QString::number(physical_memory/1024); + QString memfree = QString::number(free_memory/1024); +// QString memused = get_memory_string(used_memory/1024); + + QString memory_used = QString::number((physical_memory - free_memory) *100 / physical_memory); + + obj_memory.insert("total", memtotal); + obj_memory.insert("free", memfree); + obj_memory.insert("load", memory_used); + + //get cpu info + + host_cpu_load_info_data_t cpuinfo; + float res = -1.0f; + mach_msg_type_number_t counts = HOST_CPU_LOAD_INFO_COUNT; + if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuinfo, &count) == KERN_SUCCESS) + { + unsigned long long totalTicks = 0; + for(int i=0; i<CPU_STATE_MAX; i++) totalTicks += cpuinfo.cpu_ticks[i]; + res = calculate_cpu_load(cpuinfo.cpu_ticks[CPU_STATE_IDLE], totalTicks); + } + obj_cpu.insert("load", int(res*100)); + + //get uptime system + + enum { NANOSECONDS_IN_SEC = 1000 * 1000 * 1000 }; + double multiply = 0; + QString uptime = "00:00:00"; + if (multiply == 0) + { + mach_timebase_info_data_t s_timebase_info; + if(mach_timebase_info(&s_timebase_info) == KERN_SUCCESS) + { + // multiply to get value in the nano seconds + multiply = (double)s_timebase_info.numer / (double)s_timebase_info.denom; + // multiply to get value in the seconds + multiply /= NANOSECONDS_IN_SEC; + uptime = get_uptime_string(mach_absolute_time() * multiply); + } + } + + +// //------- + + obj_sys_data.insert("uptime", uptime); + obj_sys_data.insert("CPU", obj_cpu); + obj_sys_data.insert("memory", obj_memory); + + return obj_sys_data; +} + +float MacDiagnostic::calculate_cpu_load(unsigned long long idleTicks, unsigned long long totalTicks) +{ +// qInfo()<<"MacDiagnostic::calculate_cpu_load "; + unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks; + unsigned long long idleTicksSinceLastTime = idleTicks-_previousIdleTicks; + float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0); + _previousTotalTicks = totalTicks; + _previousIdleTicks = idleTicks; + return ret; + +} + +/// --------------------------------------------------------------- +/// Process info +/// --------------------------------------------------------------- +QJsonObject MacDiagnostic::get_process_info(int totalRam) +{ +// qInfo()<<"MacDiagnostic::get_process_info "; + QJsonObject process_info; + + QProcess proc; + QString program = "ps"; + QStringList arguments; + arguments << "-axm" << "-o" << "rss,pid,etime,comm"; + proc.start(program, arguments); + proc.waitForFinished(1000); + QString res = proc.readAll(); + + QString string=""; + + for(QString str : res.split("\n")) + { + if(str.contains("cellframe-node")) + { + string = str; + break; + } + } + + QString status = "Offline"; + QString node_dir = s_nodeDataPath; + + QString log_size, db_size, chain_size; + log_size = QString::number(get_file_size("log", node_dir) / 1024); + db_size = QString::number(get_file_size("DB", node_dir) / 1024); + chain_size = QString::number(get_file_size("chain", node_dir) / 1024); + + if(log_size.isEmpty()) log_size = "0"; + if(db_size.isEmpty()) db_size = "0"; + if(chain_size.isEmpty()) chain_size = "0"; + + process_info.insert("log_size", log_size); + process_info.insert("DB_size", db_size); + process_info.insert("chain_size", chain_size); + + + if(string.isEmpty()) + { + process_info.insert("memory_use","0"); + process_info.insert("memory_use_value","0 Kb"); + process_info.insert("uptime","00:00:00"); + } + else + { + status = "Online"; + + int pid, rss; + QString uptime, path; + + QStringList parseString = string.split(" "); + parseString.removeAll(""); + + rss = parseString[0].toInt(); + pid = parseString[1].toInt(); + uptime = parseString[2]; + path = parseString[3]; + + QString memory_use_value = QString::number(rss); + int precentUseRss = rss *100 / totalRam; + + process_info.insert("memory_use",precentUseRss); + process_info.insert("memory_use_value",memory_use_value); + process_info.insert("uptime",uptime); + process_info.insert("name","cellframe-node"); + process_info.insert("path", path); + } + + s_node_status = status == "Online" ? true : false; + + process_info.insert("status", status); + + + return process_info; +} diff --git a/diagtool/MacDiagnostic.h b/diagtool/MacDiagnostic.h new file mode 100644 index 000000000..540a1b88b --- /dev/null +++ b/diagtool/MacDiagnostic.h @@ -0,0 +1,36 @@ +#ifndef MACDIAGNOSTIC_H +#define MACDIAGNOSTIC_H + +#include "AbstractDiagnostic.h" + +#include <sys/sysctl.h> +#include <sys/types.h> +#include <mach/vm_statistics.h> +#include <mach/mach_types.h> +#include <mach/mach_init.h> +#include <mach/mach_host.h> +#include <time.h> +#include <mach/mach_time.h> + +using namespace std; + + +class MacDiagnostic : public AbstractDiagnostic +{ + Q_OBJECT +public: + explicit MacDiagnostic(AbstractDiagnostic * parent = nullptr); + +private: + QJsonObject get_sys_info(); + QJsonObject get_process_info(int totalRam); + + //cpu + float calculate_cpu_load(unsigned long long idleTick, unsigned long long totakTicks ); + +private slots: + void info_update(); + +}; + +#endif // MACDIAGNOSTIC_H diff --git a/diagtool/NodeDiagnostic.pro b/diagtool/NodeDiagnostic.pro index 828b78ba9..ee1416aaa 100644 --- a/diagtool/NodeDiagnostic.pro +++ b/diagtool/NodeDiagnostic.pro @@ -8,18 +8,36 @@ CONFIG -= app_bundle # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +#LIBS += -L$$NODE_BUILD_PATH/dap-sdk/core/ -ldap_core +include (../dap-sdk/core/libdap.pri) + SOURCES += \ AbstractDiagnostic.cpp \ DiagnosticWorker.cpp \ - LinuxDiagnostic.cpp \ main.cpp +HEADERS += \ + AbstractDiagnostic.h \ + DiagnosticWorker.h + +win32 { + DEFINES += CLI_PATH=\\\"cellframe-node-cli.exe\\\" + HEADERS += WinDiagnostic.h + SOURCES += WinDiagnostic.cpp +} + +mac { + DEFINES += CLI_PATH=\\\"./cellframe-node-cli\\\" + HEADERS += MacDiagnostic.h + SOURCES += MacDiagnostic.cpp +} + +else: !win32 { + DEFINES += CLI_PATH=\\\"/opt/cellframe-node/bin/cellframe-node-cli\\\" + HEADERS += LinuxDiagnostic.h + SOURCES += LinuxDiagnostic.cpp +} # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -HEADERS += \ - AbstractDiagnostic.h \ - DiagnosticWorker.h \ - LinuxDiagnostic.h diff --git a/diagtool/WinDiagnostic.cpp b/diagtool/WinDiagnostic.cpp new file mode 100644 index 000000000..4989cc5e1 --- /dev/null +++ b/diagtool/WinDiagnostic.cpp @@ -0,0 +1,274 @@ +#include "WinDiagnostic.h" + +WinDiagnostic::WinDiagnostic(AbstractDiagnostic *parent) + : AbstractDiagnostic{parent} +{ + connect(s_timer_update, &QTimer::timeout, + this, &WinDiagnostic::info_update, + Qt::QueuedConnection); + + GetSystemTimes(&s_prev_idle, &s_prev_kernel, &s_prev_user); +} + +void WinDiagnostic::info_update() +{ + QJsonObject proc_info; + QJsonObject sys_info; + QJsonObject cli_info; + QJsonObject full_info; + + sys_info = get_sys_info(); + sys_info.insert("mac", s_mac); +// sys_info.insert("disk", get_disk_info()); + + QString jsonFilePath = QString("%1/etc/diagdata.json").arg(s_nodeDataPath); + QFile file(jsonFilePath); + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err); + file.close(); + + if(err.error == QJsonParseError::NoError && !doc.isEmpty()) + sys_info.insert("data", doc.object()); + else + qWarning()<<err.errorString(); + } + + QJsonObject obj = sys_info["memory"].toObject(); + int mem = obj["total"].toString().toInt();; + + proc_info = get_process_info(mem); + proc_info.insert("roles", roles_processing()); + + if(s_node_status) + { + cli_info = get_cli_info(); + full_info.insert("cli_data", cli_info); + } + + full_info.insert("system", sys_info); + full_info.insert("process", proc_info); + + s_full_info.setObject(full_info); + + emit data_updated(s_full_info); +} + +QJsonObject WinDiagnostic::get_sys_info() +{ + QJsonObject obj_sys_data, obj_cpu, obj_memory; + + // get CPU load + FILETIME idle; + FILETIME kernel; + FILETIME user; + + GetSystemTimes(&idle, &kernel, &user); + + ULONGLONG sys = (ft2ull(user) - ft2ull(s_prev_user)) + + (ft2ull(kernel) - ft2ull(s_prev_kernel)); + + QString cpu_load = QString::number(int((sys - ft2ull(idle) + ft2ull(s_prev_idle)) * 100.0 / sys)); + obj_cpu.insert("load", cpu_load); + + s_prev_idle = idle; + s_prev_kernel = kernel; + s_prev_user = user; + + MEMORYSTATUSEX memory_status; + ZeroMemory(&memory_status, sizeof(MEMORYSTATUSEX)); + memory_status.dwLength = sizeof(MEMORYSTATUSEX); + GlobalMemoryStatusEx(&memory_status); + + QString memory, memory_used, memory_free; + + memory = QString::number(memory_status.ullTotalPhys / 1024); + size_t total_value = memory_status.ullTotalPhys / 1024; + size_t available_value = memory_status.ullAvailPhys / 1024; + memory_free = QString::number(memory_status.ullAvailPhys / 1024); + + memory_used = QString::number((total_value - available_value) *100 / total_value); + + obj_memory.insert("total", memory); + obj_memory.insert("free", memory_free); + obj_memory.insert("load", memory_used); + + DWORD currentTime = GetTickCount(); + + QString uptime = get_uptime_string(currentTime/1000); + + + obj_sys_data.insert("uptime", uptime); + obj_sys_data.insert("CPU", obj_cpu); + obj_sys_data.insert("memory", obj_memory); + return obj_sys_data; + +} + +long WinDiagnostic::get_memory_size(Qt::HANDLE hProc) +{ + PROCESS_MEMORY_COUNTERS pmcInfo; + + if (GetProcessMemoryInfo(hProc, &pmcInfo, sizeof(pmcInfo))) + return pmcInfo.WorkingSetSize/1024; + else return 0; + +} + +ULONGLONG WinDiagnostic::ft2ull(FILETIME &ft) { + ULARGE_INTEGER ul; + ul.HighPart = ft.dwHighDateTime; + ul.LowPart = ft.dwLowDateTime; + return ul.QuadPart; +} + +void WinDiagnostic::refresh_win_snapshot() +{ + // Get the process list snapshot. + hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + + ProcessEntry.dwSize = sizeof( ProcessEntry ); + + + // Get the first process info. + BOOL Return = FALSE; + Return = Process32First( hProcessSnapShot,&ProcessEntry ); + + // Getting process info failed. + if( !Return ) + { + qDebug()<<"Getting process info failed"; + } +} + +QJsonObject WinDiagnostic::get_process_info(int totalRam) +{ + refresh_win_snapshot(); + + hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + + // vars for get process time + FILETIME lpCreation, lpExit, lpKernel, lpUser; + SYSTEMTIME stCreation, stExit, stKernel, stUser; + long memory_size; + + HANDLE hSnapshot; + PROCESSENTRY32 pe; + long pid = 0; + BOOL hResult; + + // snapshot of all processes in the system + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + // initializing size: needed for using Process32First + pe.dwSize = sizeof(PROCESSENTRY32); + + // info about first process encountered in a system snapshot + hResult = Process32First(hSnapshot, &pe); + + + QString proc_name = "cellframe-node.exe"; + while (hResult) { + // if we find the process: return process ID + + std::wstring string(pe.szExeFile); + std::string str(string.begin(), string.end()); + QString s = QString::fromStdString(str); + + + if(!proc_name.compare(s)){ + pid = pe.th32ProcessID; + + // get process descriptor + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION , FALSE, pe.th32ProcessID); + + if(hProcess) + { + // get process times info + if(GetProcessTimes(hProcess,&lpCreation, &lpExit, &lpKernel, &lpUser)) + { + FileTimeToSystemTime(&lpCreation, &stCreation); + FileTimeToSystemTime(&lpExit, &stExit); + FileTimeToSystemTime(&lpUser, &stUser); + FileTimeToSystemTime(&lpKernel, &stKernel); + } + + memory_size = get_memory_size(hProcess); + + //TODO CPU processing + + CloseHandle(hProcess); + } + + break; + } + hResult = Process32Next(hSnapshot, &pe); + } + + CloseHandle( hProcessSnapShot ); + + QJsonObject process_info; + + QString status = "Offline"; +// QString path = NODE_PATH; + QString node_dir = QString("%1/cellframe-node/").arg(regGetUsrPath()); + + QString log_size, db_size, chain_size; + log_size = QString::number(get_file_size("log", node_dir) / 1024); + db_size = QString::number(get_file_size("DB", node_dir) / 1024); + chain_size = QString::number(get_file_size("chain", node_dir) / 1024); + + if(log_size.isEmpty()) log_size = "0"; + if(db_size.isEmpty()) db_size = "0"; + if(chain_size.isEmpty()) chain_size = "0"; + + process_info.insert("log_size", log_size); + process_info.insert("DB_size", db_size); + process_info.insert("chain_size", chain_size); + + + if(pid){ + + QDateTime dateStart; + dateStart.setMSecsSinceEpoch(0); + dateStart = dateStart.addYears(stCreation.wYear - 1970); + dateStart = dateStart.addMonths(stCreation.wMonth - 1); + dateStart = dateStart.addDays(stCreation.wDay - 1); + dateStart = dateStart.addSecs(stCreation.wHour * 60 * 60 + stCreation.wMinute * 60 + stCreation.wSecond); + + QDateTime dateNow = QDateTime::currentDateTime(); + + quint64 sec_start = dateStart.toSecsSinceEpoch(); + quint64 sec_now = dateNow.toSecsSinceEpoch(); + + long result_uptime = sec_now - sec_start; + + QString uptime = get_uptime_string(result_uptime); + + int precentUseRss = (memory_size * 100) / totalRam; + QString memory_use_value = QString::number(memory_size); + + process_info.insert("memory_use",precentUseRss); + process_info.insert("memory_use_value",memory_use_value); + process_info.insert("uptime",uptime); + process_info.insert("name","cellframe-node"); + + status = "Online"; + + }else{ + + process_info.insert("memory_use",0); + process_info.insert("memory_use_value","0 Kb"); + process_info.insert("uptime","00:00:00"); + } + + s_node_status = status == "Online" ? true : false; + + process_info.insert("status", status); +// process_info.insert("path", path); + + + return process_info; +} + diff --git a/diagtool/WinDiagnostic.h b/diagtool/WinDiagnostic.h new file mode 100644 index 000000000..769452fa6 --- /dev/null +++ b/diagtool/WinDiagnostic.h @@ -0,0 +1,38 @@ +#ifndef WINDIAGNOSTIC_H +#define WINDIAGNOSTIC_H + +#include "AbstractDiagnostic.h" + +#include <windows.h> +#include <psapi.h> +#include <tlhelp32.h> +#include "registry.h" +#include "pdh.h" + + +enum PLATFORM { WINNT1, WIN2K_XP1, WIN9X1, UNKNOWN1 }; + +class WinDiagnostic : public AbstractDiagnostic { + Q_OBJECT +public: + explicit WinDiagnostic(AbstractDiagnostic* parent = nullptr); + +private: + QJsonObject get_sys_info(); + QJsonObject get_process_info(int totalRam); + + long get_memory_size(HANDLE hProc); + ULONGLONG ft2ull(FILETIME &ft); + +private: + + HANDLE hProcessSnapShot; + PROCESSENTRY32 ProcessEntry; + FILETIME s_prev_idle, s_prev_kernel, s_prev_user; + +private slots: + void refresh_win_snapshot(); + void info_update(); +}; + +#endif // WINDIAGNOSTIC_H diff --git a/diagtool/main.cpp b/diagtool/main.cpp index 1c0a7638c..c4db95221 100644 --- a/diagtool/main.cpp +++ b/diagtool/main.cpp @@ -5,6 +5,7 @@ int main(int argc, char *argv[]) { qSetMessagePattern("%{type} %{if-category}%{category}: %{endif}%{function}: %{message}"); QCoreApplication a(argc, argv); + DiagnosticWorker * wrkr = new DiagnosticWorker(); return a.exec(); diff --git a/version.mk b/version.mk index 204b9c3c8..eb18b53fd 100644 --- a/version.mk +++ b/version.mk @@ -1,3 +1,3 @@ VERSION_MAJOR=5 VERSION_MINOR=2 -VERSION_PATCH=273 +VERSION_PATCH=274 -- GitLab