сделал страницу для разработчиков, добавил примитивный сбор журнала статистики
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
|
||||
#define TIME_NOW() std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count()
|
||||
|
||||
typedef boost::property_tree::ptree::path_type json_path;
|
||||
|
||||
@@ -64,6 +64,9 @@ static inline void rtrim(std::string &s) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), s.end());
|
||||
}
|
||||
static const char* boolAsStr(bool value) {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
class TerminalNetworkSettings {
|
||||
public:
|
||||
@@ -110,6 +113,104 @@ static std::ostream& operator<<(std::ostream& out, CP_Result result) {
|
||||
return out;
|
||||
}
|
||||
|
||||
class api_driver::StatisticsLogger {
|
||||
public:
|
||||
StatisticsLogger(): timeStart(TIME_NOW()) {}
|
||||
|
||||
int64_t timeStart;
|
||||
|
||||
bool logEn = false;
|
||||
std::atomic<int> logPeriodMs = 1000;
|
||||
std::atomic<int> maxAgeMs = 10000;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {"en": bool, "logPeriodMs": int, ""}
|
||||
*/
|
||||
std::string getSettings() {
|
||||
std::lock_guard _lock(mutex);
|
||||
std::stringstream res;
|
||||
res << "{\"en\":" << boolAsStr(this->logEn);
|
||||
res << ",\"logPeriodMs\":" << logPeriodMs;
|
||||
res << ",\"maxAgeMs\":" << maxAgeMs;
|
||||
res << '}';
|
||||
return res.str();
|
||||
}
|
||||
void setSettings(boost::property_tree::ptree &pt) {
|
||||
const bool newEn = pt.get<bool>("en");
|
||||
const int newInterval = pt.get<int>("logPeriodMs");
|
||||
const int newMaxAgeMs = pt.get<int>("maxAgeMs");
|
||||
|
||||
std::lock_guard _lock(this->mutex);
|
||||
this->logPeriodMs = newInterval;
|
||||
this->maxAgeMs = newMaxAgeMs;
|
||||
|
||||
if (newEn != this->logEn) {
|
||||
if (newEn) {
|
||||
this->logFile.open("/tmp/weblog-statistics.csv", std::ios::out);
|
||||
if (this->logFile.is_open()) {
|
||||
const auto* header = "timestamp\tpkt ok\tpkt bad\tfine freq dem\tcrs freq dem\tcrs freq compensator\tcrs time est\tfine time est\tmax level corr\torigin delay\tSNR\tmodcod\tfine freq compensator\tind freq grb\tind freq tochn\tind filt adapt\tfilter corr cinc\tcorr cnt\n";
|
||||
this->logFile.write(header, static_cast<std::streamsize>(strlen(header)));
|
||||
this->logEn = true;
|
||||
this->timeStart = TIME_NOW();
|
||||
}
|
||||
} else {
|
||||
if (this->logFile.is_open()) {
|
||||
this->logFile.close();
|
||||
}
|
||||
this->logEn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически.
|
||||
* @param item
|
||||
*/
|
||||
void putItem(const debug_metrics& item) {
|
||||
std::lock_guard _lock(this->mutex);
|
||||
if (!logEn) return;
|
||||
if (this->logFile.is_open()) {
|
||||
std::stringstream res;
|
||||
res << TIME_NOW() - this->timeStart << '\t';
|
||||
res << item.cnt_ok << '\t';
|
||||
res << item.cnt_bad << '\t';
|
||||
res << item.fine_freq_dem << '\t';
|
||||
res << item.crs_freq_dem << '\t';
|
||||
res << item.crs_freq_compensator << '\t';
|
||||
res << item.crs_time_est << '\t';
|
||||
res << item.fine_time_est << '\t';
|
||||
res << item.max_level_corr << '\t';
|
||||
res << item.origin_delay << '\t';
|
||||
res << item.SNR << '\t';
|
||||
res << item.current_modcod << '\t';
|
||||
res << item.fine_freq_compensator << '\t';
|
||||
res << item.ind_freq_grb << '\t';
|
||||
res << item.ind_freq_tochn << '\t';
|
||||
res << item.ind_filt_adapt << '\t';
|
||||
res << item.filter_corr_cinc << '\t';
|
||||
res << item.corr_cnt << '\n';
|
||||
|
||||
const auto out = res.str();
|
||||
this->logFile.write(out.c_str(), static_cast<std::streamsize>(out.length()));
|
||||
this->logFile.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// void collectExpiredItems();
|
||||
|
||||
// void resetLogs() {
|
||||
// std::lock_guard _lock(mutex);
|
||||
// logs.clear();
|
||||
// }
|
||||
|
||||
~StatisticsLogger() = default;
|
||||
private:
|
||||
// std::pmr::deque<LogItem> logs;
|
||||
std::fstream logFile{};
|
||||
std::shared_mutex mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
|
||||
*/
|
||||
@@ -140,6 +241,8 @@ private:
|
||||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDmaDebug(status_init)", CP_GetDmaDebug(sid, "status_init", &tmpDevState));
|
||||
#endif
|
||||
#ifdef MODEM_IS_SCPC
|
||||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDebugMetrics()", CP_GetDebugMetrics(sid, debugMetrics));
|
||||
|
||||
bool isCinC = getIsCinC();
|
||||
if (isCinC) {
|
||||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetCinCState()", CP_GetCinCState(sid, cinc));
|
||||
@@ -306,6 +409,22 @@ private:
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateState(): " << e.what();
|
||||
}
|
||||
|
||||
// запись статистики в лог, если нужно
|
||||
try {
|
||||
static int uc = 0;
|
||||
if (uc == 0) {
|
||||
this->statsLogs.putItem(debugMetrics);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateState(): success write statistics state to log!";
|
||||
}
|
||||
uc++;
|
||||
if (uc * CACHE_STATISTICS_UPDATE_MS >= this->statsLogs.logPeriodMs) {
|
||||
uc = 0;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateState() failed to log: " << e.what();
|
||||
}
|
||||
}},
|
||||
// обновление кеша настроек
|
||||
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .callback = [this]() {
|
||||
@@ -344,12 +463,12 @@ private:
|
||||
}
|
||||
|
||||
int64_t sleepTime = 60000; // минута по-умолчанию
|
||||
auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
|
||||
auto now = TIME_NOW();
|
||||
for (auto& u: updaters) {
|
||||
if (u.checkNeedUpdate(now)) {
|
||||
u.lastUpdate = now;
|
||||
u.callback();
|
||||
now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
|
||||
now = TIME_NOW();
|
||||
}
|
||||
|
||||
sleepTime = std::min(sleepTime, u.getNextUpdate(now));
|
||||
@@ -366,6 +485,7 @@ private:
|
||||
demodulator_state demodState{};
|
||||
device_state devState{};
|
||||
std::string deviceInitState;
|
||||
debug_metrics debugMetrics{};
|
||||
#ifdef MODEM_IS_SCPC
|
||||
CinC_state cincState{};
|
||||
#endif
|
||||
@@ -390,6 +510,8 @@ private:
|
||||
TerminalFirmwareVersion firmware;
|
||||
|
||||
public:
|
||||
StatisticsLogger statsLogs;
|
||||
|
||||
std::mutex cpApiMutex;
|
||||
TSID sid;
|
||||
boost::thread daemon;
|
||||
@@ -657,10 +779,6 @@ void api_driver::ApiDriver::startDaemon() {
|
||||
}
|
||||
}
|
||||
|
||||
static const char* boolAsStr(bool value) {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string api_driver::buildEscapedString(const std::string& source) {
|
||||
std::string str(source);
|
||||
size_t start_pos = 0;
|
||||
@@ -1174,6 +1292,14 @@ void api_driver::ApiDriver::executeInApi(const std::function<void(TSID sid)>& ca
|
||||
}
|
||||
}
|
||||
|
||||
std::string api_driver::ApiDriver::getLoggingStatisticsSettings() {
|
||||
return this->daemon->statsLogs.getSettings();
|
||||
}
|
||||
|
||||
void api_driver::ApiDriver::setLoggingStatisticsSettings(boost::property_tree::ptree &pt) {
|
||||
this->daemon->statsLogs.setSettings(pt);
|
||||
}
|
||||
|
||||
std::string api_driver::ApiDriver::loadSysInfo() {
|
||||
std::stringstream result;
|
||||
struct sysinfo info{};
|
||||
|
Reference in New Issue
Block a user