Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b2dd863e9 | |||
| c78bc592a8 | |||
| 6f7ee762ec | |||
| 0acc58bbe1 | |||
| d1ed49412c | |||
| 748f8481bc |
@@ -46,14 +46,18 @@ extern std::string G_ROCKETMQ_TOPIC;//topie
|
|||||||
extern std::string G_ROCKETMQ_TAG;//tag
|
extern std::string G_ROCKETMQ_TAG;//tag
|
||||||
extern std::string G_ROCKETMQ_KEY;//key
|
extern std::string G_ROCKETMQ_KEY;//key
|
||||||
|
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_LOG;
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_SET;
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_RC;
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_UD;
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_RT;
|
||||||
|
|
||||||
extern std::string FRONT_INST;
|
extern std::string FRONT_INST;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern std::string G_MQCONSUMER_TOPIC_SET; // C++ 中的全局变量声明
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -649,7 +653,7 @@ void producer_send(const char* strbody)
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern std::string G_MQCONSUMER_TOPIC_RT;
|
//extern std::string G_MQCONSUMER_TOPIC_RT;
|
||||||
void rocketmq_test_rt()
|
void rocketmq_test_rt()
|
||||||
{
|
{
|
||||||
Ckafka_data_t data;
|
Ckafka_data_t data;
|
||||||
@@ -663,7 +667,7 @@ void rocketmq_test_rt()
|
|||||||
data.mp_id = 123123;
|
data.mp_id = 123123;
|
||||||
my_rocketmq_send(data);
|
my_rocketmq_send(data);
|
||||||
}
|
}
|
||||||
extern std::string G_MQCONSUMER_TOPIC_UD;
|
//extern std::string G_MQCONSUMER_TOPIC_UD;
|
||||||
void rocketmq_test_ud()//用来测试台账更新
|
void rocketmq_test_ud()//用来测试台账更新
|
||||||
{
|
{
|
||||||
Ckafka_data_t data;
|
Ckafka_data_t data;
|
||||||
@@ -706,7 +710,7 @@ void rocketmq_test_only()//用来测试进程控制脚本
|
|||||||
my_rocketmq_send(data);
|
my_rocketmq_send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern std::string G_MQCONSUMER_TOPIC_RC;
|
//extern std::string G_MQCONSUMER_TOPIC_RC;
|
||||||
void rocketmq_test_rc()
|
void rocketmq_test_rc()
|
||||||
{
|
{
|
||||||
Ckafka_data_t data;
|
Ckafka_data_t data;
|
||||||
@@ -721,7 +725,7 @@ void rocketmq_test_rc()
|
|||||||
my_rocketmq_send(data);
|
my_rocketmq_send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern std::string G_MQCONSUMER_TOPIC_LOG;
|
//extern std::string G_MQCONSUMER_TOPIC_LOG;
|
||||||
void rocketmq_test_log()
|
void rocketmq_test_log()
|
||||||
{
|
{
|
||||||
Ckafka_data_t data;
|
Ckafka_data_t data;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
#include "../log4cplus/fileappender.h"
|
#include "../log4cplus/fileappender.h"
|
||||||
#include "../log4cplus/layout.h"
|
#include "../log4cplus/layout.h"
|
||||||
#include "../log4cplus/ndc.h"
|
#include "../log4cplus/ndc.h"
|
||||||
#include "../log4cplus/log4.h"
|
//#include "../log4cplus/log4.h"
|
||||||
#include "../log4cplus/spi/loggingevent.h"
|
#include "../log4cplus/spi/loggingevent.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -18,21 +18,47 @@
|
|||||||
//目录创建
|
//目录创建
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
//kafka结构定义
|
|
||||||
#include "../json/mms_json_inter.h"
|
#include "../json/mms_json_inter.h"
|
||||||
|
|
||||||
|
|
||||||
#include "../mms/rdb_client.h"
|
#include "../mms/rdb_client.h"
|
||||||
#include "../include/node.h"//lnk20241223
|
#include "../include/node.h"//lnk20241223
|
||||||
|
|
||||||
|
#include "../log4cplus/log4.h"//后移防止min/max定义冲突
|
||||||
|
///////////////////////////////////////////////lnk20260303添加日志上送控制
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct LogLevelCache { //记录日志等级的缓存,减少频繁访问全局map的开销
|
||||||
|
std::unordered_map<std::string, int> term_min; // terminal_id -> min level
|
||||||
|
std::unordered_map<std::string, int> mp_min; // mp_id -> min level
|
||||||
|
};
|
||||||
|
|
||||||
|
// append线程只读,不加锁
|
||||||
|
static std::shared_ptr<LogLevelCache> g_level_cache_sp;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
|
||||||
|
//用来控制日志上送的结构
|
||||||
|
struct LOGEntry {
|
||||||
|
std::string id;
|
||||||
|
std::string level; // terminal / measurepoint
|
||||||
|
int code; //code
|
||||||
|
int min_grade;
|
||||||
|
int countdown;
|
||||||
|
};
|
||||||
|
|
||||||
|
//日志上送map管理
|
||||||
|
std::map<std::string, LOGEntry> g_log_entries;
|
||||||
|
pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
/////////////////////////////////////////////外部定义
|
||||||
extern unsigned int g_node_id;
|
extern unsigned int g_node_id;
|
||||||
extern int g_front_seg_index;
|
extern int g_front_seg_index;
|
||||||
extern std::string FRONT_INST;
|
extern std::string FRONT_INST;
|
||||||
extern char subdir[128];
|
extern char subdir[128];
|
||||||
extern node_t* g_node;
|
extern node_t* g_node;
|
||||||
|
|
||||||
|
|
||||||
//mq
|
//mq
|
||||||
extern QMutex kafka_data_list_mutex; //Kafka发送数据锁
|
extern QMutex kafka_data_list_mutex; //Kafka发送数据锁
|
||||||
extern QList<Ckafka_data_t> kafka_data_list; //kafka发送数据链表
|
extern QList<Ckafka_data_t> kafka_data_list; //kafka发送数据链表
|
||||||
@@ -42,12 +68,153 @@ extern std::string intToString(int number);
|
|||||||
|
|
||||||
//日志主题
|
//日志主题
|
||||||
extern std::string G_LOG_TOPIC;
|
extern std::string G_LOG_TOPIC;
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
//log4命名空间
|
//log4命名空间
|
||||||
using namespace log4cplus;
|
using namespace log4cplus;
|
||||||
using namespace log4cplus::helpers;
|
using namespace log4cplus::helpers;
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
static std::string extract_logger_id(const std::string& logger_name);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////辅助函数
|
////////////////////////////////////////////////////////辅助函数
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////lnk20260303添加日志上送控制
|
||||||
|
//用于在台账中查询日志上送控制项的日志等级字符串转换为整数
|
||||||
|
static int int_to_loglevel(int v, int default_level = WARN_LOG_LEVEL)
|
||||||
|
{
|
||||||
|
switch (v) {
|
||||||
|
case 0: return ERROR_LOG_LEVEL;
|
||||||
|
case 1: return WARN_LOG_LEVEL;
|
||||||
|
case 2: return INFO_LOG_LEVEL;
|
||||||
|
case 3: return DEBUG_LOG_LEVEL;
|
||||||
|
default: return default_level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 构建日志等级缓存,减少 append 线程访问全局 map 的开销
|
||||||
|
static LogLevelCache* build_cache_unlocked()
|
||||||
|
{
|
||||||
|
LogLevelCache* nc = new LogLevelCache;
|
||||||
|
|
||||||
|
// 没 node / 没 clients:返回空 cache(查不到会兜底 WARN)
|
||||||
|
if (!g_node || g_node->n_clients <= 0 || !g_node->clients) {
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 你 LD_info 是固定 10 个就用 10;如果不是,改成实际长度
|
||||||
|
const int MAX_LD = 10;
|
||||||
|
|
||||||
|
for (int iedno = 0; iedno < g_node->n_clients; ++iedno) {
|
||||||
|
ied_t* ied = g_node->clients[iedno];
|
||||||
|
if (!ied || !ied->usr_ext) continue;
|
||||||
|
|
||||||
|
ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext;
|
||||||
|
|
||||||
|
// terminal_id 必须有效
|
||||||
|
const char* tid = ied_usr->terminal_id;
|
||||||
|
if (!tid || tid[0] == '\0') continue;
|
||||||
|
|
||||||
|
const std::string terminal_id(tid);
|
||||||
|
|
||||||
|
// 装置级阈值:0~3 -> log4cplus level(默认 WARN)
|
||||||
|
const int term_lv = int_to_loglevel(ied_usr->log_level, WARN_LOG_LEVEL);
|
||||||
|
nc->term_min[terminal_id] = term_lv;
|
||||||
|
|
||||||
|
// 监测点阈值:若非法/缺失,兜底用装置级 term_lv
|
||||||
|
for (int i = 0; i < MAX_LD; ++i) {
|
||||||
|
const char* mp = ied_usr->LD_info[i].mp_id;
|
||||||
|
if (!mp || mp[0] == '\0') continue;
|
||||||
|
|
||||||
|
const std::string mp_id(mp);
|
||||||
|
|
||||||
|
// mp 的 log_level 优先;非法则用 term_lv
|
||||||
|
const int mp_lv = int_to_loglevel(ied_usr->LD_info[i].log_level, term_lv);
|
||||||
|
nc->mp_min[mp_id] = mp_lv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
//用于更新日志等级缓存的函数,获取最新的日志上送控制项并更新到缓存中,调用时需持锁
|
||||||
|
void refresh_log_level_cache_locked()
|
||||||
|
{
|
||||||
|
std::shared_ptr<LogLevelCache> nc(build_cache_unlocked());
|
||||||
|
std::atomic_store(&g_level_cache_sp, nc);
|
||||||
|
}
|
||||||
|
const int LOGTYPE_DEFAULT = LOG_CODE_OTHER; // 默认日志类型,表示不区分具体类型的日志上送控制
|
||||||
|
static const int LOGTYPE_WILDCARD = 999; // 用于匹配任意日志类型的特殊值
|
||||||
|
static const char* ID_WILDCARD = "all"; // 用于匹配任意 ID 的特殊值
|
||||||
|
|
||||||
|
static std::string build_debug_key(const std::string& id,
|
||||||
|
const std::string& level, // terminal/measurepoint/process
|
||||||
|
int code) // 日志类型
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << id << "|" << level << "|" << code;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool find_entry_allow(const std::string& key, int level_val)
|
||||||
|
{
|
||||||
|
std::map<std::string, LOGEntry>::iterator it = g_log_entries.find(key);
|
||||||
|
if (it == g_log_entries.end() || it->second.countdown <= 0) return false;
|
||||||
|
return level_val >= it->second.min_grade;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool allow_low_level_send(const std::string& id,
|
||||||
|
const std::string& level_str,
|
||||||
|
int code,
|
||||||
|
int level_val)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&g_log_mutex);
|
||||||
|
|
||||||
|
// 1) 精确
|
||||||
|
if (find_entry_allow(build_debug_key(id, level_str, code), level_val)) {
|
||||||
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 2) logtype 通配
|
||||||
|
if (find_entry_allow(build_debug_key(id, level_str, LOGTYPE_WILDCARD), level_val)) {
|
||||||
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 3) id 通配
|
||||||
|
if (find_entry_allow(build_debug_key(ID_WILDCARD, level_str, code), level_val)) {
|
||||||
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 4) 双通配
|
||||||
|
if (find_entry_allow(build_debug_key(ID_WILDCARD, level_str, LOGTYPE_WILDCARD), level_val)) {
|
||||||
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_min_send_level_cached(const std::string& level_str, const std::string& logger_name)
|
||||||
|
{
|
||||||
|
const int DEFAULT_LEVEL = WARN_LOG_LEVEL;
|
||||||
|
if (level_str == "process") return DEFAULT_LEVEL;
|
||||||
|
|
||||||
|
const std::string id = extract_logger_id(logger_name); //terminal.<id> / monitor.<mp>
|
||||||
|
if (id.empty()) return DEFAULT_LEVEL;
|
||||||
|
|
||||||
|
std::shared_ptr<LogLevelCache> c = std::atomic_load(&g_level_cache_sp);
|
||||||
|
if (!c) return DEFAULT_LEVEL;
|
||||||
|
|
||||||
|
if (level_str == "terminal") {
|
||||||
|
auto it = c->term_min.find(id);
|
||||||
|
return (it != c->term_min.end()) ? it->second : DEFAULT_LEVEL;
|
||||||
|
}
|
||||||
|
if (level_str == "measurepoint") {
|
||||||
|
auto it = c->mp_min.find(id);
|
||||||
|
return (it != c->mp_min.end()) ? it->second : DEFAULT_LEVEL;
|
||||||
|
}
|
||||||
|
return DEFAULT_LEVEL;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////lnk20260303添加日志上送控制
|
||||||
std::string get_front_type_from_subdir() {
|
std::string get_front_type_from_subdir() {
|
||||||
if (std::strstr(subdir, "cfg_3s_data") != NULL)
|
if (std::strstr(subdir, "cfg_3s_data") != NULL)
|
||||||
return "realTime";
|
return "realTime";
|
||||||
@@ -79,12 +246,11 @@ bool create_directory_recursive(const std::string& path) {
|
|||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
std::string extract_logger_id(const std::string& logger_name) {
|
std::string extract_logger_id(const std::string& logger_name) {
|
||||||
size_t first = logger_name.find('.');
|
if (logger_name == "process") return "process";
|
||||||
size_t last = logger_name.rfind('.');
|
size_t pos = logger_name.find('.');
|
||||||
if (first != std::string::npos && last != std::string::npos && first + 1 < last) {
|
if (pos == std::string::npos) return "";
|
||||||
return logger_name.substr(first + 1, last - first - 1); // 去掉开头"terminal."和结尾".COM"
|
// 取第一个 '.' 后面的全部:terminal.<id> / monitor.<mp>
|
||||||
}
|
return logger_name.substr(pos + 1);
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_level_str(int level) {
|
std::string get_level_str(int level) {
|
||||||
@@ -98,7 +264,7 @@ std::string get_level_str(int level) {
|
|||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
TypedLogger::TypedLogger() {}
|
TypedLogger::TypedLogger() {}
|
||||||
TypedLogger::TypedLogger(const Logger& l, int t) : logger(l), logtype(t) {}
|
TypedLogger::TypedLogger(const Logger& l, int t) : logger(l), code(t) {}
|
||||||
|
|
||||||
DebugSwitch::DebugSwitch() : debug_open(false), min_level(WARN_LOG_LEVEL) {}
|
DebugSwitch::DebugSwitch() : debug_open(false), min_level(WARN_LOG_LEVEL) {}
|
||||||
void DebugSwitch::open() { debug_open = true; }
|
void DebugSwitch::open() { debug_open = true; }
|
||||||
@@ -132,46 +298,65 @@ LOG_TLS int g_log_code_tls = 0;
|
|||||||
|
|
||||||
class SendAppender : public Appender {
|
class SendAppender : public Appender {
|
||||||
protected:
|
protected:
|
||||||
void append(const spi::InternalLoggingEvent& event) {
|
void append(const spi::InternalLoggingEvent& event) override {
|
||||||
std::string logger_name = event.getLoggerName();
|
std::string logger_name = event.getLoggerName();
|
||||||
int level = event.getLogLevel();
|
int level = event.getLogLevel();
|
||||||
std::string msg = event.getMessage();
|
std::string msg = event.getMessage();
|
||||||
|
|
||||||
int logtype = (logger_name.find(".COM") != std::string::npos) ? LOGTYPE_COM : LOGTYPE_DATA;
|
|
||||||
std::string level_str;
|
std::string level_str;
|
||||||
if (logger_name.find("process") == 0)
|
if (logger_name.find("process") == 0)
|
||||||
level_str = "process";
|
level_str = "process";
|
||||||
else if (logger_name.find("monitor") != std::string::npos)
|
else if (logger_name.find("monitor") != std::string::npos)
|
||||||
level_str = "measurepoint";
|
level_str = "measurepoint";
|
||||||
else
|
else if (logger_name.find("terminal") != std::string::npos)
|
||||||
level_str = "terminal";
|
level_str = "terminal";
|
||||||
|
else
|
||||||
|
level_str = "process";
|
||||||
|
|
||||||
// ★读取 TLS 中的 code(在打日志的线程里由宏设定)
|
int code = g_log_code_tls; // TLS code
|
||||||
int code = g_log_code_tls; // 若未显式传入,则为 0
|
int safe_logtype = code; // ★关键:用 code 当 logtype 维度
|
||||||
|
|
||||||
if (level == ERROR_LOG_LEVEL || level == WARN_LOG_LEVEL || g_debug_switch.match(logger_name, level, logtype)) {
|
bool allow_send = false;
|
||||||
std::ostringstream oss;
|
int min_send_level = get_min_send_level_cached(level_str, logger_name);
|
||||||
oss << "{\"processNo\":\"" << intToString(g_front_seg_index)
|
|
||||||
<< "\",\"nodeId\":\"" << FRONT_INST
|
|
||||||
<< "\",\"businessId\":\"" << extract_logger_id(logger_name)
|
|
||||||
<< "\",\"level\":\"" << level_str
|
|
||||||
<< "\",\"grade\":\"" << get_level_str(level)
|
|
||||||
<< "\",\"logtype\":\"" << (logtype == LOGTYPE_COM ? "com" : "data")
|
|
||||||
<< "\",\"frontType\":\"" << get_front_type_from_subdir()
|
|
||||||
// ★新增:输出 code 字段(整型)
|
|
||||||
<< "\",\"code\":\"" << code
|
|
||||||
<< "\",\"log\":\"" << escape_json(msg) << "\"}";
|
|
||||||
|
|
||||||
std::string jsonString = oss.str();
|
// ① 高于台账阈值:直接上送
|
||||||
|
if (level >= min_send_level) {
|
||||||
|
allow_send = true;
|
||||||
|
} else {
|
||||||
|
// ② 低等级:默认不上送,除非命令打开
|
||||||
|
std::string ctrl_id;
|
||||||
|
if (level_str == "process") ctrl_id = "process";
|
||||||
|
else ctrl_id = extract_logger_id(logger_name);
|
||||||
|
|
||||||
Ckafka_data_t connect_info;
|
if (!ctrl_id.empty()) {
|
||||||
connect_info.strTopic = QString::fromStdString(G_LOG_TOPIC);
|
allow_send = allow_low_level_send(ctrl_id, level_str, safe_logtype, level);
|
||||||
connect_info.strText = QString::fromStdString(jsonString);
|
}
|
||||||
|
|
||||||
kafka_data_list_mutex.lock();
|
|
||||||
kafka_data_list.append(connect_info);
|
|
||||||
kafka_data_list_mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allow_send) return;
|
||||||
|
|
||||||
|
// ③ 限频:同一条日志
|
||||||
|
const std::string rkey = make_key(logger_name, level, code, msg);
|
||||||
|
if (!should_emit(rkey)) return;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "{\"processNo\":\"" << intToString(g_front_seg_index)
|
||||||
|
<< "\",\"nodeId\":\"" << FRONT_INST
|
||||||
|
<< "\",\"businessId\":\"" << extract_logger_id(logger_name)
|
||||||
|
<< "\",\"level\":\"" << level_str
|
||||||
|
<< "\",\"grade\":\"" << get_level_str(level)
|
||||||
|
<< "\",\"logtype\":\"" << safe_logtype
|
||||||
|
<< "\",\"frontType\":\"" << get_front_type_from_subdir()
|
||||||
|
<< "\",\"code\":" << code
|
||||||
|
<< ",\"log\":\"" << escape_json(msg) << "\"}";
|
||||||
|
|
||||||
|
Ckafka_data_t connect_info;
|
||||||
|
connect_info.strTopic = QString::fromStdString(G_LOG_TOPIC);
|
||||||
|
connect_info.strText = QString::fromStdString(oss.str());
|
||||||
|
|
||||||
|
kafka_data_list_mutex.lock();
|
||||||
|
kafka_data_list.append(connect_info);
|
||||||
|
kafka_data_list_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string escape_json(const std::string& input) {
|
std::string escape_json(const std::string& input) {
|
||||||
@@ -198,25 +383,58 @@ public:
|
|||||||
virtual ~SendAppender() {
|
virtual ~SendAppender() {
|
||||||
destructorImpl(); // 重要!释放 log4cplus 基类资源
|
destructorImpl(); // 重要!释放 log4cplus 基类资源
|
||||||
}
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////20260303添加日志上送控制 - 频率限制实现
|
||||||
|
private:
|
||||||
|
struct RateState {
|
||||||
|
uint64_t hit_count;
|
||||||
|
std::chrono::steady_clock::time_point last_emit;
|
||||||
|
bool has_emit;
|
||||||
|
|
||||||
|
RateState() : hit_count(0), last_emit(), has_emit(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, RateState> s_rate_map;
|
||||||
|
static std::mutex s_rate_mutex;
|
||||||
|
|
||||||
|
static std::string make_key(const std::string& logger_name, int level, int code, const std::string& msg) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << logger_name << "|" << level << "|" << code << "|" << msg;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool should_emit(const std::string& key) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
const auto now = steady_clock::now();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(s_rate_mutex);
|
||||||
|
RateState& st = s_rate_map[key];
|
||||||
|
|
||||||
|
const int RESET_SEC = 3600;
|
||||||
|
if (st.has_emit) {
|
||||||
|
auto idle = duration_cast<seconds>(now - st.last_emit).count();
|
||||||
|
if (idle >= RESET_SEC) st.hit_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
st.hit_count++;
|
||||||
|
const int period_sec = (st.hit_count > 3) ? 300 : 1;
|
||||||
|
|
||||||
|
if (!st.has_emit) {
|
||||||
|
st.last_emit = now;
|
||||||
|
st.has_emit = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto elapsed = duration_cast<seconds>(now - st.last_emit).count();
|
||||||
|
if (elapsed >= period_sec) {
|
||||||
|
st.last_emit = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
//////////////////////////////////////////////////////////////////20260303添加日志上送控制 - 频率限制实现
|
||||||
//用来控制日志上送的结构
|
std::unordered_map<std::string, SendAppender::RateState> SendAppender::s_rate_map;
|
||||||
struct LOGEntry {
|
std::mutex SendAppender::s_rate_mutex;
|
||||||
std::string id;
|
|
||||||
std::string level; // terminal / measurepoint
|
|
||||||
int logtype; // com / data
|
|
||||||
int min_grade;
|
|
||||||
int countdown;
|
|
||||||
};
|
|
||||||
|
|
||||||
//日志上送map管理
|
|
||||||
std::map<std::string, LOGEntry> g_log_entries;
|
|
||||||
pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
// 生成唯一 key
|
|
||||||
std::string build_debug_key(const std::string& id, const std::string& level, int logtype) {
|
|
||||||
return id + "|" + level + "|" + (logtype == 1 ? "COM" : "DATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 外部线程中调用:每秒更新所有倒计时,0 则删除
|
// 外部线程中调用:每秒更新所有倒计时,0 则删除
|
||||||
void update_log_entries_countdown() {
|
void update_log_entries_countdown() {
|
||||||
@@ -236,25 +454,25 @@ void update_log_entries_countdown() {
|
|||||||
pthread_mutex_unlock(&g_log_mutex);
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_log_command(const std::string& id, const std::string& level, const std::string& grade, const std::string& logtype_str) {
|
void process_log_command(const std::string& id,
|
||||||
if (level != "terminal" && level != "measurepoint") return;
|
const std::string& level,
|
||||||
|
const std::string& grade,
|
||||||
|
int code)
|
||||||
|
{
|
||||||
|
if (level != "terminal" && level != "measurepoint" && level != "process") return;
|
||||||
|
|
||||||
int type = (logtype_str == "com") ? LOGTYPE_COM : LOGTYPE_DATA;
|
|
||||||
int grade_level = (grade == "DEBUG") ? DEBUG_LOG_LEVEL : INFO_LOG_LEVEL;
|
int grade_level = (grade == "DEBUG") ? DEBUG_LOG_LEVEL : INFO_LOG_LEVEL;
|
||||||
|
|
||||||
std::string key = build_debug_key(id, level, type);
|
std::string key = build_debug_key(id, level, code);
|
||||||
|
|
||||||
pthread_mutex_lock(&g_log_mutex);
|
pthread_mutex_lock(&g_log_mutex);
|
||||||
|
LOGEntry& entry = g_log_entries[key];
|
||||||
LOGEntry& entry = g_log_entries[key]; // 会自动 insert 或取已有
|
|
||||||
entry.id = id;
|
entry.id = id;
|
||||||
entry.level = level;
|
entry.level = level;
|
||||||
entry.logtype = type;
|
entry.code = code;
|
||||||
entry.min_grade = grade_level;
|
entry.min_grade = grade_level;
|
||||||
entry.countdown = 60; // 重置倒计时
|
entry.countdown = 60;
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_log_mutex);
|
pthread_mutex_unlock(&g_log_mutex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger init_logger(const std::string& full_name, const std::string& file_dir, const std::string& base_file, SharedAppenderPtr fileAppender) {
|
Logger init_logger(const std::string& full_name, const std::string& file_dir, const std::string& base_file, SharedAppenderPtr fileAppender) {
|
||||||
@@ -286,7 +504,7 @@ log4cplus::Logger init_logger(const std::string& full_name,
|
|||||||
//进程的日志
|
//进程的日志
|
||||||
void init_logger_process() {
|
void init_logger_process() {
|
||||||
std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log";
|
std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log";
|
||||||
logger_map["process"] = TypedLogger(init_logger(std::string("process"), base_dir, std::string("process")), LOGTYPE_DATA);
|
logger_map["process"] = TypedLogger(init_logger(std::string("process"), base_dir, std::string("process")), LOGTYPE_DEFAULT);
|
||||||
std::cout << "process log init ok" << std::endl;
|
std::cout << "process log init ok" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,12 +539,10 @@ void init_loggers_bydevid(const char* dev_id)
|
|||||||
|
|
||||||
std::string device_dir = base_dir + "/" + ip_str;
|
std::string device_dir = base_dir + "/" + ip_str;
|
||||||
|
|
||||||
std::string device_key_c = std::string("terminal.") + dev_id + ".COM";
|
std::string device_key = std::string("terminal.") + dev_id;
|
||||||
std::string device_key_d = std::string("terminal.") + dev_id + ".DATA";
|
|
||||||
|
|
||||||
// 添加判断:终端日志 logger 是否已存在
|
// 添加判断:终端日志 logger 是否已存在
|
||||||
if (logger_map.find(device_key_c) == logger_map.end() &&
|
if (logger_map.find(device_key) == logger_map.end()) {
|
||||||
logger_map.find(device_key_d) == logger_map.end()) {
|
|
||||||
|
|
||||||
// 所有终端日志(com 和 data)写到同一个 device 日志文件中
|
// 所有终端日志(com 和 data)写到同一个 device 日志文件中
|
||||||
std::string file_path_t = device_dir + "/" + dev_id + ".log";
|
std::string file_path_t = device_dir + "/" + dev_id + ".log";
|
||||||
@@ -335,27 +551,23 @@ void init_loggers_bydevid(const char* dev_id)
|
|||||||
SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
|
SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
|
||||||
device_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
device_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||||
|
|
||||||
Logger device_logger_c = init_logger(device_key_c, device_dir, dev_id, device_appender); //用终端id作为日志文件名
|
Logger device_logger = init_logger(device_key, device_dir, dev_id, device_appender); //用终端id作为日志文件名
|
||||||
Logger device_logger_d = init_logger(device_key_d, device_dir, dev_id, device_appender); //用终端id作为日志文件名
|
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DEFAULT);
|
||||||
logger_map[device_key_c] = TypedLogger(device_logger_c, LOGTYPE_COM);
|
|
||||||
logger_map[device_key_d] = TypedLogger(device_logger_d, LOGTYPE_DATA);
|
|
||||||
|
|
||||||
DIY_INFOLOG(device_key_d.c_str(),"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);
|
DIY_INFOLOG(device_key.c_str(),"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化监测点
|
// 初始化监测点
|
||||||
// 监测点 logger 名称格式:monitor.<mp_id>.COM / .DATA
|
// 监测点 logger 名称格式:monitor.<mp_id>
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
if (strlen(ied_usr->LD_info[i].mp_id) > 0){
|
if (strlen(ied_usr->LD_info[i].mp_id) > 0){
|
||||||
std::ostringstream mon_key_c, mon_key_d, mon_path, mon_name;
|
std::ostringstream mon_key, mon_path, mon_name;
|
||||||
mon_key_c << "monitor." << ied_usr->LD_info[i].mp_id << ".COM";
|
mon_key << "monitor." << ied_usr->LD_info[i].mp_id;
|
||||||
mon_key_d << "monitor." << ied_usr->LD_info[i].mp_id << ".DATA";
|
|
||||||
mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
|
mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
|
||||||
mon_name << ied_usr->LD_info[i].mp_id;
|
mon_name << ied_usr->LD_info[i].mp_id;
|
||||||
|
|
||||||
// 添加判断:监测点 logger 是否已存在
|
// 添加判断:监测点 logger 是否已存在
|
||||||
if (logger_map.find(mon_key_c.str()) == logger_map.end() &&
|
if (logger_map.find(mon_key.str()) == logger_map.end()) {
|
||||||
logger_map.find(mon_key_d.str()) == logger_map.end()) {
|
|
||||||
|
|
||||||
// 所有监测点日志(com 和 data)写到同一个 monitor 日志文件中
|
// 所有监测点日志(com 和 data)写到同一个 monitor 日志文件中
|
||||||
std::string file_path_m = mon_path.str() + "/" + mon_name.str() + ".log";
|
std::string file_path_m = mon_path.str() + "/" + mon_name.str() + ".log";
|
||||||
@@ -364,12 +576,10 @@ void init_loggers_bydevid(const char* dev_id)
|
|||||||
SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
|
SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
|
||||||
monitor_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
monitor_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||||
|
|
||||||
Logger mon_logger_c = init_logger(mon_key_c.str(), mon_path.str(), mon_name.str(),monitor_appender);//用监测点号作为日志文件名
|
Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str(),monitor_appender);//用监测点号作为日志文件名
|
||||||
Logger mon_logger_d = init_logger(mon_key_d.str(), mon_path.str(), mon_name.str(),monitor_appender);
|
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DEFAULT);
|
||||||
logger_map[mon_key_c.str()] = TypedLogger(mon_logger_c, LOGTYPE_COM);
|
|
||||||
logger_map[mon_key_d.str()] = TypedLogger(mon_logger_d, LOGTYPE_DATA);
|
|
||||||
|
|
||||||
DIY_INFOLOG(mon_key_d.str().c_str(),"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);
|
DIY_INFOLOG(mon_key.str().c_str(),"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +587,9 @@ void init_loggers_bydevid(const char* dev_id)
|
|||||||
|
|
||||||
break; // 只匹配一个 terminal_id
|
break; // 只匹配一个 terminal_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//lnk20260303添加日志上送控制 - 初始化时构建日志等级缓存
|
||||||
|
refresh_log_level_cache_locked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_loggers() {
|
void init_loggers() {
|
||||||
@@ -402,8 +615,7 @@ void init_loggers() {
|
|||||||
|
|
||||||
std::string device_dir = base_dir + "/" + ip_str;
|
std::string device_dir = base_dir + "/" + ip_str;
|
||||||
|
|
||||||
std::string device_key_c = std::string("terminal.") + ied_usr->terminal_id + ".COM";
|
std::string device_key = std::string("terminal.") + ied_usr->terminal_id;
|
||||||
std::string device_key_d = std::string("terminal.") + ied_usr->terminal_id + ".DATA";
|
|
||||||
|
|
||||||
// 所有终端日志(com 和 data)写到同一个 device 日志文件中
|
// 所有终端日志(com 和 data)写到同一个 device 日志文件中
|
||||||
std::string file_path_t = device_dir + "/" + ied_usr->terminal_id + ".log";
|
std::string file_path_t = device_dir + "/" + ied_usr->terminal_id + ".log";
|
||||||
@@ -412,21 +624,18 @@ void init_loggers() {
|
|||||||
SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
|
SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
|
||||||
device_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
device_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||||
|
|
||||||
Logger device_logger_c = init_logger(device_key_c, device_dir, ied_usr->terminal_id, device_appender); //用终端id作为日志文件名
|
Logger device_logger = init_logger(device_key, device_dir, ied_usr->terminal_id, device_appender); //用终端id作为日志文件名
|
||||||
Logger device_logger_d = init_logger(device_key_d, device_dir, ied_usr->terminal_id, device_appender); //用终端id作为日志文件名
|
|
||||||
|
|
||||||
logger_map[device_key_c] = TypedLogger(device_logger_c, LOGTYPE_COM);
|
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DEFAULT);
|
||||||
logger_map[device_key_d] = TypedLogger(device_logger_d, LOGTYPE_DATA);
|
|
||||||
|
|
||||||
DIY_INFOLOG(device_key_d.c_str(),"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);
|
DIY_INFOLOG(device_key.c_str(),"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);
|
||||||
|
|
||||||
// 初始化监测点
|
// 初始化监测点
|
||||||
// 监测点 logger 名称格式:monitor.<mp_id>.COM / .DATA
|
// 监测点 logger 名称格式:monitor.<mp_id>
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
if (strlen(ied_usr->LD_info[i].mp_id) > 0){
|
if (strlen(ied_usr->LD_info[i].mp_id) > 0){
|
||||||
std::ostringstream mon_key_c, mon_key_d, mon_path, mon_name;
|
std::ostringstream mon_key, mon_path, mon_name;
|
||||||
mon_key_c << "monitor." << ied_usr->LD_info[i].mp_id << ".COM";
|
mon_key << "monitor." << ied_usr->LD_info[i].mp_id;
|
||||||
mon_key_d << "monitor." << ied_usr->LD_info[i].mp_id << ".DATA";
|
|
||||||
|
|
||||||
mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
|
mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
|
||||||
mon_name << ied_usr->LD_info[i].mp_id;
|
mon_name << ied_usr->LD_info[i].mp_id;
|
||||||
@@ -437,19 +646,19 @@ void init_loggers() {
|
|||||||
SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
|
SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
|
||||||
monitor_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
monitor_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||||
|
|
||||||
Logger mon_logger_c = init_logger(mon_key_c.str(), mon_path.str(), mon_name.str(), monitor_appender);
|
Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str(), monitor_appender);
|
||||||
Logger mon_logger_d = init_logger(mon_key_d.str(), mon_path.str(), mon_name.str(), monitor_appender);
|
|
||||||
|
|
||||||
logger_map[mon_key_c.str()] = TypedLogger(mon_logger_c, LOGTYPE_COM);
|
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DEFAULT);
|
||||||
logger_map[mon_key_d.str()] = TypedLogger(mon_logger_d, LOGTYPE_DATA);
|
|
||||||
|
|
||||||
DIY_INFOLOG(mon_key_d.str().c_str(),"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);
|
DIY_INFOLOG(mon_key.str().c_str(),"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//lnk20260303添加日志上送控制 - 初始化时构建日志等级缓存
|
||||||
|
refresh_log_level_cache_locked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_loggers_by_terminal_id(const char* terminal_id_cstr) {
|
void remove_loggers_by_terminal_id(const char* terminal_id_cstr) {
|
||||||
@@ -465,37 +674,24 @@ void remove_loggers_by_terminal_id(const char* terminal_id_cstr) {
|
|||||||
if (strcmp(ied_usr->terminal_id, terminal_id.c_str()) != 0) continue;
|
if (strcmp(ied_usr->terminal_id, terminal_id.c_str()) != 0) continue;
|
||||||
|
|
||||||
// 删除终端日志 logger
|
// 删除终端日志 logger
|
||||||
std::string com_key = "terminal." + terminal_id + ".COM";
|
std::string terminal_key = "terminal." + terminal_id;;
|
||||||
std::string data_key = "terminal." + terminal_id + ".DATA";
|
|
||||||
|
|
||||||
if (logger_map.count(com_key)) {
|
if (logger_map.count(terminal_key)) {
|
||||||
logger_map[com_key].logger.removeAllAppenders();
|
logger_map[terminal_key].logger.removeAllAppenders();
|
||||||
logger_map.erase(com_key);
|
logger_map.erase(terminal_key);
|
||||||
}
|
|
||||||
|
|
||||||
if (logger_map.count(data_key)) {
|
|
||||||
logger_map[data_key].logger.removeAllAppenders();
|
|
||||||
logger_map.erase(data_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除监测点日志 logger
|
// 删除监测点日志 logger
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
const char* mp_id = ied_usr->LD_info[i].mp_id;
|
const char* mp_id = ied_usr->LD_info[i].mp_id;
|
||||||
if (strlen(mp_id) > 0) {
|
if (strlen(mp_id) > 0) {
|
||||||
std::string mon_prefix = std::string("monitor.") + mp_id;
|
std::string mon_key = std::string("monitor.") + mp_id;
|
||||||
|
|
||||||
std::string mon_com_key = mon_prefix + ".COM";
|
if (logger_map.count(mon_key)) {
|
||||||
std::string mon_data_key = mon_prefix + ".DATA";
|
logger_map[mon_key].logger.removeAllAppenders();
|
||||||
|
logger_map.erase(mon_key);
|
||||||
if (logger_map.count(mon_com_key)) {
|
|
||||||
logger_map[mon_com_key].logger.removeAllAppenders();
|
|
||||||
logger_map.erase(mon_com_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger_map.count(mon_data_key)) {
|
|
||||||
logger_map[mon_data_key].logger.removeAllAppenders();
|
|
||||||
logger_map.erase(mon_data_key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,18 @@
|
|||||||
#include "../json/cjson.h"
|
#include "../json/cjson.h"
|
||||||
|
|
||||||
#include "../log4cplus/log4.h"//lnk添加log4
|
#include "../log4cplus/log4.h"//lnk添加log4
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////lnk20260305数据追踪相关
|
||||||
|
#include <QHash>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QMapIterator>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
// ★MOD: 全局追踪表:mp_id -> remaining times
|
||||||
|
static QMutex g_trace_mutex;
|
||||||
|
static QHash<QString, int> g_trace_map;
|
||||||
|
|
||||||
///////////////////////////////////////////////////lnk2024-10-21////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////lnk2024-10-21////////////////////////////////////////////////////////
|
||||||
extern void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr);
|
extern void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr);
|
||||||
extern std::string WEB_INTEGRITY;
|
extern std::string WEB_INTEGRITY;
|
||||||
@@ -230,7 +242,106 @@ extern int isdelta_flag;//lnk2024-8-16 角型接线标志
|
|||||||
void connectlog_pgsql(char* id,char* datetime,int status);
|
void connectlog_pgsql(char* id,char* datetime,int status);
|
||||||
///////////////////////////////////////////////lnk20241021替换web接口//////////////////////////////////
|
///////////////////////////////////////////////lnk20241021替换web接口//////////////////////////////////
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////lnk20260305数据追踪
|
||||||
|
static QString escape_json_string(const QString& s)
|
||||||
|
{
|
||||||
|
QString out = s;
|
||||||
|
out.replace("\\", "\\\\");
|
||||||
|
out.replace("\"", "\\\"");
|
||||||
|
out.replace("\r", "\\r");
|
||||||
|
out.replace("\n", "\\n");
|
||||||
|
out.replace("\t", "\\t");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开追踪:次数 times(比如 5)
|
||||||
|
void process_trace_command(const std::string& id, int times)
|
||||||
|
{
|
||||||
|
if (times <= 0) return;
|
||||||
|
QString qid = QString::fromStdString(id).trimmed();
|
||||||
|
if (qid.isEmpty()) return;
|
||||||
|
|
||||||
|
QMutexLocker lk(&g_trace_mutex);
|
||||||
|
g_trace_map[qid] = times; // 重新打开就覆盖/重置次数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否要追踪
|
||||||
|
static bool trace_is_enabled(const QString& mp_id)
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&g_trace_mutex);
|
||||||
|
auto it = g_trace_map.constFind(mp_id);
|
||||||
|
return (it != g_trace_map.constEnd() && it.value() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命中一次并扣减;扣到 0 自动删
|
||||||
|
static void trace_hit_and_decrement(const QString& mp_id)
|
||||||
|
{
|
||||||
|
QMutexLocker lk(&g_trace_mutex);
|
||||||
|
auto it = g_trace_map.find(mp_id);
|
||||||
|
if (it == g_trace_map.end()) return;
|
||||||
|
|
||||||
|
int left = it.value();
|
||||||
|
left -= 1;
|
||||||
|
if (left <= 0) g_trace_map.erase(it);
|
||||||
|
else it.value() = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
//追踪61850原始数据
|
||||||
|
static QString build_mms_multiline_text(const json_block_data* data)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
|
||||||
|
QMapIterator<QString, double> it(data->mms_str_map);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
lines << QString("%1 = %2").arg(it.key()).arg(it.value(), 0, 'g', 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString build_trace_json(const json_block_data* data)
|
||||||
|
{
|
||||||
|
if (!data) return "{}";
|
||||||
|
|
||||||
|
QString mms_text = build_mms_multiline_text(data);
|
||||||
|
|
||||||
|
QString json;
|
||||||
|
json += "{";
|
||||||
|
json += QString("\"mp_id\":\"%1\",").arg(escape_json_string(data->mp_id));
|
||||||
|
json += QString("\"func_type\":%1,").arg(data->func_type);
|
||||||
|
json += QString("\"data_time\":%1,").arg(QString::number((qlonglong)data->time));
|
||||||
|
json += QString("\"voltage_level\":\"%1\",").arg(QString::number(data->voltage_level, 'f', 6));
|
||||||
|
json += QString("\"dev_type\":\"%1\",").arg(escape_json_string(data->dev_type));
|
||||||
|
json += QString("\"mms_text\":\"%1\"").arg(escape_json_string(mms_text));
|
||||||
|
json += "}";
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_trace_if_needed(json_block_data* pdata)
|
||||||
|
{
|
||||||
|
const QString mp_id_q = pdata->mp_id;
|
||||||
|
if (trace_is_enabled(mp_id_q)) {
|
||||||
|
|
||||||
|
// 1) 组 json
|
||||||
|
QString jsonText = build_trace_json(pdata);
|
||||||
|
|
||||||
|
// 2) 组 KafkaData
|
||||||
|
Ckafka_data_t KafkaData;
|
||||||
|
KafkaData.monitor_id = pdata->monitorId;
|
||||||
|
KafkaData.mp_id = pdata->mp_id;
|
||||||
|
KafkaData.strTopic = "DATA_TRACE_TOPIC";
|
||||||
|
KafkaData.strText = jsonText;
|
||||||
|
|
||||||
|
kafka_data_list_mutex.lock();
|
||||||
|
kafka_data_list.append(KafkaData);
|
||||||
|
kafka_data_list_mutex.unlock();
|
||||||
|
|
||||||
|
// 3) 次数 -1
|
||||||
|
trace_hit_and_decrement(mp_id_q);
|
||||||
|
}
|
||||||
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////lnk20250710添加频率值存储
|
////////////////////////////////////////////////////////////////////////////////////////////lnk20250710添加频率值存储
|
||||||
struct mp_freq_save {
|
struct mp_freq_save {
|
||||||
double G_FREQ;
|
double G_FREQ;
|
||||||
@@ -2820,6 +2931,7 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char
|
|||||||
{
|
{
|
||||||
Xmldata* config2 = new Xmldata();
|
Xmldata* config2 = new Xmldata();
|
||||||
xmlinfo_list2.insert(type, config2);
|
xmlinfo_list2.insert(type, config2);
|
||||||
|
xmlinfo_list2[type]->updataflag = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2841,35 +2953,30 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char
|
|||||||
|
|
||||||
char file_name[256];
|
char file_name[256];
|
||||||
memset(file_name, 0, 256);
|
memset(file_name, 0, 256);
|
||||||
sprintf(file_name, "%s", FILE_NAME);
|
snprintf(file_name, sizeof(file_name), "%s", FILE_NAME);
|
||||||
|
file_name[sizeof(file_name) - 1] = '\0';
|
||||||
QString Qsavename;
|
QString Qsavename;
|
||||||
Qsavename.append("/FeProject/dat/").append(id).append(".xml"); //本地保存路径
|
Qsavename.append("/FeProject/dat/").append(id).append(".xml"); //本地保存路径
|
||||||
char save_name[256];
|
char save_name[256];
|
||||||
memset(save_name, 0, 256);
|
memset(save_name, 0, 256);
|
||||||
sprintf(save_name, "%s", Qsavename.toAscii().data());
|
snprintf(save_name, sizeof(save_name), "%s", Qsavename.toAscii().data());
|
||||||
|
save_name[sizeof(save_name) - 1] = '\0';
|
||||||
cout << file_name << "!!!!!!!!!!!!!!!!!!!!!!!!!!" << save_name << endl;
|
cout << file_name << "!!!!!!!!!!!!!!!!!!!!!!!!!!" << save_name << endl;
|
||||||
|
|
||||||
//mq日志
|
//mq日志
|
||||||
DIY_WARNLOG_CODE("process",LOG_CODE_ICD_AND_DOWNLOAD,"【WARN】前置获取到终端类型%s,该终端类型对应的映射文件为%s,映射文件将下载并保存在本地为%s",TMNL_TYPE,FILE_PATH,save_name);
|
DIY_WARNLOG_CODE("process",LOG_CODE_ICD_AND_DOWNLOAD,"【WARN】前置获取到终端类型%s,该终端类型对应的映射文件为%s,映射文件将下载并保存在本地为%s",TMNL_TYPE,FILE_PATH,save_name);
|
||||||
|
|
||||||
//20241028 lnk 替换为文件下载web接口
|
|
||||||
//构造文件下载接口参数
|
|
||||||
//接口示例http://192.168.1.125:10215/file/download?filePath=/path/xxx.txt
|
|
||||||
// 调用web获取文件内容
|
// 调用web获取文件内容
|
||||||
char* fileContent = NULL;
|
char* fileContent = NULL;
|
||||||
|
|
||||||
//测试下载
|
|
||||||
//char downpath[128] = {"/home/pq/FeProject/src/pt61850netd_pqfe_lnk/download/123.txt"};
|
|
||||||
//char download[128] = {"{\"filename\":\"file_test.txt\"}"};
|
|
||||||
//SendJsonAPI_web("http://192.168.1.149:8091/file/download", "", download, &fileContent);
|
|
||||||
|
|
||||||
std::string fullPath = std::string("filePath=") + std::string(FILE_PATH);
|
std::string fullPath = std::string("filePath=") + std::string(FILE_PATH);
|
||||||
|
|
||||||
//调试用
|
//调试用
|
||||||
std::cout << "fullpath" << fullPath << std::endl;
|
std::cout << "fullpath" << fullPath << std::endl;
|
||||||
|
|
||||||
SendJsonAPI_web(WEB_FILEDOWNLOAD, fullPath.c_str(), "", &fileContent);
|
SendJsonAPI_web(WEB_FILEDOWNLOAD, fullPath.c_str(), "", &fileContent);
|
||||||
if (fileContent != NULL) {
|
if (fileContent != NULL && fileContent[0] != '\0') {
|
||||||
// 创建并打开文件
|
// 创建并打开文件
|
||||||
|
|
||||||
//判断返回的是不是错误json响应
|
//判断返回的是不是错误json响应
|
||||||
@@ -3348,18 +3455,19 @@ static void scanAndResendOfflineFiles(const std::string &dirPath)
|
|||||||
// 尝试发送
|
// 尝试发送
|
||||||
char* ptr = NULL; // 接收返回
|
char* ptr = NULL; // 接收返回
|
||||||
SendJsonAPI_web(WEB_EVENT, "", jsonContent.c_str(), &ptr);
|
SendJsonAPI_web(WEB_EVENT, "", jsonContent.c_str(), &ptr);
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL && ptr[0] != '\0') {
|
||||||
|
|
||||||
cJSON* j_r = cJSON_Parse(ptr);
|
cJSON* j_r = cJSON_Parse(ptr);
|
||||||
if (j_r == NULL) {
|
if (j_r == NULL) {
|
||||||
std::cout << "old file send fail" << std::endl;
|
std::cout << "old file send fail" << std::endl;
|
||||||
// 表示有响应,则可视为成功;根据项目需要可加更精细的判断
|
|
||||||
handleCommentResponse(std::string(ptr));
|
|
||||||
|
|
||||||
DIY_WARNLOG_CODE("process",LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件失败");
|
DIY_WARNLOG_CODE("process",LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件失败");
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
// 表示有响应,则可视为成功;根据项目需要可加更精细的判断
|
||||||
|
handleCommentResponse(std::string(ptr));
|
||||||
|
|
||||||
DIY_WARNLOG_CODE("process",LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件成功");
|
DIY_WARNLOG_CODE("process",LOG_CODE_TRANSIENT_COMM,"【WARN】前置重发暂态事件成功");
|
||||||
|
|
||||||
@@ -3367,7 +3475,7 @@ static void scanAndResendOfflineFiles(const std::string &dirPath)
|
|||||||
// 删除文件
|
// 删除文件
|
||||||
remove(fileList[i].fileName.c_str());
|
remove(fileList[i].fileName.c_str());
|
||||||
|
|
||||||
free(j_r);
|
cJSON_Delete(j_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3413,7 +3521,7 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
c_xmlcfg = xmlcfg;
|
c_xmlcfg = xmlcfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(mp_id) == 0) {
|
if (NULL == mp_id || strlen(mp_id) == 0 ) {
|
||||||
std::cout << "mp_id is null" << std::endl;
|
std::cout << "mp_id is null" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3456,6 +3564,12 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* json_string = cJSON_Print(root);
|
char* json_string = cJSON_Print(root);
|
||||||
|
if (json_string == NULL) {
|
||||||
|
DIY_ERRORLOG_CODE(full_key_m_d,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点:%s暂态事件生成JSON字符串失败",mp_id);
|
||||||
|
std::cerr << "Failed to print JSON object." << std::endl;
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
printf("%s\n", json_string); // 输出 JSON 字符串
|
printf("%s\n", json_string); // 输出 JSON 字符串
|
||||||
|
|
||||||
// 发送到暂态接口
|
// 发送到暂态接口
|
||||||
@@ -3464,7 +3578,7 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
|
|
||||||
// ================ 插入新功能 =========================
|
// ================ 插入新功能 =========================
|
||||||
// ********** 新增功能开始 **********
|
// ********** 新增功能开始 **********
|
||||||
if(ptr != NULL)
|
if(ptr != NULL && ptr[0] != '\0')
|
||||||
{
|
{
|
||||||
cJSON* j_r = cJSON_Parse(ptr);
|
cJSON* j_r = cJSON_Parse(ptr);
|
||||||
// 如果发送失败(j_r == NULL),则把当前 json 存入指定目录(/FeProject/dat/qvvr/)
|
// 如果发送失败(j_r == NULL),则把当前 json 存入指定目录(/FeProject/dat/qvvr/)
|
||||||
@@ -3493,13 +3607,13 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
|
|
||||||
// 把 json_string 写入文件
|
// 把 json_string 写入文件
|
||||||
if(!writeJsonToFile(fileName.c_str(), json_string)){
|
if(!writeJsonToFile(fileName.c_str(), json_string)){
|
||||||
DIY_ERRORLOG_CODE(full_key_m_d,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点:%s无法将暂态时间为%lld的暂态事件写入本地缓存",start_tm,mp_id);
|
DIY_ERRORLOG_CODE(full_key_m_d,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点:%s无法将暂态时间为%lld的暂态事件写入本地缓存",mp_id,start_tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);
|
checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
free(j_r);
|
cJSON_Delete(j_r);
|
||||||
//后续处理
|
//后续处理
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3512,10 +3626,11 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
// ********** 新增功能结束 **********
|
// ********** 新增功能结束 **********
|
||||||
|
|
||||||
// 下面继续原逻辑,不动,处理本次发送
|
// 下面继续原逻辑,不动,处理本次发送
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL && ptr[0] != '\0') {
|
||||||
std::cout << "current qvvr handle response" << std::endl;
|
std::cout << "current qvvr handle response" << std::endl;
|
||||||
handleCommentResponse(std::string(ptr));
|
handleCommentResponse(std::string(ptr));
|
||||||
free(ptr);
|
free(ptr);
|
||||||
|
ptr = NULL;
|
||||||
} else {
|
} else {
|
||||||
// 处理 ptr 为 NULL 的情况,例如日志记录或错误处理
|
// 处理 ptr 为 NULL 的情况,例如日志记录或错误处理
|
||||||
std::cout << "Error: Received NULL response" << std::endl;
|
std::cout << "Error: Received NULL response" << std::endl;
|
||||||
@@ -3541,7 +3656,7 @@ char* mp_id,char* Qvvr_rptname,char* devtype)
|
|||||||
fileName += ".txt";
|
fileName += ".txt";
|
||||||
// 把 json_string 写入文件
|
// 把 json_string 写入文件
|
||||||
if(!writeJsonToFile(fileName.c_str(), json_string)){
|
if(!writeJsonToFile(fileName.c_str(), json_string)){
|
||||||
DIY_ERRORLOG_CODE(full_key_m_d,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点:%s无法将暂态时间为%lld的暂态事件写入本地缓存",start_tm,mp_id);
|
DIY_ERRORLOG_CODE(full_key_m_d,LOG_CODE_TRANSIENT_COMM,"【ERROR】监测点:%s无法将暂态时间为%lld的暂态事件写入本地缓存",mp_id,start_tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);
|
checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024);
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ public:
|
|||||||
bool data_have_statistic;//是否有统计数据,0没有,1有
|
bool data_have_statistic;//是否有统计数据,0没有,1有
|
||||||
|
|
||||||
QMap<QString, double> mms_str_map; //数据值(61850数据属性名, 数据值)
|
QMap<QString, double> mms_str_map; //数据值(61850数据属性名, 数据值)
|
||||||
|
|
||||||
|
bool data_trace_flag; //数据追踪标记,0不追踪,1追踪
|
||||||
};
|
};
|
||||||
|
|
||||||
class Ckafka_data_t //kafka发送数据结构类
|
class Ckafka_data_t //kafka发送数据结构类
|
||||||
|
|||||||
@@ -46,6 +46,18 @@ int StringToInt(const std::string& str);
|
|||||||
extern pthread_mutex_t mtx;//lnk20250115
|
extern pthread_mutex_t mtx;//lnk20250115
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern void SendFileWeb(const std::string& strUrl,
|
||||||
|
const char* localpath,
|
||||||
|
const char* cloudpath,
|
||||||
|
char* wavepath);
|
||||||
|
|
||||||
|
extern int DownloadFileWeb(const std::string& strUrl,
|
||||||
|
const char* remotePath,
|
||||||
|
const char* localpath);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@@ -64,6 +76,13 @@ extern "C" {
|
|||||||
extern node_t* g_node; //lnk20241223
|
extern node_t* g_node; //lnk20241223
|
||||||
extern LD_info_t* find_LD_info_only_from_mp_id(char* mp_id);//lnk20241223
|
extern LD_info_t* find_LD_info_only_from_mp_id(char* mp_id);//lnk20241223
|
||||||
extern void print_terminal(const terminal* tmnl);
|
extern void print_terminal(const terminal* tmnl);
|
||||||
|
|
||||||
|
extern ST_RET mms_mvla_obtfile(MVL_NET_INFO *net_info,
|
||||||
|
ST_CHAR *srcfilename,
|
||||||
|
ST_CHAR *destfilename,
|
||||||
|
int iTimeout);
|
||||||
|
|
||||||
|
extern pt61850app_t *g_pt61850app;
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -121,13 +140,21 @@ extern std::string G_MQCONSUMER_KEY_RC;//key
|
|||||||
extern std::string G_MQCONSUMER_TOPIC_SET;//topie_recall
|
extern std::string G_MQCONSUMER_TOPIC_SET;//topie_recall
|
||||||
extern std::string G_MQCONSUMER_TAG_SET;//tag
|
extern std::string G_MQCONSUMER_TAG_SET;//tag
|
||||||
extern std::string G_MQCONSUMER_KEY_SET;//key
|
extern std::string G_MQCONSUMER_KEY_SET;//key
|
||||||
|
|
||||||
extern std::string G_MQCONSUMER_TOPIC_LOG;//topie_log
|
extern std::string G_MQCONSUMER_TOPIC_LOG;//topie_log
|
||||||
extern std::string G_MQCONSUMER_TAG_LOG;//tag
|
extern std::string G_MQCONSUMER_TAG_LOG;//tag
|
||||||
extern std::string G_MQCONSUMER_KEY_LOG;//key
|
extern std::string G_MQCONSUMER_KEY_LOG;//key
|
||||||
extern std::string G_LOG_TOPIC;//topie
|
extern std::string G_LOG_TOPIC;//topie
|
||||||
extern std::string G_LOG_TAG;//tag
|
extern std::string G_LOG_TAG;//tag
|
||||||
extern std::string G_LOG_KEY;//key
|
extern std::string G_LOG_KEY;//key
|
||||||
|
extern std::string G_MQCONSUMER_TOPIC_FILE;//topie_file
|
||||||
|
extern std::string G_MQCONSUMER_TAG_FILE;//tag
|
||||||
|
extern std::string G_MQCONSUMER_KEY_FILE;//key
|
||||||
|
extern std::string Topic_Reply_Topic;
|
||||||
|
extern std::string Topic_Reply_Tag;
|
||||||
|
extern std::string Topic_Reply_Key;
|
||||||
|
|
||||||
|
extern std::string WEB_FILEUPLOAD;
|
||||||
|
extern std::string WEB_FILEDOWNLOAD;
|
||||||
|
|
||||||
bool showinshellflag =false;
|
bool showinshellflag =false;
|
||||||
|
|
||||||
@@ -143,6 +170,10 @@ static QMap<QString, json_block_data*> json_data_map;//CZY 2023-08-17 ww 2023年
|
|||||||
static QMap<QString, json_block_data*> json_flicker_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据
|
static QMap<QString, json_block_data*> json_flicker_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据
|
||||||
static QMap<QString, json_block_data*> json_pst_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据
|
static QMap<QString, json_block_data*> json_pst_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////lnk20260310文件控制
|
||||||
|
pthread_mutex_t g_file_req_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
std::list<file_dir_req_t*> g_file_dir_req_list;
|
||||||
|
|
||||||
bool is_blank(const std::string& str)
|
bool is_blank(const std::string& str)
|
||||||
{
|
{
|
||||||
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
|
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
|
||||||
@@ -335,7 +366,7 @@ void my_rocketmq_send(Ckafka_data_t& data)
|
|||||||
rocketmq_producer_send(senddata.c_str(), topic.c_str());//lnk20250623修复偶发性doublefree
|
rocketmq_producer_send(senddata.c_str(), topic.c_str());//lnk20250623修复偶发性doublefree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void my_kafka_send(Ckafka_data_t& data)
|
void my_kafka_send(Ckafka_data_t& data)
|
||||||
{
|
{
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
@@ -426,6 +457,7 @@ void my_kafka_send(Ckafka_data_t& data)
|
|||||||
printf("\nFailed kafka send, monitor_id:[%s] topic:[%s]\n", key.c_str(), topic.c_str());
|
printf("\nFailed kafka send, monitor_id:[%s] topic:[%s]\n", key.c_str(), topic.c_str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void my_datahub_send(Ckafka_data_t& data)
|
void my_datahub_send(Ckafka_data_t& data)
|
||||||
{
|
{
|
||||||
@@ -479,7 +511,7 @@ void my_datahub_send(Ckafka_data_t& data)
|
|||||||
add_sng_log(data.strText.toAscii().data());
|
add_sng_log(data.strText.toAscii().data());
|
||||||
|
|
||||||
}
|
}
|
||||||
DataHub_Send_Datahub(const_cast<char*>(topic.c_str()), const_cast<char*>(senddata.c_str()));
|
//DataHub_Send_Datahub(const_cast<char*>(topic.c_str()), const_cast<char*>(senddata.c_str()));
|
||||||
printf("\ndatahub send, monitor_id:[%s] topic:[%s] Success\n", key.c_str(), topic.c_str());
|
printf("\ndatahub send, monitor_id:[%s] topic:[%s] Success\n", key.c_str(), topic.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,11 +545,11 @@ void KafkaSendThread::run()
|
|||||||
QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data());
|
QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data());
|
||||||
if (SEND_FLAG == 1) //kafka推送
|
if (SEND_FLAG == 1) //kafka推送
|
||||||
{
|
{
|
||||||
my_kafka_send(data);
|
//my_kafka_send(data);
|
||||||
}
|
}
|
||||||
else if (SEND_FLAG == 2)//datahub推送
|
else if (SEND_FLAG == 2)//datahub推送
|
||||||
{
|
{
|
||||||
my_datahub_send(data);
|
//my_datahub_send(data);
|
||||||
}
|
}
|
||||||
else if (SEND_FLAG == 3)//rocketmq推送lnk10-11
|
else if (SEND_FLAG == 3)//rocketmq推送lnk10-11
|
||||||
{
|
{
|
||||||
@@ -581,7 +613,8 @@ std::string extractDataJson(const char* inputJson) {
|
|||||||
// 提取 "guid" 部分
|
// 提取 "guid" 部分
|
||||||
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
||||||
if (guidstr == NULL || guidstr->type != cJSON_String) {
|
if (guidstr == NULL || guidstr->type != cJSON_String) {
|
||||||
std::cerr << "'guid' is missing or is not an array" << std::endl;
|
std::cerr << "'guid' is missing or is not an string" << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -593,12 +626,19 @@ std::string extractDataJson(const char* inputJson) {
|
|||||||
cJSON* data = cJSON_GetObjectItem(messageBody, "data");
|
cJSON* data = cJSON_GetObjectItem(messageBody, "data");
|
||||||
if (data == NULL || data->type != cJSON_Array) {
|
if (data == NULL || data->type != cJSON_Array) {
|
||||||
std::cerr << "'data' is missing or is not an array" << std::endl;
|
std::cerr << "'data' is missing or is not an array" << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建新的 JSON 数组对象,只包含 "data" 部分
|
// 创建新的 JSON 数组对象,只包含 "data" 部分
|
||||||
cJSON* newJson = cJSON_CreateArray(); // 创建一个新的数组
|
cJSON* newJson = cJSON_CreateArray(); // 创建一个新的数组
|
||||||
|
if (newJson == NULL) {
|
||||||
|
std::cerr << "Failed to create new JSON array" << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
// 将 "data" 数组中的元素逐个添加到新数组中
|
// 将 "data" 数组中的元素逐个添加到新数组中
|
||||||
cJSON* dataItem = NULL;
|
cJSON* dataItem = NULL;
|
||||||
@@ -610,6 +650,7 @@ std::string extractDataJson(const char* inputJson) {
|
|||||||
char* newJsonString = cJSON_Print(newJson);
|
char* newJsonString = cJSON_Print(newJson);
|
||||||
if (newJsonString == NULL) {
|
if (newJsonString == NULL) {
|
||||||
std::cerr << "Error printing new JSON" << std::endl;
|
std::cerr << "Error printing new JSON" << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
cJSON_Delete(newJson);
|
cJSON_Delete(newJson);
|
||||||
return "";
|
return "";
|
||||||
@@ -620,6 +661,7 @@ std::string extractDataJson(const char* inputJson) {
|
|||||||
|
|
||||||
// 清理内存
|
// 清理内存
|
||||||
free(newJsonString);
|
free(newJsonString);
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
cJSON_Delete(newJson);
|
cJSON_Delete(newJson);
|
||||||
|
|
||||||
@@ -684,10 +726,12 @@ bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::st
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Missing expected fields in JSON message." << std::endl;
|
std::cerr << "Missing expected fields in JSON message." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root); // 清理 JSON 对象
|
cJSON_Delete(root); // 清理 JSON 对象
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -917,6 +961,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
||||||
if (guidstr == nullptr) {
|
if (guidstr == nullptr) {
|
||||||
std::cout << "Missing 'guid' in JSON." << std::endl;
|
std::cout << "Missing 'guid' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -928,6 +973,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
||||||
if (code == nullptr) {
|
if (code == nullptr) {
|
||||||
std::cout << "Missing 'code' in JSON." << std::endl;
|
std::cout << "Missing 'code' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -938,6 +984,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* processNo = cJSON_GetObjectItem(messageBody, "processNo");
|
cJSON* processNo = cJSON_GetObjectItem(messageBody, "processNo");
|
||||||
if (processNo == nullptr) {
|
if (processNo == nullptr) {
|
||||||
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -948,6 +995,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* funtion = cJSON_GetObjectItem(messageBody, "fun");
|
cJSON* funtion = cJSON_GetObjectItem(messageBody, "fun");
|
||||||
if (funtion == nullptr) {
|
if (funtion == nullptr) {
|
||||||
std::cout << "Missing 'fun' in JSON." << std::endl;
|
std::cout << "Missing 'fun' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -957,6 +1005,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* front = cJSON_GetObjectItem(messageBody, "frontType");
|
cJSON* front = cJSON_GetObjectItem(messageBody, "frontType");
|
||||||
if (front == nullptr) {
|
if (front == nullptr) {
|
||||||
std::cout << "Missing 'frontType' in JSON." << std::endl;
|
std::cout << "Missing 'frontType' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -965,6 +1014,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
|
|
||||||
if (index_value != g_front_seg_index && g_front_seg_index != 0) {
|
if (index_value != g_front_seg_index && g_front_seg_index != 0) {
|
||||||
std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -979,6 +1029,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* num = cJSON_GetObjectItem(messageBody, "processNum");
|
cJSON* num = cJSON_GetObjectItem(messageBody, "processNum");
|
||||||
if (num == nullptr) {
|
if (num == nullptr) {
|
||||||
std::cout << "Missing 'processNum' in JSON." << std::endl;
|
std::cout << "Missing 'processNum' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1037,6 +1088,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* onlyip = cJSON_GetObjectItem(messageBody, "ip");
|
cJSON* onlyip = cJSON_GetObjectItem(messageBody, "ip");
|
||||||
if (onlyip == nullptr) {
|
if (onlyip == nullptr) {
|
||||||
std::cout << "Missing 'ip' in JSON." << std::endl;
|
std::cout << "Missing 'ip' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1046,6 +1098,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
cJSON* index_item = cJSON_GetObjectItem(messageBody, "proindex");
|
cJSON* index_item = cJSON_GetObjectItem(messageBody, "proindex");
|
||||||
if (index_item == nullptr) {
|
if (index_item == nullptr) {
|
||||||
std::cout << "Missing 'proindex' in JSON." << std::endl;
|
std::cout << "Missing 'proindex' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1078,6 +1131,7 @@ int parse_set(const std::string& json_str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 释放 JSON 对象
|
// 释放 JSON 对象
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1167,9 +1221,13 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat
|
|||||||
add_indent(xmlStream, indentLevel);
|
add_indent(xmlStream, indentLevel);
|
||||||
xmlStream << "<processNo>" << json_data.processNo << "</processNo>" << std::endl;
|
xmlStream << "<processNo>" << json_data.processNo << "</processNo>" << std::endl;
|
||||||
|
|
||||||
|
//lnk20250305
|
||||||
add_indent(xmlStream, indentLevel);
|
add_indent(xmlStream, indentLevel);
|
||||||
xmlStream << "<devKey>" << json_data.dev_key << "</devKey>" << std::endl;
|
xmlStream << "<devKey>" << json_data.dev_key << "</devKey>" << std::endl;
|
||||||
|
|
||||||
|
add_indent(xmlStream, indentLevel);
|
||||||
|
xmlStream << "<loglevel>" << json_data.log_level << "</loglevel>" << std::endl;
|
||||||
|
|
||||||
// monitorData 部分
|
// monitorData 部分
|
||||||
for (int i = 0; json_data.line[i].monitor_id[0] != '\0'; i++) {
|
for (int i = 0; json_data.line[i].monitor_id[0] != '\0'; i++) {
|
||||||
const monitor& monitor = json_data.line[i];
|
const monitor& monitor = json_data.line[i];
|
||||||
@@ -1202,6 +1260,9 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat
|
|||||||
add_indent(xmlStream, indentLevel);
|
add_indent(xmlStream, indentLevel);
|
||||||
xmlStream << "<status>" << monitor.status << "</status>" << std::endl;
|
xmlStream << "<status>" << monitor.status << "</status>" << std::endl;
|
||||||
|
|
||||||
|
add_indent(xmlStream, indentLevel);
|
||||||
|
xmlStream << "<loglevel>" << monitor.log_level << "</loglevel>" << std::endl;
|
||||||
|
|
||||||
indentLevel--;
|
indentLevel--;
|
||||||
add_indent(xmlStream, indentLevel);
|
add_indent(xmlStream, indentLevel);
|
||||||
xmlStream << "</monitorData>" << std::endl;
|
xmlStream << "</monitorData>" << std::endl;
|
||||||
@@ -1309,6 +1370,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
||||||
if (guidstr == nullptr) {
|
if (guidstr == nullptr) {
|
||||||
std::cout << "Missing 'guid' in JSON." << std::endl;
|
std::cout << "Missing 'guid' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1320,6 +1382,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
||||||
if (code == nullptr) {
|
if (code == nullptr) {
|
||||||
std::cout << "Missing 'code' in JSON." << std::endl;
|
std::cout << "Missing 'code' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1331,6 +1394,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
|
cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
|
||||||
if (process == nullptr) {
|
if (process == nullptr) {
|
||||||
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1342,6 +1406,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* idstr = cJSON_GetObjectItem(messageBody, "id");
|
cJSON* idstr = cJSON_GetObjectItem(messageBody, "id");
|
||||||
if (idstr == nullptr) {
|
if (idstr == nullptr) {
|
||||||
std::cout << "Missing 'id' in JSON." << std::endl;
|
std::cout << "Missing 'id' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1352,6 +1417,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* levelstr = cJSON_GetObjectItem(messageBody, "level");
|
cJSON* levelstr = cJSON_GetObjectItem(messageBody, "level");
|
||||||
if (levelstr == nullptr) {
|
if (levelstr == nullptr) {
|
||||||
std::cout << "Missing 'level' in JSON." << std::endl;
|
std::cout << "Missing 'level' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1362,6 +1428,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* gradestr = cJSON_GetObjectItem(messageBody, "grade");
|
cJSON* gradestr = cJSON_GetObjectItem(messageBody, "grade");
|
||||||
if (gradestr == nullptr) {
|
if (gradestr == nullptr) {
|
||||||
std::cout << "Missing 'grade' in JSON." << std::endl;
|
std::cout << "Missing 'grade' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1372,16 +1439,18 @@ int parse_log(const std::string& json_str) {
|
|||||||
cJSON* logtypestr = cJSON_GetObjectItem(messageBody, "logtype");
|
cJSON* logtypestr = cJSON_GetObjectItem(messageBody, "logtype");
|
||||||
if (logtypestr == nullptr) {
|
if (logtypestr == nullptr) {
|
||||||
std::cout << "Missing 'logtype' in JSON." << std::endl;
|
std::cout << "Missing 'logtype' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string logtype = logtypestr->valuestring;
|
int logtype = logtypestr->valueint;
|
||||||
|
|
||||||
// 获取 frontType 字段
|
// 获取 frontType 字段
|
||||||
cJSON* frontTypestr = cJSON_GetObjectItem(messageBody, "frontType");
|
cJSON* frontTypestr = cJSON_GetObjectItem(messageBody, "frontType");
|
||||||
if (frontTypestr == nullptr) {
|
if (frontTypestr == nullptr) {
|
||||||
std::cout << "Missing 'frontType' in JSON." << std::endl;
|
std::cout << "Missing 'frontType' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1390,12 +1459,14 @@ int parse_log(const std::string& json_str) {
|
|||||||
|
|
||||||
if (processNo != g_front_seg_index) {
|
if (processNo != g_front_seg_index) {
|
||||||
std::cout << "msg index:"<< processNo <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
std::cout << "msg index:"<< processNo <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frontType != subdir) {
|
if (frontType != subdir) {
|
||||||
std::cout << "msg frontType:"<< frontType <<"doesnt match self frontType:" << subdir << std::endl;
|
std::cout << "msg frontType:"<< frontType <<"doesnt match self frontType:" << subdir << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1413,13 +1484,16 @@ int parse_log(const std::string& json_str) {
|
|||||||
//校验数据
|
//校验数据
|
||||||
if((level == "terminal" || level == "measurepoint") &&
|
if((level == "terminal" || level == "measurepoint") &&
|
||||||
(grade == "NORMAL" || grade == "DEBUG") &&
|
(grade == "NORMAL" || grade == "DEBUG") &&
|
||||||
(logtype == "com" || logtype == "data") &&
|
|
||||||
(!id.empty() && !is_blank(id))){
|
(!id.empty() && !is_blank(id))){
|
||||||
|
|
||||||
//开启开关
|
//开启日志临时开关
|
||||||
process_log_command(id, level, grade, logtype);
|
process_log_command(id, level, grade, logtype);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if((level == "measurepoint") && (grade == "TRACE") && (!id.empty() && !is_blank(id))){ //数据追踪
|
||||||
|
//打开监测点数据追踪开关
|
||||||
|
process_trace_command(id,5); //5表示追踪次数
|
||||||
|
}
|
||||||
else{
|
else{
|
||||||
std::cout << "type doesnt match" <<std::endl;
|
std::cout << "type doesnt match" <<std::endl;
|
||||||
//记录warm
|
//记录warm
|
||||||
@@ -1429,6 +1503,7 @@ int parse_log(const std::string& json_str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 释放 JSON 对象
|
// 释放 JSON 对象
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1469,6 +1544,7 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
cJSON* code = cJSON_GetObjectItem(messageBody, "code");
|
||||||
if (code == nullptr) {
|
if (code == nullptr) {
|
||||||
std::cout << "Missing 'code' in JSON." << std::endl;
|
std::cout << "Missing 'code' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1480,6 +1556,7 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
|
cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
|
||||||
if (process == nullptr) {
|
if (process == nullptr) {
|
||||||
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
std::cout << "Missing 'processNo' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1491,6 +1568,7 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
|
||||||
if (guidstr == nullptr) {
|
if (guidstr == nullptr) {
|
||||||
std::cout << "Missing 'guid' in JSON." << std::endl;
|
std::cout << "Missing 'guid' in JSON." << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1501,6 +1579,7 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
//进程号为0的进程处理所有台账更新消息
|
//进程号为0的进程处理所有台账更新消息
|
||||||
if (process_No != g_front_seg_index && g_front_seg_index !=0) {
|
if (process_No != g_front_seg_index && g_front_seg_index !=0) {
|
||||||
std::cout << "msg index:"<< process_No <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
std::cout << "msg index:"<< process_No <<"doesnt match self index:" << g_front_seg_index << std::endl;
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1611,6 +1690,25 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
else
|
else
|
||||||
std::strncpy(json_data.timestamp, "N/A", sizeof(json_data.timestamp) - 1);
|
std::strncpy(json_data.timestamp, "N/A", sizeof(json_data.timestamp) - 1);
|
||||||
|
|
||||||
|
|
||||||
|
//添加loglevel字段
|
||||||
|
cJSON* loglevel = cJSON_GetObjectItem(item, "loglevel"); // log_level
|
||||||
|
int tmp_level = -1;
|
||||||
|
// 先读取 loglevel
|
||||||
|
if (loglevel && loglevel->type == cJSON_Number) {
|
||||||
|
tmp_level = loglevel->valueint;
|
||||||
|
}
|
||||||
|
else if (loglevel && loglevel->type == cJSON_String) {
|
||||||
|
tmp_level = atoi(loglevel->valuestring);
|
||||||
|
}
|
||||||
|
// 判断是否合法 (0~3)
|
||||||
|
if (tmp_level >= 0 && tmp_level <= 3) {
|
||||||
|
json_data.log_level = tmp_level;
|
||||||
|
} else {
|
||||||
|
json_data.log_level = 1; // 默认日志级别
|
||||||
|
}
|
||||||
|
printf("terminal log_level: %d\n", json_data.log_level);
|
||||||
|
|
||||||
// monitorData 解析,填充到 line 数组中
|
// monitorData 解析,填充到 line 数组中
|
||||||
cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData");
|
cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData");
|
||||||
if (monitorData != nullptr && monitorData->type == cJSON_Array) {
|
if (monitorData != nullptr && monitorData->type == cJSON_Array) {
|
||||||
@@ -1626,6 +1724,27 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
else
|
else
|
||||||
std::strncpy(monitor_data.monitor_id, "N/A", sizeof(monitor_data.monitor_id) - 1);
|
std::strncpy(monitor_data.monitor_id, "N/A", sizeof(monitor_data.monitor_id) - 1);
|
||||||
|
|
||||||
|
//添加loglevel字段
|
||||||
|
cJSON* loglevel = cJSON_GetObjectItem(monitor_item, "loglevel"); // log_level
|
||||||
|
int tmp_level = -1;
|
||||||
|
// 先尝试读取 loglevel
|
||||||
|
if (loglevel && loglevel->type == cJSON_Number) {
|
||||||
|
tmp_level = loglevel->valueint;
|
||||||
|
}
|
||||||
|
else if (loglevel && loglevel->type == cJSON_String) {
|
||||||
|
tmp_level = atoi(loglevel->valuestring);
|
||||||
|
}
|
||||||
|
// 判断是否合法 (0~3)
|
||||||
|
if (tmp_level >= 0 && tmp_level <= 3) {
|
||||||
|
monitor_data.log_level = tmp_level;
|
||||||
|
}
|
||||||
|
else if (json_data.log_level >= 0 && json_data.log_level <= 3) { // 继承 terminal loglevel
|
||||||
|
monitor_data.log_level = json_data.log_level;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
monitor_data.log_level = 1; // 默认 warn
|
||||||
|
}
|
||||||
|
|
||||||
cJSON* monitor_name = cJSON_GetObjectItem(monitor_item, "name"); // monitor_name
|
cJSON* monitor_name = cJSON_GetObjectItem(monitor_item, "name"); // monitor_name
|
||||||
if (monitor_name && monitor_name->type == cJSON_String)
|
if (monitor_name && monitor_name->type == cJSON_String)
|
||||||
std::strncpy(monitor_data.monitor_name, monitor_name->valuestring, sizeof(monitor_data.monitor_name) - 1);
|
std::strncpy(monitor_data.monitor_name, monitor_name->valuestring, sizeof(monitor_data.monitor_name) - 1);
|
||||||
@@ -1723,10 +1842,492 @@ int parse_control(const std::string& json_str, const std::string& output_dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 释放 JSON 对象
|
// 释放 JSON 对象
|
||||||
|
cJSON_Delete(messageBody);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//处理文件请求
|
||||||
|
static int ParseFileDirReq(const char *body, file_dir_req_t *req)
|
||||||
|
{
|
||||||
|
if (body == NULL || req == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cJSON *root = cJSON_Parse(body);
|
||||||
|
if (root == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cJSON *guid = cJSON_GetObjectItem(root, "guid");
|
||||||
|
cJSON *frontid = cJSON_GetObjectItem(root, "frontid");
|
||||||
|
cJSON *processNo = cJSON_GetObjectItem(root, "ProcessNo");
|
||||||
|
cJSON *devid = cJSON_GetObjectItem(root, "devid");
|
||||||
|
cJSON *type = cJSON_GetObjectItem(root, "type");
|
||||||
|
cJSON *path = cJSON_GetObjectItem(root, "Path");
|
||||||
|
|
||||||
|
if (!guid || guid->type != cJSON_String ||
|
||||||
|
!frontid || frontid->type != cJSON_String ||
|
||||||
|
!processNo || processNo->type != cJSON_Number ||
|
||||||
|
!devid || devid->type != cJSON_String ||
|
||||||
|
!type || type->type != cJSON_Number ||
|
||||||
|
!path || path->type != cJSON_String)
|
||||||
|
{
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(req, 0, sizeof(file_dir_req_t));
|
||||||
|
snprintf(req->guid, sizeof(req->guid), "%s", guid->valuestring);
|
||||||
|
snprintf(req->frontid, sizeof(req->frontid), "%s", frontid->valuestring);
|
||||||
|
req->processNo = processNo->valueint;
|
||||||
|
snprintf(req->devid, sizeof(req->devid), "%s", devid->valuestring);
|
||||||
|
req->type = type->valueint;
|
||||||
|
snprintf(req->path, sizeof(req->path), "%s", path->valuestring);
|
||||||
|
req->create_time = time(NULL);
|
||||||
|
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PushFileDirReq(const file_dir_req_t *req)
|
||||||
|
{
|
||||||
|
if (req == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
file_dir_req_t *node = new file_dir_req_t;
|
||||||
|
*node = *req;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&g_file_req_mutex);
|
||||||
|
|
||||||
|
g_file_dir_req_list.push_back(node);
|
||||||
|
pthread_mutex_unlock(&g_file_req_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static file_dir_req_t* PopMatchedFileDirReq(const char *terminal_id)
|
||||||
|
{
|
||||||
|
if (terminal_id == NULL || terminal_id[0] == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
file_dir_req_t *match = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&g_file_req_mutex);
|
||||||
|
|
||||||
|
for (std::list<file_dir_req_t*>::iterator it = g_file_dir_req_list.begin();
|
||||||
|
it != g_file_dir_req_list.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
file_dir_req_t *node = *it;
|
||||||
|
if (node != NULL && strcmp(node->devid, terminal_id) == 0)
|
||||||
|
{
|
||||||
|
match = node;
|
||||||
|
g_file_dir_req_list.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_file_req_mutex);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BuildFileDirRespJsonEx(const file_dir_req_t *req,
|
||||||
|
char **names,
|
||||||
|
const char **itemTypes,
|
||||||
|
int *itemSizes,
|
||||||
|
int itemNum,
|
||||||
|
int result)
|
||||||
|
{
|
||||||
|
cJSON *root = cJSON_CreateObject();
|
||||||
|
cJSON *dirInfo = cJSON_CreateArray();
|
||||||
|
|
||||||
|
cJSON_AddStringToObject(root, "guid", req ? req->guid : "");
|
||||||
|
cJSON_AddStringToObject(root, "frontid", req ? req->frontid : "");
|
||||||
|
cJSON_AddNumberToObject(root, "processNo", req ? req->processNo : 0);
|
||||||
|
cJSON_AddStringToObject(root, "devid", req ? req->devid : "");
|
||||||
|
cJSON_AddNumberToObject(root, "type", req ? req->type : 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < itemNum; ++i)
|
||||||
|
{
|
||||||
|
cJSON *item = cJSON_CreateObject();
|
||||||
|
cJSON_AddStringToObject(item, "name", (names && names[i]) ? names[i] : "");
|
||||||
|
cJSON_AddStringToObject(item, "type", (itemTypes && itemTypes[i]) ? itemTypes[i] : "file");
|
||||||
|
cJSON_AddNumberToObject(item, "size", (itemSizes ? itemSizes[i] : 1));
|
||||||
|
cJSON_AddItemToArray(dirInfo, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_AddItemToObject(root, "dirInfo", dirInfo);
|
||||||
|
cJSON_AddNumberToObject(root, "result", result);
|
||||||
|
|
||||||
|
char *json = cJSON_PrintUnformatted(root);
|
||||||
|
std::string jsonStr = json ? json : "";
|
||||||
|
|
||||||
|
if (json) free(json);
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return jsonStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BuildFileDirRespJson(const file_dir_req_t *req,
|
||||||
|
char **filenames,
|
||||||
|
int filenum,
|
||||||
|
int result)
|
||||||
|
{
|
||||||
|
if (filenum <= 0)
|
||||||
|
return BuildFileDirRespJsonEx(req, NULL, NULL, NULL, 0, result);
|
||||||
|
|
||||||
|
const char **types = new const char*[filenum];
|
||||||
|
int *sizes = new int[filenum];
|
||||||
|
|
||||||
|
for (int i = 0; i < filenum; ++i)
|
||||||
|
{
|
||||||
|
types[i] = "dir";
|
||||||
|
sizes[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string jsonStr = BuildFileDirRespJsonEx(req, filenames, types, sizes, filenum, result);
|
||||||
|
|
||||||
|
delete [] types;
|
||||||
|
delete [] sizes;
|
||||||
|
return jsonStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BuildSingleFileRespJson(const file_dir_req_t *req,
|
||||||
|
const char *name,
|
||||||
|
const char *itemType,
|
||||||
|
int size,
|
||||||
|
int result)
|
||||||
|
{
|
||||||
|
char *names[1];
|
||||||
|
const char *types[1];
|
||||||
|
int sizes[1];
|
||||||
|
|
||||||
|
if (name == NULL || result != 0)
|
||||||
|
{
|
||||||
|
return BuildFileDirRespJsonEx(req, NULL, NULL, NULL, 0, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
names[0] = (char *)name;
|
||||||
|
types[0] = (itemType ? itemType : "file");
|
||||||
|
sizes[0] = size;
|
||||||
|
|
||||||
|
return BuildFileDirRespJsonEx(req, names, types, sizes, 1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////下载
|
||||||
|
static const char* GetFileNameOnly(const char* fullpath)
|
||||||
|
{
|
||||||
|
if (fullpath == NULL)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
const char* p1 = strrchr(fullpath, '/');
|
||||||
|
const char* p2 = strrchr(fullpath, '\\');
|
||||||
|
const char* p = p1 > p2 ? p1 : p2;
|
||||||
|
|
||||||
|
return (p ? p + 1 : fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int MakeDirRecursive(const char* dirPath)
|
||||||
|
{
|
||||||
|
if (dirPath == NULL || dirPath[0] == '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char tmp[512] = {0};
|
||||||
|
snprintf(tmp, sizeof(tmp), "%s", dirPath);
|
||||||
|
|
||||||
|
int len = strlen(tmp);
|
||||||
|
if (len <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* 去掉末尾 '/' */
|
||||||
|
if (tmp[len - 1] == '/')
|
||||||
|
tmp[len - 1] = '\0';
|
||||||
|
|
||||||
|
for (char* p = tmp + 1; *p; ++p)
|
||||||
|
{
|
||||||
|
if (*p == '/')
|
||||||
|
{
|
||||||
|
*p = '\0';
|
||||||
|
if (access(tmp, F_OK) != 0)
|
||||||
|
{
|
||||||
|
if (mkdir(tmp, 0777) != 0 && errno != EEXIST)
|
||||||
|
{
|
||||||
|
printf("mkdir failed: %s, err=%s\n", tmp, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(tmp, F_OK) != 0)
|
||||||
|
{
|
||||||
|
if (mkdir(tmp, 0777) != 0 && errno != EEXIST)
|
||||||
|
{
|
||||||
|
printf("mkdir failed: %s, err=%s\n", tmp, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SafePathName(const char* src, char* dst, size_t dstSize)
|
||||||
|
{
|
||||||
|
if (dst == NULL || dstSize == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dst[0] = '\0';
|
||||||
|
|
||||||
|
if (src == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t j = 0;
|
||||||
|
for (size_t i = 0; src[i] != '\0' && j + 1 < dstSize; ++i)
|
||||||
|
{
|
||||||
|
char c = src[i];
|
||||||
|
if ((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
|
c == '.' || c == '_' || c == '-')
|
||||||
|
{
|
||||||
|
dst[j++] = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst[j++] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int BuildTempLocalPath(char* outPath,
|
||||||
|
size_t outSize,
|
||||||
|
chnl_usr_t* chnl_usr,
|
||||||
|
const char* remotePath)
|
||||||
|
{
|
||||||
|
if (outPath == NULL || outSize == 0 || chnl_usr == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const char* fileName = GetFileNameOnly(remotePath);
|
||||||
|
if (fileName == NULL || fileName[0] == '\0')
|
||||||
|
fileName = "tmp_file.dat";
|
||||||
|
|
||||||
|
const char* ipStr = chnl_usr->ip_str;
|
||||||
|
if (ipStr == NULL || ipStr[0] == '\0')
|
||||||
|
ipStr = "unknown_ip";
|
||||||
|
|
||||||
|
char safeIp[128] = {0};
|
||||||
|
SafePathName(ipStr, safeIp, sizeof(safeIp));
|
||||||
|
|
||||||
|
char dirPath[512] = {0};
|
||||||
|
snprintf(dirPath, sizeof(dirPath), "/tmp/%s", safeIp);
|
||||||
|
|
||||||
|
/* 目录不存在则创建 */
|
||||||
|
if (MakeDirRecursive(dirPath) != 0)
|
||||||
|
{
|
||||||
|
printf("BuildTempLocalPath mkdir failed: %s\n", dirPath);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(outPath, outSize, "%s/%s", dirPath, fileName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HandleTypeDownloadAndUpload(chnl_usr_t* chnl_usr,
|
||||||
|
file_dir_req_t* req,
|
||||||
|
std::string& jsonString)
|
||||||
|
{
|
||||||
|
if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char localpath[512] = {0};
|
||||||
|
if (BuildTempLocalPath(localpath, sizeof(localpath), chnl_usr, req->path) != 0)
|
||||||
|
{
|
||||||
|
DIY_ERRORLOG_CODE("process", LOG_CODE_TRANSIENT_COMM,
|
||||||
|
"【ERROR】构造本地临时路径失败 devid=%s path=%s",
|
||||||
|
req->devid, req->path);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ST_RET ret = mms_getFile(chnl_usr->net_info,
|
||||||
|
(ST_CHAR*)localpath,
|
||||||
|
(ST_CHAR*)req->path,
|
||||||
|
3 * g_pt61850app->mmsOpTimeout);
|
||||||
|
|
||||||
|
if (ret != SD_SUCCESS)
|
||||||
|
{
|
||||||
|
DIY_ERRORLOG_CODE("process", LOG_CODE_TRANSIENT_COMM,
|
||||||
|
"【ERROR】装置文件下载失败 devid=%s, rem=%s, ret=0x%X",
|
||||||
|
req->devid, req->path, ret);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】装置文件下载成功 devid=%s, rem=%s, local=%s",
|
||||||
|
req->devid, req->path, localpath);
|
||||||
|
|
||||||
|
char wavepath[512] = {0};
|
||||||
|
SendFileWeb(WEB_FILEUPLOAD, localpath, req->path, wavepath);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req,
|
||||||
|
(wavepath[0] != 0 ? wavepath : req->path),
|
||||||
|
"file",
|
||||||
|
1,
|
||||||
|
0);
|
||||||
|
remove(localpath);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////传输
|
||||||
|
static int HandleTypeTransferToDevice(chnl_usr_t* chnl_usr,
|
||||||
|
file_dir_req_t* req,
|
||||||
|
std::string& jsonString)
|
||||||
|
{
|
||||||
|
if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char localpath[512] = {0};
|
||||||
|
if (BuildTempLocalPath(localpath, sizeof(localpath), chnl_usr, req->path) != 0)
|
||||||
|
{
|
||||||
|
DIY_ERRORLOG_CODE("process", LOG_CODE_TRANSIENT_COMM,
|
||||||
|
"【ERROR】构造本地临时路径失败 devid=%s path=%s",
|
||||||
|
req->devid, req->path);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dlRet = DownloadFileWeb(WEB_FILEDOWNLOAD, req->path, localpath);
|
||||||
|
if (dlRet != 0)
|
||||||
|
{
|
||||||
|
DIY_ERRORLOG_CODE("process", LOG_CODE_TRANSIENT_COMM,
|
||||||
|
"【ERROR】Web 文件下载失败 devid=%s, path=%s",
|
||||||
|
req->devid, req->path);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】Web 文件下载成功 devid=%s, webpath=%s, local=%s",
|
||||||
|
req->devid, req->path, localpath);
|
||||||
|
|
||||||
|
char destfilename[512] = {0};
|
||||||
|
const char* fileName = GetFileNameOnly(req->path);
|
||||||
|
snprintf(destfilename, sizeof(destfilename), "/etc/%s",
|
||||||
|
(fileName && fileName[0]) ? fileName : "tmp_file.dat");
|
||||||
|
|
||||||
|
ST_RET ret = mms_mvla_obtfile(chnl_usr->net_info,
|
||||||
|
(ST_CHAR*)localpath,
|
||||||
|
(ST_CHAR*)destfilename,
|
||||||
|
3 * g_pt61850app->mmsOpTimeout);
|
||||||
|
|
||||||
|
if (ret != SD_SUCCESS)
|
||||||
|
{
|
||||||
|
DIY_ERRORLOG_CODE("process", LOG_CODE_TRANSIENT_COMM,
|
||||||
|
"【ERROR】文件传送到装置失败 devid=%s, src=%s, dest=%s, ret=0x%X",
|
||||||
|
req->devid, localpath, destfilename, ret);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】文件传送到装置成功 devid=%s, src=%s, dest=%s",
|
||||||
|
req->devid, localpath, destfilename);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req,
|
||||||
|
destfilename,
|
||||||
|
"file",
|
||||||
|
1,
|
||||||
|
0);
|
||||||
|
|
||||||
|
remove(localpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr)
|
||||||
|
{
|
||||||
|
if (chnl_usr == NULL || chnl_usr->chnl == NULL || chnl_usr->chnl->ied == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ied_t *ied = chnl_usr->chnl->ied;
|
||||||
|
ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied);
|
||||||
|
if (ied_usr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ied_usr->terminal_id[0] == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
file_dir_req_t *req = PopMatchedFileDirReq(ied_usr->terminal_id);
|
||||||
|
if (req == NULL)
|
||||||
|
return; // 当前连接没有文件请求
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】处理文件请求 terminal_id=%s type=%d path=%s",
|
||||||
|
req->devid, req->type, req->path);
|
||||||
|
|
||||||
|
std::string jsonString;
|
||||||
|
int handleRet = -1;
|
||||||
|
|
||||||
|
if (req->type == 0)
|
||||||
|
{
|
||||||
|
/* 目录查询 */
|
||||||
|
char **filenames = NULL;
|
||||||
|
int filenum = 0;
|
||||||
|
|
||||||
|
ST_RET ret = mms_mvla_fdir(chnl_usr->net_info,
|
||||||
|
(ST_CHAR*)req->path,
|
||||||
|
3 * g_pt61850app->mmsOpTimeout,
|
||||||
|
&filenames,
|
||||||
|
&filenum,
|
||||||
|
g_pt61850app->tmp_pool);
|
||||||
|
|
||||||
|
jsonString = BuildFileDirRespJson(req,
|
||||||
|
filenames,
|
||||||
|
filenum,
|
||||||
|
(ret == SD_SUCCESS) ? 0 : ret);
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】目录请求处理完成 terminal_id=%s ret=0x%X filenum=%d",
|
||||||
|
req->devid, ret, filenum);
|
||||||
|
|
||||||
|
handleRet = (ret == SD_SUCCESS) ? 0 : -1;
|
||||||
|
}
|
||||||
|
else if (req->type == 1)
|
||||||
|
{
|
||||||
|
/* 装置下载到本地,再上传 Web */
|
||||||
|
handleRet = HandleTypeDownloadAndUpload(chnl_usr, req, jsonString);
|
||||||
|
}
|
||||||
|
else if (req->type == 2)
|
||||||
|
{
|
||||||
|
/* Web 下载到本地,再传送到装置 /etc */
|
||||||
|
handleRet = HandleTypeTransferToDevice(chnl_usr, req, jsonString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DIY_WARNLOG("process",
|
||||||
|
"【WARN】未知文件请求类型 type=%d devid=%s path=%s",
|
||||||
|
req->type, req->devid, req->path);
|
||||||
|
|
||||||
|
jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, 1);//1是失败
|
||||||
|
handleRet = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统一回 Kafka */
|
||||||
|
Ckafka_data_t dir_info;
|
||||||
|
dir_info.strTopic = QString::fromStdString(Topic_Reply_Topic);
|
||||||
|
dir_info.strText = QString::fromStdString(jsonString);
|
||||||
|
|
||||||
|
kafka_data_list_mutex.lock();
|
||||||
|
kafka_data_list.append(dir_info);
|
||||||
|
kafka_data_list_mutex.unlock();
|
||||||
|
|
||||||
|
delete req;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -1998,6 +2599,44 @@ int myMessageCallbackrecall(CPushConsumer* consumer, CMessageExt* msg)
|
|||||||
return E_CONSUME_SUCCESS;
|
return E_CONSUME_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int myMessageCallbackfile(CPushConsumer* consumer, CMessageExt* msg)
|
||||||
|
{
|
||||||
|
if (INITFLAG != 1) return 1;
|
||||||
|
|
||||||
|
if (msg == NULL) {
|
||||||
|
std::cerr << "Received null message." << std::endl;
|
||||||
|
return E_RECONSUME_LATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* body = GetMessageBody(msg);
|
||||||
|
const char* key = GetMessageKeys(msg);
|
||||||
|
|
||||||
|
if (body == NULL) {
|
||||||
|
std::cerr << "Message body is NULL." << std::endl;
|
||||||
|
return E_RECONSUME_LATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIY_INFOLOG("process","【NORMAL】前置消费topic:%s_%s的文件控制消息",
|
||||||
|
FRONT_INST.c_str(), G_MQCONSUMER_TOPIC_FILE.c_str());
|
||||||
|
|
||||||
|
std::cout << "file Callback received message: " << body << std::endl;
|
||||||
|
std::cout << "Message Key: " << (key ? key : "N/A") << std::endl;
|
||||||
|
|
||||||
|
file_dir_req_t req;
|
||||||
|
if (ParseFileDirReq(body, &req) != 0)
|
||||||
|
{
|
||||||
|
DIY_WARNLOG("process", "【WARN】文件控制消息解析失败: %s", body);
|
||||||
|
return E_CONSUME_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushFileDirReq(&req);
|
||||||
|
|
||||||
|
DIY_INFOLOG("process",
|
||||||
|
"【NORMAL】文件目录请求已入队 guid=%s devid=%s path=%s",
|
||||||
|
req.guid, req.devid, req.path);
|
||||||
|
|
||||||
|
return E_CONSUME_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void mqconsumerThread::run()
|
void mqconsumerThread::run()
|
||||||
{
|
{
|
||||||
@@ -2010,6 +2649,9 @@ void mqconsumerThread::run()
|
|||||||
std::vector<Subscription> subscriptions;
|
std::vector<Subscription> subscriptions;
|
||||||
// 初始化消费者1 //lnk20241230只有实时进程会订阅实时topic,不订阅实时topic的进程无法触发实时数据
|
// 初始化消费者1 //lnk20241230只有实时进程会订阅实时topic,不订阅实时topic的进程无法触发实时数据
|
||||||
if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID){
|
if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID){
|
||||||
|
|
||||||
|
//lnk20260310添加文件管理
|
||||||
|
subscriptions.push_back(Subscription(std::string(FRONT_INST) + "_" + G_MQCONSUMER_TOPIC_FILE, G_MQCONSUMER_TAG_FILE, myMessageCallbackfile));
|
||||||
subscriptions.push_back(Subscription(std::string(FRONT_INST) + "_" + G_MQCONSUMER_TOPIC_RT, G_MQCONSUMER_TAG_RT, myMessageCallbackrtdata));
|
subscriptions.push_back(Subscription(std::string(FRONT_INST) + "_" + G_MQCONSUMER_TOPIC_RT, G_MQCONSUMER_TAG_RT, myMessageCallbackrtdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -670,6 +670,8 @@ struct monitor // 监测点台账
|
|||||||
char timestamp[64];
|
char timestamp[64];
|
||||||
char status[255];
|
char status[255];
|
||||||
|
|
||||||
|
int log_level;//日志级别,0:ERROR,1:WARN,2:NORMAL,3:DEBUG
|
||||||
|
|
||||||
};
|
};
|
||||||
struct terminal // 终端台账
|
struct terminal // 终端台账
|
||||||
{
|
{
|
||||||
@@ -692,6 +694,7 @@ struct terminal // 终端台账
|
|||||||
char timestamp[64];
|
char timestamp[64];
|
||||||
monitor line[10]; // 最多 10 个监测点
|
monitor line[10]; // 最多 10 个监测点
|
||||||
|
|
||||||
|
int log_level;//日志级别,0:ERROR,1:WARN,2:NORMAL,3:DEBUG
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -24,12 +24,9 @@
|
|||||||
|
|
||||||
#include "appender.h"
|
#include "appender.h"
|
||||||
|
|
||||||
#define LOGTYPE_COM 1
|
|
||||||
#define LOGTYPE_DATA 2
|
|
||||||
|
|
||||||
struct TypedLogger {
|
struct TypedLogger {
|
||||||
log4cplus::Logger logger;
|
log4cplus::Logger logger;
|
||||||
int logtype;
|
int code;
|
||||||
TypedLogger();
|
TypedLogger();
|
||||||
TypedLogger(const log4cplus::Logger& l, int t);
|
TypedLogger(const log4cplus::Logger& l, int t);
|
||||||
};
|
};
|
||||||
@@ -47,7 +44,7 @@ struct DebugSwitch {
|
|||||||
void set_level(int level);
|
void set_level(int level);
|
||||||
void enable_type(int type);
|
void enable_type(int type);
|
||||||
void disable_type(int type);
|
void disable_type(int type);
|
||||||
bool match(const std::string& logger_name, int level, int logtype);
|
bool match(const std::string& logger_name, int level, int code);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::map<std::string, TypedLogger> logger_map;
|
extern std::map<std::string, TypedLogger> logger_map;
|
||||||
@@ -71,11 +68,14 @@ log4cplus::Logger init_logger(const std::string& full_name,
|
|||||||
const std::string& base_file,
|
const std::string& base_file,
|
||||||
log4cplus::SharedAppenderPtr fileAppender);
|
log4cplus::SharedAppenderPtr fileAppender);
|
||||||
|
|
||||||
void process_log_command(const std::string& id, const std::string& level, const std::string& grade, const std::string& logtype_str);
|
void process_log_command(const std::string& id, const std::string& level, const std::string& grade, int code);
|
||||||
|
|
||||||
|
|
||||||
void update_log_entries_countdown();
|
void update_log_entries_countdown();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////lnk20260306数据追踪
|
||||||
|
void process_trace_command(const std::string& id, int times);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void remove_loggers_by_terminal_id(const char* terminal_id_cstr);
|
void remove_loggers_by_terminal_id(const char* terminal_id_cstr);
|
||||||
@@ -89,7 +89,7 @@ void log_warn(const char* key, const char* msg);
|
|||||||
void log_error(const char* key, const char* msg);
|
void log_error(const char* key, const char* msg);
|
||||||
|
|
||||||
void send_reply_to_kafka_c(const char* guid, const char* step, const char* result);
|
void send_reply_to_kafka_c(const char* guid, const char* step, const char* result);
|
||||||
void send_reply_to_kafka_recall(const char* guid, const char* step, const char* result,const char* lineIndex,const char* recallStartDate,const char* recallEndDate);
|
void send_reply_to_kafka_recall_c(const char* guid, const char* step, const char* result,const char* lineIndex,const char* recallStartDate,const char* recallEndDate);
|
||||||
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...);
|
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...);
|
||||||
|
|
||||||
// ====================== ★新增:线程局部变量透传 code ======================
|
// ====================== ★新增:线程局部变量透传 code ======================
|
||||||
|
|||||||
@@ -45,10 +45,10 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
extern char* OSS_ENDPOINT;
|
//extern char* OSS_ENDPOINT;
|
||||||
extern char* ACCESS_KEY_ID;
|
//extern char* ACCESS_KEY_ID;
|
||||||
extern char* ACCESS_KEY_SECRET;
|
//extern char* ACCESS_KEY_SECRET;
|
||||||
extern char* BUCKET_NAME;
|
//extern char* BUCKET_NAME;
|
||||||
|
|
||||||
extern char* POSTGRES_SCHEMA;
|
extern char* POSTGRES_SCHEMA;
|
||||||
extern char* POSTGRES_TABLEPREFIX;
|
extern char* POSTGRES_TABLEPREFIX;
|
||||||
@@ -105,16 +105,16 @@ void TestToken();
|
|||||||
void TestBodyPost();//WW 测试qt post
|
void TestBodyPost();//WW 测试qt post
|
||||||
void TestSMSPost();//WW 测试qt post
|
void TestSMSPost();//WW 测试qt post
|
||||||
void TestJson(char* szJson);
|
void TestJson(char* szJson);
|
||||||
void TestOSS();//WW 测试
|
//void TestOSS();//WW 测试
|
||||||
void PutOSS(char* File_Name, char* data); //zw修改 2023-9-7 上送oss文件
|
//void PutOSS(char* File_Name, char* data); //zw修改 2023-9-7 上送oss文件
|
||||||
void GetOSS(char* File_Name, char* savepath); //zw修改 2023-9-7 获取oss文件
|
//void GetOSS(char* File_Name, char* savepath); //zw修改 2023-9-7 获取oss文件
|
||||||
void DelOSS(char* File_Name);
|
//void DelOSS(char* File_Name);
|
||||||
void delete_object_new(char* File_Name);
|
void delete_object_new(char* File_Name);
|
||||||
void coutTest();//CZY 2023-09-11 test
|
void coutTest();//CZY 2023-09-11 test
|
||||||
void TestOBS();//WW 20230921 测试华为云服务器
|
//void TestOBS();//WW 20230921 测试华为云服务器
|
||||||
void OBSFile(char* localpath, char* cloudpath,const char* code);
|
//void OBSFile(char* localpath, char* cloudpath,const char* code);
|
||||||
void OBSFile_del(char* cloudpath, const char* code);
|
//void OBSFile_del(char* cloudpath, const char* code);
|
||||||
void DataHub_Send_Datahub(char* topic, char* data);//datahub通讯
|
//void DataHub_Send_Datahub(char* topic, char* data);//datahub通讯
|
||||||
void Nacos_GetParam(char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret);//nacos
|
void Nacos_GetParam(char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret);//nacos
|
||||||
void Nacos_GetParam_Ptr(const char* code, char** ptr);
|
void Nacos_GetParam_Ptr(const char* code, char** ptr);
|
||||||
void Read_Nacos_Param_Postgres(char** database_ip, char** database_port, char** postgres_database, char** postgres_username, char** postgres_password, char** postgres_schema, char** postgres_dnsname, char** postgres_tableprefix);
|
void Read_Nacos_Param_Postgres(char** database_ip, char** database_port, char** postgres_database, char** postgres_username, char** postgres_password, char** postgres_schema, char** postgres_dnsname, char** postgres_tableprefix);
|
||||||
@@ -171,6 +171,21 @@ typedef struct {
|
|||||||
|
|
||||||
bool get_xml_config_by_dev_type(const char* dev_type, XmlConfigC* out_cfg);
|
bool get_xml_config_by_dev_type(const char* dev_type, XmlConfigC* out_cfg);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////文件控制请求参数
|
||||||
|
typedef struct file_dir_req_t
|
||||||
|
{
|
||||||
|
struct file_dir_req_t *next;
|
||||||
|
struct file_dir_req_t *prev;
|
||||||
|
|
||||||
|
char guid[128];
|
||||||
|
char frontid[128];
|
||||||
|
int processNo;
|
||||||
|
char devid[128];
|
||||||
|
int type;
|
||||||
|
char path[256];
|
||||||
|
time_t create_time;
|
||||||
|
} file_dir_req_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ extern apr_pool_t* g_init_pool;
|
|||||||
extern int g_DevFlag; //日志配置中读取的参数,暂无特定使用lnk20250121
|
extern int g_DevFlag; //日志配置中读取的参数,暂无特定使用lnk20250121
|
||||||
|
|
||||||
extern int IED_COUNT;
|
extern int IED_COUNT;
|
||||||
|
extern int RECALL_ONLY_FLAG; //lnk20260309添加一个全局变量,标志是否只运行补招程序
|
||||||
|
|
||||||
//lnk20250115end
|
//lnk20250115end
|
||||||
|
|
||||||
@@ -1328,6 +1329,7 @@ void print_monitor(const monitor* mon) {
|
|||||||
printf("Terminal Connect: %s\n", is_empty(mon->terminal_connect) ? "N/A" : mon->terminal_connect);
|
printf("Terminal Connect: %s\n", is_empty(mon->terminal_connect) ? "N/A" : mon->terminal_connect);
|
||||||
printf("Timestamp: %s\n", is_empty(mon->timestamp) ? "N/A" : mon->timestamp);
|
printf("Timestamp: %s\n", is_empty(mon->timestamp) ? "N/A" : mon->timestamp);
|
||||||
printf("Status: %s\n", is_empty(mon->status) ? "N/A" : mon->status);
|
printf("Status: %s\n", is_empty(mon->status) ? "N/A" : mon->status);
|
||||||
|
printf("Log Level: %d\n", mon->log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打印 terminal 结构体信息
|
// 打印 terminal 结构体信息
|
||||||
@@ -1346,6 +1348,7 @@ void print_terminal(const terminal* tmnl) {
|
|||||||
printf("Address: %s\n", is_empty(tmnl->addr_str) ? "N/A" : tmnl->addr_str);
|
printf("Address: %s\n", is_empty(tmnl->addr_str) ? "N/A" : tmnl->addr_str);
|
||||||
printf("Port: %s\n", is_empty(tmnl->port) ? "N/A" : tmnl->port);
|
printf("Port: %s\n", is_empty(tmnl->port) ? "N/A" : tmnl->port);
|
||||||
printf("Timestamp: %s\n", is_empty(tmnl->timestamp) ? "N/A" : tmnl->timestamp);
|
printf("Timestamp: %s\n", is_empty(tmnl->timestamp) ? "N/A" : tmnl->timestamp);
|
||||||
|
printf("Log Level: %d\n", tmnl->log_level);
|
||||||
|
|
||||||
// 打印监测点信息,如果监测点字段为空,则打印 N/A
|
// 打印监测点信息,如果监测点字段为空,则打印 N/A
|
||||||
int i;
|
int i;
|
||||||
@@ -1416,11 +1419,14 @@ void check_ledger_update()//lnk20250113
|
|||||||
//调试用
|
//调试用
|
||||||
print_trigger_update_xml(trigger_ledger_update_xml);
|
print_trigger_update_xml(trigger_ledger_update_xml);
|
||||||
|
|
||||||
//处理台账更新加台账锁lnk20250114
|
//处理台账更新添加控制标志
|
||||||
//pthread_mutex_lock(&mtx); printf("ledgerupdate hold lock !!!!!!!!!!!");
|
if (RECALL_ONLY_FLAG != 1 || (g_node_id != STAT_DATA_BASE_NODE_ID)) {
|
||||||
process_ledger_update(trigger_ledger_update_xml); //台账更新
|
process_ledger_update(trigger_ledger_update_xml); //台账更新
|
||||||
//pthread_mutex_unlock(&mtx); printf("ledgerupdate free lock !!!!!!!!!!!");
|
}
|
||||||
|
else{
|
||||||
|
printf("only process recall config, skip ledger update\n");
|
||||||
|
DIY_WARNLOG_CODE("process",LOG_CODE_SPACE_ALARM,"【WARN】当前配置为仅日志模式,统计数据进程跳过台账更新");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用完后释放动态分配的内存
|
// 使用完后释放动态分配的内存
|
||||||
@@ -1545,6 +1551,9 @@ void CheckAllConnectedChannel()
|
|||||||
|
|
||||||
if(chnl_usr->m_state == CHANNEL_CONNECTED)
|
if(chnl_usr->m_state == CHANNEL_CONNECTED)
|
||||||
{
|
{
|
||||||
|
if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {
|
||||||
|
HandleFileDirReqForChannel(chnl_usr);//文件目录请求
|
||||||
|
}
|
||||||
|
|
||||||
ChannelCheckIECReports(chnl_usr);//报告
|
ChannelCheckIECReports(chnl_usr);//报告
|
||||||
if ( (g_node_id == SOE_COMTRADE_BASE_NODE_ID) || (g_node_id == HIS_DATA_BASE_NODE_ID) || (g_node_id == NEW_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID))
|
if ( (g_node_id == SOE_COMTRADE_BASE_NODE_ID) || (g_node_id == HIS_DATA_BASE_NODE_ID) || (g_node_id == NEW_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID))
|
||||||
@@ -2091,13 +2100,13 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info )
|
|||||||
memset(oss_file_fullname_cfg, 0, sizeof(oss_file_fullname_cfg));
|
memset(oss_file_fullname_cfg, 0, sizeof(oss_file_fullname_cfg));
|
||||||
apr_snprintf(oss_file_fullname_cfg, sizeof(oss_file_fullname_cfg), "comtrade/wave/%s/%s", LD_info->mp_id, cfg_only_filename_ret);
|
apr_snprintf(oss_file_fullname_cfg, sizeof(oss_file_fullname_cfg), "comtrade/wave/%s/%s", LD_info->mp_id, cfg_only_filename_ret);
|
||||||
if (FILE_FLAG == 1) {
|
if (FILE_FLAG == 1) {
|
||||||
PutOSS(oss_file_fullname_cfg, loc_file_fullname_cfg);//使用buffer推送文件
|
//PutOSS(oss_file_fullname_cfg, loc_file_fullname_cfg);//使用buffer推送文件
|
||||||
}
|
}
|
||||||
else if (FILE_FLAG == 2) {
|
else if (FILE_FLAG == 2) {
|
||||||
OBSFile(loc_file_fullname_cfg, oss_file_fullname_cfg, "putObject");//这里并没有上传文件流
|
//OBSFile(loc_file_fullname_cfg, oss_file_fullname_cfg, "putObject");//这里并没有上传文件流
|
||||||
}
|
}
|
||||||
else if(FILE_FLAG==3){
|
else if(FILE_FLAG==3){
|
||||||
WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_cfg, uuid_cfg, filename_cfg);//通过form-data上传文件
|
//WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_cfg, uuid_cfg, filename_cfg);//通过form-data上传文件
|
||||||
}
|
}
|
||||||
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
||||||
else if (FILE_FLAG == 4) {
|
else if (FILE_FLAG == 4) {
|
||||||
@@ -2129,13 +2138,13 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info )
|
|||||||
memset(oss_file_fullname_dat, 0, sizeof(oss_file_fullname_dat));
|
memset(oss_file_fullname_dat, 0, sizeof(oss_file_fullname_dat));
|
||||||
apr_snprintf(oss_file_fullname_dat, sizeof(oss_file_fullname_dat), "comtrade/wave/%s/%s", LD_info->mp_id, dat_only_filename_ret);
|
apr_snprintf(oss_file_fullname_dat, sizeof(oss_file_fullname_dat), "comtrade/wave/%s/%s", LD_info->mp_id, dat_only_filename_ret);
|
||||||
if (FILE_FLAG == 1) {
|
if (FILE_FLAG == 1) {
|
||||||
PutOSS(oss_file_fullname_dat, loc_file_fullname_dat);//使用buffer推送文件
|
//PutOSS(oss_file_fullname_dat, loc_file_fullname_dat);//使用buffer推送文件
|
||||||
}
|
}
|
||||||
else if (FILE_FLAG == 2) {
|
else if (FILE_FLAG == 2) {
|
||||||
OBSFile(loc_file_fullname_dat, oss_file_fullname_dat, "putObject");//这里并没有上传文件流
|
//OBSFile(loc_file_fullname_dat, oss_file_fullname_dat, "putObject");//这里并没有上传文件流
|
||||||
}
|
}
|
||||||
else if(FILE_FLAG==3){
|
else if(FILE_FLAG==3){
|
||||||
WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_dat, uuid_dat, filename_dat);//通过form-data上传文件
|
//WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_dat, uuid_dat, filename_dat);//通过form-data上传文件
|
||||||
}
|
}
|
||||||
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
||||||
else if (FILE_FLAG == 4) {
|
else if (FILE_FLAG == 4) {
|
||||||
|
|||||||
@@ -1457,6 +1457,29 @@ ST_VOID u_mvl_ident_ind (MVL_IND_PEND *indCtrl)
|
|||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* getFile */
|
/* getFile */
|
||||||
|
/*
|
||||||
|
先向远端发 fopen,打开远程文件
|
||||||
|
|
||||||
|
拿到这个远程文件会话句柄 frsmid
|
||||||
|
|
||||||
|
循环发 fread,一块一块把远程文件内容读回来并写入本地文件
|
||||||
|
|
||||||
|
最后发 fclose,关闭远程文件
|
||||||
|
|
||||||
|
clientNetInfo:客户端和 MMS 服务器之间的网络连接信息
|
||||||
|
|
||||||
|
loc_file:本地保存的文件路径
|
||||||
|
|
||||||
|
rem_file:远端设备上的文件路径
|
||||||
|
|
||||||
|
iTimeout:每次请求等待响应的超时时间
|
||||||
|
|
||||||
|
返回值:
|
||||||
|
|
||||||
|
SD_SUCCESS:下载成功
|
||||||
|
|
||||||
|
其他:失败错误码
|
||||||
|
*/
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
ST_RET mms_getFile (MVL_NET_INFO *clientNetInfo, ST_CHAR *loc_file,
|
ST_RET mms_getFile (MVL_NET_INFO *clientNetInfo, ST_CHAR *loc_file,
|
||||||
ST_CHAR *rem_file, ST_INT iTimeout)
|
ST_CHAR *rem_file, ST_INT iTimeout)
|
||||||
@@ -1523,6 +1546,59 @@ ERR:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//***************************lnk20260309下发文件到装置*********************/
|
||||||
|
ST_RET mms_putFile(MVL_NET_INFO *clientNetInfo,
|
||||||
|
ST_CHAR *src_file,
|
||||||
|
ST_CHAR *dest_file,
|
||||||
|
ST_INT iTimeout)
|
||||||
|
{
|
||||||
|
MVL_REQ_PEND *reqCtrl = NULL;
|
||||||
|
ST_RET ret = SD_FAILURE;
|
||||||
|
|
||||||
|
if (clientNetInfo == NULL)
|
||||||
|
{
|
||||||
|
printf("\n mms_putFile failed: clientNetInfo is NULL");
|
||||||
|
return SD_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_file == NULL || src_file[0] == '\0')
|
||||||
|
{
|
||||||
|
printf("\n mms_putFile failed: src_file is NULL or empty");
|
||||||
|
return SD_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest_file == NULL || dest_file[0] == '\0')
|
||||||
|
{
|
||||||
|
printf("\n mms_putFile failed: dest_file is NULL or empty");
|
||||||
|
return SD_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mvla_obtfile(clientNetInfo, src_file, dest_file, &reqCtrl);
|
||||||
|
if (ret == SD_SUCCESS)
|
||||||
|
ret = waitReqDone(reqCtrl, iTimeout);
|
||||||
|
|
||||||
|
if (ret != SD_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("\n mms_putFile failed, src='%s', dest='%s', ret=0x%X",
|
||||||
|
src_file, dest_file, ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("\n mms_putFile OK, src='%s', dest='%s'",
|
||||||
|
src_file, dest_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reqCtrl != NULL)
|
||||||
|
{
|
||||||
|
mvl_free_req_ctrl(reqCtrl);
|
||||||
|
reqCtrl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
//************************************************************************/
|
||||||
|
/* putFile */
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* init_mem */
|
/* init_mem */
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ extern int SOCKET_PORT;
|
|||||||
extern int G_TEST_FLAG;
|
extern int G_TEST_FLAG;
|
||||||
extern int g_front_seg_index;
|
extern int g_front_seg_index;
|
||||||
extern int g_front_seg_num;
|
extern int g_front_seg_num;
|
||||||
|
extern int RECALL_ONLY_FLAG; //lnk20260309添加一个全局变量,标志是否只运行补招程序
|
||||||
|
|
||||||
#include "../rocketmq/SimpleProducer.h"
|
#include "../rocketmq/SimpleProducer.h"
|
||||||
#include "../cfg_parse/custom_printf.h"//lnk20250225
|
#include "../cfg_parse/custom_printf.h"//lnk20250225
|
||||||
@@ -187,42 +188,45 @@ apr_status_t init_rdb()
|
|||||||
init_config();
|
init_config();
|
||||||
GetServerIndexFromDB();
|
GetServerIndexFromDB();
|
||||||
|
|
||||||
rv = parse_device_cfg_web();
|
//只有补招运行时,统计不读取台账和模型
|
||||||
if (rv != APR_SUCCESS) {
|
if (RECALL_ONLY_FLAG != 1 || (g_node_id != STAT_DATA_BASE_NODE_ID)) {
|
||||||
echo_errg("Parsed device config xml file with error,try to run! \n");
|
rv = parse_device_cfg_web();
|
||||||
|
if (rv != APR_SUCCESS) {
|
||||||
|
echo_errg("Parsed device config xml file with error,try to run! \n");
|
||||||
|
|
||||||
//char buf[256];
|
//char buf[256];
|
||||||
//format_log_msg(buf,sizeof(buf),"前置的%s%d号进程调用web台账接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
//format_log_msg(buf,sizeof(buf),"前置的%s%d号进程调用web台账接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
||||||
//log_error("process", buf);
|
//log_error("process", buf);
|
||||||
DIY_ERRORLOG_CODE("process",LOG_CODE_LEDGER,"【ERROR】前置的%s%d号进程调用web台账接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
DIY_ERRORLOG_CODE("process",LOG_CODE_LEDGER,"【ERROR】前置的%s%d号进程调用web台账接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
//台账读取过后初始化各级的日志
|
//台账读取过后初始化各级的日志
|
||||||
init_loggers();
|
init_loggers();
|
||||||
|
|
||||||
rv = parse_model_cfg_web();
|
|
||||||
if (rv != APR_SUCCESS) {//不可能
|
|
||||||
echo_errg("Parsed model with error,try to run! \n");
|
|
||||||
|
|
||||||
//char buf[256];
|
rv = parse_model_cfg_web();
|
||||||
//format_log_msg(buf,sizeof(buf),"前置的%s%d号进程调用web模型接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
if (rv != APR_SUCCESS) {//不可能
|
||||||
//log_error("process", buf);
|
echo_errg("Parsed model with error,try to run! \n");
|
||||||
DIY_ERRORLOG_CODE("process",LOG_CODE_ICD_AND_DOWNLOAD,"【ERROR】前置的%s%d号进程调用web模型接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
|
||||||
|
|
||||||
return rv;
|
//char buf[256];
|
||||||
}
|
//format_log_msg(buf,sizeof(buf),"前置的%s%d号进程调用web模型接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
||||||
|
//log_error("process", buf);
|
||||||
|
DIY_ERRORLOG_CODE("process",LOG_CODE_ICD_AND_DOWNLOAD,"【ERROR】前置的%s%d号进程调用web模型接口失败", get_front_msg_from_subdir(), g_front_seg_index);
|
||||||
|
|
||||||
Set_xml_nodeinfo();//解析xml模型
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
rv = parse_rpt_log_ini();//报告块初始化
|
Set_xml_nodeinfo();//解析xml模型
|
||||||
if (rv != APR_SUCCESS) {
|
|
||||||
echo_errg("Failed to parse report log define ini file! \n");
|
|
||||||
|
|
||||||
DIY_ERRORLOG_CODE("process",LOG_CODE_RPTINIT,"【ERROR】前置的%s%d号进程报告初始化失败", get_front_msg_from_subdir(), g_front_seg_index);
|
rv = parse_rpt_log_ini();//报告块初始化
|
||||||
|
if (rv != APR_SUCCESS) {
|
||||||
|
echo_errg("Failed to parse report log define ini file! \n");
|
||||||
|
|
||||||
return rv;
|
DIY_ERRORLOG_CODE("process",LOG_CODE_RPTINIT,"【ERROR】前置的%s%d号进程报告初始化失败", get_front_msg_from_subdir(), g_front_seg_index);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app_get_private_config(g_my_conf_fname) != APR_SUCCESS) {
|
if (app_get_private_config(g_my_conf_fname) != APR_SUCCESS) {
|
||||||
|
|||||||
@@ -255,6 +255,9 @@ struct LD_info_t{
|
|||||||
rptinfo_t **rptinfo; /**< rptinfo_t* 数组 */
|
rptinfo_t **rptinfo; /**< rptinfo_t* 数组 */
|
||||||
int read_flag ; //CZY 2023-02-28 判断是否将监测点是否有效
|
int read_flag ; //CZY 2023-02-28 判断是否将监测点是否有效
|
||||||
|
|
||||||
|
//测点日志等级
|
||||||
|
int log_level; //0 ERROR 1 WARN 2 NORMAL 3 DEBUG
|
||||||
|
|
||||||
char mp_id[256];//CZY 2023-08-20 监测点编码,例:8afaa
|
char mp_id[256];//CZY 2023-08-20 监测点编码,例:8afaa
|
||||||
char terminal_code[256];//CZY 2023-08-20 终端编码
|
char terminal_code[256];//CZY 2023-08-20 终端编码
|
||||||
//int ld_ins;//CZY 2023-08-20 逻辑设备实例号,例:1
|
//int ld_ins;//CZY 2023-08-20 逻辑设备实例号,例:1
|
||||||
@@ -273,8 +276,8 @@ struct LD_info_t{
|
|||||||
int registcount;//lnk20250812
|
int registcount;//lnk20250812
|
||||||
bool has_logged_regist;//lnk20250812
|
bool has_logged_regist;//lnk20250812
|
||||||
|
|
||||||
//不使用
|
|
||||||
int iUnitOfTime;//CZY 2023-08-17 WW 2022年12月7日15:43:34 装置上送事件持续时间单位切换(0-ms; 1-s)
|
int iUnitOfTime;//CZY 2023-08-17 WW 2022年12月7日15:43:34 装置上送事件持续时间单位切换(0-ms; 1-s)
|
||||||
|
//不使用
|
||||||
int iStatOfTime;//CZY 2023-08-17 WW 2022年12月7日15:48:33 统计数据时间 0-北京时间 1-UTC时间
|
int iStatOfTime;//CZY 2023-08-17 WW 2022年12月7日15:48:33 统计数据时间 0-北京时间 1-UTC时间
|
||||||
int iJournalTime;//CZY 2023-08-17 WW 2022年12月7日15:52:32 补招日志时间(0-UTC时间(日志、录波文件均为UTC时间); 1-北京时间(日志北京时间、录波文件UTC时间 注:仅四川地区+8小时读取补招日志))
|
int iJournalTime;//CZY 2023-08-17 WW 2022年12月7日15:52:32 补招日志时间(0-UTC时间(日志、录波文件均为UTC时间); 1-北京时间(日志北京时间、录波文件UTC时间 注:仅四川地区+8小时读取补招日志))
|
||||||
//不使用
|
//不使用
|
||||||
@@ -327,6 +330,8 @@ struct ied_usr_t{
|
|||||||
void *cookie;
|
void *cookie;
|
||||||
double last_call_wavelist_time ; //上次召录波列表时间
|
double last_call_wavelist_time ; //上次召录波列表时间
|
||||||
|
|
||||||
|
int log_level; //0 ERROR 1 WARN 2 NORMAL 3 DEBUG
|
||||||
|
|
||||||
char terminal_id[256];//CZY 2023-08-20 终端id,例:8afaa9a15707483a0157262f8e78077d
|
char terminal_id[256];//CZY 2023-08-20 终端id,例:8afaa9a15707483a0157262f8e78077d
|
||||||
char org_name[256];//CZY 2023-08-20 所属单位,例:南京供公司
|
char org_name[256];//CZY 2023-08-20 所属单位,例:南京供公司
|
||||||
char maint_name[256];//CZY 2023-08-20 运维单位,例:南京供公司
|
char maint_name[256];//CZY 2023-08-20 运维单位,例:南京供公司
|
||||||
@@ -527,6 +532,8 @@ int extract_timestamp_from_cfg_file(char *comtrade_fn,long long *start_tm,long l
|
|||||||
int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm);
|
int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm);
|
||||||
QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm);
|
QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm);
|
||||||
|
|
||||||
|
void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
286
set_process.sh
286
set_process.sh
@@ -8,9 +8,216 @@
|
|||||||
|
|
||||||
#前置all的重置或者新增都是由稳态的第一个进程来处理,所有进程收到这条消息后先判断自己的进程号是否是1,而且是稳态,否则不处理,所有操作均由这个进程完成,
|
#前置all的重置或者新增都是由稳态的第一个进程来处理,所有进程收到这条消息后先判断自己的进程号是否是1,而且是稳态,否则不处理,所有操作均由这个进程完成,
|
||||||
|
|
||||||
|
if [ -z "$SETSID" ]; then
|
||||||
|
export SETSID=1
|
||||||
|
nohup setsid "$0" "$@" >> /tmp/set_process_detach.log 2>&1 < /dev/null &
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 关闭从父进程继承来的 socket / pipe / 文件描述符
|
||||||
|
for fd_path in /proc/$$/fd/*; do
|
||||||
|
fd_num=$(basename "$fd_path")
|
||||||
|
case "$fd_num" in
|
||||||
|
0|1|2) ;;
|
||||||
|
*) eval "exec ${fd_num}>&-" 2>/dev/null ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# 设置日志文件路径
|
# 设置日志文件路径
|
||||||
LOGFILE="$FEP_ENV/dat/log/start_fe.log"
|
LOGFILE="$FEP_ENV/dat/log/start_fe.log"
|
||||||
|
|
||||||
|
INI_FILE="/FeProject/etc/config/mykafka.ini"
|
||||||
|
|
||||||
|
LOCK_FILE="/tmp/set_process.lock"
|
||||||
|
|
||||||
|
if [ -f "$LOCK_FILE" ]; then
|
||||||
|
old_pid=$(cat "$LOCK_FILE")
|
||||||
|
if ps -p "$old_pid" > /dev/null 2>&1; then
|
||||||
|
echo "Already running: $old_pid"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Stale lock found, removing"
|
||||||
|
rm -f "$LOCK_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $$ > "$LOCK_FILE"
|
||||||
|
trap "rm -f $LOCK_FILE" EXIT
|
||||||
|
|
||||||
|
get_ini_value() {
|
||||||
|
local key="$1"
|
||||||
|
local line
|
||||||
|
|
||||||
|
line=$(grep -E "^[[:space:]]*${key}=" "$INI_FILE" | tail -n 1)
|
||||||
|
[ -z "$line" ] && return 1
|
||||||
|
|
||||||
|
# 去掉 key=
|
||||||
|
line="${line#*=}"
|
||||||
|
# 去掉首尾空格
|
||||||
|
line=$(echo "$line" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
|
||||||
|
|
||||||
|
[ -n "$line" ] || return 1
|
||||||
|
echo "$line"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "$@" | tee -a "$LOGFILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_local_port_released() {
|
||||||
|
local PORT="$1"
|
||||||
|
|
||||||
|
for retry in $(seq 1 3); do
|
||||||
|
for i in $(seq 1 20); do
|
||||||
|
if ! ss -lntp 2>/dev/null | grep -q ":${PORT}[[:space:]]"; then
|
||||||
|
log "[OK] Local port $PORT released"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "[WAIT] Local port $PORT still in use... ($i/20)"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
log "[RETRY] Local port $PORT not released, retry $retry/3"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
log "[FAIL] Local port $PORT still in use after retries:"
|
||||||
|
ss -lntp 2>/dev/null | grep ":${PORT}[[:space:]]" | tee -a "$LOGFILE"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_remote_conn_released() {
|
||||||
|
local REMOTE_IP="$1"
|
||||||
|
local REMOTE_PORT="$2"
|
||||||
|
|
||||||
|
for retry in $(seq 1 3); do
|
||||||
|
for i in $(seq 1 20); do
|
||||||
|
if ! ss -ntp 2>/dev/null \
|
||||||
|
| grep "${REMOTE_IP}:${REMOTE_PORT}" \
|
||||||
|
| grep -E 'pt61850netd_pqfe|fe_watchdog|fe_main' >/dev/null; then
|
||||||
|
log "[OK] Remote ${REMOTE_IP}:${REMOTE_PORT} released"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[WAIT] Remote ${REMOTE_IP}:${REMOTE_PORT} still exists... ($i/20)"
|
||||||
|
ss -ntp 2>/dev/null \
|
||||||
|
| grep "${REMOTE_IP}:${REMOTE_PORT}" \
|
||||||
|
| grep -E 'pt61850netd_pqfe|fe_watchdog|fe_main' \
|
||||||
|
| tee -a "$LOGFILE"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
log "[RETRY] Remote ${REMOTE_IP}:${REMOTE_PORT} not released, retry $retry/3"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
log "[FAIL] Remote ${REMOTE_IP}:${REMOTE_PORT} still exists:"
|
||||||
|
ss -ntp 2>/dev/null \
|
||||||
|
| grep "${REMOTE_IP}:${REMOTE_PORT}" \
|
||||||
|
| grep -E 'pt61850netd_pqfe|fe_watchdog|fe_main' \
|
||||||
|
| tee -a "$LOGFILE"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_value_released() {
|
||||||
|
local key="$1"
|
||||||
|
local value="$2"
|
||||||
|
|
||||||
|
[ -z "$value" ] && return 0
|
||||||
|
|
||||||
|
# 纯端口
|
||||||
|
if echo "$value" | grep -Eq '^[0-9]+$'; then
|
||||||
|
[ "$value" = "0" ] && { log "[SKIP] $key disabled"; return 0; }
|
||||||
|
|
||||||
|
log "[CHECK] $key local port: $value"
|
||||||
|
check_local_port_released "$value"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# URL
|
||||||
|
if echo "$value" | grep -Eq '^[a-zA-Z]+://'; then
|
||||||
|
local hostport ip port
|
||||||
|
hostport=$(echo "$value" | sed -n 's#^[a-zA-Z]\+://\([^/]*\).*#\1#p')
|
||||||
|
ip="${hostport%%:*}"
|
||||||
|
port="${hostport##*:}"
|
||||||
|
|
||||||
|
if [ -n "$ip" ] && [ -n "$port" ] && [ "$ip" != "$port" ]; then
|
||||||
|
log "[CHECK] $key remote: $ip:$port"
|
||||||
|
check_remote_conn_released "$ip" "$port"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[SKIP] $key invalid URL: $value"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ip:port
|
||||||
|
if echo "$value" | grep -Eq '^[^:]+:[0-9]+$'; then
|
||||||
|
local ip="${value%%:*}"
|
||||||
|
local port="${value##*:}"
|
||||||
|
|
||||||
|
log "[CHECK] $key remote: $ip:$port"
|
||||||
|
check_remote_conn_released "$ip" "$port"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[SKIP] $key unsupported value: $value"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_key_released() {
|
||||||
|
local key="$1"
|
||||||
|
local value
|
||||||
|
|
||||||
|
value=$(get_ini_value "$key") || {
|
||||||
|
log "[SKIP] $key not found"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
log "==== Checking $key = $value ===="
|
||||||
|
check_value_released "$key" "$value"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
check_all_resources_released() {
|
||||||
|
local ret=0
|
||||||
|
|
||||||
|
log "=============================="
|
||||||
|
log " Start checking resources..."
|
||||||
|
log "=============================="
|
||||||
|
|
||||||
|
# 本地端口
|
||||||
|
check_key_released "TestPort" || ret=1
|
||||||
|
check_key_released "HttpPort" || ret=1
|
||||||
|
check_key_released "SocketPort" || ret=1
|
||||||
|
|
||||||
|
# MQ
|
||||||
|
check_key_released "Ipport" || ret=1
|
||||||
|
check_key_released "ConsumerIpport" || ret=1
|
||||||
|
|
||||||
|
# Web
|
||||||
|
check_key_released "WebDevice" || ret=1
|
||||||
|
check_key_released "WebIcd" || ret=1
|
||||||
|
check_key_released "WebIntegrity" || ret=1
|
||||||
|
check_key_released "WebComflag" || ret=1
|
||||||
|
check_key_released "WebEvent" || ret=1
|
||||||
|
check_key_released "WebFileupload" || ret=1
|
||||||
|
check_key_released "WebFiledownload" || ret=1
|
||||||
|
|
||||||
|
if [ $ret -eq 0 ]; then
|
||||||
|
log "✅ ALL resources released"
|
||||||
|
else
|
||||||
|
log "❌ Some resources NOT released"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 输出当前时间并打印进程停止信息
|
# 输出当前时间并打印进程停止信息
|
||||||
echo "" ; echo ""
|
echo "" ; echo ""
|
||||||
echo "****** `date "+%F %R:%S"` start setting Processes after 3 sec ******"
|
echo "****** `date "+%F %R:%S"` start setting Processes after 3 sec ******"
|
||||||
@@ -20,7 +227,7 @@ echo "****** `date "+%F %R:%S"` start setting Processes after 3 sec ******" >>"$
|
|||||||
|
|
||||||
# 函数检查并处理日志文件大小
|
# 函数检查并处理日志文件大小
|
||||||
check_log_file() {
|
check_log_file() {
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ] && [ -f "$1" ]; then
|
||||||
FILE_SIZE=0
|
FILE_SIZE=0
|
||||||
FILE_SIZE=$(du "$1" | awk '{print $1}')
|
FILE_SIZE=$(du "$1" | awk '{print $1}')
|
||||||
|
|
||||||
@@ -45,23 +252,46 @@ check_log_file $LOGFILE
|
|||||||
|
|
||||||
# 定义查找并杀死进程的函数
|
# 定义查找并杀死进程的函数
|
||||||
kill_process_by_name() {
|
kill_process_by_name() {
|
||||||
PROCESS_NAME=$1
|
local PROCESS_NAME="$1"
|
||||||
PID=$(ps -ef | grep "$PROCESS_NAME" | grep -v "grep" | awk '{print $2}')
|
local PIDS
|
||||||
|
|
||||||
if [ -n "$PID" ]; then
|
PIDS=$(ps -ef | grep "$PROCESS_NAME" | grep -v grep | awk '{print $2}')
|
||||||
echo "Found process '$PROCESS_NAME' with PID: $PID"
|
|
||||||
|
if [ -n "$PIDS" ]; then
|
||||||
|
echo "Found process '$PROCESS_NAME' with PID(s): $PIDS"
|
||||||
echo "Killing process..."
|
echo "Killing process..."
|
||||||
kill -9 $PID
|
|
||||||
if [ $? -eq 0 ]; then
|
for pid in $PIDS; do
|
||||||
echo "Process '$PROCESS_NAME' killed successfully."
|
kill -15 "$pid" 2>/dev/null
|
||||||
else
|
done
|
||||||
echo "Failed to kill the process '$PROCESS_NAME'."
|
|
||||||
fi
|
sleep 3
|
||||||
|
|
||||||
|
for pid in $PIDS; do
|
||||||
|
if ps -p "$pid" >/dev/null 2>&1; then
|
||||||
|
echo "Process still exists, force kill: $pid"
|
||||||
|
kill -9 "$pid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
else
|
else
|
||||||
echo "Process '$PROCESS_NAME' not found."
|
echo "Process '$PROCESS_NAME' not found."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait_all_exit() {
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
COUNT=$(ps -ef | grep -E 'pt61850netd_pqfe|fe_watchdog' | grep -v grep | wc -l)
|
||||||
|
if [ "$COUNT" -eq 0 ]; then
|
||||||
|
echo "All FE processes exited"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "Waiting FE processes exit... ($COUNT still running)"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Timeout waiting FE processes exit"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# 功能块开始
|
# 功能块开始
|
||||||
handle_reset() {
|
handle_reset() {
|
||||||
# 功能:reset
|
# 功能:reset
|
||||||
@@ -71,22 +301,28 @@ handle_reset() {
|
|||||||
if [ "$2" == "all" ]; then
|
if [ "$2" == "all" ]; then
|
||||||
|
|
||||||
# 关闭旧的看门狗进程
|
# 关闭旧的看门狗进程
|
||||||
kill_process_by_name "/FeProject/bin/fe_watchdog"
|
#kill_process_by_name "/FeProject/bin/fe_watchdog"
|
||||||
|
|
||||||
# 关闭旧的 stat 进程
|
# 关闭旧的 stat 进程
|
||||||
kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_stat_data"
|
#kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_stat_data"
|
||||||
|
|
||||||
# 关闭旧的 recall 进程
|
# 关闭旧的 recall 进程
|
||||||
kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_recallhis_data"
|
#kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_recallhis_data"
|
||||||
|
|
||||||
# 关闭旧的 3s 进程
|
# 关闭旧的 3s 进程
|
||||||
kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_3s_data"
|
#kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_3s_data"
|
||||||
|
|
||||||
# 关闭旧的 comtrade 进程
|
# 关闭旧的 comtrade 进程
|
||||||
kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_soe_comtrade"
|
#kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_soe_comtrade"
|
||||||
|
|
||||||
|
/home/pq/FeProject/boot/stop_fe.sh
|
||||||
|
|
||||||
|
wait_all_exit || exit 1
|
||||||
|
|
||||||
|
check_all_resources_released || exit 1
|
||||||
|
|
||||||
#关闭进程后等待一段时间,防止端口占用
|
#关闭进程后等待一段时间,防止端口占用
|
||||||
#sleep 5
|
sleep 5
|
||||||
|
|
||||||
# 清空 runtime.cf 中的所有进程配置
|
# 清空 runtime.cf 中的所有进程配置
|
||||||
sed -i '/cfg_stat_data/d' /home/pq/FeProject/etc/runtime.cf
|
sed -i '/cfg_stat_data/d' /home/pq/FeProject/etc/runtime.cf
|
||||||
@@ -119,6 +355,9 @@ handle_reset() {
|
|||||||
sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_soe_comtrade^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf
|
sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_soe_comtrade^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 修改后等一下
|
||||||
|
sleep 1
|
||||||
|
|
||||||
# 确保文件已被写入并刷新
|
# 确保文件已被写入并刷新
|
||||||
sync
|
sync
|
||||||
@@ -230,14 +469,13 @@ handle_add() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 获取当前脚本的进程ID
|
# 获取当前脚本的进程ID
|
||||||
CURRENT_PID=$$
|
#CURRENT_PID=$$
|
||||||
|
|
||||||
# 检查是否有其他的set_process.sh脚本正在运行,排除当前脚本
|
# 检查是否有其他的set_process.sh脚本正在运行,排除当前脚本
|
||||||
if pgrep -f "set_process.sh" | grep -v "^$CURRENT_PID$" > /dev/null; then
|
#if pgrep -f "set_process.sh" | grep -v "^$CURRENT_PID$" > /dev/null; then
|
||||||
echo "set_process.sh is already running. Exiting..."
|
# echo "set_process.sh is already running. Exiting..."
|
||||||
echo "set_process.sh is already running. Exiting..." >>"$LOGFILE"
|
# echo "set_process.sh is already running. Exiting..." >>"$LOGFILE"
|
||||||
exit 1
|
# exit 1
|
||||||
fi
|
#fi
|
||||||
|
|
||||||
#脚本应该等待3秒钟
|
#脚本应该等待3秒钟
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|||||||
Reference in New Issue
Block a user