From 8a2e6ea53773e3e14224c7237e1fecc8d5656c92 Mon Sep 17 00:00:00 2001 From: lnk Date: Fri, 9 May 2025 16:53:07 +0800 Subject: [PATCH] add log4cplus --- .vscode/settings.json | 3 +- cfg_parse/SimpleProducer.cpp | 22 +- cfg_parse/base64.cpp | 66 +- cfg_parse/cfg_parser.cpp | 2223 +++++++++--------- cfg_parse/datahub.cpp | 30 +- cfg_parse/log4.cpp | 478 ++++ cfg_parse/nacos.cpp | 298 +-- cfg_parse/obs_huaweiyun.cpp | 86 +- cfg_parse/oss_aliyun.cpp | 32 +- cfg_parse/uds_huaweiyun.cpp | 102 +- include/rocketmq/SimpleProducer.h | 8 +- json/create_json.cpp | 2382 ++++++++++---------- json/mms_json_inter.h | 58 +- json/save2json.cpp | 1041 +++++---- json/save2json.h | 135 +- log4cplus/appender.h | 340 +++ log4cplus/asyncappender.h | 110 + log4cplus/boost/deviceappender.hxx | 201 ++ log4cplus/callbackappender.h | 73 + log4cplus/clfsappender.h | 98 + log4cplus/clogger.h | 126 ++ log4cplus/config.h.cmake.in | 335 +++ log4cplus/config.h.in | 471 ++++ log4cplus/config.hxx | 217 ++ log4cplus/config/defines.hxx.in | 247 ++ log4cplus/config/macosx.h | 37 + log4cplus/config/win32.h | 194 ++ log4cplus/config/windowsh-inc-full.h | 42 + log4cplus/config/windowsh-inc.h | 159 ++ log4cplus/configurator.h | 389 ++++ log4cplus/consoleappender.h | 105 + log4cplus/exception.h | 56 + log4cplus/fileappender.h | 428 ++++ log4cplus/fstreams.h | 56 + log4cplus/helpers/appenderattachableimpl.h | 119 + log4cplus/helpers/connectorthread.h | 107 + log4cplus/helpers/eventcounter.h | 91 + log4cplus/helpers/fileinfo.h | 59 + log4cplus/helpers/lockfile.h | 69 + log4cplus/helpers/loglog.h | 145 ++ log4cplus/helpers/pointer.h | 210 ++ log4cplus/helpers/property.h | 172 ++ log4cplus/helpers/queue.h | 158 ++ log4cplus/helpers/snprintf.h | 62 + log4cplus/helpers/socket.h | 163 ++ log4cplus/helpers/socketbuffer.h | 79 + log4cplus/helpers/stringhelper.h | 271 +++ log4cplus/helpers/thread-config.h | 58 + log4cplus/helpers/timehelper.h | 169 ++ log4cplus/hierarchy.h | 324 +++ log4cplus/hierarchylocker.h | 79 + log4cplus/initializer.h | 62 + log4cplus/internal/customloglevelmanager.h | 151 ++ log4cplus/internal/cygwin-win32.h | 55 + log4cplus/internal/env.h | 102 + log4cplus/internal/internal.h | 244 ++ log4cplus/internal/socket.h | 219 ++ log4cplus/layout.h | 645 ++++++ log4cplus/log4.h | 80 + log4cplus/log4cplus.h | 66 + log4cplus/log4judpappender.h | 91 + log4cplus/logger.h | 325 +++ log4cplus/loggingmacros.h | 427 ++++ log4cplus/loglevel.h | 200 ++ log4cplus/mdc.h | 77 + log4cplus/msttsappender.h | 112 + log4cplus/ndc.h | 329 +++ log4cplus/nteventlogappender.h | 84 + log4cplus/nullappender.h | 65 + log4cplus/qt4debugappender.h | 103 + log4cplus/qt5debugappender.h | 103 + log4cplus/socketappender.h | 164 ++ log4cplus/spi/appenderattachable.h | 88 + log4cplus/spi/factory.h | 275 +++ log4cplus/spi/filter.h | 404 ++++ log4cplus/spi/loggerfactory.h | 65 + log4cplus/spi/loggerimpl.h | 216 ++ log4cplus/spi/loggingevent.h | 239 ++ log4cplus/spi/objectregistry.h | 113 + log4cplus/spi/rootlogger.h | 75 + log4cplus/streams.h | 55 + log4cplus/syslogappender.h | 167 ++ log4cplus/tchar.h | 63 + log4cplus/thread/impl/syncprims-cxx11.h | 35 + log4cplus/thread/impl/syncprims-impl.h | 90 + log4cplus/thread/impl/syncprims-pmsm.h | 119 + log4cplus/thread/impl/threads-impl.h | 96 + log4cplus/thread/impl/tls.h | 193 ++ log4cplus/thread/syncprims-pub-impl.h | 359 +++ log4cplus/thread/syncprims.h | 354 +++ log4cplus/thread/threads.h | 113 + log4cplus/tracelogger.h | 87 + log4cplus/tstring.h | 128 ++ log4cplus/version.h | 58 + log4cplus/win32consoleappender.h | 93 + log4cplus/win32debugappender.h | 69 + mms/db_interface.h | 51 +- mms/main.c | 98 +- mms/mms_process.c | 645 +++--- mms/mmscli_log.c | 76 +- mms/mmscli_rpt.c | 248 +- mms/mmsclient.c | 206 +- mms/parse_xml.c | 22 +- mms/rdb_client.c | 120 +- mms/rdb_client.h | 254 +-- mms/rdb_ext_utils.c | 134 +- pt61850netd_pqfe.pro | 13 +- rocketmq/CPushConsumer.h | 107 + rocketmq/SimpleProducer.h | 59 +- 109 files changed, 18240 insertions(+), 4034 deletions(-) create mode 100644 cfg_parse/log4.cpp create mode 100644 log4cplus/appender.h create mode 100644 log4cplus/asyncappender.h create mode 100644 log4cplus/boost/deviceappender.hxx create mode 100644 log4cplus/callbackappender.h create mode 100644 log4cplus/clfsappender.h create mode 100644 log4cplus/clogger.h create mode 100644 log4cplus/config.h.cmake.in create mode 100644 log4cplus/config.h.in create mode 100644 log4cplus/config.hxx create mode 100644 log4cplus/config/defines.hxx.in create mode 100644 log4cplus/config/macosx.h create mode 100644 log4cplus/config/win32.h create mode 100644 log4cplus/config/windowsh-inc-full.h create mode 100644 log4cplus/config/windowsh-inc.h create mode 100644 log4cplus/configurator.h create mode 100644 log4cplus/consoleappender.h create mode 100644 log4cplus/exception.h create mode 100644 log4cplus/fileappender.h create mode 100644 log4cplus/fstreams.h create mode 100644 log4cplus/helpers/appenderattachableimpl.h create mode 100644 log4cplus/helpers/connectorthread.h create mode 100644 log4cplus/helpers/eventcounter.h create mode 100644 log4cplus/helpers/fileinfo.h create mode 100644 log4cplus/helpers/lockfile.h create mode 100644 log4cplus/helpers/loglog.h create mode 100644 log4cplus/helpers/pointer.h create mode 100644 log4cplus/helpers/property.h create mode 100644 log4cplus/helpers/queue.h create mode 100644 log4cplus/helpers/snprintf.h create mode 100644 log4cplus/helpers/socket.h create mode 100644 log4cplus/helpers/socketbuffer.h create mode 100644 log4cplus/helpers/stringhelper.h create mode 100644 log4cplus/helpers/thread-config.h create mode 100644 log4cplus/helpers/timehelper.h create mode 100644 log4cplus/hierarchy.h create mode 100644 log4cplus/hierarchylocker.h create mode 100644 log4cplus/initializer.h create mode 100644 log4cplus/internal/customloglevelmanager.h create mode 100644 log4cplus/internal/cygwin-win32.h create mode 100644 log4cplus/internal/env.h create mode 100644 log4cplus/internal/internal.h create mode 100644 log4cplus/internal/socket.h create mode 100644 log4cplus/layout.h create mode 100644 log4cplus/log4.h create mode 100644 log4cplus/log4cplus.h create mode 100644 log4cplus/log4judpappender.h create mode 100644 log4cplus/logger.h create mode 100644 log4cplus/loggingmacros.h create mode 100644 log4cplus/loglevel.h create mode 100644 log4cplus/mdc.h create mode 100644 log4cplus/msttsappender.h create mode 100644 log4cplus/ndc.h create mode 100644 log4cplus/nteventlogappender.h create mode 100644 log4cplus/nullappender.h create mode 100644 log4cplus/qt4debugappender.h create mode 100644 log4cplus/qt5debugappender.h create mode 100644 log4cplus/socketappender.h create mode 100644 log4cplus/spi/appenderattachable.h create mode 100644 log4cplus/spi/factory.h create mode 100644 log4cplus/spi/filter.h create mode 100644 log4cplus/spi/loggerfactory.h create mode 100644 log4cplus/spi/loggerimpl.h create mode 100644 log4cplus/spi/loggingevent.h create mode 100644 log4cplus/spi/objectregistry.h create mode 100644 log4cplus/spi/rootlogger.h create mode 100644 log4cplus/streams.h create mode 100644 log4cplus/syslogappender.h create mode 100644 log4cplus/tchar.h create mode 100644 log4cplus/thread/impl/syncprims-cxx11.h create mode 100644 log4cplus/thread/impl/syncprims-impl.h create mode 100644 log4cplus/thread/impl/syncprims-pmsm.h create mode 100644 log4cplus/thread/impl/threads-impl.h create mode 100644 log4cplus/thread/impl/tls.h create mode 100644 log4cplus/thread/syncprims-pub-impl.h create mode 100644 log4cplus/thread/syncprims.h create mode 100644 log4cplus/thread/threads.h create mode 100644 log4cplus/tracelogger.h create mode 100644 log4cplus/tstring.h create mode 100644 log4cplus/version.h create mode 100644 log4cplus/win32consoleappender.h create mode 100644 log4cplus/win32debugappender.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 049df12..69cdc40 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -138,6 +138,7 @@ "node.h": "c", "save2json.h": "c", "custom_printf.h": "c", - "suicacse.h": "c" + "suicacse.h": "c", + "log4.h": "c" } } \ No newline at end of file diff --git a/cfg_parse/SimpleProducer.cpp b/cfg_parse/SimpleProducer.cpp index c6e0657..f9d2971 100644 --- a/cfg_parse/SimpleProducer.cpp +++ b/cfg_parse/SimpleProducer.cpp @@ -6,18 +6,18 @@ #include #include "../mms/db_interface.h" -#include "../include/rocketmq/CProducer.h" -#include "../include/rocketmq/CMessage.h" -#include "../include/rocketmq/CSendResult.h" -#include "../include/rocketmq/SimpleProducer.h" +#include "../rocketmq/CProducer.h" +#include "../rocketmq/CMessage.h" +#include "../rocketmq/CSendResult.h" +#include "../rocketmq/SimpleProducer.h" //测试300数据用lnk20241202 #include #include //测试300数据用 //lnk20241209添加队列选择 -#include "../include/rocketmq/MQSelector.h" -#include "../include/rocketmq/MQMessageQueue.h" +#include "../rocketmq/MQSelector.h" +#include "../rocketmq/MQMessageQueue.h" //#include #include #include @@ -25,13 +25,13 @@ #include //引入消费起点 -#include "../include/rocketmq/DefaultMQPushConsumer.h" -#include "../include/rocketmq/ConsumeType.h" +#include "../rocketmq/DefaultMQPushConsumer.h" +#include "../rocketmq/ConsumeType.h" // 引入提供的消费者接口头文件 -#include "../include/rocketmq/CPushConsumer.h" -#include "../include/rocketmq/CCommon.h" -#include "../include/rocketmq/CMessageExt.h" +#include "../rocketmq/CPushConsumer.h" +#include "../rocketmq/CCommon.h" +#include "../rocketmq/CMessageExt.h" #include #include // 用于互斥锁(在 C++98 中没有 std::mutex) #include // for std::pair diff --git a/cfg_parse/base64.cpp b/cfg_parse/base64.cpp index f484789..f40f88e 100644 --- a/cfg_parse/base64.cpp +++ b/cfg_parse/base64.cpp @@ -19,7 +19,7 @@ using namespace std; #include #include "../mms/db_interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" #ifdef __cplusplus @@ -27,15 +27,15 @@ extern "C" { #endif /* __cplusplus */ - // Base64 + // Base64 编码表 const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; - //base64 + //base64 解码表 static const unsigned char base64_decode_table[] = { - //ÿ16 + //每行16个 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //1 - 16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //17 - 32 0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63, //33 - 48 @@ -47,26 +47,26 @@ extern "C" { }; /** - * @brief base64_decode base64 - * @param indata - * @param inlen ݴС - * @param outdata - * @param outlen ݴС - * @return int 0ɹ -1Ч - * ע⣺ݵĴС44ı + * @brief base64_decode base64解码 + * @param indata 需解码的数据 + * @param inlen 需解码的数据大小 + * @param outdata 解码后输出的数据 + * @param outlen 解码后输出的数据大小 + * @return int 0:成功 -1:无效参数 + * 注意:解码的数据的大小必须大于4,且是4的倍数 */ int base64_decode(const char* indata, int inlen, char* outdata, long* outlen) { if (indata == NULL || inlen <= 0 || (outdata == NULL && outlen == NULL)) { return -1; } - if (inlen < 4 || inlen % 4 != 0) { //ҪݳȲ4ı //inlen < 4 || + if (inlen < 4 || inlen % 4 != 0) { //需要解码的数据长度不是4的倍数 //inlen < 4 || return -1; } int i, j; - //ַ + //计算解码后的字符串长度 int len = inlen / 4 * 3; if (indata[inlen - 1] == '=') { len--; @@ -88,10 +88,10 @@ extern "C" { return 0; } - // Base64 뺯 + // Base64 编码函数 char* base64_encode_char(const unsigned char* data, size_t input_length, size_t* output_length) { - *output_length = 4 * ((input_length + 2) / 3); // ȼ - char* encoded_data = (char*)malloc(*output_length + 1); // ڴ棬+1 Ϊ '\0' + *output_length = 4 * ((input_length + 2) / 3); // 输出长度计算 + char* encoded_data = (char*)malloc(*output_length + 1); // 分配内存,+1 为 '\0' if (encoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { @@ -107,47 +107,47 @@ extern "C" { encoded_data[j++] = (i * 2 + 1 / 3) < *output_length ? base64_chars[triple & 0x3F] : '='; } - encoded_data[*output_length] = '\0'; // ַ + encoded_data[*output_length] = '\0'; // 添加字符串结束符 return encoded_data; } /// - /// жַǷΪpower{}ʽ + /// 判断字符串是否为power{}格式 /// - /// ȡַ - /// ֶ - /// ֶγ - /// ȡݳ + /// 待提取字符串 + /// 结果字段 + /// 字段长度限制 + /// 提取出的内容长度 /// bool extract_if_power(const char* str, char* output, size_t output_size, size_t* extracted_length) { const char* prefix = "power{"; size_t prefix_length = strlen(prefix); - // ǰ׺ + // 检查前缀 if (strncmp(str, prefix, prefix_length) != 0) { - return false; // ǰ׺ƥ + return false; // 前缀不匹配 } - // ұպϵĻ + // 查找闭合的花括号 const char* close_brace = strchr(str + prefix_length, '}'); if (close_brace == NULL) { - return false; // ûҵպϵĻ + return false; // 没有找到闭合的花括号 } - // Ҫȡݳ + // 计算要提取的内容长度 size_t content_length = close_brace - (str + prefix_length); if (content_length >= output_size) { - return false; // ̫޷ + return false; // 内容太长,无法放入输出缓冲区 } - // ݵ + // 复制内容到输出缓冲区 strncpy(output, str + prefix_length, content_length); - output[content_length] = '\0'; // ӿֹ - printf("text: %s,length:%d\n", output, content_length); // ע⣺Ҫȷınullַֹ - // ȡݳ + output[content_length] = '\0'; // 添加空终止符 + printf("text: %s,length:%d\n", output, content_length); // 注意:这里需要确保文本是以null终止的字符串 + // 设置提取出的内容长度 *extracted_length = content_length; - return true; // ȡɹ + return true; // 提取成功 } #ifdef __cplusplus diff --git a/cfg_parse/cfg_parser.cpp b/cfg_parse/cfg_parser.cpp index b2838b5..8e2c209 100644 --- a/cfg_parse/cfg_parser.cpp +++ b/cfg_parse/cfg_parser.cpp @@ -25,8 +25,8 @@ using namespace std; #include #include //lnk 2024-10-16 -#include //дȥص豸 -#include //ϴļ +#include //写去重的设备类型 +#include //上传文件 #include "../mms/db_interface.h" #include "../json/save2json.h" @@ -34,9 +34,12 @@ using namespace std; #include "../mms/rdb_client.h" #include "../mms/interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" +#include "../log4cplus/log4.h"//lnk添加log4 +#include + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -50,19 +53,19 @@ extern "C" { extern int g_front_seg_index; extern unsigned int g_no_auth; - extern char g_onlyIP[255]; //ֱijIPΪ + extern char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 int g_DevFlag = 0; #ifdef __cplusplus } #endif -///////////////////////////////lnk20250118̨˱ʹõڴأ̬ڴصķʽÿڴطһiedݣݲʹãֻʵֺ -// ڴ洢ն ID ͶӦӳ +///////////////////////////////lnk20250118台账变更使用的内存池:动态内存池的方式,每个内存池放一个ied的所有相关内容,这个方案暂不使用,只保留相关实现函数 +// 用于存储终端 ID 和对应的子池 std::list > pool_list; /////////////////////////////////////////////////// -//ZW 2023-10-10 нṹ +//ZW 2023-10-10 单条补招结构 class RecallInfo { public: @@ -70,45 +73,45 @@ public: long long endtime; }; -//CZY 2023-09-17 +//CZY 2023-09-17 控制命令解析 class ProgramParam { public: - QList terminal_list;//նidб - QString file_name;//װãװossеλ + QList terminal_list;//终端id列表 + QString file_name;//程序下装可用,下装程序在oss中的位置 }; -//CZY 2023-09-17 +//CZY 2023-09-17 控制命令解析 class RecallParam { public: - QString mp_id;//id - QString start;//ʼʱ - QString end;//ݽʱ - int voltage;//̬ݱ־ - int stat;//̬ݱ־ + QString mp_id;//监测点id + QString start;//补招数据起始时间 + QString end;//补招数据结束时间 + int voltage;//暂态数据标志 + int stat;//稳态数据标志 }; -//CZY 2023-10-12 װʶԿ +//CZY 2023-10-12 装置识别码与密钥 class terminal_ext // { public: - char terminal_identify_code[100];//նʶ - char terminal_key[100];//նԿ + char terminal_identify_code[100];//终端识别码 + char terminal_key[100];//终端密钥 }; -class CJournalRecall //־нṹ +class CJournalRecall //日志补招结构类 { public: - QString MonitorID; //· - QString StartTime; //ݲʼʱ - QString EndTime; //ݲнʱ - QString STEADY; //ʷͳݱʶ 0-У1- - QString VOLTAGE; //̬¼ʶ 0-У1- + QString MonitorID; //线路监测点号 + QString StartTime; //数据补招起始时间 + QString EndTime; //数据补招结束时间 + QString STEADY; //补招历史统计数据标识 0-不补招;1-补招 + QString VOLTAGE; //补招暂态事件标识 0-不补招;1-补招 }; /*lnk 2024-10-15 */ -class ledger_monitor //̨ +class ledger_monitor //监测点台账 { public: char monitor_id[64]; @@ -119,10 +122,10 @@ public: char terminal_connect[64]; char timestamp[64]; char status[255]; - char count_cfg[64]; //̨˵һ֣¼ݿҵ̨̨ + char count_cfg[64]; //不是台账的一部分,用来记录数据库或业务中台的台账数量 }; -class terminal_dev //ն̨ +class terminal_dev //终端台账 { public: char terminal_id[64]; @@ -139,21 +142,21 @@ public: char port[64]; char timestamp[64]; - //lnk20250210ӽ̺ + //lnk20250210添加进程号 char processNo[64]; ledger_monitor line[10]; - char count_cfg[64]; //̨˵һ֣¼ݿҵ̨̨ + char count_cfg[64]; //不是台账的一部分,用来记录数据库或业务中台的台账数量 }; -class icd_model //icdģ +class icd_model //icd模型 { public: char model_id[64]; char tmnl_type[64]; - char tmnl_type_id[64]; //ʹ - char tmnl_factory[64]; //ʹ + char tmnl_type_id[64]; //不使用 + char tmnl_factory[64]; //不使用 char file_name[128]; char file_path[128]; char timestamp[64]; @@ -161,31 +164,31 @@ public: /*lnk 2024-10-15 */ -list g_StatisticLackList; //־нṹ +list g_StatisticLackList; //日志补招结构类链表 -QMutex g_StatisticLackList_list_mutex; //recall +QMutex g_StatisticLackList_list_mutex; //recall队列数据锁 -QString DEVIE_CONFIG_FN = QString("Device_Config.xml");// -QString LINE_CONFIG_FN = QString("Line_Config.xml");// -QString JSON_CONFIG_FN_old = QString("JiangSu_Config.xml");//Ĭӳļ -QString THREE_SECS_CONFIG_FN = QString("Trigger3S.xml");//ʵʱ -QString RECALL_CONFIG_FN = QString("Recall.xml");// +QString DEVIE_CONFIG_FN = QString("Device_Config.xml");//不用 +QString LINE_CONFIG_FN = QString("Line_Config.xml");//不用 +QString JSON_CONFIG_FN_old = QString("JiangSu_Config.xml");//默认映射文件 +QString THREE_SECS_CONFIG_FN = QString("Trigger3S.xml");//实时数据用 +QString RECALL_CONFIG_FN = QString("Recall.xml");//不用 -//lnk20241220һ̨˸µļ֤¸̨ +//lnk20241220创建一个用来台账更新的文件,保证数据完整的情况下更新台账 std::string LEDGER_UPDATE_FN = "LedgerUpdate.log"; const int MAX_CPUNO = 10; -//lnk20250121ն̨ -int IED_COUNT = 300; //Ĭ300 +//lnk20250121终端台账数量配置 +int IED_COUNT = 300; //默认300 extern int INITFLAG; -//lnk2024-8-14ӽͽ߱־,0ڽνߣ1ڽν +//lnk2024-8-14添加角型接线标志,0不存在角形接线,1存在角形接线 int isdelta_flag = 0; //////CZY 2023-09-06 config -//ǰflag:1Ϊ,0Ϊر +//多前置flag:1为开启,0为关闭 int MULTIPLE_NODE_FLAG = 1; extern const char* PROGRAM_VERSION; @@ -199,18 +202,18 @@ int MULIT_NODE_INTERVAL; int COMMUNICATION_LOG_STATUS_TIME; int COMMUNICATION_LOG_ABNORMAL_TIME; -char* POSTGRES_DATABASE;//ݿ -char* POSTGRES_USERNAME;//ݿû -char* POSTGRES_PASSWORD;//ݿ -char* POSTGRES_SCHEMA;//ݿģʽ -char* POSTGRES_DNSNAME;//ȡpostgres/guass -char* POSTGRES_TABLEPREFIX;//ǰ׺ +char* POSTGRES_DATABASE;//数据库库名 +char* POSTGRES_USERNAME;//数据库用户名 +char* POSTGRES_PASSWORD;//数据库密码 +char* POSTGRES_SCHEMA;//数据库模式名 +char* POSTGRES_DNSNAME;//取postgres/guass库 +char* POSTGRES_TABLEPREFIX;//表名前缀 -char* CLIENT_ID;//̨CLIENT_ID -char* CLIENT_SECRET;//̨CLIENT_SECRET -char* TOKEN_URL;//̨ȡtokenӿ -char* DEVICE_URL;//̨ȡն˽ӿ -char* GRANT_TYPE;//̨GRANT_TYPE +char* CLIENT_ID;//中台CLIENT_ID +char* CLIENT_SECRET;//中台CLIENT_SECRET +char* TOKEN_URL;//中台取token接口 +char* DEVICE_URL;//中台取终端接口 +char* GRANT_TYPE;//中台GRANT_TYPE char* UDS_UPLOAD_URL; char* UDS_DOWNLOAD_URL; @@ -247,8 +250,8 @@ char* DOMAIN_NAME; extern int g_front_seg_index; extern int g_front_seg_num; -/*ֲñlnk10-9*/ -// +/*移植配置变量lnk10-9*/ +//生产者 std::string G_ROCKETMQ_PRODUCER = "";//rocketmq producer std::string G_ROCKETMQ_IPPORT = "";//rocketmq ip+port std::string G_ROCKETMQ_TOPIC = "";//topie @@ -256,7 +259,7 @@ std::string G_ROCKETMQ_TAG = "";//tag std::string G_ROCKETMQ_KEY = "";//key int QUEUENUM = 0; std::string BROKERNAME = ""; -// +//消费者 std::string G_ROCKETMQ_CONSUMER = "";//rocketmq consumer std::string G_MQCONSUMER_IPPORT = "";//consumer ip+port std::string G_MQCONSUMER_TOPIC_RT = "";//consumer topie @@ -284,45 +287,54 @@ std::string G_CONNECT_TOPIC = "";//consumer topie std::string G_CONNECT_TAG = "";//consumer tag std::string G_CONNECT_KEY = "";//consumer key +//心跳 +std::string Heart_Beat_Topic = ""; +std::string Heart_Beat_Tag = ""; +std::string Heart_Beat_Key = ""; +//消息响应 +std::string Topic_Reply_Topic = ""; +std::string Topic_Reply_Tag = ""; +std::string Topic_Reply_Key = ""; + int G_TEST_FLAG = 0; int G_TEST_NUM = 0; -int TEST_PORT = 11000;//ڵǰ̵¼shellĶ˿ +int TEST_PORT = 11000;//用于当前进程登录测试shell的端口 -std::string G_TEST_LIST = "";//õķʵݵնб -std::vector TESTARRAY;//б +std::string G_TEST_LIST = "";//测试用的发送实际数据的终端列表 +std::vector TESTARRAY;//解析的列表数组 -//ն˺ͼ״̬ɸѡ +//终端和监测点的状态筛选 std::string TERMINAL_STATUS = ""; std::string MONITOR_STATUS = ""; std::string ICD_FLAG = ""; -//socketÿ +//保留socket连接设置开关 int SOCKET_PORT = 13000; int SOCKETENABLE = 0; -//httpų́lnk20241031 +//添加http配置和台账配置lnk20241031 int HTTPENABLE = 0; std::string HTTP_IP = ""; int HTTP_PORT = 12000; -/*webӿlnk202411-6*/ +/*添加web接口lnk202411-6*/ std::string WEB_DEVICE = ""; std::string WEB_ICD = ""; -std::string WEB_INTEGRITY = ""; //ݲʹ +std::string WEB_INTEGRITY = ""; //暂不使用 std::string WEB_COMFLAG = ""; std::string WEB_EVENT = ""; std::string WEB_FILEUPLOAD = ""; std::string WEB_FILEDOWNLOAD = ""; -//lnk20250115̨ +//lnk20250115添加台账锁 extern pthread_mutex_t mtx; /*lnk 2024-10-21 */ std::string intToString(int number); ////////////////////////////////////////////////////////////////////////// -extern int server_socket; //Web Socketʵ -extern unsigned int g_node_id; //ǰó(100-500) +extern int server_socket; //Web Socket服务端实例 +extern unsigned int g_node_id; //前置程序类型(100-500) //WW 2023-08-20 end //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -344,9 +356,9 @@ void parse_log_switch_ini(unsigned int* error, unsigned int* warn, unsigned int* } -//lnk20250328Ӳбõĺ +//lnk20250328添加测试列表用的函数 void parseTestList(const std::string& input) { - TESTARRAY.clear(); // վ + TESTARRAY.clear(); // 清空旧数据 size_t start = 0; size_t end = 0; @@ -360,7 +372,7 @@ void parseTestList(const std::string& input) { start = end + 1; } - // һ IDûжŽβ + // 添加最后一个 ID(如果没有逗号结尾) if (start < input.length()) { std::string lastId = input.substr(start); if (!lastId.empty()) { @@ -397,7 +409,7 @@ void init_config() { CITY_FLAG = settings.value("Flag/CityFlag", 0).toInt(); qDebug() << "Read CITY_FLAG:" << CITY_FLAG << endl; -//̨lnk20241031////////////////////////////////////////////////////////////// +//台账配置lnk20241031////////////////////////////////////////////////////////////// TERMINAL_STATUS = settings.value("Ledger/TerminalStatus", 0).toString().toStdString(); std::cout << "Read TERMINAL_STATUS:" << TERMINAL_STATUS << std::endl; MONITOR_STATUS = settings.value("Ledger/MonitorStatus", 0).toString().toStdString(); @@ -406,10 +418,10 @@ void init_config() { std::cout << "Read ICD_FLAG:" << ICD_FLAG << std::endl; IED_COUNT = settings.value("Ledger/IedCount", 0).toInt(); -//////////////////////////////////////////////////socket/////////////////// +//////////////////////////////////////////////////添加socket开关/////////////////// SOCKETENABLE = settings.value("Socket/SocketEnable", 0).toInt(); SOCKET_PORT = settings.value("Socket/SocketPort", 0).toInt(); -//////http////////////////////////////////////////////////////////////////// +//////添加http配置////////////////////////////////////////////////////////////////// HTTPENABLE = settings.value("Http/HttpEnable", 0).toInt(); ba = settings.value("Http/HttpIp", "").toString().toLatin1(); HTTP_IP = strdup(ba.data()); @@ -566,8 +578,8 @@ void init_config() { qDebug() << "Read UDS_UPLOAD_URL:" << UDS_UPLOAD_URL << endl; qDebug() << "Read UDS_DOWNLOAD_URL:" << UDS_DOWNLOAD_URL << endl; -/*rocketmqĽ10-9 *///////////////////////////////////////////////////////////////// -// +/*添加rocketmq的解析10-9 *///////////////////////////////////////////////////////////////// +//生产者 ba = settings.value("RocketMq/producer", "").toString().toLatin1(); G_ROCKETMQ_PRODUCER = strdup(ba.data()); ba = settings.value("RocketMq/Ipport", "").toString().toLatin1(); @@ -579,7 +591,24 @@ void init_config() { ba = settings.value("RocketMq/Key", "").toString().toLatin1(); G_ROCKETMQ_KEY = strdup(ba.data()); QUEUENUM = settings.value("RocketMq/Queuenum", 0).toInt(); -// + + //心跳 + ba = settings.value("RocketMq/Heart_Beat_Topic", "").toString().toLatin1(); + Heart_Beat_Topic = strdup(ba.data()); + ba = settings.value("RocketMq/Heart_Beat_Tag", "").toString().toLatin1(); + Heart_Beat_Tag = strdup(ba.data()); + ba = settings.value("RocketMq/Heart_Beat_Key", "").toString().toLatin1(); + Heart_Beat_Key = strdup(ba.data()); + //消息响应 + ba = settings.value("RocketMq/Topic_Reply_Topic", "").toString().toLatin1(); + Topic_Reply_Topic = strdup(ba.data()); + ba = settings.value("RocketMq/Topic_Reply_Tag", "").toString().toLatin1(); + Topic_Reply_Tag = strdup(ba.data()); + ba = settings.value("RocketMq/Topic_Reply_Key", "").toString().toLatin1(); + Topic_Reply_Key = strdup(ba.data()); + + +//消费者 ba = settings.value("RocketMq/consumer", "").toString().toLatin1(); G_ROCKETMQ_CONSUMER = strdup(ba.data()); ba = settings.value("RocketMq/ConsumerIpport", "").toString().toLatin1(); @@ -633,18 +662,18 @@ void init_config() { G_CONNECT_TAG = strdup(ba.data()); ba = settings.value("RocketMq/CONNECTKey", "").toString().toLatin1(); G_CONNECT_KEY = strdup(ba.data()); -//MQ +//MQ测试 G_TEST_FLAG = settings.value("RocketMq/Testflag", 0).toInt(); G_TEST_NUM = settings.value("RocketMq/Testnum", 0).toInt(); ba = settings.value("RocketMq/TestList", 0).toString().toLatin1(); G_TEST_LIST = strdup(ba.data()); - parseTestList(G_TEST_LIST);//õնб + parseTestList(G_TEST_LIST);//解析测试用的终端列表 -//shell +//测试shell TEST_PORT = settings.value("RocketMq/TestPort", 0).toInt(); -//شӡ +//生产者相关打印 std::cout << "Read G_ROCKETMQ_PRODUCER:" << G_ROCKETMQ_PRODUCER << std::endl; std::cout << "Read G_ROCKETMQ_IPPORT:" << G_ROCKETMQ_IPPORT << std::endl; std::cout << "Read G_ROCKETMQ_TOPIC:" << G_ROCKETMQ_TOPIC << std::endl; @@ -657,7 +686,7 @@ void init_config() { std::cout << "Read G_CONNECT_TOPIC:" << G_CONNECT_TOPIC << std::endl; std::cout << "Read G_CONNECT_TAG:" << G_CONNECT_TAG << std::endl; std::cout << "Read G_CONNECT_KEY:" << G_CONNECT_KEY << std::endl; -//شӡ +//消费者相关打印 std::cout << "Read G_ROCKETMQ_CONSUMER:" << G_ROCKETMQ_CONSUMER << std::endl; std::cout << "Read G_MQCONSUMER_IPPORT:" << G_MQCONSUMER_IPPORT << std::endl; std::cout << "Read G_MQCONSUMER_TOPIC_RT:" << G_MQCONSUMER_TOPIC_RT << std::endl; @@ -678,12 +707,12 @@ void init_config() { std::cout << "Read G_MQCONSUMER_TOPIC_LOG:" << G_MQCONSUMER_TOPIC_LOG << std::endl; std::cout << "Read G_MQCONSUMER_TAG_LOG:" << G_MQCONSUMER_TAG_LOG << std::endl; std::cout << "Read G_MQCONSUMER_KEY_LOG:" << G_MQCONSUMER_KEY_LOG << std::endl; -//Mqشӡ +//Mq测试相关打印 std::cout << "Read G_TEST_FLAG:" << G_TEST_FLAG << std::endl; std::cout << "Read G_TEST_NUM:" << G_TEST_NUM << std::endl; -//20241212lnkӶǰ +//20241212lnk添加多前置 if (g_front_seg_index != 0 && g_front_seg_num != 0) { MULTIPLE_NODE_FLAG = 1; std::cout << "this is multiple process of index:" << g_front_seg_index << std::endl; @@ -693,23 +722,23 @@ void init_config() { std::cout << "this is single process" << std::endl; } -//20250109lnkӽ̲Դӡ˿ - if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ +//20250109lnk添加进程测试打印端口 + if (g_node_id == STAT_DATA_BASE_NODE_ID)//统计采集 TEST_PORT = TEST_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; - else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//补召 TEST_PORT = TEST_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3秒采集 TEST_PORT = TEST_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//暂态录波 TEST_PORT = TEST_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; } } -// CZY ping IP -// ִȡ +// CZY 测试 ping IP +// 执行命令并获取输出结果 std::string executeCommand(const std::string& command) { std::string result = ""; FILE* pipe = popen(command.c_str(), "r"); @@ -741,7 +770,7 @@ bool telnet_port_socket(const char* ip, int port) { return false; } - // ӳʱʱΪ5 + // 设置连接超时时间为5秒 struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; @@ -769,7 +798,7 @@ bool telnet_port_socket(const char* ip, int port) { return false; } else if (ret == 0) { - // ӳʱ + // 连接超时 close(sockfd); return false; } @@ -778,25 +807,25 @@ bool telnet_port_socket(const char* ip, int port) { socklen_t len = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len); if (error == 0) { - // ӳɹ + // 连接成功 close(sockfd); return true; } else { - // ʧ + // 连接失败 close(sockfd); return false; } } } else { - // ʧ + // 连接失败 close(sockfd); return false; } } - // ӳɹ + // 连接成功 close(sockfd); return true; } @@ -806,7 +835,7 @@ bool ping_ip(const std::string& ip) { std::string command = "ping -c 1 -w 2.5 " + ip; std::string result = executeCommand(command); - // жǷ "1 packets transmitted, 1 received" ַ + // 判断输出结果是否包含 "1 packets transmitted, 1 received" 字符串 if (result.find("1 packets transmitted, 1 received") != std::string::npos) { return true; } @@ -815,11 +844,11 @@ bool ping_ip(const std::string& ip) { } } void pingPrint(QTcpSocket* clientSocket, const std::string &msg) { - // ׼ + // 输出到标准输出 std::cout << msg << std::endl; - // ¼־ļ + // 记录到日志文件 add_comm_log(const_cast(msg.c_str())); - // clientSocket Ϊգ͵ shell + // 如果 clientSocket 不为空,则发送到 shell if (clientSocket != nullptr) { clientSocket->write((msg + "\r\n").c_str()); clientSocket->flush(); @@ -829,12 +858,12 @@ int Worker::init_ping_telnet(QTcpSocket* clientSocket, int& ip_count, int& telne pingPrint(clientSocket, "start test ping telnet"); ied_t* ied = NULL; int iedno; - // 豸 + // 遍历所有设备 for (iedno = 0; iedno < g_node->n_clients && !g_stopTelnetTest; iedno++) { - // **1. 룬û ``` ˳** - if (clientSocket->waitForReadyRead(100)) { // ? + // **1. 监听输入,用户输入 ``` 退出** + if (clientSocket->waitForReadyRead(100)) { // ? 监听输入 QByteArray input = clientSocket->readAll().trimmed(); - if (input == "`") { // ? û ```˳־ģʽ + if (input == "`") { // ? 用户输入 ```,退出日志模式 std::cout << "Received '`' from shell socket! Exiting viewlog...\n"; g_stopTelnetTest = true; break; @@ -879,7 +908,7 @@ int Worker::init_ping_telnet(QTcpSocket* clientSocket, int& ip_count, int& telne " telnet_count:" + intToString(telnet_count); pingPrint(clientSocket, countMsg); - // ļ + // 更新配置文件 QString MyKafkaIniFilename = QString("../etc/") + QString("testping.ini"); QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); settings.setValue("test/IpCount", ip_count); @@ -896,28 +925,28 @@ bool isCharPtrEmpty(const char* str) { return str == nullptr || str[0] == '\0' || str == ""; } -// CZY 2024-07-24 ַǷȫΪ +// CZY 2024-07-24 函数:检查字符串是否全为数字 int isAllDigits(const char* str) { while (*str) { if (!isdigit((unsigned char)*str)) { - return 0; // ַַ + return 0; // 发现非数字字符 } str++; } - return 1; // ַ + return 1; // 所有字符都是数字 } -// CZY 2024-07-24ַתΪintܣ +// CZY 2024-07-24函数:将字符串转换为int(如果可能) int stringToInt(const char* str, int* result) { if (isAllDigits(str)) { - *result = atoi(str); // ʹatoiתעatoi - return 1; // תɹ + *result = atoi(str); // 使用atoi进行转换,注意atoi不会检查溢出 + return 1; // 转换成功 } - return 0; // תʧ + return 0; // 转换失败 } -int GetServerIndexFromDB() //ȡǰ÷ +int GetServerIndexFromDB() //获取前置服务器序号 { register int fd, interface; @@ -939,7 +968,7 @@ int GetServerIndexFromDB() // while (interface-- > 0) { printf("net device %s\n", buf[interface].ifr_name); - /*ȷǷֻ֧ģʽ Jugde whether the net card status is promisc */ + /*确保网卡是否支持混杂模式 Jugde whether the net card status is promisc */ if (!(ioctl(fd, SIOCGIFFLAGS, (char*)&buf[interface]))) { if (buf[interface].ifr_flags & IFF_PROMISC) { printf("the interface is PROMISC \n"); @@ -951,7 +980,7 @@ int GetServerIndexFromDB() // perror(str); } - /*ж״̬Ƿ Judge whether the net card status is up */ + /*判断网卡状态是否打开 Judge whether the net card status is up */ if (buf[interface].ifr_flags & IFF_UP) { printf("the interface status is UP\n"); } @@ -959,7 +988,7 @@ int GetServerIndexFromDB() // printf("the interface status is DOWN\n"); } - /*ȡIPַ Get IP of the net card */ + /*获取网卡IP地址 Get IP of the net card */ if (!(ioctl(fd, SIOCGIFADDR, (char*)&buf[interface]))) { printf("IP address is: %s\n", inet_ntoa(((struct sockaddr_in*)(&buf[interface].ifr_addr))->sin_addr)); @@ -970,7 +999,7 @@ int GetServerIndexFromDB() // perror(str); } - /*ȡHWַ Get HW ADDRESS of the net card */ + /*获取网卡的HW地址 Get HW ADDRESS of the net card */ if (!(ioctl(fd, SIOCGIFHWADDR, (char*)&buf[interface]))) { printf("HW address is: "); sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", @@ -1003,56 +1032,56 @@ int GetServerIndexFromDB() // void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* log_cfg_strlist, char* type) { char* tmp; - tmp = Get_xmlpath(type);//ȡģid - if (tmp == NULL) {//ҲģͱʹĬϵͺźļ - //zw޸ 2023 - 8 - 15 ĽXML ԭRptLogCfg.iniȡ + tmp = Get_xmlpath(type);//获取模型id号 + if (tmp == NULL) {//找不到模型编号使用默认的型号和配置文件 + //zw修改 2023 - 8 - 15 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 if (strcmp(subdir, "cfg_stat_data") == 0) { QString devtype; devtype.append(type); QString devtype2; - devtype2.append("HL-6810");//̬ĬͺHL-6810 + devtype2.append("HL-6810");//稳态默认型号HL-6810 qDebug() << "cfg_stat_data"; - QString xml_dir = QString("../") + QString("etc/"); //Linuxµ· + QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径 - QDomDocument doc; //½QDomDocumentһXMLĵ - QFile file(xml_dir + QString("JiangSu_Config.xml"));//ĬļJiangSu_Config.xml - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 + QFile file(xml_dir + QString("JiangSu_Config.xml"));//默认配置文件JiangSu_Config.xml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { qDebug() << "Read RPT Error1"; return; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { qDebug() << "Read RPT Error2"; file.close(); return; } file.close(); - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); // - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { qDebug() << "ReportStat"; - QDomNodeList list = e.childNodes(); //Ԫصӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - QString strTag2 = node.toElement().tagName(); //DataTypeڵ + QString strTag2 = node.toElement().tagName(); //DataType节点 if ("ReportStat" == strTag2) { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) @@ -1076,45 +1105,45 @@ void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* l if (strcmp(subdir, "cfg_soe_comtrade") == 0) { qDebug() << "cfg_soe_comtrade"; - QString xml_dir = QString("../") + QString("etc/"); //Linuxµ· + QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径 - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(xml_dir + QString("JiangSu_Config.xml")); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { qDebug() << "Read RPT Error1"; return; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { qDebug() << "Read RPT Error2"; file.close(); return; } file.close(); - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); // - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { qDebug() << "ReportEvent"; - QDomNodeList list = e.childNodes(); //Ԫصӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - QString strTag2 = node.toElement().tagName(); //DataTypeڵ + QString strTag2 = node.toElement().tagName(); //DataType节点 if ("ReportEvent" == strTag2) { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) @@ -1141,70 +1170,70 @@ void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* l log_cfg_strlist->append(log_cfg_str); } } - else//ͺŲΪնȡָļ + else//型号不为空读取指定的配置文件 { QString tmppath; tmppath.append("/FeProject/dat/").append(tmp).append(".xml"); qDebug() << tmppath; - //lnk20241126 + //lnk20241126调试用 std::cout << "rptcfgfile:" << tmppath.toStdString() << std::endl; - //zw޸ 2023 - 8 - 15 ĽXML ԭRptLogCfg.iniȡ + //zw修改 2023 - 8 - 15 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 if (strcmp(subdir, "cfg_stat_data") == 0) { qDebug() << "cfg_stat_data"; - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(tmppath); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { qDebug() << "Read RPT Error1"; - //lnk20241126 + //lnk20241126调试用 std::cout << "Read RPT Error1" << std::endl; return; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { qDebug() << "Read RPT Error2"; - //lnk20241126 + //lnk20241126调试用 std::cout << "Read RPT Error2" << std::endl; file.close(); return; } file.close(); - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); // - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { qDebug() << "ReportStat"; - QDomNodeList list = e.childNodes(); //Ԫصӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - QString strTag2 = node.toElement().tagName(); //DataTypeڵ + QString strTag2 = node.toElement().tagName(); //DataType节点 if ("ReportStat" == strTag2) { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) { rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); - qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();//ȡ + qDebug() << node2.toElement().attribute("ReportControl").toAscii().data();//读取各个报告配置 } } } @@ -1216,51 +1245,51 @@ void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* l n = n.nextSibling(); } - QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";//־д + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0";//日志的配置是写死的 log_cfg_strlist->append(log_cfg_str); } - //lnkʵʱ20241125 + //lnk添加实时数据20241125 if (strcmp(subdir, "cfg_3s_data") == 0) { qDebug() << "cfg_3s_data"; - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(tmppath); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { qDebug() << "Read RPT Error1"; return; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { qDebug() << "Read RPT Error2"; file.close(); return; } file.close(); - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); // - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { qDebug() << "ReportReal"; - QDomNodeList list = e.childNodes(); //Ԫصӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - QString strTag2 = node.toElement().tagName(); //DataTypeڵ + QString strTag2 = node.toElement().tagName(); //DataType节点 if ("ReportReal" == strTag2) { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) @@ -1278,7 +1307,7 @@ void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* l n = n.nextSibling(); } - //ʵʱû־ + //实时数据没有日志 //QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; //log_cfg_strlist->append(log_cfg_str); } @@ -1286,43 +1315,43 @@ void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* l if (strcmp(subdir, "cfg_soe_comtrade") == 0) { qDebug() << "cfg_soe_comtrade"; - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(tmppath); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { qDebug() << "Read RPT Error1"; return; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { qDebug() << "Read RPT Error2"; file.close(); return; } file.close(); - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); // - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { qDebug() << "ReportEvent"; - QDomNodeList list = e.childNodes(); //Ԫصӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - QString strTag2 = node.toElement().tagName(); //DataTypeڵ - if ("ReportEvent" == strTag2)//ֵ + QString strTag2 = node.toElement().tagName(); //DataType节点 + if ("ReportEvent" == strTag2)//区分点 { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) @@ -1378,14 +1407,14 @@ int parse_rpt_log_ini() QStringList* log_temp = new QStringList(); rpt_cfg_strlists.insert(type, rpt_temp); log_cfg_strlists.insert(type, log_temp); - //g_DevFlagûʹ + //g_DevFlag没有使用 parse_one_rpt_log_ini(g_DevFlag, rpt_cfg_strlists[type], log_cfg_strlists[type], ied_usr->dev_type); } for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); - char str[256]; //256С + char str[256]; //256大小 char* tmp = Get_IED(ied_usr->dev_type); if(tmp == NULL){std::cerr << "front read ied config error!" << std::endl;continue;} qDebug() << tmp << endl; @@ -1416,7 +1445,7 @@ int parse_rpt_log_ini() } } - //ƿ־ƿ鴦 + //报告控制块和日志控制块处理结束后清理容器 for (QMap::iterator it1 = log_cfg_strlists.begin(); it1 != log_cfg_strlists.end(); ++it1) { delete it1.value(); @@ -1431,28 +1460,28 @@ int parse_rpt_log_ini() return APR_SUCCESS; } -//̨˸²/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//台账更新部分/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string LEDGER_UPDATE_DIR = "../etc/ledgerupdate/"; std::list find_xml_belong_to_this_process() { - char prefix[20]; // Ҫ20ַʵҪ - sprintf(prefix, "%d_%d", g_node_id, g_front_seg_index); // g_node_idg_front_seg_indexʽΪַ + char prefix[20]; // 假设最多需要20个字符(根据实际需要调整) + sprintf(prefix, "%d_%d", g_node_id, g_front_seg_index); // 将g_node_id和g_front_seg_index格式化为字符串 - DIR *dir = opendir(LEDGER_UPDATE_DIR.c_str()); // Ŀ¼ + DIR *dir = opendir(LEDGER_UPDATE_DIR.c_str()); // 打开目录 struct dirent *entry; - std::list found_files; // ڴ洢ҵƥļ + std::list found_files; // 用于存储找到的所有匹配文件名 if (dir == NULL) { std::cout << "Failed to open directory: " << LEDGER_UPDATE_DIR << std::endl; - return found_files; // ؿյlist + return found_files; // 返回空的list } - // Ŀ¼еļ + // 遍历目录中的所有文件 while ((entry = readdir(dir)) != NULL) { std::string filename = entry->d_name; - // ų "." ".." Ŀ¼ + // 排除 "." 和 ".." 目录 if (filename == "." || filename == "..") { continue; } @@ -1460,19 +1489,19 @@ std::list find_xml_belong_to_this_process() std::cout << "find" << filename << "in" << LEDGER_UPDATE_DIR << std::endl; - // жļǷ prefix ͷչ .xml + // 判断文件名是否以 prefix 开头且扩展名是 .xml if (filename.find(prefix) == 0 && filename.substr(filename.find_last_of('.') + 1) == "xml") { std::string full_path = LEDGER_UPDATE_DIR + filename; - found_files.push_back(full_path); // · + found_files.push_back(full_path); // 将完整路径加入容器 } } - closedir(dir); // رĿ¼ + closedir(dir); // 关闭目录 - return found_files; // ҵļ + return found_files; // 返回所有找到的文件名 } -// ȡǩеֵͨú +// 提取标签中的值的通用函数 std::string extract_value(const std::string& data, const std::string& tag) { size_t start_pos = data.find("<" + tag + ">"); if (start_pos == std::string::npos) return ""; @@ -1482,13 +1511,13 @@ std::string extract_value(const std::string& data, const std::string& tag) { return data.substr(start_pos + tag.length() + 2, end_pos - start_pos - tag.length() - 2); } -// str_tag terminal ӵӦ +// 根据 str_tag 将 terminal 添加到对应的数组 void add_terminal_to_trigger_update(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const terminal& work_terminal) { if (str_tag == "add") { std::cout << "new ledger!!!!"<new_update_num < MAX_UPDATEA_NUM) { trigger_update_xml->new_updates[trigger_update_xml->new_update_num] = work_terminal; - trigger_update_xml->new_update_num+= 1; // ն˵ + trigger_update_xml->new_update_num+= 1; // 更新新终端的数量 } else { std::cerr << "Exceeded MAX_UPDATEA_NUM limit for new updates!" << std::endl; } @@ -1497,7 +1526,7 @@ void add_terminal_to_trigger_update(trigger_update_xml_t* trigger_update_xml, co std::cout << "modify ledger!!!"<modify_update_num < MAX_UPDATEA_NUM) { trigger_update_xml->modify_updates[trigger_update_xml->modify_update_num] = work_terminal; - trigger_update_xml->modify_update_num+= 1; // ޸ն˵ + trigger_update_xml->modify_update_num+= 1; // 更新修改终端的数量 } else { std::cerr << "Exceeded MAX_UPDATEA_NUM limit for modify updates!" << std::endl; } @@ -1507,11 +1536,11 @@ void add_terminal_to_trigger_update(trigger_update_xml_t* trigger_update_xml, co } } -// XML ݲȡ terminal Ϣ -void parse_terminal_from_data(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const std::string& data) { - terminal work_terminal = {}; // µ terminal +// 解析 XML 数据并提取 terminal 信息 +void parse_terminal_from_data(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const std::string& data,const std::string& guid_value) { + terminal work_terminal = {}; // 创建新的 terminal 对象 - // ȡֶ + // 提取各个字段 strcpy(work_terminal.terminal_id, extract_value(data, "id").c_str()); strcpy(work_terminal.terminal_code, extract_value(data, "terminalCode").c_str()); strcpy(work_terminal.org_name, extract_value(data, "orgName").c_str()); @@ -1527,18 +1556,22 @@ void parse_terminal_from_data(trigger_update_xml_t* trigger_update_xml, const st strcpy(work_terminal.port, extract_value(data, "port").c_str()); strcpy(work_terminal.timestamp, extract_value(data, "updateTime").c_str()); + //添加guid20250506 + strncpy(work_terminal.guid, guid_value.c_str(), sizeof(work_terminal.guid) - 1); + work_terminal.guid[sizeof(work_terminal.guid) - 1] = '\0'; + size_t monitor_pos = 0; size_t monitor_count = 0; - // ÿ monitorDataദ 10 + // 查找每个 monitorData,最多处理 10 个 while ((monitor_pos = data.find(" λ + monitor_count++; // 增加 monitor 的计数 + monitor_pos = monitor_end_pos; // 移动 monitor_pos 到下一个 的位置 } - // str_tag terminal ӵӦ + // 根据 str_tag 将 terminal 添加到相应的数组 add_terminal_to_trigger_update(trigger_update_xml, str_tag, work_terminal); } -void parse_ledger_update(trigger_update_xml_t* trigger_update_xml, const std::string& strTag, const std::string& data) +void parse_ledger_update(trigger_update_xml_t* trigger_update_xml, const std::string& strTag, const std::string& data,const std::string& guid_value) { std::cout << "record one xml.."<delete_update_num < MAX_UPDATEA_NUM) { trigger_update_xml->delete_updates[trigger_update_xml->delete_update_num] = delete_terminal; - trigger_update_xml->delete_update_num += 1; // Ӽ + trigger_update_xml->delete_update_num += 1; // 增加计数 } } @@ -1604,7 +1642,7 @@ void parse_ledger_update(trigger_update_xml_t* trigger_update_xml, const std::st int load_ledger_update_from_xml(trigger_update_xml_t* trigger_update_xml, const std::string& xml_fn) { std::cout << "start to load one xml.."< ǩ + // 查找 标签 size_t ledger_pos = content.find(""); if (ledger_pos == std::string::npos) { std::cerr << "ledger_update tag not found!" << std::endl; return -1; } - // , , ǩ + // === 新增:查找 标签 === + std::string guid_value; + size_t guid_start = content.find("", ledger_pos); + size_t guid_end = content.find("", ledger_pos); + if (guid_start != std::string::npos && guid_end != std::string::npos && guid_end > guid_start) { + size_t guid_value_start = guid_start + std::string("").length(); + guid_value = content.substr(guid_value_start, guid_end - guid_value_start); + + std::cout << "Found guid: " << guid_value << std::endl; + } else { + std::cout << "No guid found in xml." << std::endl; + } + + + // 查找 , , 标签 size_t add_pos = content.find("", ledger_pos); size_t delete_pos = content.find("", ledger_pos); size_t modify_pos = content.find("", ledger_pos); - // ȷĸǩڣȡӦλ + // 确定哪个标签存在,并获取相应的位置 size_t target_pos = std::string::npos; std::string target_tag; @@ -1648,23 +1700,23 @@ int load_ledger_update_from_xml(trigger_update_xml_t* trigger_update_xml, const target_tag = "modify"; } - //ûҵȷıǩ˳ + //没找到正确的标签退出处理 if (target_pos == std::string::npos) { std::cerr << "No , , or tag found!" << std::endl; return -1; } - // ĿǩĽλ + // 查找目标标签的结束位置 size_t end_pos = content.find("", target_pos); if (end_pos == std::string::npos) { std::cerr << "Closing tag not found!" << std::endl; return -1; } - // ȡĿǩ + // 提取目标标签的内容 std::string target_content = content.substr(target_pos + target_tag.length() + 2, end_pos - (target_pos + target_tag.length() + 2)); - // е + // 解析 和其中的内容 size_t data_pos = 0; while ((data_pos = target_content.find("", data_pos)) != std::string::npos) { size_t data_end_pos = target_content.find("", data_pos); @@ -1677,16 +1729,16 @@ int load_ledger_update_from_xml(trigger_update_xml_t* trigger_update_xml, const std::cout << "ledger data_content is " << data_content <ǩĿǰÿļֻһ̨ + // 移动到下一个标签,目前每个文件只有一个台账 data_pos = data_end_pos + 15; } std::cout << "load one xml finish"<::iterator it = result.begin(); it != result.end(); ++it) { const std::string& filename = *it; std::cout << filename << std::endl; - //ÿļȡնˣжնǷ + //解析每个文件,提取终端,判断终端是否满足更新条件 apr_sleep(apr_time_from_sec(1) / 10); - //һļݵݽṹ + //加载一个文件的内容到数据结构 if (!load_ledger_update_from_xml(trigger_update_xml, filename)) { std::cout << "read /etc/ledgerupdate/" << filename << " success..." << std::endl; } - //ļɾ + //处理过的文件删除掉 if (std::remove(filename.c_str()) != 0) { std::cerr << "Failed to remove file: " << filename << " Error: " << strerror(errno) << std::endl; @@ -1718,11 +1770,11 @@ int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml) } } else { - //std::cout << "No matching XML files found." << std::endl;//ٲҪĴӡ + //std::cout << "No matching XML files found." << std::endl;//减少不必要的打印 return APR_EGENERAL; } - //ݷسɹд + //有数据返回成功,后续进行处理 //printf("Modify Update Count: %d\n", trigger_update_xml->modify_update_num); //printf("Delete Update Count: %d\n", trigger_update_xml->delete_update_num); //printf("New Update Count: %d\n", trigger_update_xml->new_update_num); @@ -1730,14 +1782,14 @@ int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml) printf("ledger update xml have data...\n"); return APR_SUCCESS; } - else{//ݷʧܣ + else{//无数据返回失败,后续不处理 printf("ledger update xml no data...\n"); return APR_EGENERAL; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//ʵʱ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//实时触发部分///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QString THREE_SECS_WEBSERVICE_DIR = QString("../etc/trigger3s/"); QString get_3s_trig_fn() @@ -1761,13 +1813,13 @@ int getValueFromElemAttrStr(QString str) return -1; } -//lnk20241125Ӵӡ///////////////////////////////////////////////////////////////////////////////////////////////// -// ӡ trigger_t ṹĺ +//lnk20241125添加打印调试用///////////////////////////////////////////////////////////////////////////////////////////////// +// 打印 trigger_t 结构体的函数 void print_trigger(const trigger_t& trigger) { printf(" dev_idx: %d, line_id: %d, real_data: %d, soe_data: %d, limit: %d, count: %d\n", trigger.dev_idx, trigger.line_id, trigger.real_data, trigger.soe_data, trigger.limit, trigger.count); } -// ӡ trigger_3s_xml_t ṹĺ +// 打印 trigger_3s_xml_t 结构体的函数 void print_trigger_3s_xml(const trigger_3s_xml_t& trigger_3s_xml) { printf("Work Trigger Count: %d\n", trigger_3s_xml.work_trigger_num); for (int i = 0; i < trigger_3s_xml.work_trigger_num; ++i) { @@ -1794,7 +1846,7 @@ void print_trigger_3s_xml(const trigger_3s_xml_t& trigger_3s_xml) { } } -//ʵʱļ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//实时触发文件处理部分////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void parse_3s_trigger(trigger_3s_xml_t* trigger_3s_xml, QString parentTag, QDomElement& trigger_e) { QString e_atr(""); @@ -1825,32 +1877,32 @@ void parse_3s_trigger(trigger_3s_xml_t* trigger_3s_xml, QString parentTag, QDomE else if (parentTag == "Modify") { trigger_3s_xml->modify_triggers[trigger_3s_xml->modify_trigger_num++] = trigger; } - //lnk20241125 + //调试用lnk20241125 print_trigger_3s_xml(*trigger_3s_xml); } int load_3s_data_from_xml(trigger_3s_xml_t* trigger_3s_xml, QString xml_fn) { - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(xml_fn); if (!file.open(QIODevice::ReadOnly)) - return APR_EBADPATH; //ֻʽ + return APR_EBADPATH; //以只读方式打开 bool ret = doc.setContent(&file); file.close(); if (!ret) return APR_EBADF; - //ļݶdoc - QDomElement docElem = doc.documentElement(); //ظԪ - QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ - while (!n.isNull()) { //ڵ㲻Ϊ - if (n.isElement()) { //ڵԪ - QDomElement e = n.toElement(); //תΪԪ + //将文件内容读到doc中 + QDomElement docElem = doc.documentElement(); //返回根元素 + QDomNode n = docElem.firstChild(); //返回根节点的第一个子节点 + while (!n.isNull()) { //如果节点不为空 + if (n.isElement()) { //如果节点是元素 + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); if (strTag == "Work" || strTag == "New" || strTag == "Delete" || strTag == "Modify") { - QDomNodeList list = e.childNodes(); //Ԫeӽڵб - for (int i = 0; i < list.count(); i++) { //б + QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表 + for (int i = 0; i < list.count(); i++) { //遍历该列表 QDomNode node = list.at(i); if (node.isElement()) { QDomElement trigger_e = node.toElement(); @@ -1862,7 +1914,7 @@ int load_3s_data_from_xml(trigger_3s_xml_t* trigger_3s_xml, QString xml_fn) } } } - n = n.nextSibling(); //һֵܽڵ + n = n.nextSibling(); //下一个兄弟节点 } return APR_SUCCESS; @@ -1874,15 +1926,15 @@ int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml) printf("begin 3s xml...\n"); memset(trigger_3s_xml, 0, sizeof(trigger_3s_xml_t)); - //ļ¼ڽеʵʱ + //这个文件是用来记录正在进行中的实时触发 QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); - load_3s_data_from_xml(trigger_3s_xml, (cfg_dir + THREE_SECS_CONFIG_FN)); ///Feproject/etc/Trigger3S.xml + load_3s_data_from_xml(trigger_3s_xml, (cfg_dir + THREE_SECS_CONFIG_FN)); //加载/Feproject/etc/Trigger3S.xml - QString the_webservice_xml_fn = get_3s_trig_fn();// ../etc/trigger3s/Ŀ¼µµxmlļļʵʱĿ + QString the_webservice_xml_fn = get_3s_trig_fn();// ../etc/trigger3s/目录下的最新的xml文件,这个文件是用来打开实时触发的开关 printf("the_webservice_xml_fn.size():%d\n",the_webservice_xml_fn.size()); - if (the_webservice_xml_fn.size() > 4) {//ļ4˵ҵļ + if (the_webservice_xml_fn.size() > 4) {//文件名大于4说明找到文件 apr_sleep(apr_time_from_sec(1) / 10); the_webservice_xml_fn = THREE_SECS_WEBSERVICE_DIR + the_webservice_xml_fn; load_3s_data_from_xml(trigger_3s_xml, the_webservice_xml_fn); @@ -1897,7 +1949,7 @@ int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml) return APR_EGENERAL; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//3s¼дļ +//3s触发记录写入文件 void append_triggers(QDomDocument& doc, QDomElement& root, QString parentTag, trigger_t* trigger, int trigger_num) { QString str; @@ -1948,82 +2000,82 @@ int create_3s_xml(trigger_3s_xml_t* trigger_3s_xml) return APR_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ܣָ .cfg ļȡʼʱʹʱ䣬תΪ뼶ʱ -// -// - comtrade_fnļΪοڶλӦ .cfg ļ -// -// - start_tmصʼʱλ룩 -// - trig_tmصĴʱλ룩 -// ֵ -// - APR_SUCCESS ʾɹ APR_EBADF ʾļ +// 函数功能:从指定的 .cfg 配置文件中提取起始时间和触发时间,并将其转化为毫秒级时间戳。 +// 输入参数: +// - comtrade_fn:输入的文件名,作为参考用于定位对应的 .cfg 配置文件。 +// 输出参数: +// - start_tm:返回的起始时间戳(单位:毫秒)。 +// - trig_tm:返回的触发时间戳(单位:毫秒)。 +// 返回值: +// - 返回 APR_SUCCESS 表示成功,返回 APR_EBADF 表示文件错误。 int extract_timestamp_from_cfg_file(char* comtrade_fn, long long* start_tm, long long* trig_tm) { - // ȡļϢ·ļȡ + // 获取文件名信息,路径和文件名提取 QFileInfo fi(QString::fromAscii(comtrade_fn)); QString fn = fi.fileName(); - QString cfgFileName_temp = QString("../comtrade/") + fn; // ƴ.cfgļ· + QString cfgFileName_temp = QString("../comtrade/") + fn; // 拼接.cfg文件的路径 - // ļǷ ".cfg" ".CFG" β + // 检查文件是否以 ".cfg" 或 ".CFG" 结尾 if (!cfgFileName_temp.endsWith(".cfg", Qt::CaseInsensitive) && !cfgFileName_temp.endsWith(".CFG", Qt::CaseInsensitive)) - return APR_EBADF; // ļҪ󣬷ļ + return APR_EBADF; // 如果文件名不符合要求,返回文件错误 - // ļ + // 打开配置文件 QFile cfgFile_temp(cfgFileName_temp); - if (!cfgFile_temp.exists()) { // ļ + if (!cfgFile_temp.exists()) { // 如果文件不存在 qDebug() << QString("Cannot find corresponding .cfg file: %1").arg(cfgFileName_temp); cfgFile_temp.close(); return APR_EBADF; } - else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) { // ļ޷ + else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) { // 如果文件无法打开 qDebug() << QString("Cannot open file %1:\n%2.").arg(cfgFileName_temp).arg(cfgFile_temp.errorString()); return APR_EBADF; } else { QStringList datContentList_temp; - QTextStream in_temp(&cfgFile_temp); // ıȡļ - // GBK صĴ루ע͵ˣ + QTextStream in_temp(&cfgFile_temp); // 创建文本流读取文件 + // 忽略 GBK 编码相关的代码(被注释掉了) - QString start_time_str(""); // ڴ洢ʼʱַ - QString trigger_time_str(""); // ڴ洢ʱַ + QString start_time_str(""); // 用于存储起始时间字符串 + QString trigger_time_str(""); // 用于存储触发时间字符串 - // жȡļ + // 按行读取配置文件内容 while (!in_temp.atEnd()) { - QString line_temp = in_temp.readLine().trimmed(); // ȡȥհַ - QString upper_line_temp = line_temp.toUpper(); // תΪдַ + QString line_temp = in_temp.readLine().trimmed(); // 读取并去除空白字符 + QString upper_line_temp = line_temp.toUpper(); // 转换为大写字符 - // ȡ "ASCII" "BINARY" ַֹͣ + // 如果读取到 "ASCII" 或 "BINARY" 字符串,则停止处理 if ((upper_line_temp == QString("ASCII")) || (upper_line_temp == QString("BINARY"))) break; else { - // ûУʼʱʹʱ + // 如果没有,更新起始时间和触发时间 start_time_str = trigger_time_str; trigger_time_str = line_temp; } } - // ȡ start_time_str ȴ3ȥ3ַͨǺ벿֣ + // 如果提取到的 start_time_str 长度大于3,则去掉最后3个字符(通常是毫秒部分) if (start_time_str.size() > 3) start_time_str = start_time_str.left(start_time_str.size() - 3); - // start_time_str תΪ QDateTime 󣬲תΪԼԪĺ + // 将 start_time_str 转换为 QDateTime 对象,并转换为自纪元以来的毫秒数 QDateTime start_time_dt = QDateTime::fromString(start_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); - *start_tm = start_time_dt.toMSecsSinceEpoch(); // תΪʱֵ start_tm + *start_tm = start_time_dt.toMSecsSinceEpoch(); // 转换为毫秒时间戳并赋值给 start_tm - // ͬʱ䣨ȥ3ַתΪʱ + // 同样处理触发时间(去掉最后3个字符并转换为时间戳) if (trigger_time_str.size() > 3) trigger_time_str = trigger_time_str.left(trigger_time_str.size() - 3); QDateTime trigger_time_dt = QDateTime::fromString(trigger_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); - *trig_tm = trigger_time_dt.toMSecsSinceEpoch(); // תΪʱֵ trig_tm + *trig_tm = trigger_time_dt.toMSecsSinceEpoch(); // 转换为毫秒时间戳并赋值给 trig_tm - cfgFile_temp.close(); // رļ + cfgFile_temp.close(); // 关闭文件 } - return APR_SUCCESS; // ɹ + return APR_SUCCESS; // 成功返回 } -//¼/////////////////////////////////////////////////////////////////////////////// -//WW 2023-11-01 ¼κŲintƥ +//录波部分/////////////////////////////////////////////////////////////////////////////// +//WW 2023-11-01 增加录波段号采用int类型匹配 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 j; @@ -2034,14 +2086,14 @@ int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int for (j = 0; j < filenum; ++j) { char fileNameTemp[64]; - strcpy(fileNameTemp, filenames[j]); //ʱ װ¼ļ + strcpy(fileNameTemp, filenames[j]); //临时存放 装置录波文件名 printf(" %s ", fileNameTemp); - if (strstr(fileNameTemp, domname) == NULL) //:"PQMonitor_PQM1" װ¼ļ:"PQMonitor_PQM1_000001_20191121_154534_689.CFG/.DAT/.HDR"Ӵ + if (strstr(fileNameTemp, domname) == NULL) //例:域名:"PQMonitor_PQM1" 不是 装置录波文件名:"PQMonitor_PQM1_000001_20191121_154534_689.CFG/.DAT/.HDR"的子串 continue; char* p = strtok(fileNameTemp, "_"); //PQMonitor p = strtok(NULL, "_"); //PQM1 p = strtok(NULL, "_"); //000001 - int nFltNum = atoi(p); //ַת + int nFltNum = atoi(p); //将字符转换成整型 if (nFltNum == fltnum) { @@ -2062,7 +2114,7 @@ int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int *dat_idx = j; } - if (*cfg_idx != -1 && *dat_idx != -1)//ļѾҵ + if (*cfg_idx != -1 && *dat_idx != -1)//两个文件都已经找到 break; } @@ -2074,7 +2126,7 @@ int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int } //WW2023-11-01 end -//в//////////////////////////////////////////////////////////////////////////////// +//补招部分//////////////////////////////////////////////////////////////////////////////// void parse_recall(recall_xml_t* recall_xml, QString parentTag, QDomElement& recall_e, char* id) { recall_t recall; @@ -2105,17 +2157,17 @@ int delete_recall_xml(char* id) QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml"); - //ָļ + //指定文件夹名 QDir dir(cfg_dir); if (!dir.exists()) { qDebug() << "folder does not exist!"; return false; } - //ָļ׺ָ + //指定文件后缀名,可指定多种类型 QStringList filter(file_name); - //ָͺ򣬰µ޸ʱȡ + //指定查找类型和排序,按最新的修改时间获取 QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); - for (int i = 0; i < files.size(); i++) {//նȡļ + for (int i = 0; i < files.size(); i++) {//清空读取文件 QString qstrRecallPath = cfg_dir + QString("/") + files[i]; QFile::remove(qstrRecallPath); } @@ -2127,27 +2179,27 @@ int parse_recall_xml(recall_xml_t* recall_xml, char* id) QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml"); - //lnk20241225ļ - //ָļ + //lnk20241225这里文件名 + //指定文件夹名 QDir dir(cfg_dir); if (!dir.exists()) { qDebug() << "folder does not exist!"; return false; } - //ָļ׺ָ + //指定文件后缀名,可指定多种类型 QStringList filter(file_name); - //ָͺ򣬰µ޸ʱȡ + //指定查找类型和排序,按最新的修改时间获取 QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); for (int i = 0; i < files.size(); i++) { QString qstrRecallPath = cfg_dir + QString("/") + files[i]; qDebug() << qstrRecallPath; - QDomDocument doc; //½QDomDocumentһXMLĵ + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 QFile file(qstrRecallPath); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "file.open error"; - continue; //ֻʽ + continue; //以只读方式打开 } bool ret = doc.setContent(&file); file.close(); @@ -2156,16 +2208,16 @@ int parse_recall_xml(recall_xml_t* recall_xml, char* id) qDebug() << "doc.setContent error"; continue; } - //ļݶdoc - QDomElement docElem = doc.documentElement(); //ظԪ - QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ - while (!n.isNull()) { //ڵ㲻Ϊ - if (n.isElement()) { //ڵԪ - QDomElement e = n.toElement(); //תΪԪ + //将文件内容读到doc中 + QDomElement docElem = doc.documentElement(); //返回根元素 + QDomNode n = docElem.firstChild(); //返回根节点的第一个子节点 + while (!n.isNull()) { //如果节点不为空 + if (n.isElement()) { //如果节点是元素 + QDomElement e = n.toElement(); //将其转换为元素 QString strTag = e.tagName(); if (strTag == "Work" || strTag == "New") { - QDomNodeList list = e.childNodes(); //Ԫeӽڵб - for (int i = 0; i < list.count(); i++) { //б + QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表 + for (int i = 0; i < list.count(); i++) { //遍历该列表 QDomNode node = list.at(i); if (node.isElement()) { QDomElement recall_e = node.toElement(); @@ -2177,7 +2229,7 @@ int parse_recall_xml(recall_xml_t* recall_xml, char* id) } } } - n = n.nextSibling(); //һֵܽڵ + n = n.nextSibling(); //下一个兄弟节点 } } @@ -2191,7 +2243,7 @@ void process_recall_config(recall_xml_t* recall_xml) recall_t* recall_work; int recall_num; int need_write_file; - QList recallinfo_list_hour; //ж-СʱΪ + QList recallinfo_list_hour; //待补招队列-以小时为最大间隔 need_write_file = FALSE; recall = recall_xml->new_recalls; @@ -2231,7 +2283,7 @@ void process_recall_config(recall_xml_t* recall_xml) LD_info->autorecall[j]->end = recall[j].end_time; - //lnk20241030䲹̬̬־ÿļкܶʱ¼ + //lnk20241030补充补招稳态暂态标志,每个文件都有很多条时间记录 LD_info->autorecall[j]->need_steady = recall[j].need_steady; LD_info->autorecall[j]->need_voltage = recall[j].need_voltage; @@ -2264,7 +2316,7 @@ void WebSocketThread::run() printf("accept client %s:%d failed,error msg=%s\n\a", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), strerror(errno)); continue; } - printf("\naccept client %s:%d succesaddress_len= %dclient_socket= %d\n", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), address_len, client_socket); + printf("\naccept client %s:%d succes,address_len= %d,client_socket= %d\n", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), address_len, client_socket); char buffer[256]; int iRet = 0; @@ -2297,53 +2349,53 @@ void WebSocketThread::run() return; } -string MatchErrorMessage(int errorCode) //ݴƥϢ +string MatchErrorMessage(int errorCode) //根据错误码匹配错误消息 { string strErrorMessage = ""; switch (errorCode) { case 0: - strErrorMessage = "success"; //"ɹ" + strErrorMessage = "success"; //"成功" break; default: - strErrorMessage = "error"; //""; + strErrorMessage = "error"; //"错误"; break; //case 10002: - // strErrorMessage = "Incorrect message length structure"; //"ijȽṹ"; + // strErrorMessage = "Incorrect message length structure"; //"报文长度结构错误"; // break; //case 10003: - // strErrorMessage = "JSON string parsing error"; //"JSONַ"; + // strErrorMessage = "JSON string parsing error"; //"JSON字符串解析出错"; // break; //case 10004: - // strErrorMessage = "Socket handling error"; //"socket쳣"; + // strErrorMessage = "Socket handling error"; //"socket处理出现异常"; // break; //case 10005: - // strErrorMessage = "The device corresponding to ID was not found"; //"IDӦװδҵ"; + // strErrorMessage = "The device corresponding to ID was not found"; //"ID对应的装置未找到"; // break; //case 10006: - // strErrorMessage = "The monitoring point corresponding to ID has not been found"; //"IDӦļδҵ"; + // strErrorMessage = "The monitoring point corresponding to ID has not been found"; //"ID对应的监测点未找到"; // break; //case 10007: - // strErrorMessage = "Wrong parameter passed in"; //"IJ쳣"; + // strErrorMessage = "Wrong parameter passed in"; //"传入的参数异常"; // break; //case 10008: - // strErrorMessage = "The same type of operation is being performed"; //"ͬһ͵IJִ"; + // strErrorMessage = "The same type of operation is being performed"; //"有同一类型的操作正在执行"; // break; //case 10009: - // strErrorMessage = "The device turned off the corresponding function"; //"װùر˶Ӧ"; + // strErrorMessage = "The device turned off the corresponding function"; //"装置关闭了对应功能"; // break; //case 10010: - // strErrorMessage = "The TYPE parameter passed in is exceptional"; //"TYPE쳣"; + // strErrorMessage = "The TYPE parameter passed in is exceptional"; //"传入的TYPE参数异常"; // break; //default: - // strErrorMessage = "An unknown error"; //"δ֪"; + // strErrorMessage = "An unknown error"; //"未知错误"; // break; } return strErrorMessage; } -int SendMessageToWeb(int socketClient, int iErrorCode) //Web Socketͻ˷Ϣ +int SendMessageToWeb(int socketClient, int iErrorCode) //向Web Socket客户端发送消息 { string strSendJson = ""; char cTemp[8]; @@ -2355,7 +2407,7 @@ int SendMessageToWeb(int socketClient, int iErrorCode) // string strErrorMessage = MatchErrorMessage(iErrorCode); //if (2 == Log_Enable) - // printf("룺%dƥ䵽Ϣ%s\n", iErrorCode, strErrorMessage.c_str()); + // printf("错误码:%d,匹配到的消息:%s\n", iErrorCode, strErrorMessage.c_str()); strSendJson = "{\"errors\":\"" + strErrorMessage + "\",\"status\":\"" + strErrorCode + "\"}"; strcpy(sendBuffer, strSendJson.c_str()); @@ -2367,17 +2419,17 @@ int SendMessageToWeb(int socketClient, int iErrorCode) // } //if (1 == Log_Enable) - // printf("ͻ%d[%d]Ϣ%s\n", socketClient, iErrorCode, sendBuffer); + // printf("服务端向客户端%d发送[%d]消息:%s\n", socketClient, iErrorCode, sendBuffer); return sendLength; } -int ExecuteWebCommand(LD_info_t* LD_info, int iType) //ִWeb SocketϢ +int ExecuteWebCommand(LD_info_t* LD_info, int iType) //执行Web Socket命令消息 { try { //if (1 == Log_Enable) - // printf(">>>·%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // printf(">>>线路%d,\"%s\",iType= %d,real_data= %s,soe_data= %s,limit= %d,count= %d\n", LD_info->line_id, LD_info->name, // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); if (0 == iType || 1 == iType) @@ -2388,14 +2440,14 @@ int ExecuteWebCommand(LD_info_t* LD_info, int iType) //ִ LD_info->real_data = 1; LD_info->soe_data = 1; //if (1 == Log_Enable) - // printf(">>>%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // printf(">>>触发%d,\"%s\",iType= %d,real_data= %s,soe_data= %s,limit= %d,count= %d\n", LD_info->line_id, LD_info->name, // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); } else { //LD_info->heart_beat = 1; //if (1 == Log_Enable) - // printf(">>>%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // printf(">>>持续%d,\"%s\",iType= %d,real_data= %s,soe_data= %s,limit= %d,count= %d\n", LD_info->line_id, LD_info->name, // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); } } @@ -2405,29 +2457,29 @@ int ExecuteWebCommand(LD_info_t* LD_info, int iType) //ִ LD_info->real_data = 0; LD_info->soe_data = 0; //if (1 == Log_Enable) - // printf(">>>ֹͣ%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // printf(">>>停止%d,\"%s\",iType= %d,real_data= %s,soe_data= %s,limit= %d,count= %d\n", LD_info->line_id, LD_info->name, // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); } } catch (exception& e) { - printf("/ֹͣ·%d\"%s\"ʧܣԭ%s\n", LD_info->line_id, LD_info->name, e.what()); + printf("触发/停止线路%d,\"%s\"失败,原因:%s\n", LD_info->line_id, LD_info->name, e.what()); return 10004; } return 10000; } -void Get_Recall_Time_Char(char* start_time, char* end_time, QList& recallinfo_list_hour) //Բж +void Get_Recall_Time_Char(char* start_time, char* end_time, QList& recallinfo_list_hour) //数据完整性补招判断 { QDateTime start_dt = QDateTime::fromString(start_time, "yyyy-MM-dd HH:mm:ss"); QDateTime end_dt = QDateTime::fromString(end_time, "yyyy-MM-dd HH:mm:ss"); - long long starttime = start_dt.toMSecsSinceEpoch() / 1000; //ʼʱ - long long endtime = end_dt.toMSecsSinceEpoch() / 1000; //нʱ - QList timestamp_list; //ݿԼ¼ʱ - QList recallinfo_list; //ж + long long starttime = start_dt.toMSecsSinceEpoch() / 1000; //补招起始时间 + long long endtime = end_dt.toMSecsSinceEpoch() / 1000; //补招结束时间 + QList timestamp_list; //数据库完整性记录时间点 + QList recallinfo_list; //待补招队列 RecallInfo info; info.starttime = starttime; @@ -2464,19 +2516,19 @@ void Get_Recall_Time_Char(char* start_time, char* end_time, QList& r } -int HandleReceiveMessage(int socketClient, char buffer[256]) //ղWeb Socketͻ˷Ϣ +int HandleReceiveMessage(int socketClient, char buffer[256]) //接收并处理Web Socket客户端发来的信息 { int iErrorCode = 000000; try { QString qstrBuffer = QString(QLatin1String(buffer)); - printf("ffeͻ%dϢqstrBur= %s\n", socketClient, qstrBuffer.toAscii().data()); - cJSON* json_root = cJSON_Parse(qstrBuffer.toUtf8().constData()); //jsonʽл + printf("来自ffe客户端%d消息:qstrBur= %s\n", socketClient, qstrBuffer.toAscii().data()); + cJSON* json_root = cJSON_Parse(qstrBuffer.toUtf8().constData()); //json格式序列化 if (json_root == NULL) { return 10000; } - QString qstrCode = NULL;//¼ָ + QString qstrCode = NULL;//记录指令 cJSON* json_code = NULL; cJSON* json_param = NULL; cJSON* json_program_param = NULL; @@ -2489,28 +2541,28 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // QList wave_param; ProgramParam program_param; - json_code = cJSON_GetObjectItem(json_root, "code"); //ȡcode + json_code = cJSON_GetObjectItem(json_root, "code"); //获取code if (json_code != NULL) { qstrCode = json_code->valuestring; } else { return 10000; } - json_param = cJSON_GetObjectItem(json_root, "param"); //ȡparam + json_param = cJSON_GetObjectItem(json_root, "param"); //获取param if (json_param == NULL) { return 10000; } if (qstrCode == "dev_update" || qstrCode == "model_update" || qstrCode == "program_update") { - //豸¼¼ʱ - json_update_time = cJSON_GetObjectItem(json_param, "update_time"); //ȡupdate_time + //设备更新记录更新时间 + json_update_time = cJSON_GetObjectItem(json_param, "update_time"); //获取update_time if (json_update_time != NULL) { update_time = json_update_time->valuestring; } } else if (qstrCode == "manual_wave") { - //ֶ¼δ - json_wave_param = cJSON_GetObjectItem(json_param, "wave_param"); //ȡwave_param - int array_size = cJSON_GetArraySize(json_wave_param); //ȡС + //手动录波:功能未完成 + json_wave_param = cJSON_GetObjectItem(json_param, "wave_param"); //获取wave_param + int array_size = cJSON_GetArraySize(json_wave_param); //获取数组大小 int i; for (i = 0; i < array_size; i++) @@ -2523,11 +2575,11 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // } else if (qstrCode == "model_update") { - //նбͳļ - json_program_param = cJSON_GetObjectItem(json_param, "program_param"); //ȡprogram_param + //程序参数:终端列表和程序文件 + json_program_param = cJSON_GetObjectItem(json_param, "program_param"); //获取program_param cJSON* json_temp = NULL; - json_temp = cJSON_GetObjectItem(json_program_param, "terminal_list"); //ȡ - int array_size = cJSON_GetArraySize(json_temp); //ȡС + json_temp = cJSON_GetObjectItem(json_program_param, "terminal_list"); //获取 + int array_size = cJSON_GetArraySize(json_temp); //获取数组大小 int i; for (i = 0; i < array_size; i++) @@ -2537,16 +2589,16 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // program_param.terminal_list.append(json_node->valuestring); } } - json_node = cJSON_GetObjectItem(json_program_param, "file_name"); //ȡfile_name + json_node = cJSON_GetObjectItem(json_program_param, "file_name"); //获取file_name if (json_node != NULL) { program_param.file_name = json_node->valuestring; } } - else if (qstrCode == "manual_recall") {//ֶеָ - //в - json_recall_param = cJSON_GetObjectItem(json_param, "recall_param"); //ȡrecall_param + else if (qstrCode == "manual_recall") {//手动补招的指令 + //补招参数 + json_recall_param = cJSON_GetObjectItem(json_param, "recall_param"); //获取recall_param cJSON* json_temp = NULL; - int array_size = cJSON_GetArraySize(json_recall_param); //ȡС + int array_size = cJSON_GetArraySize(json_recall_param); //获取数组大小 int i; QList recallinfo_list_hour; char start_time[64]; @@ -2556,16 +2608,16 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // { json_temp = cJSON_GetArrayItem(json_recall_param, i);//array if (json_temp != NULL) { - json_node = cJSON_GetObjectItem(json_temp, "mp_id"); //ȡmp_id + json_node = cJSON_GetObjectItem(json_temp, "mp_id"); //获取mp_id if (json_node != NULL) { mp_id = QString::fromUtf8(json_node->valuestring); } if (i == 0) { - json_node = cJSON_GetObjectItem(json_temp, "start"); //ȡstart + json_node = cJSON_GetObjectItem(json_temp, "start"); //获取start if (json_node != NULL) { apr_snprintf(start_time, sizeof(start_time), "%s", json_node->valuestring);//start_time } - json_node = cJSON_GetObjectItem(json_temp, "end"); //ȡend + json_node = cJSON_GetObjectItem(json_temp, "end"); //获取end if (json_node != NULL) { apr_snprintf(end_time, sizeof(end_time), "%s", json_node->valuestring);//end_time } @@ -2576,7 +2628,7 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // jr.MonitorID = mp_id; jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); - jr.STEADY = QString::number(1, 10);//Ĭ϶11ʮת + jr.STEADY = QString::number(1, 10);//默认都是1,1的十进制转化 jr.VOLTAGE = QString::number(1, 10); g_StatisticLackList_list_mutex.lock(); g_StatisticLackList.push_back(jr); @@ -2586,11 +2638,11 @@ int HandleReceiveMessage(int socketClient, char buffer[256]) // } } cJSON_Delete(json_root); - SendMessageToWeb(socketClient, 000000);//Ӧweb + SendMessageToWeb(socketClient, 000000);//响应web } catch (exception& e) { - printf("ͻˣ%d͵Ϣԭ%s\n", socketClient, e.what()); + printf("处理客户端:%d发送的消息错误,原因:%s\n", socketClient, e.what()); return 10004; } return 000000; @@ -2608,12 +2660,12 @@ void Cout_account_information() { LD_info_t* LD_info = NULL; ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); int cpuno; - QString text;//װpgsql + QString text;//待组装的pgsql语句 text.append(QString("terminal_code: \"%1\" ,ip:\"%2\" ,port:\"%3\" ,cpucount:\"%4\" ").arg(ied_usr->terminal_code).arg(ied->channel[0].addr_str).arg(ied->channel[0].port).arg(ied->cpucount)); add_comm_log(const_cast(text.toLocal8Bit().constData())); for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); - QString text2;//װpgsql + QString text2;//待组装的pgsql语句 text2.append(QString("mp_id: \"%1\" terminal_code:\"%2\" ").arg(LD_info->mp_id).arg(LD_info->terminal_code)); add_comm_log(const_cast(text2.toLocal8Bit().constData())); } @@ -2622,26 +2674,26 @@ void Cout_account_information() { } /// -/// ɾڵxml +/// 删除过期的xml /// void DeletcRecallXml() { QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); QString file_name = QString(subdir) + QString("_") + QString("*") + QString("_Recall.xml"); - //ָļ + //指定文件夹名 QDir dir(cfg_dir); if (!dir.exists()) { qDebug() << "folder does not exist!"; return; } QStringList filter(file_name); - //ָͺ򣬰µ޸ʱȡ + //指定查找类型和排序,按最新的修改时间获取 QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); - // 趨˵ںʱ + // 设定过滤的日期和时间 QDateTime saveDaysAgo = QDateTime::currentDateTime().addDays(-2); - for (int i = 0; i < files.size(); i++) {//նȡļ + for (int i = 0; i < files.size(); i++) {//清空读取文件 QFileInfo fileInfo(dir.filePath(files[i])); if (fileInfo.lastModified() < saveDaysAgo) { QFile::remove(fileInfo.absoluteFilePath()); @@ -2660,7 +2712,7 @@ void CreateRecallXml() g_StatisticLackList_list_mutex.lock(); if (g_StatisticLackList.size() > 0) { - printf("insert ID_CJournalRecall_Map\n"); + printf("insert ID_CJournalRecall_Map!\n"); QMap > ID_CJournalRecall_Map; list::iterator sl = g_StatisticLackList.begin(); @@ -2690,7 +2742,7 @@ void CreateRecallXml() std::string strRecallPath = qstrRecallPath.toStdString(); QFile file(strRecallPath.c_str()); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - printf("вѯ,%sʧ,޷д·ã\n", qstrRecallPath.toAscii().data()); + printf("补招查询完成,打开%s失败,无法写入线路补招配置!\n", qstrRecallPath.toAscii().data()); QMap >().swap(ID_CJournalRecall_Map); return; } @@ -2726,9 +2778,9 @@ void CreateRecallXml() g_StatisticLackList.clear(); g_StatisticLackList_list_mutex.unlock(); } -///////zw޸ 2023-8-30 end +///////zw修改 2023-8-30 end -/*/////////////////////////////////////////////////////////lnk2024-10-11ƳsqlIJԴ/////////////////////////////////////////////////////////////*/ +/*/////////////////////////////////////////////////////////lnk2024-10-11移除sql的测试代码/////////////////////////////////////////////////////////////*/ std::string intToString(int number) { if (number == 0) return "0"; std::string str; @@ -2747,17 +2799,17 @@ std::string intToString(int number) { otl_datetime parseTimestamp(const std::string timestampStr) { otl_datetime timestamp; - // ꡢ¡աʱ֡ + // 定义年、月、日、时、分、秒变量 int year, month, day, hour, minute, second; - // ʹַн + // 使用字符串流进行解析 std::istringstream ss(timestampStr); - char discard; // ڶָ + char discard; // 用于丢弃分隔符 - // ַ + // 解析字符串 ss >> year >> discard >> month >> discard >> day >> hour >> discard >> minute >> discard >> second; - // ֵ otl_datetime + // 将解析的值赋给 otl_datetime timestamp.year = year; timestamp.month = month; timestamp.day = day; @@ -2777,45 +2829,45 @@ size_t req_reply_web(void* ptr, size_t size, size_t nmemb, void* stream) void SendWebAPI_web(const string strUrl, const char* code, char** ptr) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { char url[100]; sprintf(url, "%s?%s", strUrl.c_str(), code); - //printf(">>>json %s\n", url);//ٲҪĴӡ - // URL + //printf(">>>json %s\n", url);//减少不必要的打印 + // 设置URL curl_easy_setopt(curl, CURLOPT_URL, url); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); - //ݽ + //数据接收 string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); - //header + //设置header curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("web failed res code: "); } else { printf(">>> web return str:%s \n", resPost0.c_str()); - *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 㹻ڴռ + *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 分配足够的内存空间 if (*ptr != NULL) { strcpy(*ptr, resPost0.c_str()); } @@ -2831,23 +2883,23 @@ void SendWebAPI_web(const string strUrl, const char* code, char** ptr) curl_easy_cleanup(curl); } -/*/////////////////////////////////////////////////////////lnk10-24webӿ޸/////////////////////////////////////////////////////////////*/ -//jsonַ -// صֱ׷ӵ *ptr +/*/////////////////////////////////////////////////////////lnk10-24根据web接口修改/////////////////////////////////////////////////////////////*/ +//添加了json字符串的入参 +// 回调函数,将数据直接追加到 *ptr 中 size_t req_reply_http(void* contents, size_t size, size_t nmemb, void* userp) { size_t realsize = size * nmemb; char** responsePtr = (char**)userp; - size_t oldLen = strlen(*responsePtr); // ǰг - char* temp = (char*)realloc(*responsePtr, oldLen + realsize + 1); // +1 ռ '\0' + size_t oldLen = strlen(*responsePtr); // 当前已有长度 + char* temp = (char*)realloc(*responsePtr, oldLen + realsize + 1); // +1 留空间给 '\0' if (temp == NULL) { printf("Memory reallocation failed!\n"); return 0; } *responsePtr = temp; - memcpy(*responsePtr + oldLen, contents, realsize); // ֱӿԭʼ - (*responsePtr)[oldLen + realsize] = '\0'; // ֶַ + memcpy(*responsePtr + oldLen, contents, realsize); // 直接拷贝原始数据 + (*responsePtr)[oldLen + realsize] = '\0'; // 手动添加字符串结束符 return realsize; } @@ -2856,18 +2908,18 @@ void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::str CURL* curl = curl_easy_init(); CURLcode res; - // ʼ *ptr ַ + // 初始化 *ptr 并分配空字符串 *ptr = (char*)malloc(1); if (*ptr == NULL) { printf("Memory allocation failed!\n"); return; } - (*ptr)[0] = '\0'; // ΪַԱ strncat + (*ptr)[0] = '\0'; // 为空字符串以便 strncat 操作 if (curl) { char url[256]; snprintf(url, sizeof(url), "%s?%s", strUrl.c_str(), code); - //printf(">>>json %s\n", url);//ٲҪĴӡ + //printf(">>>json %s\n", url);//减少不必要的打印 curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_http); @@ -2899,7 +2951,7 @@ void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::str } } /*void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr) { - // curl ʼ + // curl 初始化 CURL* curl = curl_easy_init(); CURLcode res; @@ -2908,44 +2960,44 @@ void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::str sprintf(url, "%s?%s", strUrl.c_str(), code); printf(">>>json %s\n", url); - // URL + // 设置 URL curl_easy_setopt(curl, CURLOPT_URL, url); - // ݽպд뺯 + // 设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); - // ݽ + // 数据接收 std::string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); - // óʱʱ + // 设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); if(json != ""){ - // HTTP Ϊ POST + // 设置 HTTP 方法为 POST curl_easy_setopt(curl, CURLOPT_POST, 1L); - // JSON ʽ body + // 设置 JSON 格式的 body 数据 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str()); } - // ͷ + // 设置请求头 struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - // ִ + // 执行请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("web failed res code: %s\n", curl_easy_strerror(res)); } else { printf(">>> web return str: %s \n", resPost0.c_str()); - // ڴ沢Ʒؽ - *ptr = (char*)malloc(resPost0.size() + 1); // 㹻ڴռ + // 分配内存并复制返回结果 + *ptr = (char*)malloc(resPost0.size() + 1); // 分配足够的内存空间 if (*ptr != NULL) { strcpy(*ptr, resPost0.c_str()); } else { @@ -2953,7 +3005,7 @@ void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::str } } - // ͷ + // 清理请求头 curl_slist_free_all(headers); } else { printf(">>> web curl init failed"); @@ -2961,7 +3013,7 @@ void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::str curl_easy_cleanup(curl); }*/ -// ӡ terminal_dev_map ݵĺ +// 打印 terminal_dev_map 中所有内容的函数 void printTerminalDevMap(const QMap& terminal_dev_map) { QMap::const_iterator it; for (it = terminal_dev_map.constBegin(); it != terminal_dev_map.constEnd(); ++it) { @@ -2985,7 +3037,7 @@ void printTerminalDevMap(const QMap& terminal_dev_map) { << ", Port:" << QString(dev->port) << ", Timestamp:" << QString(dev->timestamp); - // ӡϢ + // 打印监测点信息 for (int i = 0; i < 10; ++i) { qDebug() << " Monitor ID:" << QString(dev->line[i].monitor_id) << ", Terminal Code:" << QString(dev->line[i].terminal_code) @@ -3002,8 +3054,8 @@ void printTerminalDevMap(const QMap& terminal_dev_map) { } } -//ӡǰ̵̨////////////////////////////////////////////////////////////////////////// -// ӡṹϢĵݹ麯 +//打印当前进程的台账////////////////////////////////////////////////////////////////////////// +// 打印结构体信息的递归函数 void printLedger(const ied_usr_t& ied_usr) { std::cout << "------------------------------------" << std::endl; std::cout << "|-- terminal_id: " << ied_usr.terminal_id << std::endl; @@ -3024,7 +3076,7 @@ void printLedger(const ied_usr_t& ied_usr) { std::cout << "|-- terminal_code: " << ied_usr.terminal_code << std::endl; std::cout << "|-- update_flag: " << ied_usr.update_flag << std::endl; - // ӡÿLD_info + // 打印每个LD_info的内容 for (int i = 0; i < 10; ++i) { if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) { std::cout << "|-- LD_info[" << i << "]:" << std::endl; @@ -3044,7 +3096,7 @@ void printLedger(const ied_usr_t& ied_usr) { std::cout << " |-- time: " << ied_usr.LD_info[i].time << std::endl; std::cout << " |-- update_flag: " << ied_usr.LD_info[i].update_flag << std::endl; std::cout << " |-- monitor_status: " << ied_usr.LD_info[i].monitor_status << std::endl; -//countݲӡ +//count暂不打印数组 std::cout << " |-- rptcount: " << ied_usr.LD_info[i].rptcount << std::endl; std::cout << " |-- logcount: " << ied_usr.LD_info[i].logcount << std::endl; //rpt @@ -3093,12 +3145,12 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_index: " + QByteArray::number(ied_usr.dev_idx) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_cpucount: " + QByteArray::number(ied->cpucount) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_ip: " + QByteArray(ied->channel[0].addr_str) + "\n"); - char portStr[20]; // ڴŶ˿ںŵַ - sprintf(portStr, "%u", ied->channel[0].port); // ˿ںתΪַ + char portStr[20]; // 用于存放端口号的字符串 + sprintf(portStr, "%u", ied->channel[0].port); // 将端口号转为字符串 outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_port: " + QByteArray(portStr) + "\n"); - char statusStr[20]; // ڴ״ַ̬ - sprintf(statusStr, "%u", ied->channel[0].status); // ״̬תΪַ + char statusStr[20]; // 用于存放状态的字符串 + sprintf(statusStr, "%u", ied->channel[0].status); // 将连接状态转为字符串 outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_connect_status: " + QByteArray(statusStr) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_type: " + QByteArray(ied_usr.dev_type) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write("|-- dev_key: " + QByteArray(ied_usr.dev_key) + "\n"); @@ -3115,7 +3167,7 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K");outputDevice->write("|-- terminal_code: " + QByteArray(ied_usr.terminal_code) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write("|-- update_flag: " + QByteArray::number(ied_usr.update_flag) + "\n"); - // ӡÿLD_info + // 打印每个LD_info的内容 for (int i = 0; i < 10; ++i) { if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) { outputDevice->write("\r\x1B[K");outputDevice->write("|-- LD_info[" + QByteArray::number(i) + "]:\n"); @@ -3139,7 +3191,7 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K");outputDevice->write(" |-- update_flag: " + QByteArray::number(ied_usr.LD_info[i].update_flag) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write(" |-- monitor_status: " + QByteArray(ied_usr.LD_info[i].monitor_status) + "\n"); - // countݲӡ + // count暂不打印数组 outputDevice->write("\r\x1B[K");outputDevice->write(" |-- rptcount: " + QByteArray::number(ied_usr.LD_info[i].rptcount) + "\n"); outputDevice->write("\r\x1B[K");outputDevice->write(" |-- logcount: " + QByteArray::number(ied_usr.LD_info[i].logcount) + "\n"); @@ -3148,7 +3200,7 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K");outputDevice->write(" |-- autorecallcount: " + QByteArray::number(ied_usr.LD_info[i].autorecallcount) + "\n"); for (int j = 0; j < ied_usr.LD_info[i].autorecallcount && - ied_usr.LD_info[i].autorecall != NULL && // LD_info->autorecall + ied_usr.LD_info[i].autorecall != NULL && // 保护 LD_info->autorecall 本身 ied_usr.LD_info[i].autorecall[j] != NULL; j++) { @@ -3157,7 +3209,7 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { if (ied_usr.LD_info[i].autorecall[j] == NULL) { outputDevice->write(" |-- [Error] autorecall[j] is NULL\n"); - continue; // NULL ָ + continue; // 避免访问 NULL 指针 } outputDevice->write("\r\x1B[K"); @@ -3211,7 +3263,7 @@ void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K");outputDevice->write("------------------------------------\n"); } -// ӡ豸ϢضնϢ +// 打印所有设备信息或特定终端信息 void ledger(const char* terminal_id, QIODevice* outputDevice) { outputDevice->write("\r\x1B[K"); outputDevice->write("print ledger in shell"); @@ -3224,7 +3276,7 @@ void ledger(const char* terminal_id, QIODevice* outputDevice) { if(ied != NULL){ ied_usr = (ied_usr_t*)ied->usr_ext; if (ied_usr != NULL && (terminal_id == NULL || strcmp(ied_usr->terminal_id, terminal_id) == 0)) { - printLedgerinshell(*ied_usr, outputDevice); // ʹ QIODevice + printLedgerinshell(*ied_usr, outputDevice); // 使用 QIODevice 输出 //std::cout << "!!! print to log !!!"<< std::endl; //printLedger(*ied_usr); if(terminal_id != NULL && strcmp(ied_usr->terminal_id, terminal_id) == 0){ @@ -3240,22 +3292,22 @@ void ledger(const char* terminal_id, QIODevice* outputDevice) { std::cout << "terminal not exsist: " << terminal_id << std::endl; QByteArray msg = "terminal not exsist: " + QByteArray(terminal_id) + "\n"; outputDevice->write("\r\x1B[K"); - outputDevice->write(msg); // QIODevice + outputDevice->write(msg); // 输出到 QIODevice } } -//lnk20250210ӡָı +//lnk20250210打印指定的变量名 void value_print(const char *variableName, QTcpSocket *clientSocket) { - char buffer[256]; // ڴ洢ֵĻ + char buffer[256]; // 用于存储变量值的缓冲区 pthread_mutex_lock(&mtx); std::cout << "value_print hold lock !!!!!!!!!!!" << std::endl; - // ӡֵ + // 打印变量值 if (strcmp(variableName, "frontindex") == 0) { - sprintf(buffer, "frontindex = %d", g_front_seg_index); // int תΪַ + sprintf(buffer, "frontindex = %d", g_front_seg_index); // 将 int 转换为字符串 clientSocket->write("\r\x1B[K"); - clientSocket->write(buffer); // ַͻ + clientSocket->write(buffer); // 发送字符串到客户端 } else if (strcmp(variableName, "remtable") == 0) { sprintf(buffer, "remtable = %d",g_pt61850app->chnl_counts); @@ -3323,17 +3375,17 @@ void Worker::handleViewLogCommand(const QString& command, QTcpSocket* clientSock } stopViewLog = false; - activeClient = clientSocket; // ¼ǰ shell socket + activeClient = clientSocket; // 记录当前 shell socket clientSocket->write("\r\x1B[K"); clientSocket->write(QString("Viewing logs for level: %1 (Press '`' to exit)\n> ").arg(logLevel).toUtf8()); clientSocket->flush(); while (!stopViewLog) { - // **1. 룬û ``` ˳** - if (clientSocket->waitForReadyRead(500)) { // ? + // **1. 监听输入,用户输入 ``` 退出** + if (clientSocket->waitForReadyRead(500)) { // ? 监听输入 QByteArray input = clientSocket->readAll().trimmed(); - if (input == "`") { // ? û ```˳־ģʽ + if (input == "`") { // ? 用户输入 ```,退出日志模式 std::cout << "Received '`' from shell socket! Exiting viewlog...\n"; stopViewLog = true; showinshellflag = false; @@ -3341,7 +3393,7 @@ void Worker::handleViewLogCommand(const QString& command, QTcpSocket* clientSock } } - // **2. ȡ־ݲ** + // **2. 获取日志内容并发送** pthread_mutex_lock(logMutex); if (!logList->empty()) { std::string logEntry = logList->front(); @@ -3355,39 +3407,39 @@ void Worker::handleViewLogCommand(const QString& command, QTcpSocket* clientSock } } else { pthread_mutex_unlock(logMutex); - usleep(500000); // ? ֹ CPU 100% ռ + usleep(500000); // ? 防止 CPU 100% 占用 } } - // **3. ˳ `viewlog` Shell** + // **3. 退出 `viewlog`,返回 Shell** clientSocket->write("\r\x1B[K"); clientSocket->write("\nLog view stopped. Returning to shell.\n> "); clientSocket->flush(); } ////////////////////////////////////////////////////////////////////////////////////////////////// -// JSON ĺ ǰö̬ +// 解析 JSON 的函数 多前置动态均分 int terminal_ledger_web(QMap* terminal_dev_map, const std::vector& codes, int index, int num) { - //޸ΪindexȡӦ̨ˣnumûˣindexֵҲû + //后续修改为根据index来获取对应的台账,num就没有作用了,index用来均分的也没有作用了 if(1 == MULTIPLE_NODE_FLAG){ - // ֤ + // 参数验证 if (num <= 0) { std::cerr << "Error: 'num' must be greater than 0." << std::endl; - return 1; // ʵĴ + return 1; // 返回适当的错误码 } index = index - 1; if (index < 0 || index >= num) { std::cerr << "Error: 'index' must be in the range [0, num-1]." << std::endl; - return 1; // ʵĴ + return 1; // 返回适当的错误码 } } - // ȡ + // 获取参数 if (codes.empty()) { std::cerr << "Error: 'codes' vector is empty." << std::endl; return 1; @@ -3397,7 +3449,7 @@ int terminal_ledger_web(QMap* terminal_dev_map, char* ptr = NULL; - // API + // 发送 API 请求 SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr); if (ptr == NULL) { @@ -3405,24 +3457,24 @@ int terminal_ledger_web(QMap* terminal_dev_map, return 1; } - // + // 调试用 printf("ptr:%s\n", ptr); - cJSON* root = cJSON_Parse(ptr); //jsonʽл + cJSON* root = cJSON_Parse(ptr); //json格式序列化 int retry = 0; if (root == NULL) { printf("web error %s\n", cJSON_GetErrorPtr()); - //ط + //重发多次 while(root == NULL){ - // ǰͷ֮ǰ ptr Աڴй© + // 在重试前释放之前的 ptr 以避免内存泄漏 if (ptr != NULL) { free(ptr); ptr = NULL; } - //url + //测试用url参数 //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr); @@ -3434,26 +3486,26 @@ int terminal_ledger_web(QMap* terminal_dev_map, root = cJSON_Parse(ptr); retry++;if(retry>3)break; } - // ԺȻʧܣȷ˳ǰͷκѷڴ + // 如果重试后仍然失败,确保退出前释放任何已分配的内存 if (root == NULL) { printf("web error %s\n", cJSON_GetErrorPtr()); - return 1; // ҪʵĴ + return 1; // 根据需要返回适当的错误码 } } - // ȡ "code" "msg" + // 获取 "code" 和 "msg" cJSON* codeItem = cJSON_GetObjectItem(root, "code"); cJSON* msgItem = cJSON_GetObjectItem(root, "msg"); - // ʹ std::string ȡֵ + // 使用 std::string 获取值 std::string code = (codeItem != NULL && codeItem->type == cJSON_String) ? codeItem->valuestring : "not found"; std::string msg = (msgItem != NULL && msgItem->type == cJSON_String) ? msgItem->valuestring : "not found"; - // ӡ + // 打印结果 std::cout << "code: " << code << std::endl; std::cout << "msg: " << msg << std::endl; - // ȡ "data" + // 获取 "data" 数组 cJSON* data = cJSON_GetObjectItem(root, "data"); if (!data || data->type != cJSON_Array) { std::cerr << "Error: 'data' is not an array." << std::endl; @@ -3473,7 +3525,7 @@ int terminal_ledger_web(QMap* terminal_dev_map, return 1; } - //޸ΪindexȡӦ̨ˣپ֣ȡ̨˲жϽ̺ + //后续修改为根据index来获取对应的台账,将不再均分,获取所有台账并判断进程号 #if 0 int base_size = 0; int remainder = 0; @@ -3481,15 +3533,15 @@ int terminal_ledger_web(QMap* terminal_dev_map, int end_index = data_size; if(1 == MULTIPLE_NODE_FLAG){ - // ÿݵĴС + // 计算每份的大小 base_size = data_size / num; remainder = data_size % num; - // 㵱ǰݵʼͽ + // 计算当前份的起始和结束索引 start_index = index * base_size + (index < remainder ? index : remainder); end_index = start_index + base_size + (index < remainder ? 1 : 0); - // ȷС + // 确保结束索引不超过数组大小 if (end_index > data_size) { end_index = data_size; } @@ -3498,18 +3550,18 @@ int terminal_ledger_web(QMap* terminal_dev_map, int start_index = 0; int end_index = data_size; - // ָΧڵԪ + // 遍历指定范围内的元素 for (int i = start_index; i < end_index; ++i) { cJSON* item = cJSON_GetArrayItem(data, i); if (!item || item->type != cJSON_Object) { std::cerr << "Warning: Invalid item at index " << i << "." << std::endl; - continue; // Ч + continue; // 跳过无效的项 } terminal_dev* dev = new terminal_dev(); - memset(dev, 0, sizeof(terminal_dev)); // ʼṹ + memset(dev, 0, sizeof(terminal_dev)); // 初始化结构体 - // ֶ + // 解析各个字段 cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id if (id && id->type == cJSON_String) strncpy(dev->terminal_id, id->valuestring, sizeof(dev->terminal_id) - 1); else strncpy(dev->terminal_id, "N/A", sizeof(dev->terminal_id) - 1); @@ -3554,8 +3606,8 @@ int terminal_ledger_web(QMap* terminal_dev_map, if (series && series->type == cJSON_String) strncpy(dev->dev_series, series->valuestring, sizeof(dev->dev_series) - 1); else strncpy(dev->dev_series, "N/A", sizeof(dev->dev_series) - 1); - //lnk20250210̨˽̺ - cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNoתΪַ + //lnk20250210台账进程号 + cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNo转为字符串 if (processNo && processNo->type == cJSON_Number) snprintf(dev->processNo, sizeof(dev->processNo), "%d", processNo->valueint); else strncpy(dev->processNo, "N/A", sizeof(dev->processNo) - 1); @@ -3567,15 +3619,15 @@ int terminal_ledger_web(QMap* terminal_dev_map, if (updateTime && updateTime->type == cJSON_String) strncpy(dev->timestamp, updateTime->valuestring, sizeof(dev->timestamp) - 1); else strncpy(dev->timestamp, "N/A", sizeof(dev->timestamp) - 1); - // monitorData + // 解析 monitorData 数组 cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData"); if (monitorData && monitorData->type == cJSON_Array) { int j = 0; cJSON* monitorItem; cJSON_ArrayForEach(monitorItem, monitorData) { if (j >= 10){ - std::cout << "һնֻʮ" << std::endl; - break; // Ϊ10 + std::cout << "一个终端最多只能有十个监测点" << std::endl; + break; // 限制为最多10个 } cJSON* monitor_id = cJSON_GetObjectItem(monitorItem, "id"); // monitor_id @@ -3598,7 +3650,7 @@ int terminal_ledger_web(QMap* terminal_dev_map, if (ptType && ptType->type == cJSON_String) strncpy(dev->line[j].terminal_connect, ptType->valuestring, sizeof(dev->line[j].terminal_connect) - 1); else strncpy(dev->line[j].terminal_connect, "N/A", sizeof(dev->line[j].terminal_connect) - 1); - // Ӽ״̬ + // 添加监测点状态 cJSON* monitorstatus = cJSON_GetObjectItem(monitorItem, "status"); // status if (monitorstatus && monitorstatus->type == cJSON_String) strncpy(dev->line[j].status, monitorstatus->valuestring, sizeof(dev->line[j].status) - 1); else strncpy(dev->line[j].status, "N/A", sizeof(dev->line[j].status) - 1); @@ -3607,106 +3659,106 @@ int terminal_ledger_web(QMap* terminal_dev_map, } } - // ׼ - QString key = QString(dev->terminal_id);//idcode֣еcode + // 准备键 + QString key = QString(dev->terminal_id);//用id而不是code区分:有的code存在乱码 - // Ƿظ + // 检查是否存在重复键 if (terminal_dev_map->contains(key)) { std::cerr << "Duplicate terminal_code found: " << key.toStdString() << std::endl; - // ɾɵ terminal_dev Աڴй© + // 删除旧的 terminal_dev 对象以避免内存泄漏 delete terminal_dev_map->value(key); - // Ƴɵļֵ + // 移除旧的键值对 terminal_dev_map->remove(key); - // µ terminal_dev - if(atoi(dev->processNo) == g_front_seg_index || g_front_seg_index == 0){//lnk20250210ƥ̺ - // + // 插入新的 terminal_dev 对象 + if(atoi(dev->processNo) == g_front_seg_index || g_front_seg_index == 0){//lnk20250210匹配进程号 + //调试用 std::cout<< "process num match" << std::endl; - terminal_dev_map->insert(key, dev);}//޸Ϊֻн̺ƥindex¼뵱ǰ + terminal_dev_map->insert(key, dev);}//后续修改为只有进程号匹配上index才录入当前进程 } else { - // µ terminal_dev - if(atoi(dev->processNo) == g_front_seg_index || g_front_seg_index == 0){//lnk20250210ƥ̺ - // + // 插入新的 terminal_dev 对象 + if(atoi(dev->processNo) == g_front_seg_index || g_front_seg_index == 0){//lnk20250210匹配进程号 + //调试用 std::cout<< "process num match" << std::endl; - terminal_dev_map->insert(key, dev);}//޸Ϊֻн̺ƥindex¼뵱ǰ - // + terminal_dev_map->insert(key, dev);}//后续修改为只有进程号匹配上index才录入当前进程 + //调试用 //std::cout << "i = " << i << std::endl; //std::cout << "terminal_dev_map.size:" << terminal_dev_map->size() << std::endl; - }//ظ־ҪַŲ + }//如果出现重复项,日志要有体现方便排查 } - // ͷԴ + // 释放资源 cJSON_Delete(root); free(ptr); - return 0; // ȷзֵ + return 0; // 确保函数有返回值 } int parse_device_cfg_web() { std::cout << "parse_device_cfg_web" << endl; - std::vector codes; //μ + std::vector codes; //入参集合 ied_t* ied; ied_usr_t* ied_usr; chnl_usr_t* chnl_usr; - int count_cfg = 0; //ն̨ - int count_real = 0; //ն̨˵ļ + int count_cfg = 0; //终端台账总数 + int count_real = 0; //遍历终端台账的计数器 - //ӿںϲֻһwebӿڻȡն̨˺ͼ̨ + //接口合并,只用一个web接口获取终端台账和监测点台账 QMap terminal_dev_map; - //json + //构造入参json std::string input_jstr = "{"; input_jstr += "\"ip\":\"" + std::string(FRONT_IP) + "\","; input_jstr += "\"runFlag\":" + TERMINAL_STATUS + ""; input_jstr += "}"; - std::cout << "input_jstr: " << input_jstr << std::endl; // + std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果 - codes.push_back(input_jstr); //ǷҪɸѡ״ֱ̬ļ + codes.push_back(input_jstr); //是否需要筛选状态直接在配置文件控制 terminal_ledger_web(&terminal_dev_map,codes,g_front_seg_index,g_front_seg_num); codes.clear(); - // + //调试用 //printTerminalDevMap(terminal_dev_map); - count_cfg = terminal_dev_map.size();//̨˵ + count_cfg = terminal_dev_map.size();//容器的数量就是台账的数量 std::cout << "terminal_ledger_num:" << count_cfg << std::endl; g_node->n_clients = count_cfg; - //↑ٵiedĿռļеն̨lnk20250121 - if(IED_COUNT < count_cfg){ //dzʼܶȡֹ̨ʧµı - //Ƕ̣IED_COUNTӦΪƽ - //ǵӦΪն - //̶ͬʱ򵥽Ӧôն̨ʱ̲־޷ͬӡ + //这里开辟的ied的空间由配置文件中的终端台账数量决定lnk20250121 + if(IED_COUNT < count_cfg){ //申请数至少是初始化能读取到的台账数,防止设置失误导致的崩溃。 + //如果是多进程,IED_COUNT应该设置为大于平均数, + //如果是单进程则应该设置为大于终端总数, + //单进程多进程同时存在则单进程应该大于终端总数,否则添加台账时单进程部分就无法同步添加。 g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); - //ʾ + //添加提示 std::cout << "!!!!!!!!!!single process can not add any ledger unless reboot!!!!!!!"<< std::endl; } else{ - g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, IED_COUNT * sizeof(ied_t*));//g_node->clients ڴռ洢 count_cfg ied_t* ͵ָ루һָ飩ǣָڴָ룩ָ + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, IED_COUNT * sizeof(ied_t*));//g_node->clients 这块大内存空间存储了 count_cfg 个 ied_t* 类型的指针(即一个指针数组)这是(指向内存块的指针)的指针数组 } - //ied + //把ied放入数组 for (int k = 0; k < count_cfg; k++){ - // + //调试用 std::cout << "!!!!!!!!!!gnodeindex:" << k << std::endl; - g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));}//ÿ g_node->clients[k] ָڴǶģÿ ied_t ṹռõڴ飩ָڴָ + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));}//每个 g_node->clients[k] 指向的内存块是独立的(每个 ied_t 结构体占用的内存块)这是指向内存块的指针 -//ȡն̨˱滻Ϊwebӿ +//读取终端台账表替换为web接口 ////////////////////////////////////////////////////////////////////////////////////////////////// - // + //读数据 try { char terminal_id[64]; char terminal_code[64]; @@ -3721,19 +3773,19 @@ int parse_device_cfg_web() char addr_str[64]; char port_char[64]; - //lnk20250210ӽ̺ + //lnk20250210添加进程号 char processNo[64]; otl_datetime timestamp; - // ն̨ + // 遍历终端台账容器 QMap::iterator it; for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) { terminal_dev* value = it.value(); - // ȷ value Ϊ + // 确保 value 不为空 if (value != nullptr) { - // ҵжӦƲȡֵ + // 找到容器中对应名称并取值 strncpy(terminal_id, value->terminal_id, sizeof(terminal_id) - 1); strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1); strncpy(org_name, value->org_name, sizeof(org_name) - 1); @@ -3746,29 +3798,29 @@ int parse_device_cfg_web() strncpy(dev_series, value->dev_series, sizeof(dev_series) - 1); strncpy(addr_str, value->addr_str, sizeof(addr_str) - 1); strncpy(port_char, value->port, sizeof(port_char) - 1); - strncpy(processNo, value->processNo, sizeof(processNo) - 1);//̺ + strncpy(processNo, value->processNo, sizeof(processNo) - 1);//进程号 timestamp = parseTimestamp(value->timestamp); - //ն̨ + //处理终端台账 ied = g_node->clients[count_real++]; - //Ŀռiedصied - ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));//ն̨initpoolռ + //这里申请的空间基于ied的数量,挂载到ied上 + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));//终端台账在initpool中申请空间 ied->usr_ext = ied_usr; if (ied_usr == NULL) return APR_ENOMEM; ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; - //Ŀռiedصied - ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//̨initpoolռ + //这里申请的空间基于ied的数量,挂载到ied上 + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//监测点台账在initpool中申请空间 if (ied_usr->LD_info == NULL) return APR_ENOMEM; - ied_usr->dev_flag = ENABLE;//նЧ - ied->chncount = 1;//豸ͨŶ˿ - //Ŀռiedصied - ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//ͨŽṹg_cfg_poolռ䣺ն˵ip˿ڵ + ied_usr->dev_flag = ENABLE;//终端有效 + ied->chncount = 1;//设备通信端口总数 + //这里申请的空间基于ied的数量,挂载到ied上 + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//通信结构在g_cfg_pool中申请空间:终端的ip端口等 ied->channel[0].ied = ied; ied->channel[0].status = STATUS_BREAKOFF; ied->cpucount = 0; @@ -3781,7 +3833,7 @@ int parse_device_cfg_web() apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl; } - /*ҪϢ + /*不需要这三个信息 if (org_name != NULL) { apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name cout << "ied_usr->org_name:" << ied_usr->org_name << endl; @@ -3810,7 +3862,7 @@ int parse_device_cfg_web() cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl; } - //lnk20250210̨˽̺ + //lnk20250210台账进程号 if (processNo != NULL) { apr_snprintf(ied_usr->processNo, sizeof(ied_usr->processNo), "%s", processNo);//processNo cout << "ied_usr->processNo:" << ied_usr->processNo << endl; @@ -3835,7 +3887,7 @@ int parse_device_cfg_web() cout << "defalut dev_key:" << ied_usr->dev_key << endl; } - //lnk20241125ʵʱ + //lnk20241125实时数据用 ied_usr->dev_idx = count_real; cout << "dev_idx:" << ied_usr->dev_idx << endl; @@ -3855,20 +3907,20 @@ int parse_device_cfg_web() if (port_char != NULL) { int port = 102; if (stringToInt(port_char, &port)) { - // תɹportStrȫΪ֣ѾתΪint͵port + // 转换成功,portStr全为数字,并且已经转换为int类型的port ied->channel[0].port = port;//DEV_PortID cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID } else { ied->channel[0].port = 102;//DEV_PortID - cout << "ied_usr->port:" << port_char << ",ǺϷ˿.ʹĬ϶˿:" << ied->channel[0].port << endl;//DEV_PortID + cout << "ied_usr->port:" << port_char << ",非合法端口.使用默认端口:" << ied->channel[0].port << endl;//DEV_PortID } } if (timestamp.year != 0) { - //// struct tm + //// 构造struct tm对象 struct tm timeinfo; - timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 - timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900 + timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1 timeinfo.tm_mday = timestamp.day; timeinfo.tm_hour = timestamp.hour; timeinfo.tm_min = timestamp.minute; @@ -3878,8 +3930,8 @@ int parse_device_cfg_web() cout << "ied_usr->time:" << ied_usr->time << endl; } - //Ŀռiedصied - chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));//չͨŽṹg_init_poolռ䣺չ¼һЩʱϢ + //这里申请的空间基于ied的数量,挂载到ied上 + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t));//拓展定义的通信结构在g_init_pool中申请空间:拓展记录一些开关时间信息 ied->channel[0].connect = chnl_usr; chnl_usr->chnl = &(ied->channel[0]); chnl_usr->chnl_id = 0; @@ -3887,14 +3939,14 @@ int parse_device_cfg_web() chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); g_pt61850app->chnl_counts++; - // + //调试用 //std::cout << "value:" << terminal_id <<" "<n_clients << std::endl; if (g_node->n_clients <= 0) { @@ -3911,45 +3963,45 @@ int parse_device_cfg_web() char monitor_status[64]; //otl_datetime timestamp; - //for (int j = 0; j < 10; ++j) { // 10 + //for (int j = 0; j < 10; ++j) { // 假设最多有10个监测点 for (int j = 0; value->line[j].monitor_id[0] != '\0'; ++j){ ledger_monitor& monitor = value->line[j]; - // ID ǷΪԱЧ + // 检查监测点 ID 是否为空以避免访问无效数据 /*if (monitor.monitor_id[0] != '\0') { std::cout << " Monitor ID: " << monitor.monitor_id << std::endl; - std::cout << " Terminal Code: " << monitor.terminal_code << std::endl; //ӦΪգjson + std::cout << " Terminal Code: " << monitor.terminal_code << std::endl; //应该为空,json不带 std::cout << " Monitor Name: " << monitor.monitor_name << std::endl; std::cout << " Logical Device Seq: " << monitor.logical_device_seq << std::endl; std::cout << " Voltage Level: " << monitor.voltage_level << std::endl; std::cout << " Terminal Connect: " << monitor.terminal_connect << std::endl; - std::cout << " Timestamp: " << monitor.timestamp << std::endl; //ӦΪjson + std::cout << " Timestamp: " << monitor.timestamp << std::endl; //应该为空json不带 std::cout << " monitor_status: " << monitor.status << std::endl;*/ strncpy(monitor_id, monitor.monitor_id, sizeof(monitor_id) - 1); - //strncpy(terminal_code, monitor.terminal_code, sizeof(terminal_code) - 1); //ϼȡ + //strncpy(terminal_code, monitor.terminal_code, sizeof(terminal_code) - 1); //从上级获取 strncpy(monitor_name, monitor.monitor_name, sizeof(monitor_name) - 1); strncpy(logical_device_seq, monitor.logical_device_seq, sizeof(logical_device_seq) - 1); strncpy(voltage_level, monitor.voltage_level, sizeof(voltage_level) - 1); strncpy(terminal_connect, monitor.terminal_connect, sizeof(terminal_connect) - 1); - //timestamp = parseTimestamp(monitor.timestamp); //ϼȡ - strncpy(monitor_status, monitor.status, sizeof(monitor_status) - 1);//Ӽ״̬ - //̨˴ + //timestamp = parseTimestamp(monitor.timestamp); //从上级获取 + strncpy(monitor_status, monitor.status, sizeof(monitor_status) - 1);//添加监测点状态 + //监测点台账处理 count_real_monitor++; memset(&line_info, 0, sizeof(line_info)); - line_info.line_id = count_real_monitor; //ź + line_info.line_id = count_real_monitor; //监测点排号 cout << "line_id:" << line_info.line_id << endl; strcpy(line_info.mp_id, monitor_id); cout << "mp_id:" << line_info.mp_id << endl; - strcpy(line_info.terminal_code, terminal_code); //ϼȡն˺ + strcpy(line_info.terminal_code, terminal_code); //从上级获取的终端号 cout << "terminal_code:" << line_info.terminal_code << endl; if (isCharPtrEmpty(logical_device_seq)) { - line_info.cpuno = 1; //Ĭϼʵ1 + line_info.cpuno = 1; //默认监测点实例号1 cout << "logical_device_seq:is null,set cpuno:"<< line_info.cpuno << endl; } else { @@ -3964,20 +4016,20 @@ int parse_device_cfg_web() strcpy(line_info.v_wiring_type, terminal_connect); cout << "v_wiring_type:" << line_info.v_wiring_type << endl; - //lnk2024-8-14¼߱־ + //lnk2024-8-14记录接线标志 if (strcmp(line_info.v_wiring_type, "0") != 0) { - isdelta_flag = 1; //һΪͽǰþҪڶб + isdelta_flag = 1; //存在一个监测点为角型接线则这个前置就要启动第二个配置列表 cout << "monitor_id" << monitor_id << "v_wiring_type:" << line_info.v_wiring_type << "is delta wiring:" << isdelta_flag << endl; } strcpy(line_info.monitor_status, monitor_status); cout << "monitor_status:" << line_info.monitor_status << endl; - //// struct tm + //// 构造struct tm对象 struct tm timeinfo; - timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 //ϼȡtimestamp - timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_year = timestamp.year - 1900; // 年份需要减去1900 //从上级获取的timestamp + timeinfo.tm_mon = timestamp.month - 1; // 月份需要减去1 timeinfo.tm_mday = timestamp.day; timeinfo.tm_hour = timestamp.hour; timeinfo.tm_min = timestamp.minute; @@ -3990,36 +4042,36 @@ int parse_device_cfg_web() strcpy(line_info.name, monitor_name); cout << "name:" << line_info.name << endl; - line_info.read_flag = ENABLE; //Ч + line_info.read_flag = ENABLE; //监测点有效 - //ied = find_ied_from_dev_code(line_info.terminal_code); //ҪϼնˣѾն + //ied = find_ied_from_dev_code(line_info.terminal_code); //不需要再找上级终端了,已经在终端里了 if (ied && ied->usr_ext && line_info.cpuno && (static_cast(line_info.cpuno) < 10)) { - char str[256]; //256С + char str[256]; //256大小 byte_t cpuno = line_info.cpuno; cout << "cpuno:" << (int)line_info.cpuno << endl; cout << "index cpuno:" << cpuno-1 << endl; ied_usr = (ied_usr_t*)ied->usr_ext; - ied_usr->LD_info[cpuno - 1] = line_info; //cpunoĬ1 + ied_usr->LD_info[cpuno - 1] = line_info; //cpuno默认是1 ied_usr->LD_info[cpuno - 1].ied = ied; - apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);//߼תΪPQMonitorPQM+߼ + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno);//将监测点逻辑号转为PQMonitorPQM+逻辑号 - //lnk20250208ʹapr_pstrdupֱӸ - //ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);// str еĸʽַƵڴ g_init_pool Сied_usr->LD_info[cpuno - 1].LD_name 洢ַĸLD_name PQMonitorPQM{cpuno} ʽ - // g_init_pool ڴз̶ 256 ֽڵڴ + //lnk20250208不使用apr_pstrdup,后续直接复用 + //ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str);//将 str 中的格式化字符串复制到内存池 g_init_pool 中。ied_usr->LD_info[cpuno - 1].LD_name 存储了这个字符串的副本,LD_name 现在是 PQMonitorPQM{cpuno} 的形式。 + // 从 g_init_pool 内存池中分配固定 256 字节的内存 ied_usr->LD_info[cpuno - 1].LD_name = (char *)apr_palloc(g_init_pool, 256); - // ڴ棬ֹ + // 清空内存,防止残留数据 memset(ied_usr->LD_info[cpuno - 1].LD_name, 0, 256); - // str еݸƵԤȷڴУิ 256 ֽڣ + // 将 str 中的内容复制到预先分配的内存中,最多复制 256 字节(包含结束符) apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256); - //Ŀռiedصied - ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); //дֱΪ ied_usr->LD_info[cpuno - 1] Աht_fcd ht_full_fcda˿յĹϣapr_hash_make(g_init_pool) g_init_pool ڴΪϣڴռ - ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);//ǵ key ֵ value ںĴпܻᱻ + //这里申请的空间基于ied的数量,挂载到ied上 + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); //这两行代码分别为 ied_usr->LD_info[cpuno - 1] 的两个成员(ht_fcd 和 ht_full_fcda)创建了空的哈希表。apr_hash_make(g_init_pool) 会在 g_init_pool 内存池中为这两个哈希表分配内存空间 + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool);//它们的 key 值和 value 在后续的代码中可能会被填充 ied_usr->LD_info[cpuno - 1].rptcount = 0; cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; @@ -4049,39 +4101,39 @@ int parse_device_cfg_web() int parse_model_web(QMap* icd_model_map,const std::vector& codes) { - std::string parm = codes[0]; //װͺбʽ["ͺ1","ͺ2"...] + std::string parm = codes[0]; //装置型号列表,格式["型号1","型号2"...] char* ptr=NULL; - //url + //测试用url参数 //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr); - // ptr ǷΪ NULL std::string ʼʧ + // 检查 ptr 是否为 NULL,避免 std::string 初始化失败 if (ptr == NULL) { - // ptr Ϊ NULL ־¼ + // 处理 ptr 为 NULL 的情况,例如日志记录或错误处理 std::cout << "Error: Received NULL response"<< std::endl; return 1; } - // + //调试用 printf("ptr:%s\n",ptr); - cJSON* root = cJSON_Parse(ptr); //jsonʽл + cJSON* root = cJSON_Parse(ptr); //json格式序列化 int retry = 0; if (root == NULL) { printf("web error %s\n", cJSON_GetErrorPtr()); - //ط + //重发多次 while(root == NULL){ - // ǰͷ֮ǰ ptr Աڴй© + // 在重试前释放之前的 ptr 以避免内存泄漏 if (ptr != NULL) { free(ptr); ptr = NULL; } - //url + //测试用url参数 //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr); if(ptr == NULL){ @@ -4100,11 +4152,11 @@ int parse_model_web(QMap* icd_model_map,const std::vectorvaluestring : "not found"; std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found"; - // ӡ + // 打印结果 std::cout << "code: " << code << std::endl; std::cout << "msg: " << msg << std::endl; @@ -4120,7 +4172,7 @@ int parse_model_web(QMap* icd_model_map,const std::vectortype == cJSON_String) strncpy(model->file_name, fileName->valuestring, sizeof(model->file_name) - 1); - cJSON* filePath = cJSON_GetObjectItem(item, "filePath");// + cJSON* filePath = cJSON_GetObjectItem(item, "filePath");//新增 if (filePath && filePath->type == cJSON_String) strncpy(model->file_path, filePath->valuestring, sizeof(model->file_path) - 1); cJSON* devType = cJSON_GetObjectItem(item, "devType");//tmnl_type @@ -4129,62 +4181,62 @@ int parse_model_web(QMap* icd_model_map,const std::vectortype == cJSON_String) strncpy(model->timestamp, updateTime->valuestring, sizeof(model->timestamp) - 1); - // ӵ QMap + // 添加到 QMap icd_model_map->insert(model->model_id, model); } } cJSON_Delete(root); - free(ptr); // SendJsonAPI_web ڴ棬ǵͷ + free(ptr); // 如果 SendJsonAPI_web 分配了内存,记得释放 - return 0; // ȷзֵ + return 0; // 确保函数有返回值 } int parse_model_cfg_web() { - std::vector codes;//μ + std::vector codes;//入参集合 QMap icd_model_map; ///////////////////////////////////////////////////////////////////////// - // - //codes.push_back("code1=model1"); //նͺб + //测试用 + //codes.push_back("code1=model1"); //填入终端型号列表 - //ʹжͺбjsonַ - // ǰм + //使用中端型号列表构建入参json字符串 + // 遍历前置所有监测点 ied_t* ied; ied_usr_t* ied_usr; std::cout << "g_node->n_clients" << g_node->n_clients << std::endl; - std::set devTypes; // ȥصļset + std::set devTypes; // 用于去重的集合set for (int t = 0; t < g_node->n_clients; t++) { ied = (ied_t*)g_node->clients[t]; ied_usr = (ied_usr_t*)ied->usr_ext; - // dev_type һַͣ뼯 ,ȥ + // 假设 dev_type 是一个字符串类型,加入集合 ,这里会去重 if (strlen(ied_usr->dev_type) > 0) { devTypes.insert(std::string(ied_usr->dev_type)); } } - // ֶ JSON ַ + // 手动构建 JSON 字符串 std::string input_jstr = "["; - bool first = true; // ڴ + bool first = true; // 用于处理逗号 for (std::set::iterator it = devTypes.begin(); it != devTypes.end(); ++it) { if (!first) { - input_jstr += ","; // Ӷ + input_jstr += ","; // 添加逗号 } - first = false; // һ֮Ϊ false - input_jstr += "\"" + *it + "\""; // ַ + first = false; // 第一次之后设置为 false + input_jstr += "\"" + *it + "\""; // 添加字符串 } - input_jstr += "]"; // JSON - std::cout << "input_jstr: " << input_jstr << std::endl; // + input_jstr += "]"; // 结束 JSON 数组 + std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果 if(ICD_FLAG == "1"){ - codes.push_back(input_jstr); //նͺб-ȡָicdļ + codes.push_back(input_jstr); //填入终端型号列表-获取指定的icd配置文件 } else{ - codes.push_back("[]"); //-ȡеicdļ + codes.push_back("[]"); //不填-获取所有的icd配置文件 } ///////////////////////////////////////////////////////////////////////// @@ -4201,14 +4253,14 @@ int parse_model_cfg_web() //char timestamp[64]; otl_datetime timestamp; - // ն̨ + // 遍历终端台账容器 QMap::iterator it; for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) { icd_model* value = it.value(); - // ȷ value Ϊ + // 确保 value 不为空 if (value != nullptr) { - // ҵжӦƲȡֵ + // 找到容器中对应名称并取值 strncpy(model_id, value->model_id, sizeof(model_id) - 1); strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1); strncpy(file_path, value->file_path, sizeof(file_path) - 1); @@ -4220,7 +4272,7 @@ int parse_model_cfg_web() std::cout << "filepath" << file_path << std::endl; std::cout << "filename" << file_name << std::endl; - //lnk20241125 + //lnk20241125测试用 //strncpy(tmnl_type, "PS_NET", sizeof(tmnl_type) - 1); Set_xml_databaseinfo(model_id, tmnl_type, file_path, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second); @@ -4234,22 +4286,22 @@ int parse_model_cfg_web() return e.code; } } -////////////////////////////////////////////////////////////icdģعlnk20250116 +////////////////////////////////////////////////////////////icd模型重构函数lnk20250116 char* parse_model_cfg_web_one(ied_t* ied) { - std::vector codes;//μ + std::vector codes;//入参集合 QMap icd_model_map; ied_usr_t* ied_usr; ied_usr = (ied_usr_t*)ied->usr_ext; - // ֶ JSON ַ + // 手动构建 JSON 字符串 std::string input_jstr = "["; input_jstr += "\"" + std::string(ied_usr->dev_type) + "\""; - input_jstr += "]"; // JSON - std::cout << "input_jstr: " << input_jstr << std::endl; // + input_jstr += "]"; // 结束 JSON 数组 + std::cout << "input_jstr: " << input_jstr << std::endl; // 输出结果 - codes.push_back(input_jstr); //նͺб-ȡָicdļ + codes.push_back(input_jstr); //填入终端型号列表-获取指定的icd配置文件 parse_model_web(&icd_model_map,codes); @@ -4260,16 +4312,16 @@ char* parse_model_cfg_web_one(ied_t* ied) char tmnl_type[64]; char file_name[128]; char file_path[128]; - otl_datetime timestamp;//ʹ + otl_datetime timestamp;//不使用 - // ն̨ + // 遍历终端台账容器 QMap::iterator it; for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) { icd_model* value = it.value(); - // ȷ value Ϊ + // 确保 value 不为空 if (value != nullptr) { - // ҵжӦƲȡֵ + // 找到容器中对应名称并取值 strncpy(model_id, value->model_id, sizeof(model_id) - 1); strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1); strncpy(file_path, value->file_path, sizeof(file_path) - 1); @@ -4292,7 +4344,7 @@ char* parse_model_cfg_web_one(ied_t* ied) } } //////////////////////////////////////////////////////////// -//ʱҪʱ־һЩܣͳһ޸ +//定时任务不需要定时日志清理和其他一些功能,统一放在这里修改 void OnTimerThread::run() { msleep(10000); @@ -4301,7 +4353,7 @@ void OnTimerThread::run() bool account_update = true; bool asd = true; - //ǰʱȡ + //当前时间获取 apr_time_t previousTime = apr_time_now();// apr_time_exp_t localTime; apr_time_exp_gmt(&localTime, previousTime); @@ -4310,7 +4362,7 @@ void OnTimerThread::run() << localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec << endl; - //ģʽ + //单联模式 if (g_onlyIP[0] != 0) { printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP); @@ -4325,23 +4377,24 @@ void OnTimerThread::run() int pgmin = 0; int mp_num_hour = 0; - // + //添加入参容器 std::vector codes; while (1) { - //߳ʱ + //进入线程时间 previousTime = apr_time_now(); apr_time_exp_gmt(&localTime, previousTime); - if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//̨˸,ڵ,ͨѶ + //记录连接终端数 + if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//台账更新,多节点,通讯 - //־¼ + //日志记录 if (mp_num_hour != localTime.tm_hour) { pthread_mutex_lock(&mtx); std::cout << "ontime hold lock !!!!!!!!!!!" << std::endl; std::string mp_num_str = ""; mp_num_str.append("connected device count:"); - mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString());//¼ӵļ + mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString());//记录连接的检测点数 mp_num_str.append(",g_node clients:"); mp_num_str.append(QString::number(g_node->n_clients).toStdString()); @@ -4350,94 +4403,98 @@ void OnTimerThread::run() pthread_mutex_unlock(&mtx); std::cout << "ontime free lock !!!!!!!!!!!" << std::endl; } - } + } + + //添加日志开关控制lnk20250508 + update_log_entries_countdown(); + msleep(1000); } printf(">>>OnTimerThread::run() is end!!!\n"); } -//web +//补招web处理函数 int recall_json_handle(const char* jstr) { - //ָ̬/̬ȫ - int stat = 0; // + //不指定稳态/暂态则全部补招 + int stat = 0; //都不补 int voltage= 0; try{ std::vector recallParams; - cJSON* json_root = cJSON_Parse(jstr); //jsonʽл //һ + cJSON* json_root = cJSON_Parse(jstr); //json格式序列化 //第一个参数 if (json_root == NULL) { - std::cout << "json root"<< std::endl; + std::cout << "json root解析错误"<< std::endl; return 10000; } - // ÿ + // 遍历数组的每个对象 if (json_root->type == cJSON_Array) { for (cJSON* item = json_root->child; item != nullptr; item = item->next) { - // ȡ monitorId + // 获取 monitorId 数组 cJSON* monitorIdArray = cJSON_GetObjectItem(item, "monitorId"); cJSON* timeIntervalArray = cJSON_GetObjectItem(item, "timeInterval"); - //жdataTypeǷΪ + //判断dataType是否为空 cJSON* datatype = cJSON_GetObjectItem(item, "dataType"); - //쳣жϷֹ + //添加异常判断防止崩溃 if(monitorIdArray == NULL || timeIntervalArray == NULL || datatype == NULL ){ - std::cout << "jsonݽ "<< std::endl; + std::cout << "json内容解析错误 "<< std::endl; return 10000; } - if(strcmp(datatype->valuestring, "") != 0)//ǿ + if(strcmp(datatype->valuestring, "") != 0)//非空 { - stat = (strcmp(datatype->valuestring, "0") == 0) ? 1 : 0;//̬ - voltage= (strcmp(datatype->valuestring, "1") == 0) ? 1 : 0;//̬ + stat = (strcmp(datatype->valuestring, "0") == 0) ? 1 : 0;//稳态 + voltage= (strcmp(datatype->valuestring, "1") == 0) ? 1 : 0;//暂态 } - else //ջ + else //空或其他 { stat = 1; voltage= 1; } - // - if(monitorIdArray != nullptr && monitorIdArray->child != nullptr)std::cout << "monitorIdArrayijԱΪ"<< monitorIdArray->child->valuestring << std::endl; - if(monitorIdArray != nullptr && monitorIdArray->child == nullptr)std::cout << "monitorIdArrayûгԱ"<< std::endl; + //调试用 + if(monitorIdArray != nullptr && monitorIdArray->child != nullptr)std::cout << "monitorIdArray的成员为"<< monitorIdArray->child->valuestring << std::endl; + if(monitorIdArray != nullptr && monitorIdArray->child == nullptr)std::cout << "monitorIdArray没有成员"<< std::endl; - //monitorIdArrayݵ + //monitorIdArray有数据的情况 if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && timeIntervalArray->type == cJSON_Array && monitorIdArray->child != nullptr) { - // monitorId + // 遍历 monitorId 数组 for (cJSON* idItem = monitorIdArray->child; idItem != nullptr; idItem = idItem->next) { QString monitorId = QString(idItem->valuestring); - //жеǰǷڱ20241230ַֹDZ̵ļ㴥 + //添加判断数组中当前监测点是否属于本进程20241230,防止出现非本进程的监测点触发补招 int mppair = 0; ied_t* ied; ied_usr_t* ied_usr; for (int t = 0; t < g_node->n_clients; t++){ ied = (ied_t*)g_node->clients[t]; ied_usr = (ied_usr_t*)ied->usr_ext; - for (int m = 0; m<10; m++){//10 + for (int m = 0; m<10; m++){//最多10个 - if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue;//յ + if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue;//跳过空的 - if(strcmp(ied_usr->LD_info[m].mp_id,monitorId.toStdString().c_str()) == 0){//ƥ + if(strcmp(ied_usr->LD_info[m].mp_id,monitorId.toStdString().c_str()) == 0){//匹配上了 mppair = 1; - break;//ҵ˳ѭ + break;//找到就退出监测点循环 } } - if(mppair == 1)break;//ҵ˳նѭ + if(mppair == 1)break;//找到就退出终端循环 } - if(mppair == 0)continue;//ǰ̵ļ㶼ûҵţ˵DZ̵ļ㣬һ - // + if(mppair == 0)continue;//当前进程的监测点都没有找到这个检测点号,说明不是本进程的监测点,处理数组的下一个监测点 + //调试用 std::cout << "find mpid:" << monitorId.toStdString() << "in this process,mppair=" << mppair <child; timeItem != nullptr; timeItem = timeItem->next) { QString timeInterval = QString(timeItem->valuestring); QString start = timeInterval.left(timeInterval.indexOf("~")); QString end = timeInterval.mid(timeInterval.indexOf("~") + 1); - // RecallParam ӵб + // 创建 RecallParam 对象并添加到列表中 RecallParam param; param.mp_id = monitorId; @@ -4449,12 +4506,12 @@ int recall_json_handle(const char* jstr) } } } - //monitorIdArrayΪյ + //monitorIdArray为空的情况 else if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && monitorIdArray->child == nullptr) { - // monitorIdArray Ϊ + // monitorIdArray 为空 std::cout << "monitorIdArray is null" << std::endl; - //м㲹 - // ǰм + //所有监测点补招 + // 遍历前置所有监测点 ied_t* ied; ied_usr_t* ied_usr; std::cout << "g_node->n_clients" << g_node->n_clients << std::endl; @@ -4467,13 +4524,13 @@ int recall_json_handle(const char* jstr) std::cout << "ied_usr->LD_info[m].mp_id" << m << " "<< ied_usr->LD_info[m].mp_id << std::endl; QString monitorId = QString(ied_usr->LD_info[m].mp_id); - // timeInterval + // 遍历 timeInterval 数组 for (cJSON* timeItem = timeIntervalArray->child; timeItem != nullptr; timeItem = timeItem->next) { QString timeInterval = QString(timeItem->valuestring); QString start = timeInterval.left(timeInterval.indexOf("~")); QString end = timeInterval.mid(timeInterval.indexOf("~") + 1); - // RecallParam ӵб + // 创建 RecallParam 对象并添加到列表中 RecallParam param; param.mp_id = monitorId; param.start = start; @@ -4486,12 +4543,12 @@ int recall_json_handle(const char* jstr) } } else{ - std::cout << "monitorIdArray ڻͲȷ" << std::endl; + std::cout << "monitorIdArray 不存在或类型不正确" << std::endl; } } } - cJSON_Delete(json_root); //webδ - //ȡв + cJSON_Delete(json_root); //web入参处理结束 + //遍历容器取出所有补招 for (std::vector::iterator it = recallParams.begin(); it != recallParams.end(); ++it) { QList recallinfo_list_hour; @@ -4513,10 +4570,10 @@ int recall_json_handle(const char* jstr) jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); - //̬̬webȡ - //jr.STEADY = QString::number(1, 10); // 1 תΪֵַ - //jr.VOLTAGE = QString::number(1, 10);// 1 תΪֵַ - // + //现在暂态稳态根据web获取 + //jr.STEADY = QString::number(1, 10); // 将整数 1 转换为字符串并赋值 + //jr.VOLTAGE = QString::number(1, 10);// 将整数 1 转换为字符串并赋值 + //调试用 //std::cout << "stat" << it->stat << "voltage" << it->voltage << std::endl; jr.STEADY = QString::number(it->stat); jr.VOLTAGE = QString::number(it->voltage); @@ -4529,7 +4586,7 @@ int recall_json_handle(const char* jstr) } catch (exception& e) { - printf("ͻ˷͵Ϣԭ%s\n", e.what()); + printf("处理客户端发送的消息错误,原因:%s\n", e.what()); return 10004; } @@ -4541,7 +4598,7 @@ int rtdata_http(const char* jstr) } -// ⲿhttpÿӣ +// 声明外部函数,http功能用库链接,单独编译 #ifdef __cplusplus extern "C" { #endif @@ -4558,31 +4615,31 @@ bool threadmsghttp(int fun); void RecallJsonResponse(int result) { char* ptr=NULL; - // JSON + // 创建 JSON 对象 cJSON* json_response = cJSON_CreateObject(); - // ֶ + // 添加字段 if(result == 000000){ cJSON_AddStringToObject(json_response, "code", "A0000"); - cJSON_AddStringToObject(json_response, "msg", "ݲִгɹ"); + cJSON_AddStringToObject(json_response, "msg", "数据补招执行成功"); } else{ cJSON_AddStringToObject(json_response, "code", "A0002"); - cJSON_AddStringToObject(json_response, "msg", "ݲִʧ"); + cJSON_AddStringToObject(json_response, "msg", "数据补招执行失败"); } - cJSON_AddNullToObject(json_response, "data"); // Ϊ null + cJSON_AddNullToObject(json_response, "data"); // 设置为 null - // JSON תΪַ + // 将 JSON 对象转换为字符串 char* json_string = cJSON_Print(json_response); std::cout << json_string << std::endl; - //ͻظԷֻһ - SendJsonAPI_web("÷", "", json_string ,&ptr); + //发送回复给对方,只发一次 + SendJsonAPI_web("调用方", "", json_string ,&ptr); - // + // 清理 cJSON_Delete(json_response); - free(json_string); // ͷŴӡַڴ + free(json_string); // 释放打印字符串的内存 } #endif @@ -4593,30 +4650,30 @@ void WebhttpThread::run() while(1){ - //н - if (!threadmsghttp(1) && g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//httpһϢ,״̬ΪfalseٴϢhttpʱϢDz߳̿ʼȡ + //补招进程 + if (!threadmsghttp(1) && g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//http处理一条消息,状态变为false,不再处理消息(http此时可能有消息来但是不处理)后这个线程开始读取数据 - const char* data = getReceivedData(1);//httpȡ,ָ + const char* data = getReceivedData(1);//从http中取数据,指针 std::cout << "recall data cfg:" << data <= 0) { - // val ĸ 6 λתΪ Base64 ַӵ + // 将 val 的高 6 位转化为 Base64 字符,并添加到输出中 out.push_back(base64_chars[(val >> valb) & 0x3F]); - valb -= 6; // ÿαλƫ 6 λ + valb -= 6; // 每次编码后,位偏移量减少 6 位 } } - // ʣλ '=' ַ + // 如果还有剩余的位数,补充 '=' 字符 while (valb > -6) { out.push_back('='); - valb -= 6; // ÿһ '='λƫ 6 λ + valb -= 6; // 每次添加一个 '=',位偏移量减少 6 位 } - return out; // رַ + return out; // 返回编码后的字符串 } void handleUploadResponse(const std::string& response, char* wavepath) { - // JSON Ӧ + // 解析 JSON 响应 cJSON* json_data = cJSON_Parse(response.c_str()); if (json_data == nullptr) { std::cerr << "Error parsing response: " << cJSON_GetErrorPtr() << std::endl; return; } - // ȡֶ + // 提取字段 cJSON* codeItem = cJSON_GetObjectItem(json_data, "code"); cJSON* msgItem = cJSON_GetObjectItem(json_data, "msg"); cJSON* dataItem = cJSON_GetObjectItem(json_data, "data"); @@ -4695,24 +4752,24 @@ void handleUploadResponse(const std::string& response, char* wavepath) { std::string fileName = fileNameItem->valuestring; std::string url = urlItem->valuestring; - // Ϣ + // 输出信息 std::cout << "File Path: " << name << std::endl; std::cout << "Uploaded File Name: " << fileName << std::endl; std::cout << "File URL: " << url << std::endl; - // ҵһ '.' + // 找到最后一个 '.' size_t pos = fileName.find_last_of('.'); std::string nameWithoutExt; if (pos != std::string::npos) { - // ȡȥ׺IJ + // 截取去掉后缀的部分 nameWithoutExt = fileName.substr(0, pos); } else { - // ûк׺ֱʹԭļ + // 如果没有后缀,直接使用原文件名 nameWithoutExt = fileName; } - // wavepath + // 拷贝到 wavepath strcpy(wavepath, nameWithoutExt.c_str()); std::cout << "wavepath: " << wavepath << std::endl; @@ -4721,12 +4778,12 @@ void handleUploadResponse(const std::string& response, char* wavepath) { std::cerr << "Error: Missing expected fields in JSON response." << std::endl; } - // ͷ JSON + // 释放 JSON 对象 cJSON_Delete(json_data); } -//jsonṹ͵ķʽ +//这是json结构发送的方式 /*void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) { - // ӱ·ȡļ + // 从本地路径读取文件内容 std::ifstream file(localpath, std::ios::binary); if (!file) { std::cerr << "Failed to open file: " << localpath << std::endl; @@ -4735,46 +4792,46 @@ void handleUploadResponse(const std::string& response, char* wavepath) { std::ostringstream ss; ss << file.rdbuf(); - std::string fileContent = ss.str();//ļ - std::string encodedFile = base64_encode(fileContent);//ļ + std::string fileContent = ss.str();//文件流 + std::string encodedFile = base64_encode(fileContent);//文件流编码 - // JSON ʵҪ + // 创建 JSON 对象 实现入参要求 cJSON* json_root = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "multipartFile", cJSON_CreateString(encodedFile.c_str())); - cJSON_AddItemToObject(json_root, "path", cJSON_CreateString(cloudpath));//Զ· - cJSON_AddItemToObject(json_root, "isReserveName", cJSON_CreateBool(true)); // ֵ + cJSON_AddItemToObject(json_root, "path", cJSON_CreateString(cloudpath));//远端路径 + cJSON_AddItemToObject(json_root, "isReserveName", cJSON_CreateBool(true)); // 布尔值 char* szjson = cJSON_Print(json_root); std::cout << ">>> json: " << szjson << std::endl; - // curl ʼ + // curl 初始化 CURL* curl = curl_easy_init(); if (curl) { - // Ϊ POST + // 设置请求为 POST 请求 curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, "Content-Type: application/json")); - // óʱʱ + // 设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); std::string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); // ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); // 设置数据接收和写入函数 - // ִ + // 执行请求 CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "lnk web failed: " << curl_easy_strerror(res) << std::endl; } else { std::cout << "lnk web success, response: " << resPost0 << std::endl; - handleUploadResponse(resPost0,wavepath); // Ӧ + handleUploadResponse(resPost0,wavepath); // 处理响应 } - // + // 清理 free(szjson); } else { std::cerr << ">>> curl init failed" << std::endl; @@ -4783,66 +4840,66 @@ void handleUploadResponse(const std::string& response, char* wavepath) { cJSON_Delete(json_root); }*/ -//dataformͷʽ +//这是dataform发送方式 void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) { - // ʼ curl + // 初始化 curl CURL* curl = curl_easy_init(); if (curl) { - // URL POST + // 设置请求 URL 和 POST 请求 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); - // + // 创建表单数据 curl_httppost* formpost = nullptr; curl_httppost* lastptr = nullptr; - // ļֶΣֱӴӱ·ȡļ + // 添加文件字段,直接从本地路径读取文件内容 curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_FILE, localpath, CURLFORM_END); - // `path` ֶ + // 添加 `path` 字段 curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "path", CURLFORM_COPYCONTENTS, cloudpath, CURLFORM_END); - // `isReserveName` ֶ + // 添加 `isReserveName` 字段 curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "isReserveName", CURLFORM_COPYCONTENTS, "true", CURLFORM_END); - // ñݵ + // 设置表单数据到请求 curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - // ͷϢ + // 设置头信息 struct curl_slist* header_list = nullptr; header_list = curl_slist_append(header_list, "Content-Type: multipart/form-data"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - // óʱʱ + // 设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); - // дӦݵĺ + // 设置写入响应数据的函数 std::string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); - // ִ + // 执行请求 CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "http web failed: " << curl_easy_strerror(res) << std::endl; } else { std::cout << "http web success, response: " << resPost0 << std::endl; - handleUploadResponse(resPost0, wavepath); // Ӧ + handleUploadResponse(resPost0, wavepath); // 处理响应 } - // - curl_formfree(formpost); // ͷű - curl_slist_free_all(header_list); // ͷͷб + // 清理 + curl_formfree(formpost); // 释放表单数据 + curl_slist_free_all(header_list); // 释放头部列表 curl_easy_cleanup(curl); } else { std::cerr << ">>> curl init failed" << std::endl; @@ -4851,7 +4908,7 @@ void SendFileWeb(const std::string& strUrl, const char* localpath, const char* c void SOEFileWeb(char* localpath,char* cloudpath, char* wavepath) { - //ʾipΪʵip + //示例ip,更换为实际ip即可 SendFileWeb(WEB_FILEUPLOAD,localpath,cloudpath,wavepath); } @@ -4863,8 +4920,8 @@ void SOEFileWeb_test() SOEFileWeb(localpath,cloudpath,wavepath); std::cout << "wavepath:" << wavepath << std::endl; } -/*/////////////////////////////////////////////////////////lnk10-24webӿ޸/////////////////////////////////////////////////////////////*/ -/*װCɵǫ̃˸º *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/*/////////////////////////////////////////////////////////lnk10-24根据web接口修改/////////////////////////////////////////////////////////////*/ +/*封装C可调用的台账更新函数 *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_index,int ied_take) { @@ -4872,7 +4929,7 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i ied_usr_t* ied_usr = NULL; ied_usr = (ied_usr_t*)ied->usr_ext; - // update[i] ед뵽 ied_usr + // 将 update[i] 中的数据写入到 ied_usr 中 if (strlen(update[i].terminal_id) != 0) { apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", update[i].terminal_id); printf("ied_usr->terminal_id: %s\n", ied_usr->terminal_id); @@ -4901,18 +4958,18 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", update[i].dev_series); printf("ied_usr->dev_series: %s\n", ied_usr->dev_series); } else { - apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ""); // ĬΪַ + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ""); // 默认为空字符串 printf("ied_usr->dev_series (default): %s\n", ied_usr->dev_series); } if (update[i].dev_key != NULL) { apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", update[i].dev_key); printf("ied_usr->dev_key: %s\n", ied_usr->dev_key); } else { - apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ""); // ĬΪַ + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ""); // 默认为空字符串 printf("ied_usr->dev_key (default): %s\n", ied_usr->dev_key); } - ied_usr->dev_idx = terminal_index; //նźţg_node± + ied_usr->dev_idx = terminal_index; //终端排号,g_node下标 printf("dev_idx: %d\n", ied_usr->dev_idx); ied->channel[0].channel_type = CHANNEL_TYPE_IPV4; // channel @@ -4929,32 +4986,32 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i if (update[i].port != NULL) { int port = 102; if (stringToInt(update[i].port, &port)) { - // תɹportStrȫΪ֣ѾתΪint͵port + // 转换成功,portStr全为数字,并且已经转换为int类型的port ied->channel[0].port = port; // DEV_PortID printf("ied_usr->port: %d\n", ied->channel[0].port); // DEV_PortID } else { ied->channel[0].port = 102; // DEV_PortID - printf("ied_usr->port: %s, ǺϷ˿. ʹĬ϶˿: %d\n", update[i].port, ied->channel[0].port); // DEV_PortID + printf("ied_usr->port: %s, 非合法端口. 使用默认端口: %d\n", update[i].port, ied->channel[0].port); // DEV_PortID } } if (update[i].timestamp != NULL && strlen(update[i].timestamp) > 0) { - // struct tm - struct tm timeinfo = {0}; // ʼΪ0 - // ʱַʽΪ "YYYY-MM-DD HH:MM:SS" - // ʹsscanfַȡʱֶ + // 构造struct tm对象 + struct tm timeinfo = {0}; // 初始化为0 + // 假设时间字符串格式为 "YYYY-MM-DD HH:MM:SS" + // 使用sscanf从字符串中提取各个时间字段 if (sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec) == 6) { - // ݴ1900ʼ + // 将年份从1900开始计算 timeinfo.tm_year -= 1900; - // ·ݴ0ʼ㣬ȥ1 + // 月份从0开始计算,减去1 timeinfo.tm_mon -= 1; - // tm_isdstгʼͨΪ-1mktimeԶж + // 对tm_isdst进行初始化,通常可以设置为-1,由mktime自动判断 timeinfo.tm_isdst = -1; - // ʹmktimestruct tmתΪtime_t + // 使用mktime将struct tm转换为time_t time_t raw_time = mktime(&timeinfo); - // жmktimeǷɹ + // 判断mktime是否成功 if (raw_time != -1) { ied_usr->time = (long long)raw_time; printf("ied_usr->time: %lld\n", ied_usr->time); @@ -4967,34 +5024,34 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i } } - //ʹпռҪ + //如果是使用已有空间则不需要再申请 if(!ied_take){ chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); ied->channel[0].connect = chnl_usr; - g_pt61850app->chnl_counts++; //Ҫ + g_pt61850app->chnl_counts++; //新增的需要添加 } else{ chnl_usr = (chnl_usr_t*)ied->channel[0].connect; } - chnl_usr->chnl = &(ied->channel[0]);//еiedֵԭʹڵģٸֵһ + chnl_usr->chnl = &(ied->channel[0]);//如果是已有的ied,这个值是原本就存在的,再赋值一次 chnl_usr->chnl_id = 0; chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); - // monitorData ед뵽 LD_info - int count_real_monitor = 0; //̨˵ļ + // 将 monitorData 中的数据写入到 LD_info 中 + int count_real_monitor = 0; //遍历监测点台账的计数器 int j; for (j = 0; j < 10 && update[i].line[j].monitor_id[0] != '\0'; ++j) { monitor monitor_data = update[i].line[j]; - // + //监测点计数 count_real_monitor++; - // ʼֵ LD_info漰ָIJֶΪ + // 初始化用于值拷贝的 LD_info,里面涉及指针的部分都为空 LD_info_t line_info; memset(&line_info, 0, sizeof(line_info)); char logical_device_seq[64]; - // Ϣ + // 填充监测点信息 strncpy(line_info.mp_id, monitor_data.monitor_id, sizeof(line_info.mp_id) - 1); strncpy(line_info.name, monitor_data.monitor_name, sizeof(line_info.name) - 1); strncpy(line_info.voltage_level, monitor_data.voltage_level, sizeof(line_info.voltage_level) - 1); @@ -5003,13 +5060,13 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i strncpy(line_info.terminal_code, monitor_data.terminal_code, sizeof(line_info.terminal_code) - 1); strncpy(logical_device_seq, monitor_data.logical_device_seq, sizeof(logical_device_seq) - 1); if (isCharPtrEmpty(logical_device_seq)) { - line_info.cpuno = 1; // Ĭϼʵ1 + line_info.cpuno = 1; // 默认监测点实例号1 printf("logical_device_seq: is null, set cpuno: %d\n", (int)line_info.cpuno); } else { line_info.cpuno = atoi(logical_device_seq); printf("logical_device_seq: %d\n", (int)line_info.cpuno); } - line_info.line_id = count_real_monitor; // ¼նź + line_info.line_id = count_real_monitor; // 记录终端排号 printf("line_id: %d\n", line_info.line_id); printf("mp_id: %s\n", line_info.mp_id); @@ -5019,31 +5076,31 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i printf("monitor_status: %s\n", line_info.monitor_status); printf("name: %s\n", line_info.name); - //lnk20250214 + //lnk20250214角形 if (strcmp(line_info.v_wiring_type, "0") != 0) { - isdelta_flag = 1; //һΪͽǰþҪڶб + isdelta_flag = 1; //存在一个监测点为角型接线则这个前置就要启动第二个配置列表 cout << "monitor_id" << line_info.mp_id << "v_wiring_type:" << line_info.v_wiring_type << "is delta wiring:" << isdelta_flag << endl; } - // ʱ + // 填充时间戳 if (update[i].timestamp[0] != '\0') { struct tm timeinfo; char timestamp[64]; - // update[i].timestampʽΪ "YYYY-MM-DD HH:MM:SS" - // 磺"2023-01-14 12:34:56" + // 假设update[i].timestamp格式为 "YYYY-MM-DD HH:MM:SS" + // 例如:"2023-01-14 12:34:56" sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); - // ݴ1900꿪ʼ + // 将年份从1900年开始计算 timeinfo.tm_year -= 1900; - // ·ݴ0ʼ1 + // 月份从0开始,减1 timeinfo.tm_mon -= 1; - // tm_isdstгʼͨΪ-1mktimeԶж + // 对tm_isdst进行初始化,通常可以设置为-1,由mktime自动判断 timeinfo.tm_isdst = -1; - // ʹmktimestruct tmתΪtime_t + // 使用mktime将struct tm转换为time_t time_t raw_time = mktime(&timeinfo); - // жmktimeǷɹ + // 判断mktime是否成功 if (raw_time != -1) { line_info.time = (long long)raw_time; printf("time: %lld\n", line_info.time); @@ -5052,31 +5109,31 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i return -1; } } - line_info.read_flag = 1; //Ч - // LD_info + line_info.read_flag = 1; //监测点有效 + // 填充 LD_info if (ied && ied->usr_ext && line_info.cpuno && ((int)line_info.cpuno < 10)) { char str[256]; - byte_t cpuno = line_info.cpuno; //ʹ̨˵߼кţʹԭied£кСԭôµIJֻᱻǣɾʱûԭеֻԴڴУᱻʹ + byte_t cpuno = line_info.cpuno; //使用新台账的逻辑序列号,在使用原有ied的情况下,如果序列号数量小于原有数量,那么新的部分会被覆盖,如果删除时没有清理,原有的其他部分会仍存在内存中,但不会被使用 printf("cpuno: %d\n", (int)line_info.cpuno); printf("index cpuno: %d\n", cpuno - 1); ied_usr = (ied_usr_t*)ied->usr_ext; - //ied_usr->LD_info[cpuno - 1] = line_info;//ں棬ΪҪжԭеָ - //ied_usr->LD_info[cpuno - 1].ied = ied; //ں棬ΪҪжԭеָ + //ied_usr->LD_info[cpuno - 1] = line_info;//这个放在后面,因为需要先判断原有的指针 + //ied_usr->LD_info[cpuno - 1].ied = ied; //这个放在后面,因为需要先判断原有的指针 - //¼ܵеldname + //用来记录可能的已有的ldname char *ldname = NULL; - //¼еı桢־ + //用来记录可能已有的报告、日志数组 loginfo_t **loginfo = NULL; rptinfo_t **rptinfo = NULL; - // + //调试 //printf("check error111 !!!!!!!!!!!!!!\n"); -///////// //еIJռÿռ +///////// //清空已有的补招数组占用空间 if (ied_usr->LD_info[cpuno - 1].autorecallcount != 0) { for (int j = 0; j < ied_usr->LD_info[cpuno - 1].autorecallcount; j++) { if(NULL != ied_usr->LD_info[cpuno - 1].autorecall[j]){ @@ -5090,17 +5147,17 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i ied_usr->LD_info[cpuno - 1].autorecallcount = 0; } - // + //调试 //printf("check error112 !!!!!!!!!!!!!!\n"); -//////// //¼ԭеı־ +//////// //记录原有的报告和日志数组 loginfo = ied_usr->LD_info[cpuno - 1].loginfo?ied_usr->LD_info[cpuno - 1].loginfo:NULL; rptinfo = ied_usr->LD_info[cpuno - 1].rptinfo?ied_usr->LD_info[cpuno - 1].rptinfo:NULL; - // + //调试 //printf("check error113 !!!!!!!!!!!!!!\n"); - //ظڴ棬ʹѴڵiedô֮ǰʼͷ˹ϣɾ̨ʱûҪԭ + //避免重复分配内存,如果使用已存在的ied,那么它之前初始化就分配了哈希表,如果在删除台账时没有清除,则需要将原来的清除 if (ied_usr->LD_info[cpuno - 1].ht_fcd != NULL) { apr_hash_clear(ied_usr->LD_info[cpuno - 1].ht_fcd); } @@ -5108,73 +5165,73 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i apr_hash_clear(ied_usr->LD_info[cpuno - 1].ht_full_fcda); } - // + //调试 //printf("check error116 !!!!!!!!!!!!!!\n"); - //Щеڴ棬Ҫ̨ɾʱӦ + //这些可能是已有的内存,如果存在则需要清除,(在台账删除时就应该清除) apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); - // ûֵʱ LD_nameظڴ + // 仅在没有值时更新 LD_name,避免重复分配内存 if (ied_usr->LD_info[cpuno - 1].LD_name == NULL) { - //lnk20250208 + //lnk20250208调试用 std::cout << "new space for LD_name" << std::endl; - //lnk20250208ʹapr_pstrdupʹù̶СڴֱӸ + //lnk20250208不使用apr_pstrdup,使用固定大小,后续都在这块内存上直接复用 //ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); - // g_init_pool ڴз̶ 256 ֽڵڴ + // 从 g_init_pool 内存池中分配固定 256 字节的内存 ied_usr->LD_info[cpuno - 1].LD_name = (char *)apr_palloc(g_init_pool, 256); - // ڴ棬ֹ + // 清空内存,防止残留数据 memset(ied_usr->LD_info[cpuno - 1].LD_name, 0, 256); - // str еݸƵԤȷڴУิ 256 ֽڣ + // 将 str 中的内容复制到预先分配的内存中,最多复制 256 字节(包含结束符) apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256); - } else {//滻ԭпռϸ + } else {//已有则替换,在原有空间上覆盖 - //lnk20250208 + //lnk20250208调试用 std::cout << "old space for LD_name:" << ied_usr->LD_info[cpuno - 1].LD_name <LD_info[cpuno - 1].LD_name, 0, 256); //printf("check error333 !!!!!!!!!!!!!!\n"); - apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256); //ԭпռ串 + apr_cpystrn(ied_usr->LD_info[cpuno - 1].LD_name, str, 256); //原有空间覆盖 //printf("check error222 !!!!!!!!!!!!!!\n"); } ldname = ied_usr->LD_info[cpuno - 1].LD_name; - // + //调试 //printf("check error114 !!!!!!!!!!!!!!\n"); - ied_usr->LD_info[cpuno - 1] = line_info;//ں棬ΪҪжԭеָ - ied_usr->LD_info[cpuno - 1].ied = ied; //ں棬ΪҪжԭеָ + ied_usr->LD_info[cpuno - 1] = line_info;//这个放在后面,因为需要先判断原有的指针 + ied_usr->LD_info[cpuno - 1].ied = ied; //这个放在后面,因为需要先判断原有的指针 - // + //调试 //printf("check error115 !!!!!!!!!!!!!!\n"); - ied_usr->LD_info[cpuno - 1].LD_name = ldname;//¼ԭеϵldname + ied_usr->LD_info[cpuno - 1].LD_name = ldname;//记录原有的或者新的ldname - // + //调试 printf("ledger ied_usr->LD_info[cpuno - 1].LD_name: %s\n", ied_usr->LD_info[cpuno - 1].LD_name); - ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); //´ϣ + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); //重新创建哈希表 ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); - ied_usr->LD_info[cpuno - 1].rptcount = 0; //㣬ֵied_usr->LD_info[cpuno - 1] = line_info;ʱӦþ0Ŀռڱʼʱ + ied_usr->LD_info[cpuno - 1].rptcount = 0; //报告数清零,这个值在ied_usr->LD_info[cpuno - 1] = line_info;时应该就已清0,报告的空间会在报告块初始化时分配 printf("rptcount: %d\n", ied_usr->LD_info[cpuno - 1].rptcount); - //ʹԭеı־ռ - ied_usr->LD_info[cpuno - 1].loginfo = loginfo; //µĻǾɵĿռ䣬ʼ涼Ὣ + //使用原有的报告日志空间 + ied_usr->LD_info[cpuno - 1].loginfo = loginfo; //不管是新的还是旧的空间,后续初始化报告都会将它覆盖 ied_usr->LD_info[cpuno - 1].rptinfo = rptinfo; - if (cpuno > ied->cpucount) {//̨˵߼Ŵiedԭеcpuʼ0cpu¼жٸ + if (cpuno > ied->cpucount) {//新台账的逻辑号大于ied原有的cpu数(初始化是0),则更新cpu数,用来记录有多少个监测点 ied->cpucount = cpuno; } } @@ -5183,8 +5240,8 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i return 0; } -////////////////////////////////////////////////////////////////////////̨˸¼¼־ -// ȡǰʱ䲢ʽΪ "YYYY-MM-DD HH:MM:SS" +////////////////////////////////////////////////////////////////////////台账更新记录日志 +// 获取当前时间并格式化为 "YYYY-MM-DD HH:MM:SS" std::string get_current_time() { std::time_t t = std::time(NULL); struct std::tm tm = *std::localtime(&t); @@ -5194,49 +5251,49 @@ std::string get_current_time() { return std::string(buffer); } -// д־Ŀ +// 写入日志条目 void write_log_entry(std::ofstream &log_file, const std::string &action, const std::string &terminal_id, const std::string ¤t_time) { log_file << terminal_id << "\t" << action << "time:" << current_time << "\n"; } -// ̨˸־ +// 创建台账更新日志 void create_ledger_log(trigger_update_xml_t* ledger_update_xml) { std::cout << "create_ledger_log." << std::endl; std::string log_filename = "../etc/" + std::string(LEDGER_UPDATE_FN); - std::ofstream log_file(log_filename.c_str(), std::ios::app); // ׷ģʽļ + std::ofstream log_file(log_filename.c_str(), std::ios::app); // 以追加模式打开文件 if (!log_file.is_open()) { std::cerr << "Failed to open log file: " << log_filename << std::endl; return; } - std::vector > new_entries; // ڴ洢newterminal_idʱ - std::vector > modify_entries; // ڴ洢modifyterminal_idʱ - std::vector > delete_entries; // ڴ洢deleteterminal_idʱ + std::vector > new_entries; // 用于存储new的terminal_id和时间 + std::vector > modify_entries; // 用于存储modify的terminal_id和时间 + std::vector > delete_entries; // 用于存储delete的terminal_id和时间 - std::string current_time = get_current_time(); // ȡǰʱ + std::string current_time = get_current_time(); // 获取当前时间 - // new_updates + // 处理 new_updates for (int i = 0; i < ledger_update_xml->new_update_num; ++i) { std::string terminal_id = ledger_update_xml->new_updates[i].terminal_id; new_entries.push_back(std::make_pair(terminal_id, current_time)); } - // modify_updates + // 处理 modify_updates for (int i = 0; i < ledger_update_xml->modify_update_num; ++i) { std::string terminal_id = ledger_update_xml->modify_updates[i].terminal_id; modify_entries.push_back(std::make_pair(terminal_id, current_time)); } - // delete_updates + // 处理 delete_updates for (int i = 0; i < ledger_update_xml->delete_update_num; ++i) { std::string terminal_id = ledger_update_xml->delete_updates[i].terminal_id; delete_entries.push_back(std::make_pair(terminal_id, current_time)); } - // д־ļ + // 写入日志文件 if (!new_entries.empty()) { log_file << "\n"; for (size_t i = 0; i < new_entries.size(); ++i) { @@ -5264,49 +5321,49 @@ void create_ledger_log(trigger_update_xml_t* ledger_update_xml) { log_file.close(); std::cout << "Ledger log has been updated." << std::endl; } -///////////////////////////////////////////////////////////////////////////̨ڴ䲿ֹܴ룺δʹ -// ɾָӳ +///////////////////////////////////////////////////////////////////////////台账内存分配部分功能代码:未使用 +// 删除指定的子池 void delete_sub_pool(const char* terminal_id) { std::list >::iterator it; for (it = pool_list.begin(); it != pool_list.end(); ++it) { if (it->first == terminal_id) { - apr_pool_destroy(it->second); // ӳ - pool_list.erase(it); // Ƴ + apr_pool_destroy(it->second); // 销毁子池 + pool_list.erase(it); // 从容器中移除 break; } } } -//ҶӦӳ +//找对应的子池 apr_pool_t* find_sub_pool(const char* terminal_id) { std::list >::iterator it; for (it = pool_list.begin(); it != pool_list.end(); ++it) { if (it->first == terminal_id) { - return it->second; // ҵӦӳ + return it->second; // 找到对应的子池 } } - return NULL; // ûҵӦӳ + return NULL; // 没有找到对应的子池 } -// ӳزӵ +// 创建子池并添加到容器 apr_pool_t* create_sub_pool(apr_pool_t* parent_pool, const char* terminal_id) { apr_pool_t* new_sub_pool = NULL; - // ڸдһӳ + // 在父池中创建一个子池 apr_pool_create(&new_sub_pool, parent_pool); if (new_sub_pool == NULL) { - return NULL; // ʧ + return NULL; // 创建失败 } - // ӳغն ID 洢 + // 将子池和终端 ID 存储在容器中 pool_list.push_back(std::make_pair(std::string(terminal_id), new_sub_pool)); return new_sub_pool; } ////////////////////////////////////////////////////////////////////////////////////////////////// -//̨˱ıʼ +//台账变更的报告块初始化 int parse_rpt_log_ini_one(ied_t* ied) { QMap rpt_cfg_strlists; @@ -5324,44 +5381,44 @@ int parse_rpt_log_ini_one(ied_t* ied) { QStringList* rpt_temp = new QStringList(); QStringList* log_temp = new QStringList(); - rpt_cfg_strlists.insert(type, rpt_temp);//б - log_cfg_strlists.insert(type, log_temp);//־б - //g_DevFlagûʹ + rpt_cfg_strlists.insert(type, rpt_temp);//报告控制列表 + log_cfg_strlists.insert(type, log_temp);//日志控制列表 + //g_DevFlag没有使用 parse_one_rpt_log_ini(g_DevFlag, rpt_cfg_strlists[type], log_cfg_strlists[type], ied_usr->dev_type); } - //lnk20250208 + //lnk20250208调试用 std::cout << "ied->cpucount:" << (int)(ied->cpucount) <cpucount; cpuno++) {//iedʵʵļ + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) {//根据ied实际的检测点数遍历 - //lnk20250208 + //lnk20250208调试用 std::cout << "cpuno:" << cpuno << "log init !!!!!!" <LD_info[cpuno]); - //Щеڴ棬жϲܴg_init_poolзڴ棬lnk20250122 + //这些可能是已有的内存,经过判断才能从g_init_pool中分配内存,lnk20250122 char str[256]; char* tmp = Get_IED(ied_usr->dev_type); if(tmp == NULL){std::cerr << "front read ied config error!" << std::endl;continue;} qDebug() << tmp << endl; apr_snprintf(str, sizeof(str), tmp, cpuno + 1); - // + //调试 printf("logini ied_usr->LD_info[cpuno - 1].LD_name: %s\n", ied_usr->LD_info[cpuno].LD_name); - delete[] tmp;//Get_IEDзڴ棬ʹúɾ + delete[] tmp;//Get_IED中分配了内存,使用后删除 - //lnk20250208 + //lnk20250208调试用 std::cout << "cpuno:" << cpuno << " fill report control" <size()); for (int i = 0; i < rpt_cfg_strlists[type]->size(); ++i) { apr_snprintf(buf, sizeof(buf), "%s", rpt_cfg_strlists[type]->at(i).toAscii().constData()); fill_rptctrl_by_cfg(LD_info, i, buf); } - //ʼ־ + //初始化监测点的日志控制 init_logctrl_by_count(LD_info, log_cfg_strlists[type]->size()); for (int i = 0; i < log_cfg_strlists[type]->size(); ++i) { apr_snprintf(buf, sizeof(buf), "%s", log_cfg_strlists[type]->at(i).toAscii().constData()); @@ -5372,7 +5429,7 @@ int parse_rpt_log_ini_one(ied_t* ied) } } - //ƿ־ƿ鴦 + //报告控制块和日志控制块处理结束后清理容器 for (QMap::iterator it1 = log_cfg_strlists.begin(); it1 != log_cfg_strlists.end(); ++it1) { delete it1.value(); @@ -5396,14 +5453,14 @@ apr_status_t init_rem_dib_table_one(ied_t *ied) ied_usr_t* ied_usr; - //λúg_nodeһ + //插入的位置和g_node一样 ied_usr = (ied_usr_t*)ied->usr_ext; pos = ied_usr->dev_idx - 1; std::cout << "!!!!!!!!!rem_dib_table pos is " << pos << std::endl; for(chnl_no=0 ; chnl_nochncount; chnl_no++) { - chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;//ʼʱѸռ + chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;//初始化时已根据最大数量申请空间 g_pt61850app->chnl_usr[pos] = chnl_usr; std::cout << "!!!!!!!!!g_pt61850app pos " << pos << "is " << ied_usr->terminal_id << "is" << (chnl_usr == NULL?"NULL":"NOTNULL") << std::endl; @@ -5411,7 +5468,7 @@ apr_status_t init_rem_dib_table_one(ied_t *ied) ip.s_addr = htonl(ied->channel[chnl_no].addr); strcpy(chnl_usr->ip_str,inet_ntoa(ip)); printf( " add_rem_dib_table %s:%d \n",chnl_usr->ip_str ,ied->channel[chnl_no].port ); - add_rem_dib_table (pos++,chnl_usr->ip_str,ied->channel[chnl_no].port );//ǰն˵IP˿ڼ¼УҪעӵ±꣬ɾնˣڵԴڣٴʹʱᱻ滻 + add_rem_dib_table (pos++,chnl_usr->ip_str,ied->channel[chnl_no].port );//当前终端的IP端口记录到表中,这里要注意添加的下标,如果删除终端,这个表内的内容仍存在,再次使用时会被替换 { char comm_str[256]; memset(comm_str,0,256); @@ -5421,16 +5478,16 @@ apr_status_t init_rem_dib_table_one(ied_t *ied) } return APR_SUCCESS; } -///////////////////////////////////////////////////////////////////////////////////////////////////ied +///////////////////////////////////////////////////////////////////////////////////////////////////清理ied void clearLogInfo(loginfo_t *loginfo) { if (loginfo == nullptr) { - return; // ָΪգֱӷ + return; // 如果传入的指针为空,直接返回 } - // ַ + // 清空字符数组 memset(loginfo->logName, 0, sizeof(loginfo->logName)); - // ָԱ + // 清空其他非指针成员 loginfo->IntgPd = 0; loginfo->reasonCode = 0; loginfo->TrgOpt = 0; @@ -5440,23 +5497,23 @@ void clearLogInfo(loginfo_t *loginfo) { loginfo->need_steady = 0; loginfo->need_voltage = 0; - // ָԱͷڴ + // 对指针成员进行清理,但不释放内存 if (loginfo->lcbName != nullptr) { - memset(loginfo->lcbName, 0, strlen(loginfo->lcbName)); // ַ + memset(loginfo->lcbName, 0, strlen(loginfo->lcbName)); // 清空字符串内容 } if (loginfo->datasetName != nullptr) { - memset(loginfo->datasetName, 0, strlen(loginfo->datasetName)); // ַ + memset(loginfo->datasetName, 0, strlen(loginfo->datasetName)); // 清空字符串内容 } - // LD_info ָ룬,ָϼ + // 由于 LD_info 是指针,它不清理,仍指向上级 } void clearRptInfo(rptinfo_t *rptinfo) { if (rptinfo == nullptr) { - return; // ָΪգֱӷ + return; // 如果传入的指针为空,直接返回 } - // ַͷָԱ + // 清空字符数组和非指针成员 rptinfo->instanceNeedSuffix = 0; rptinfo->TrgOpt = 0; @@ -5482,18 +5539,18 @@ void clearRptInfo(rptinfo_t *rptinfo) { rptinfo->pstflag = 0; - // ָԱͷڴ + // 对指针成员进行清理,但不释放内存 if (rptinfo->rptID != nullptr) { - memset(rptinfo->rptID, 0, strlen(rptinfo->rptID)); // ַ + memset(rptinfo->rptID, 0, strlen(rptinfo->rptID)); // 清空字符串内容 } - // LD_info ָ룬Ҫָ򸸼 + // 由于 LD_info 是指针,它不需要清理,仍指向父级 //rptinfo->LD_info = nullptr; - // RCBC_INFO ṹָд + // 对 RCBC_INFO 结构体指针进行处理 if (rptinfo->m_rcb_info != nullptr) { - // Ҫѡṹڲݣͷڴ - rptinfo->m_rcb_info = nullptr;//գΪָָͨرʱᱻ + // 如果需要,可以选择清理结构体内部内容,但不释放内存 + rptinfo->m_rcb_info = nullptr;//这里可以清空,因为这个指针指向的区域在连接通道关闭时会被清理 } } @@ -5503,37 +5560,37 @@ void clearLDInfo(LD_info_t *ld_info) { return; } - //ԭiedָ + //保留原来的ied指向 - //ձ + //清空报告 if (ld_info->rptinfo != nullptr) { for (int i = 0; i < ld_info->rptcount; ++i) { if (ld_info->rptinfo[i] != nullptr) { - clearRptInfo(ld_info->rptinfo[i]); //ձƿ + clearRptInfo(ld_info->rptinfo[i]); //清空报告控制块 } } } std::cout << "clean RptInfo!!!" << std::endl; - //־ + //清空日志 if (ld_info->loginfo != nullptr) { for (int i = 0; i < ld_info->logcount; ++i) { if (ld_info->loginfo[i] != nullptr) { - clearLogInfo(ld_info->loginfo[i]); //־ƿ + clearLogInfo(ld_info->loginfo[i]); //清空日志控制块 } } } std::cout << "clean loginfo_t!!!" << std::endl; - //ղ + //清空补招 if (ld_info->autorecall != nullptr) { for (int i = 0; i < ld_info->autorecallcount; ++i) { if (ld_info->autorecall[i] != nullptr) { memset(ld_info->autorecall[i], 0, sizeof(autorecall_t)); - delete ld_info->autorecall[i]; //ɾԪؿռ䣬ڲеݣѾռ䣬Ҫͷ + delete ld_info->autorecall[i]; //删除数组元素空间,如果有正在补招的内容,则已经申请空间,需要释放 } } - delete ld_info->autorecall; //ɾռ + delete ld_info->autorecall; //删除数组空间 } std::cout << "clean autorecall_t!!!" << std::endl; @@ -5544,7 +5601,7 @@ void clearLDInfo(LD_info_t *ld_info) { apr_hash_clear(ld_info->ht_full_fcda); } - // ָԱ + // 清空其他指针成员 if (ld_info->name != nullptr) { memset(ld_info->name, 0, sizeof(char) * 256); } @@ -5567,38 +5624,38 @@ void clearLDInfo(LD_info_t *ld_info) { memset(ld_info->terminal_code, 0, sizeof(char) * 256); } - ld_info->cpuno = 0; //߼к + ld_info->cpuno = 0; //清空逻辑序列号 - ld_info->time = 0; //̨˸ʱ0 - ld_info->update_flag = 0; //±־ݲʹ + ld_info->time = 0; //台账更新时间清0 + ld_info->update_flag = 0; //监测点更新标志,暂不使用 - ld_info->rptRecvFlag = 0;//ñ־ + ld_info->rptRecvFlag = 0;//重置报告标志 ld_info->rptRecvCheckFlag = 0; ld_info->rptPstRecvFlag = 0; ld_info->rptPstRecvCheckFlag = 0; - ld_info->read_flag = 0;//Ч + ld_info->read_flag = 0;//监测点无效 ld_info->rptcount = 0; ld_info->logcount = 0; ld_info->autorecallflag = 0; ld_info->autorecallcount = 0; - //ld_info->group = 0; //ʹ + //ld_info->group = 0; //不使用 - //ʵʱݲ + //清空实时数据部分 ld_info->line_id = 0; ld_info->real_data = 0; ld_info->soe_data = 0; ld_info->limit = 0; ld_info->count = 0; - //ld_info->SubV_Index = 0; //ʹ - //ld_info->Dev_Index = 0; //ʹ - //ld_info->Sub_Index = 0; //ʹ - //ld_info->GD_Index = 0; //ʹ + //ld_info->SubV_Index = 0; //不使用 + //ld_info->Dev_Index = 0; //不使用 + //ld_info->Sub_Index = 0; //不使用 + //ld_info->GD_Index = 0; //不使用 - //̬ṹ + //清空暂态结构 for (int i = 0; i < QVVR_NUM; ++i) { ld_info->qvvr[i].used_status = 0; ld_info->qvvr[i].QVVR_start = 0; @@ -5606,14 +5663,14 @@ void clearLDInfo(LD_info_t *ld_info) { ld_info->qvvr[i].QVVR_time = 0; ld_info->qvvr[i].QVVR_PerTime = 0.0f; ld_info->qvvr[i].QVVR_Amg = 0.0f; - memset(ld_info->qvvr[i].QVVR_Rptname, 0, sizeof(ld_info->qvvr[i].QVVR_Rptname)); // ַ + memset(ld_info->qvvr[i].QVVR_Rptname, 0, sizeof(ld_info->qvvr[i].QVVR_Rptname)); // 清空字符数组 ld_info->qvvr[i].timestamp = 0; } ld_info->qvvr_idx = 0; memset(ld_info->FltNum, 0, sizeof(ld_info->FltNum)); - ld_info->RDRE_FltNum = 0; //¼ + ld_info->RDRE_FltNum = 0; //录波号清零 } @@ -5624,17 +5681,17 @@ void clearIedUsr(ied_usr_t *ied_usr) { return; } - // ied_usr_t еķָ벿 - //ied_usr->dev_idx = 0;//index + // 清空 ied_usr_t 中的非指针部分 + //ied_usr->dev_idx = 0;//保留index ied_usr->dev_flag = UNUSED; ied_usr->last_call_wavelist_time = 0; - ied_usr->time = 0; //̨˸ʱ - ied_usr->update_flag = 0; //̨˸±־ݲʹ + ied_usr->time = 0; //台账更新时间 + ied_usr->update_flag = 0; //台账更新标志暂不使用 - // ָ벿֣ǿָ + // 清空指针部分,但不清理非空指针 if (ied_usr->LD_info != nullptr) { - // LD_info Ϊգڲ + // 如果 LD_info 不为空,清理它内部的内容 for (int i = 0; i < MAX_CPUNO; ++i) { LD_info_t * ld =NULL; ld = (LD_info_t *)&ied_usr->LD_info[i]; @@ -5644,11 +5701,11 @@ void clearIedUsr(ied_usr_t *ied_usr) { } } - if (ied_usr->cookie != nullptr) { //ʹ + if (ied_usr->cookie != nullptr) { //不使用 std::cout << "cookie not null" << std::endl; } - // ָ벿֣ҲԲ0Ḳ + // 清空其他非指针部分,也可以不清0,后续都会覆盖 memset(ied_usr->dev_type, 0, sizeof(ied_usr->dev_type)); memset(ied_usr->dev_key, 0, sizeof(ied_usr->dev_key)); memset(ied_usr->dev_series, 0, sizeof(ied_usr->dev_series)); @@ -5661,9 +5718,9 @@ void clearIedUsr(ied_usr_t *ied_usr) { memset(ied_usr->terminal_code, 0, sizeof(ied_usr->terminal_code)); } -// channel cpuinfo ķָ벿 +// 清空 channel 和 cpuinfo 的非指针部分 void clear_channel_and_cpuinfo(byte_t chncount, channel_t *channel, byte_t cpucount, cpuinfo_t *cpuinfo) { - // channel еÿԪصķֶָ + // 清空 channel 数组中的每个元素的非指针字段 for (byte_t i = 0; i < chncount && (&channel[i] != NULL); ++i) { channel[i].master = 0; channel[i].channel_type = 0; @@ -5675,11 +5732,11 @@ void clear_channel_and_cpuinfo(byte_t chncount, channel_t *channel, byte_t cpuco channel[i].last_send_ticks = 0; channel[i].ied_id = 0; - // channel chnl_usr_t - // رʱָ뱾 + // 清理 channel 里的 chnl_usr_t 部分 + // 关闭连接时已清理,保留指针本身 } - // cpuinfo еÿԪصķֶָ + // 清空 cpuinfo 数组中的每个元素的非指针字段 for (byte_t i = 0; i < cpucount && (&cpuinfo[i] != NULL); ++i) { cpuinfo[i].addr = 0; cpuinfo[i].status = 0; @@ -5698,61 +5755,61 @@ void clearIed(ied_t *ied) { return; } - // ied_t id + // 清空 ied_t 的id ied->id = 0; - //ied->flags = 0; //δʹ - //ied->type = 0; //δʹ + //ied->flags = 0; //未使用 + //ied->type = 0; //未使用 - //channel //cpuinfo + //清理channel //清理cpuinfo clear_channel_and_cpuinfo(ied->chncount,ied->channel,ied->cpucount,ied->cpuinfo); - ied->chncount = 0; //ͨ - ied->cpucount = 0; //ռ + ied->chncount = 0; //清空通道数 + ied->cpucount = 0; //清空检测点数 - // + //名称清理 memset(ied->name, 0, LONGNAME); - //ied->station = 0; //δʹ - //ied->node = 0; //δʹ - //ied->frequency = 0; //δʹ - //ied->delay = 0; //δʹ - //ied->count = 0; //δʹ + //ied->station = 0; //未使用 + //ied->node = 0; //未使用 + //ied->frequency = 0; //未使用 + //ied->delay = 0; //未使用 + //ied->count = 0; //未使用 - //鶨岿δʹ + //数据组定义部分未使用 //ied->groups = NULL; //ied->htgroups = NULL; - //ϵͳδʹ + //系统令牌未使用 //ied->systoken_st = 0; - //ied->index = 0; //δʹ - ied->status = STATUS_NOINIT; //豸״̬Ϊδʼ - //ied->last_ticks = 0; //δʹ - //ied->last_gi = 0; //δʹ + //ied->index = 0; //未使用 + ied->status = STATUS_NOINIT; //设备状态设为未初始化 + //ied->last_ticks = 0; //未使用 + //ied->last_gi = 0; //未使用 - // ָ벿 + // 清空指针部分 if (ied->usr_ext != nullptr) { ied_usr_t *ied_usr = (ied_usr_t*)ied->usr_ext; clearIedUsr(ied_usr); } if (ied->sys_ext != nullptr) { - //ʹ + //不使用 } if (ied->app_ext != nullptr) { - //ʹ + //不使用 } } -/*װCɵǫ̃˸º *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Ժ +/*封装C可调用的台账更新函数 *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//测试函数 std::string my_to_string(long long value) { std::stringstream ss; ss << value; return ss.str(); } -//lnk20250328ƥ䵽ն +//lnk20250328用来跳过匹配到的终端 bool shouldSkipTerminal(const char* terminal_id) { for (size_t i = 0; i < TESTARRAY.size(); ++i) { if (TESTARRAY[i] == terminal_id) { @@ -5767,46 +5824,46 @@ void rocketmq_test_300(int mpnum,int front_index) { data.strTopic = QString::fromStdString(G_ROCKETMQ_TOPIC); data.mp_id = "0"; - // ȡļ - std::ifstream file("long_string.txt"); // ļд洢ַ + // 读取文件内容 + std::ifstream file("long_string.txt"); // 文件中存储长字符串 std::stringstream buffer; buffer << file.rdbuf(); - std::string file_contents = buffer.str(); // ȡļ + std::string file_contents = buffer.str(); // 获取文件内容 std::string base_strText = file_contents; - // ȡǰʱΪʼʱ - std::time_t t = std::time(NULL);//ȡǰϵͳʱ䣨 1970 1 1 ͨΪ UNIX ʱ - std::tm* time_info = std::localtime(&t);// std::time_tʾǰ UNIX ʱתΪʱ䣨std::tm ṹ - time_info->tm_sec = 0; // λ - //time_info->tm_msec = 0; // λҪȷʹø߾ʱ䣩 + // 获取当前时间作为开始时间 + std::time_t t = std::time(NULL);//获取当前的系统时间(自 1970 年 1 月 1 日以来的秒数,通常称为 UNIX 时间戳) + std::tm* time_info = std::localtime(&t);//将 std::time_t(表示当前的 UNIX 时间戳)转换为本地时间(std::tm 结构) + time_info->tm_sec = 0; // 清零秒位 + //time_info->tm_msec = 0; // 清零毫秒位(如果需要更精确,使用高精度时间) - // ȡǰʱ룩 - std::time_t base_time_t = std::mktime(time_info);// std::tm ṹʱ䣩ת std::time_tʱ + // 获取当前的时间戳(秒) + std::time_t base_time_t = std::mktime(time_info);//将 std::tm 结构(本地时间)转换回 std::time_t(时间戳) - // ÿϢʱȷӣ - long long current_time_ms = static_cast(base_time_t) * 1000; // ÿӵλ + // 计算每条消息的时间戳,精确到分钟,毫秒和秒清零 + long long current_time_ms = static_cast(base_time_t) * 1000; // 每分钟递增,单位毫秒 - // 趨ܵϢ + // 设定总的消息数量 int total_messages = mpnum; ied_t* ied; ied_usr_t* ied_usr; - // ѭ 300 Ϣ + // 循环发送 300 条消息 for (int i = 0; (total_messages != 0 && g_front_seg_index == 1 && g_node_id == 100) && i < g_node->n_clients; ++i) { ied = (ied_t*)g_node->clients[i]; if(ied != NULL){ ied_usr = (ied_usr_t*)ied->usr_ext; - //ն + //跳过正常的终端 if (shouldSkipTerminal(ied_usr->terminal_id)) { std::cout << ied_usr->terminal_id << " use true message " << std::endl; continue; } for (int j = 0; j < 10 && ied_usr->LD_info[j].mp_id[0] != '\0'; j++){ - // ޸ Monitor ֵ + // 修改 Monitor 值 char monitor_id[256] = {}; strncpy(monitor_id, ied_usr->LD_info[j].mp_id, sizeof(monitor_id) - 1); monitor_id[sizeof(monitor_id) - 1] = '\0'; @@ -5815,12 +5872,12 @@ void rocketmq_test_300(int mpnum,int front_index) { data.monitor_id = i + j; - std::string modified_time = my_to_string(current_time_ms); // ʱתΪͣUnixʱ + std::string modified_time = my_to_string(current_time_ms); // 时间转换为整数类型(Unix时间戳) - // 滻Ϣе Monitor TIME ֶΣֻƥֶƥֵ + // 替换消息中的 Monitor 和 TIME 字段(只匹配字段名,不匹配具体数值) std::string modified_strText = base_strText; - // 滻 Monitor ֶ + // 替换 Monitor 字段 size_t monitor_pos = modified_strText.find("\"Monitor\""); if (monitor_pos != std::string::npos) { size_t colon_pos = modified_strText.find(":", monitor_pos); @@ -5831,7 +5888,7 @@ void rocketmq_test_300(int mpnum,int front_index) { } } - // 滻 TIME ֶ + // 替换 TIME 字段 size_t time_pos = modified_strText.find("\"TIME\""); if (time_pos != std::string::npos) { size_t colon_pos = modified_strText.find(":", time_pos); @@ -5842,17 +5899,17 @@ void rocketmq_test_300(int mpnum,int front_index) { } } - // + // 更新数据 data.strText = QString::fromStdString(modified_strText); - // + // 发送数据 my_rocketmq_send(data); - // Ϣ + // 输出调试信息 std::cout << "Sent message " << (i + 1) << " with Monitor " << data.monitor_id << " and TIME " << modified_time << std::endl; - // ȴһϢķ̶ͣΪ1ӣ - //QThread::sleep(60); // ÿηͼ1 + // 等待下一条消息的发送(固定为1分钟) + //QThread::sleep(60); // 每次发送间隔1分钟 } } } @@ -5860,66 +5917,66 @@ void rocketmq_test_300(int mpnum,int front_index) { std::cout << "Finished sending " << total_messages << " messages." << std::endl; } -///////////////////////////////////////////////////////////////////////////////lnkʵʱ־20250205 -// ------------------ ȫ־б ------------------ +///////////////////////////////////////////////////////////////////////////////lnk实时日志部分20250205 +// ------------------ 全局日志列表和锁 ------------------ std::list errorList; std::list warnList; std::list normalList; -std::list debugList; // debugList +std::list debugList; // 新增 debugList pthread_mutex_t errorListMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t warnListMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t normalListMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t debugListMutex = PTHREAD_MUTEX_INITIALIZER; // debugList +pthread_mutex_t debugListMutex = PTHREAD_MUTEX_INITIALIZER; // 新增 debugList 互斥锁 -// ------------------ ------------------ -bool errorOutputEnabled = false; // Ƿ error д errorList -bool warnOutputEnabled = false; // Ƿ warn д warnList -bool normalOutputEnabled = false; // Ƿ normal д normalList -bool debugOutputEnabled = false; // debug +// ------------------ 输出开关 ------------------ +bool errorOutputEnabled = false; // 是否将 error 级别写入 errorList +bool warnOutputEnabled = false; // 是否将 warn 级别写入 warnList +bool normalOutputEnabled = false; // 是否将 normal 级别写入 normalList +bool debugOutputEnabled = false; // 新增 debug 开关 -// ------------------ ڻָԭʼ ------------------ +// ------------------ 用于恢复原始缓冲区 ------------------ static std::streambuf* g_originalCoutBuf = NULL; static std::streambuf* g_originalClogBuf = NULL; static std::streambuf* g_originalCerrBuf = NULL; -// ------------------ ־ö٣C++98 ------------------ +// ------------------ 日志级别枚举(C++98) ------------------ enum LogLevel { LOGERROR, LOGWARN, LOGNORMAL, - LOGDEBUG // debug + LOGDEBUG // 新增 debug 级别 }; // ------------------------------------------------------------------ -// TeeStreamBuf: дԭʼbuf(ն)ٿlist +// TeeStreamBuf: 先写到原始buf(保持终端输出),再拷贝到list里 // ------------------------------------------------------------------ class TeeStreamBuf : public std::streambuf { public: - // ĬϹ죺ȰָΪNULL + // 默认构造:先把指针设为NULL TeeStreamBuf() : m_originalBuf(NULL), m_level(LOGNORMAL) { pthread_mutex_init(&m_mutex, NULL); } - // ι죺ֱӳʼ + // 带参构造:直接初始化 TeeStreamBuf(std::streambuf* originalBuf, LogLevel level) : m_originalBuf(originalBuf), m_level(level) { pthread_mutex_init(&m_mutex, NULL); } - // ٻ + // 析构函数:销毁互斥锁 virtual ~TeeStreamBuf() { pthread_mutex_destroy(&m_mutex); } - // Զ init(...) ͬһ + // 自定义 init(...) 函数:在同一个对象上重新设置 void init(std::streambuf* originalBuf, LogLevel level) { m_originalBuf = originalBuf; @@ -5930,34 +5987,34 @@ public: } protected: - // flush std::endl ʱ sync() + // 当 flush 或 std::endl 时会调用 sync() virtual int sync() { - // ԭʼִͬ + // 先让原始缓冲区执行同步 if (m_originalBuf) { m_originalBuf->pubsync(); } - // ٽĻ flush + // 再将自身的缓存 flush flushBuffer(); - return 0; // ɹ + return 0; // 成功 } - // дһַʱoverflow() + // 当写入一个新字符时,overflow() 被调用 virtual int_type overflow(int_type ch) { if (ch == traits_type::eof()) { return ch; } - // 1) дԭʼ ն + // 1) 写到原始缓冲区 → 保留终端输出 if (m_originalBuf) { if (m_originalBuf->sputc(static_cast(ch)) == traits_type::eof()) { return traits_type::eof(); } } - // 2) 浽ǵʱ棬ע - pthread_mutex_lock(&m_mutex); //ֹ߳lnk20250305 + // 2) 存到我们的临时缓存,注意加锁保护 + pthread_mutex_lock(&m_mutex); //防止多线程推入崩溃lnk20250305 m_buffer.push_back(static_cast(ch)); - // 3) о flushBuffer() + // 3) 遇到换行就 flushBuffer() if (ch == '\n') { flushBuffer_locked(); } @@ -5966,13 +6023,13 @@ protected: } private: - // ڲ汾ٶѾ + // 内部版本:假定互斥锁已经被加锁 void flushBuffer_locked() { if (m_buffer.empty()) { return; } - // ݵȼͶӦأ m_buffer дӦ list + // 根据等级和对应开关,将 m_buffer 写入相应的 list switch (m_level) { case LOGERROR: if (debugOutputEnabled) { @@ -6031,7 +6088,7 @@ private: m_buffer.clear(); } - // ӿڣڲ m_buffer + // 对外接口,内部对 m_buffer 加锁 void flushBuffer() { pthread_mutex_lock(&m_mutex); @@ -6040,7 +6097,7 @@ private: } private: - // ֹԶɵĸֵ + // 禁止自动生成的赋值函数 TeeStreamBuf& operator=(const TeeStreamBuf&); private: @@ -6050,21 +6107,21 @@ private: pthread_mutex_t m_mutex; }; -// ------------------ ȫTee󣨱ظֵ ------------------ +// ------------------ 全局Tee对象(避免重复赋值) ------------------ static TeeStreamBuf g_errorTeeBuf; static TeeStreamBuf g_warnTeeBuf; static TeeStreamBuf g_normalTeeBuf; -// ------------------ ṩһȫֵ debug ------------------ -// ԭʼbufĬΪ NULLնˣֻ浽 debugList(ؿ) +// ------------------ 我们另外提供一个全局的 debug 输出流 ------------------ +// 其原始buf默认为 NULL(不输出到终端),只存到 debugList(若开关开) //static std::ostream g_debug(&g_debugTeeBuf); -// qDebug() ӳ䵽ȫ +// 让 qDebug() 映射到这个全局流 //#define qDebug() g_debug -// ------------------ ض ------------------ -// ֻڵһʱ init(...) ʼ TeeStreamBuf -// ֮ʱ new ֱֵ֮ǰõĶ +// ------------------ 重定向函数 ------------------ +// 只在第一次启用时,用 init(...) 初始化 TeeStreamBuf; +// 之后再启用时,不再 new 或 赋值,而是直接用之前构造好的对象。 void redirectErrorOutput(bool enabled) { errorOutputEnabled = enabled; @@ -6113,61 +6170,61 @@ void redirectNormalOutput(bool enabled) } } -// ------------------ ض ------------------ +// ------------------ 重定向函数 ------------------ void redirectDebugOutput(bool enable) { debugOutputEnabled = enable; - // ȥ clog.rdbuf() - // ȥ install κ msg handler + // 不去改 clog.rdbuf() + // 不去 install 任何 msg handler } -// ------------------ Qt4 Ϣ ------------------ +// ------------------ Qt4 消息处理函数 ------------------ void myQtMsgHandler(QtMsgType type, const char *msg) { - // ϢΣд debugList + // 不论消息类型如何,都写入 debugList if (debugOutputEnabled) { pthread_mutex_lock(&debugListMutex); debugList.push_back(msg); pthread_mutex_unlock(&debugListMutex); } - // Ϣѡ + // 根据消息类型选择输出流 FILE* output = nullptr; const char* typeStr = ""; switch (type) { case QtDebugMsg: typeStr = "Debug"; - output = stdout; // Debug ߱׼ + output = stdout; // Debug 走标准输出 break; case QtWarningMsg: typeStr = "Warning"; - output = stderr; // Warning ߱׼ + output = stderr; // Warning 走标准错误 break; case QtCriticalMsg: typeStr = "Critical"; - output = stderr; // Critical ߱׼ + output = stderr; // Critical 走标准错误 break; case QtFatalMsg: typeStr = "Fatal"; - output = stderr; // Fatal ߱׼ + output = stderr; // Fatal 走标准错误 break; } fprintf(output, "[%s] %s\n", typeStr, msg); fflush(output); - // Fatal ʱ˳ + // Fatal 时进程退出 if (type == QtFatalMsg) { abort(); } } -// ------------------ Զ printf ------------------ -// ʾ normal => ջnormalList(ؿ) -// һȫ־̬ĻΪ printfmtx +// ------------------ 自定义 printf 输出 ------------------ +// 这里示例:把它当成 normal 级别 => 最终会进入normalList(若开关开) +// 定义一个全局静态的互斥锁,名称为 printfmtx static pthread_mutex_t printfmtx = PTHREAD_MUTEX_INITIALIZER; -// RAIIװ +// RAII风格的锁包装类 class LockGuard { public: explicit LockGuard(pthread_mutex_t& mutex) : mtx(mutex) { @@ -6182,7 +6239,7 @@ private: int customPrintf(const char* format, ...) { - // ڽ뺯ʱԶ˳ʱԶ + // 在进入函数时自动加锁,退出时自动解锁 LockGuard lock(printfmtx); va_list args; @@ -6197,7 +6254,7 @@ int customPrintf(const char* format, ...) return -1; } - // ʽַ std::cout + // 将格式化后的字符串输出到 std::cout std::cout << buffer << std::endl; return written; @@ -6211,11 +6268,11 @@ void echo_msg_errexy(const char *file_name, int line_no, int rv, const char *fmt vsnprintf(__buf, sizeof(__buf), fmt, __ap); va_end(__ap); - // ն + // 终端输出 printf("[ERROR] rv=%d %s:%d => %s", rv, file_name, line_no, __buf); fflush(stdout); - // д errorList + // 写入 errorList if (errorOutputEnabled) { pthread_mutex_lock(&errorListMutex); errorList.push_back(std::string(__buf)); @@ -6230,11 +6287,11 @@ void echo_msg_warnexy(const char *file_name, int line_no, const char *fmt, ...) vsnprintf(__buf, sizeof(__buf), fmt, __ap); va_end(__ap); - // ն + // 终端输出 printf("[WARN ] %s:%d => %s", file_name, line_no, __buf); fflush(stdout); - // д warnList + // 写入 warnList if (warnOutputEnabled) { pthread_mutex_lock(&warnListMutex); warnList.push_back(std::string(__buf)); @@ -6249,11 +6306,11 @@ void echo_msg_debugexy(const char *file_name, int line_no, const char *fmt, ...) vsnprintf(__buf, sizeof(__buf), fmt, __ap); va_end(__ap); - // ն + // 终端输出 printf("[DEBUG] %s:%d => %s", file_name, line_no, __buf); fflush(stdout); - // д normalList + // 写入 normalList if (normalOutputEnabled) { pthread_mutex_lock(&normalListMutex); normalList.push_back(std::string(__buf)); @@ -6264,11 +6321,69 @@ void echo_msg_debugexy(const char *file_name, int line_no, const char *fmt, ...) void Worker::telnetetst(QTcpSocket* clientSocket) { int ip_count = 0; int telnet_count = 0; - //ڲʱ̨˼lnk20250114 + //在测试连接时给台账加锁lnk20250114 pthread_mutex_lock(&mtx); std::cout << "testping hold lock !!!!!!!!!!!" << std::endl; Worker::init_ping_telnet(clientSocket,ip_count, telnet_count); Cout_account_information(); pthread_mutex_unlock(&mtx); std::cout << "testping free lock !!!!!!!!!!!" << std::endl; } +//////////////////////////////////////////////////////////////////////////////// +const char* get_front_msg_from_subdir() { + if (std::strstr(subdir, "cfg_3s_data") != NULL) + return "实时数据进程"; + else if (std::strstr(subdir, "cfg_soe_comtrade") != NULL) + return "暂态和告警进程"; + else if (std::strstr(subdir, "cfg_recallhis_data") != NULL) + return "稳态补招进程"; + else if (std::strstr(subdir, "cfg_stat_data") != NULL) + return "稳态统计进程"; + else + return "unknown"; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void send_reply_to_kafka(const std::string& guid, const std::string& step, const std::string& result) { + // 构造 JSON 字符串 + std::ostringstream oss; + oss << "{" + << "\"guid\":\"" << guid << "\"," + << "\"step\":\"" << step << "\"," + << "\"result\":\"" << result << "\"" + << "}"; + + std::string jsonString = oss.str(); + + // 封装 Kafka 消息 + Ckafka_data_t connect_info; + connect_info.strTopic = QString::fromStdString(Topic_Reply_Topic); + connect_info.strText = QString::fromStdString(jsonString); + + // 加入发送队列(带互斥锁保护) + kafka_data_list_mutex.lock(); + kafka_data_list.append(connect_info); + kafka_data_list_mutex.unlock(); +} + +void send_heartbeat_to_kafka(const std::string& status) { + // 构造 JSON 字符串 + std::ostringstream oss; + oss << "{" + << "\"nodeId\":\"" << FRONT_INST << "\"," + << "\"frontType\":\"" << get_front_type_from_subdir() << "\"," + << "\"processNum\":\"" << g_front_seg_index << "\"," + << "\"status\":\"" << status << "\"" + << "}"; + + std::string jsonString = oss.str(); + + // 封装 Kafka 消息 + Ckafka_data_t connect_info; + connect_info.strTopic = QString::fromStdString(Heart_Beat_Topic); + connect_info.strText = QString::fromStdString(jsonString); + + // 加入发送队列(带互斥锁保护) + kafka_data_list_mutex.lock(); + kafka_data_list.append(connect_info); + kafka_data_list_mutex.unlock(); +} \ No newline at end of file diff --git a/cfg_parse/datahub.cpp b/cfg_parse/datahub.cpp index 2cfb208..03b8847 100644 --- a/cfg_parse/datahub.cpp +++ b/cfg_parse/datahub.cpp @@ -17,7 +17,7 @@ using namespace std; #include #include #include "../mms/db_interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" #ifdef __cplusplus @@ -35,29 +35,29 @@ size_t req_reply_datahub(void* ptr, size_t size, size_t nmemb, void* stream) void SendWebAPI_Datahub(const string strUrl,char* topic,char* data) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "topic", cJSON_CreateString(topic)); @@ -67,16 +67,16 @@ void SendWebAPI_Datahub(const string strUrl,char* topic,char* data) curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_datahub); string resPost0; @@ -84,22 +84,22 @@ void SendWebAPI_Datahub(const string strUrl,char* topic,char* data) curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>Testaliyun datahub Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("aliyun datahub failed res code: "); } else { printf("aliyun datahub success,string %s", resPost0.c_str()); - //webapiֵж + //后期添加webapi返回值判断 } curl_slist_free_all(header_list); diff --git a/cfg_parse/log4.cpp b/cfg_parse/log4.cpp new file mode 100644 index 0000000..3da00b2 --- /dev/null +++ b/cfg_parse/log4.cpp @@ -0,0 +1,478 @@ + +#include "../log4cplus/logger.h" +#include "../log4cplus/configurator.h" +#include "../log4cplus/fileappender.h" +#include "../log4cplus/layout.h" +#include "../log4cplus/ndc.h" +#include "../log4cplus/log4.h" +#include "../log4cplus/spi/loggingevent.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +//目录创建 +#include +#include +//kafka结构定义 +#include "../json/mms_json_inter.h" + + +#include "../mms/rdb_client.h" +#include "../include/node.h"//lnk20241223 + + +extern unsigned int g_node_id; +extern int g_front_seg_index; +extern char subdir[128]; +extern node_t* g_node; + + +//mq +extern QMutex kafka_data_list_mutex; //Kafka发送数据锁 +extern QList kafka_data_list; //kafka发送数据链表 + +//辅助函数 +extern std::string intToString(int number); + +//日志主题 +extern std::string G_LOG_TOPIC; + +//log4命名空间 +using namespace log4cplus; +using namespace log4cplus::helpers; + +////////////////////////////////////////////////////////辅助函数 +std::string get_front_type_from_subdir() { + if (std::strstr(subdir, "cfg_3s_data") != NULL) + return "realTime"; + else if (std::strstr(subdir, "cfg_soe_comtrade") != NULL) + return "comtrade"; + else if (std::strstr(subdir, "cfg_recallhis_data") != NULL) + return "recall"; + else if (std::strstr(subdir, "cfg_stat_data") != NULL) + return "stat"; + else + return "unknown"; +} + +// 递归创建目录 +bool create_directory_recursive(const std::string& path) { + size_t pos = 0; + std::string current; + while (pos != std::string::npos) { + pos = path.find('/', pos + 1); + current = path.substr(0, pos); + if (!current.empty() && access(current.c_str(), F_OK) != 0) { + if (mkdir(current.c_str(), 0755) != 0) { + perror(("mkdir failed: " + current).c_str()); + return false; + } + } + } + return true; +} +////////////////////////////////////////////////////////////////////// +TypedLogger::TypedLogger() {} +TypedLogger::TypedLogger(const Logger& l, int t) : logger(l), logtype(t) {} + +DebugSwitch::DebugSwitch() : debug_open(false), min_level(WARN_LOG_LEVEL) {} +void DebugSwitch::open() { debug_open = true; } +void DebugSwitch::close() { + debug_open = false; + targets.clear(); + type_enable.clear(); +} +void DebugSwitch::set_target(const std::string& name) { targets.insert(name); } +void DebugSwitch::set_level(int level) { min_level = level; } +void DebugSwitch::enable_type(int type) { type_enable[type] = true; } +void DebugSwitch::disable_type(int type) { type_enable[type] = false; } + +bool DebugSwitch::match(const std::string& logger_name, int level, int logtype) { + if (!debug_open) return false; + if (level < min_level) return false; + if (type_enable.count(logtype) && !type_enable[logtype]) return false; + std::set::iterator it; + for (it = targets.begin(); it != targets.end(); ++it) { + if (logger_name.find(*it) != std::string::npos) + return true; + } + return false; +} + +std::map logger_map; +DebugSwitch g_debug_switch; + +class SendAppender : public Appender { +protected: + void append(const spi::InternalLoggingEvent& event) { + std::string logger_name = event.getLoggerName(); + int level = event.getLogLevel(); + std::string msg = event.getMessage(); + + int logtype = (logger_name.find(".COM") != std::string::npos) ? LOGTYPE_COM : LOGTYPE_DATA; + std::string level_str; + if (logger_name.find("process") == 0) + level_str = "process"; + else if (logger_name.find("monitor") != std::string::npos) + level_str = "measurepoint"; + else + level_str = "terminal"; + + if (level == ERROR_LOG_LEVEL || level == WARN_LOG_LEVEL || g_debug_switch.match(logger_name, level, logtype)) { + std::ostringstream oss; + oss << "{\"processNo\":\"" << intToString(g_front_seg_index) + << "\",\"id\":\"" << logger_name + << "\",\"level\":\"" << level_str + << "\",\"grade\":\"" << level + << "\",\"logtype\":\"" << (logtype == LOGTYPE_COM ? "com" : "data") + << "\",\"frontType\":\"" << get_front_type_from_subdir() + << "\",\"log\":\"" << escape_json(msg) << "\"}"; + + std::string jsonString = oss.str(); + + Ckafka_data_t connect_info; + connect_info.strTopic = QString::fromStdString(G_LOG_TOPIC); + connect_info.strText = QString::fromStdString(jsonString); + + 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::ostringstream ss; + for (unsigned int i = 0; i < input.size(); ++i) { + switch (input[i]) { + case '\\': ss << "\\\\"; break; + case '"': ss << "\\\""; break; + case '\n': ss << "\\n"; break; + case '\r': ss << "\\r"; break; + case '\t': ss << "\\t"; break; + default: ss << input[i]; break; + } + } + return ss.str(); + } + + virtual void close() { + // 可空实现 + } + +public: + SendAppender() {} +}; + +//用来控制日志上送的结构 +struct LOGEntry { + std::string id; + std::string level; // terminal / measurepoint + int logtype; // com / data + int min_grade; + int countdown; +}; + +//日志上送map管理 +std::map 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 则删除 +void update_log_entries_countdown() { + pthread_mutex_lock(&g_log_mutex); + std::map::iterator it = g_log_entries.begin(); + while (it != g_log_entries.end()) { + if (it->second.countdown > 0) { + it->second.countdown--; + if (it->second.countdown == 0) { + std::cout << "[LOG] debug日志上送自动关闭: " << it->first << std::endl; + it = g_log_entries.erase(it); + continue; + } + } + ++it; + } + 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) { + if (level != "terminal" && level != "measurepoint") return; + + int type = (logtype_str == "com") ? LOGTYPE_COM : LOGTYPE_DATA; + int grade_level = (grade == "DEBUG") ? DEBUG_LOG_LEVEL : INFO_LOG_LEVEL; + + std::string key = build_debug_key(id, level, type); + + pthread_mutex_lock(&g_log_mutex); + + LOGEntry& entry = g_log_entries[key]; // 会自动 insert 或取已有 + entry.id = id; + entry.level = level; + entry.logtype = type; + entry.min_grade = grade_level; + entry.countdown = 60; // 重置倒计时 + + pthread_mutex_unlock(&g_log_mutex); + +} + +Logger init_logger(const std::string& full_name, const std::string& file_dir, const std::string& base_file) { + // 确保日志目录存在 + create_directory_recursive(file_dir); + + Logger logger = Logger::getInstance(full_name); + std::string file_path = file_dir + "/" + base_file + ".log"; + + // 使用滚动日志(大小轮转),最多保留 2 个备份,每个最大 1MB + SharedAppenderPtr fileAppender(new RollingFileAppender(file_path, 1 * 1024 * 1024, 2)); + + fileAppender->setLayout(std::auto_ptr( + new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n"))); + + SharedAppenderPtr sendAppender(new SendAppender()); + logger.addAppender(fileAppender); + logger.addAppender(sendAppender); + logger.setLogLevel(DEBUG_LOG_LEVEL); + return logger; +} + +//进程的日志 +void init_logger_process() { + std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log"; + logger_map["process"] = TypedLogger(init_logger("process", base_dir, "process"), LOGTYPE_DATA); + std::cout << "process log init ok" << std::endl; +} + +//终端的日志 +void init_loggers_bydevid(const char* dev_id) +{ + if (!dev_id) return; + + std::string terminal_id(dev_id); // 转为 std::string + std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log"; + + ied_t* ied = NULL; + int iedno; + ied_usr_t* ied_usr = NULL; + + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + + if (!ied || !ied->usr_ext) { + std::cout << "ied No."<< iedno << " is null" << std::endl; + continue; + } + + ied_usr = (ied_usr_t*)ied->usr_ext; + + //跳过不匹配的终端 + if (strcmp(ied_usr->terminal_id, dev_id) != 0) continue; + + const char* ip_cstr = (ied->channel[0].addr_str != NULL) ? ied->channel[0].addr_str : "unknown"; + + std::string ip_str(ip_cstr); + + std::string device_dir = base_dir + "/" + ip_str; + + std::string device_key = std::string("terminal.") + dev_id; + + // 添加判断:终端日志 logger 是否已存在 + if (logger_map.find(ip_str + ".COM") == logger_map.end() && + logger_map.find(ip_str + ".DATA") == logger_map.end()) { + + // 所有终端日志(com 和 data)写到同一个 device 日志文件中 + Logger device_logger = init_logger(device_key, device_dir, dev_id); //用终端id作为日志文件名 + logger_map[ip_str + ".COM"] = TypedLogger(device_logger, LOGTYPE_COM); + logger_map[ip_str + ".DATA"] = TypedLogger(device_logger, LOGTYPE_DATA); + } + + // 初始化监测点 + // 监测点 logger 名称格式:monitor..COM / .DATA + for (int i = 0; i < 10; ++i) { + if (strlen(ied_usr->LD_info[i].mp_id) > 0){ + std::ostringstream mon_key, mon_path, mon_name; + mon_key << "monitor." << ied_usr->LD_info[i].mp_id; + mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录 + mon_name << ied_usr->LD_info[i].mp_id; + + // 添加判断:监测点 logger 是否已存在 + if (logger_map.find(mon_key.str() + ".COM") == logger_map.end() && + logger_map.find(mon_key.str() + ".DATA") == logger_map.end()) { + + Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str()); + logger_map[mon_key.str() + ".COM"] = TypedLogger(mon_logger, LOGTYPE_COM); + logger_map[mon_key.str() + ".DATA"] = TypedLogger(mon_logger, LOGTYPE_DATA); + } + } + + } + + break; // 只匹配一个 terminal_id + } +} + +void init_loggers() { + std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log"; + + ied_t* ied = NULL; + int iedno; + ied_usr_t* ied_usr = NULL; + + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + + if (!ied || !ied->usr_ext) { + std::cout << "ied No."<< iedno << " is null" << std::endl; + continue; + } + + ied_usr = (ied_usr_t*)ied->usr_ext; + + const char* ip_cstr = (ied->channel[0].addr_str != NULL) ? ied->channel[0].addr_str : "unknown"; + + std::string ip_str(ip_cstr); + + std::string device_dir = base_dir + "/" + ip_str; + + std::string device_key = std::string("terminal.") + ied_usr->terminal_id; + + // 所有终端日志(com 和 data)写到同一个 device 日志文件中 + Logger device_logger = init_logger(device_key, device_dir, ied_usr->terminal_id); //用终端id作为日志文件名 + logger_map[device_key + ".COM"] = TypedLogger(device_logger, LOGTYPE_COM); + logger_map[device_key + ".DATA"] = TypedLogger(device_logger, LOGTYPE_DATA); + + char buf[256]; + sprintf(buf, "终端id:%s终端级日志初始化完毕", ied_usr->terminal_id); + LOG4CPLUS_DEBUG(logger_map[device_key + ".DATA"].logger, buf); + + // 初始化监测点 + // 监测点 logger 名称格式:monitor..COM / .DATA + for (int i = 0; i < 10; ++i) { + if (strlen(ied_usr->LD_info[i].mp_id) > 0){ + std::ostringstream mon_key, mon_path, mon_name; + mon_key << "monitor." << ied_usr->LD_info[i].mp_id; + mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录 + mon_name << ied_usr->LD_info[i].mp_id; + + Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str()); + + logger_map[mon_key.str() + ".COM"] = TypedLogger(mon_logger, LOGTYPE_COM); + logger_map[mon_key.str() + ".DATA"] = TypedLogger(mon_logger, LOGTYPE_DATA); + + char buf[256]; + sprintf(buf, "监测点id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].mp_id); + LOG4CPLUS_DEBUG(logger_map[mon_key.str() + ".DATA"].logger, buf); + } + + } + + } +} + +void remove_loggers_by_terminal_id(const char* terminal_id_cstr) { + if (!g_node || !terminal_id_cstr) return; + + std::string terminal_id(terminal_id_cstr); // 转为 std::string + + 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; + if (strcmp(ied_usr->terminal_id, terminal_id.c_str()) != 0) continue; + + // 删除终端日志 logger + std::string com_key = "terminal." + terminal_id + ".COM"; + std::string data_key = "terminal." + terminal_id + ".DATA"; + + if (logger_map.count(com_key)) { + logger_map[com_key].logger.removeAllAppenders(); + logger_map.erase(com_key); + } + + if (logger_map.count(data_key)) { + logger_map[data_key].logger.removeAllAppenders(); + logger_map.erase(data_key); + } + + // 删除监测点日志 logger + for (int i = 0; i < 10; ++i) { + const char* mp_id = ied_usr->LD_info[i].mp_id; + if (strlen(mp_id) > 0) { + std::string mon_prefix = std::string("monitor.") + mp_id; + + std::string mon_com_key = mon_prefix + ".COM"; + std::string mon_data_key = mon_prefix + ".DATA"; + + 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); + } + } + } + + std::cout << "[LOG] Logger for terminal_id=" << terminal_id << " removed.\n"; + break; // 找到匹配终端后退出 + } +} + +extern "C" { + + // 公共函数 + void log4_log_with_level(const char* key, const char* msg, int level) { + std::map::iterator it = logger_map.find(key); + if (it == logger_map.end()) return; + + Logger logger = it->second.logger; + switch (level) { + case 0: LOG4CPLUS_DEBUG(logger, msg); break; + case 1: LOG4CPLUS_INFO(logger, msg); break; + case 2: LOG4CPLUS_WARN(logger, msg); break; + case 3: LOG4CPLUS_ERROR(logger, msg); break; + default: break; + } + } + + // 四个包装函数 + void log_debug(const char* key, const char* msg) { log4_log_with_level(key, msg, 0); } + void log_info (const char* key, const char* msg) { log4_log_with_level(key, msg, 1); } + void log_warn (const char* key, const char* msg) { log4_log_with_level(key, msg, 2); } + void log_error(const char* key, const char* msg) { log4_log_with_level(key, msg, 3); } + +} + + +/* +int main() { + initialize(); + init_loggers(); + + LOG4CPLUS_INFO(logger_map["process.1.data"].logger, "程序启动,PID=" << getpid()); + + LOG4CPLUS_WARN(logger_map["terminal.192.168.1.1.com"].logger, "串口异常,尝试重连"); + LOG4CPLUS_INFO(logger_map["terminal.192.168.1.1.data"].logger, "终端运行状态正常"); + LOG4CPLUS_DEBUG(logger_map["measurepoint.192.168.1.1.monitor1.data"].logger, "电压测量值=220.1V"); + + process_log_command("192.168.1.1.monitor1", "measurepoint", "DEBUG", "data"); + LOG4CPLUS_DEBUG(logger_map["measurepoint.192.168.1.1.monitor1.data"].logger, "频率测量值=50.0Hz"); + + sleep(65); + LOG4CPLUS_ERROR(logger_map["terminal.192.168.1.2.data"].logger, "终端掉线"); + + return 0; +} +*/ \ No newline at end of file diff --git a/cfg_parse/nacos.cpp b/cfg_parse/nacos.cpp index 8277f09..9c0e2f9 100644 --- a/cfg_parse/nacos.cpp +++ b/cfg_parse/nacos.cpp @@ -18,7 +18,7 @@ using namespace std; #include #include #include "../mms/db_interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" #ifdef __cplusplus @@ -35,39 +35,39 @@ size_t req_reply_nacos(void* ptr, size_t size, size_t nmemb, void* stream) void read_nacos_param(const char* ptr, char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret) { //cout << ">>>GetDevice in reply" << (char*)ptr; int flag = 1; - cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json = cJSON_Parse((char*)ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "postgres_uid"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "postgres_uid"); //获取result if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { strcpy(postgres_uid, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "postgres_pwd"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "postgres_pwd"); //获取result if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { strcpy(postgres_pwd, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "web_clientid"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "web_clientid"); //获取result if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { strcpy(web_clientid, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "web_clientsecret"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "web_clientsecret"); //获取result if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { strcpy(web_clientsecret, json_node->valuestring); } @@ -77,57 +77,57 @@ void read_nacos_param(const char* ptr, char* postgres_uid, char* postgres_pwd, c } void releaseMemory(char** ptr) { if (*ptr != NULL) { - free(*ptr); // ͷڴ + free(*ptr); // 释放内存 } } void SendWebAPI_Nacos(const string strUrl, const char* code, char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); char* szjson = cJSON_Print(json_root); printf(">>>json %s\n", szjson); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_nacos); string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>Test nacos Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("nacos failed res code: "); } else { printf("nacos success,string %s", resPost0.c_str()); - //webapiֵж + //后期添加webapi返回值判断 read_nacos_param(resPost0.c_str(), postgres_uid, postgres_pwd, web_clientid, web_clientsecret); } curl_slist_free_all(header_list); @@ -142,34 +142,34 @@ void SendWebAPI_Nacos(const string strUrl, const char* code, char* postgres_uid, } void SendWebAPI_Nacos_Ptr(const string strUrl, const char* code, char** ptr) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { char url[100]; sprintf(url, "%s?code=%s", strUrl.c_str(), code); printf(">>>json %s\n", url); - // URL + // 设置URL curl_easy_setopt(curl, CURLOPT_URL, url); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_nacos); string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("nacos failed res code: "); } else { printf(">>> nacos return str:%s \n", resPost0.c_str()); - *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 㹻ڴռ + *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 分配足够的内存空间 if (*ptr != NULL) { strcpy(*ptr, resPost0.c_str()); } @@ -196,96 +196,96 @@ void Read_Nacos_Param_Postgres(char** database_ip, char** database_port, char** char* ptr=NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "postgres", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "ip"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "ip"); //获取result if (json_node && json_node->type == cJSON_String) { if (*database_ip != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*database_ip); } - *database_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *database_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*database_ip, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "port"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "port"); //获取result if (json_node && json_node->type == cJSON_String) { if (*database_port != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*database_port); } - *database_port = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *database_port = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*database_port, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "database"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "database"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_database != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_database); } - *postgres_database = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_database = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_database, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "username"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "username"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_username != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_username); } - *postgres_username = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_username = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_username, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "password"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "password"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_password != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_password); } - *postgres_password = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_password = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_password, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "schema"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "schema"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_schema != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_schema); } - *postgres_schema = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_schema = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_schema, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "dnsname"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "dnsname"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_dnsname != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_dnsname); } - *postgres_dnsname = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_dnsname = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_dnsname, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "tablePrefix"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "tablePrefix"); //获取result if (json_node && json_node->type == cJSON_String) { if (*postgres_tableprefix != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*postgres_tableprefix); } - *postgres_tableprefix = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *postgres_tableprefix = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*postgres_tableprefix, json_node->valuestring); } } @@ -299,132 +299,132 @@ void Read_Nacos_Param_Kafka(char** broker_list, char** topic_stat, char** topic_ char* ptr = NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "kafka", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "brokerList"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "brokerList"); //获取result if (json_node && json_node->type == cJSON_String) { if (*broker_list != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*broker_list); } - *broker_list = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *broker_list = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*broker_list, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "hisTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "hisTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_stat != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_stat); } - *topic_stat = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_stat = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_stat, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "pstTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "pstTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_pst != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_pst); } - *topic_pst = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_pst = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_pst, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "pltTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "pltTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_plt != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_plt); } - *topic_plt = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_plt = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_plt, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "eventTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "eventTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_event != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_event); } - *topic_event = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_event = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_event, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "almTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "almTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_alarm != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_alarm); } - *topic_alarm = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_alarm = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_alarm, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "sngTopic"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "sngTopic"); //获取result if (json_node && json_node->type == cJSON_String) { if (*topic_sng != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*topic_sng); } - *topic_sng = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *topic_sng = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*topic_sng, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "protocol"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "protocol"); //获取result if (json_node && json_node->type == cJSON_String) { if (*protocol != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*protocol); } - *protocol = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *protocol = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*protocol, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "mechanisms"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "mechanisms"); //获取result if (json_node && json_node->type == cJSON_String) { if (*mechanisms != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*mechanisms); } - *mechanisms = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *mechanisms = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*mechanisms, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "serviceName"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "serviceName"); //获取result if (json_node && json_node->type == cJSON_String) { if (*service_name != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*service_name); } - *service_name = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *service_name = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*service_name, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "principal"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "principal"); //获取result if (json_node && json_node->type == cJSON_String) { if (*principal != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*principal); } - *principal = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *principal = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*principal, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "domainName"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "domainName"); //获取result if (json_node && json_node->type == cJSON_String) { if (*domain_name != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*domain_name); } - *domain_name = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *domain_name = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*domain_name, json_node->valuestring); } } @@ -435,69 +435,69 @@ void Read_Nacos_Param_Web(char** client_id, char** client_secret, char** token_u char* ptr = NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "web", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "clientId"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "clientId"); //获取result if (json_node && json_node->type == cJSON_String) { if (*client_id != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*client_id); } - *client_id = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *client_id = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*client_id, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "clientSecret"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "clientSecret"); //获取result if (json_node && json_node->type == cJSON_String) { if (*client_secret != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*client_secret); } - *client_secret = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *client_secret = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*client_secret, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "tokenUrl"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "tokenUrl"); //获取result if (json_node && json_node->type == cJSON_String) { if (*token_url != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*token_url); } - *token_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *token_url = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*token_url, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "deviceUrl"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "deviceUrl"); //获取result if (json_node && json_node->type == cJSON_String) { if (*device_url != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*device_url); } - *device_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *device_url = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*device_url, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "grantType"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "grantType"); //获取result if (json_node && json_node->type == cJSON_String) { if (*grant_type != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*grant_type); } - *grant_type = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *grant_type = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*grant_type, json_node->valuestring); } @@ -509,46 +509,46 @@ void Read_Nacos_Param_Flag(int* file_flag, int* send_flag, int* front_inst, ch char* ptr = NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "flag", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error: %s\n", ptr); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "fileFlag"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "fileFlag"); //获取result if (json_node && json_node->type == cJSON_String) { *file_flag= atoi(json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "sendFlag"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "sendFlag"); //获取result if (json_node && json_node->type == cJSON_String) { *send_flag = atoi(json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "frontInst"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "frontInst"); //获取result if (json_node && json_node->type == cJSON_String) { *front_inst = atoi(json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "frontIP"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "frontIP"); //获取result if (json_node && json_node->type == cJSON_String) { //***postgres_pwd = json_node->valuestring; if (*front_ip != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*front_ip); } - *front_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *front_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*front_ip, json_node->valuestring); } @@ -560,35 +560,35 @@ void Read_Nacos_Param_Recall(int* recall_len, int* recall_sta, int* recall_daily char* ptr = NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "recall", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "recall_lenth"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "recall_lenth"); //获取result if (json_node && json_node->type == cJSON_String) { *recall_len = atoi(json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "recall_start"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "recall_start"); //获取result if (json_node && json_node->type == cJSON_String) { *recall_sta = atoi(json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "recall_dailytime"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "recall_dailytime"); //获取result if (json_node && json_node->type == cJSON_String) { *recall_daily = atoi(json_node->valuestring); } @@ -600,51 +600,51 @@ void Read_Nacos_Param_Uds(char** uds_upload_url, char** uds_download_url, char** char* ptr = NULL; SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "uds", &ptr); int flag = 1; - cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json = cJSON_Parse(ptr); //json格式序列化 cJSON* json_node; cJSON* json_param; if (json == NULL) { printf("nacos error %s\n", cJSON_GetErrorPtr()); } else { - json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + json_node = cJSON_GetObjectItem(json, "status"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { printf("status error :%s\n", cJSON_GetErrorPtr()); flag = 0; } - json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + json_node = cJSON_GetObjectItem(json, "errors"); //获取result if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { printf("errors get falie: %s\n", cJSON_GetErrorPtr()); flag = 0; } if (flag) { printf("read nacos success\n"); - json_param = cJSON_GetObjectItem(json, "param"); //ȡresult - json_node = cJSON_GetObjectItem(json_param, "udsUploadUrl"); //ȡresult + json_param = cJSON_GetObjectItem(json, "param"); //获取result + json_node = cJSON_GetObjectItem(json_param, "udsUploadUrl"); //获取result if (json_node && json_node->type == cJSON_String) { if (*uds_upload_url != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*uds_upload_url); } - *uds_upload_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *uds_upload_url = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*uds_upload_url, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "udsDownloadUrl"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "udsDownloadUrl"); //获取result if (json_node && json_node->type == cJSON_String) { if (*uds_download_url != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*uds_download_url); } - *uds_download_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *uds_download_url = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*uds_download_url, json_node->valuestring); } - json_node = cJSON_GetObjectItem(json_param, "UdsDeleteUrl"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "UdsDeleteUrl"); //获取result if (json_node && json_node->type == cJSON_String) { if (*uds_delete_url != NULL) { - // Ѿڴ棬ͷڴ + // 如果已经分配了内存,则释放内存 free(*uds_delete_url); } - *uds_delete_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + *uds_delete_url = (char*)malloc(strlen(json_node->valuestring) + 1); // 分配内存 strcpy(*uds_delete_url, json_node->valuestring); } diff --git a/cfg_parse/obs_huaweiyun.cpp b/cfg_parse/obs_huaweiyun.cpp index 18f9b18..7bbd145 100644 --- a/cfg_parse/obs_huaweiyun.cpp +++ b/cfg_parse/obs_huaweiyun.cpp @@ -19,7 +19,7 @@ using namespace std; #include #include "../mms/db_interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" #ifdef __cplusplus extern "C" { @@ -40,33 +40,33 @@ size_t req_reply_device(void* ptr, size_t size, size_t nmemb, void* stream) void SendWebAPI_Test(const string strUrl) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON* json_param = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "code", cJSON_CreateString("putObject")); cJSON_AddItemToObject(json_root, "param", json_param); - //param + //param层 cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString("comtrade/pq/Device.xml")); cJSON_AddItemToObject(json_param, "localfile_name", cJSON_CreateString("/FeProject/etc/Device_Config.xml")); @@ -77,16 +77,16 @@ void SendWebAPI_Test(const string strUrl) //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); @@ -95,14 +95,14 @@ void SendWebAPI_Test(const string strUrl) curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>TestHuaweiyun Obs Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("Huaweiyun Obs failed res code: " ); } @@ -128,32 +128,32 @@ void TestOBS() void SendWebAPI(const string strUrl, char* localpath, char* cloudpath,const char* code) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON* json_param = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); cJSON_AddItemToObject(json_root, "param", json_param); - //param + //param层 cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString(cloudpath)); cJSON_AddItemToObject(json_param, "localfile_name", cJSON_CreateString(localpath)); @@ -161,16 +161,16 @@ void SendWebAPI(const string strUrl, char* localpath, char* cloudpath,const char printf(">>>json %s\n", szjson); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); @@ -179,14 +179,14 @@ void SendWebAPI(const string strUrl, char* localpath, char* cloudpath,const char curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>TestHuaweiyun Obs Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("Huaweiyun Obs failed res code: "); } @@ -212,32 +212,32 @@ void OBSFile(char* localpath,char* cloudpath,const char* code) void SendWebAPI_del(const string strUrl, char* cloudpath, const char* code) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON* json_param = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); cJSON_AddItemToObject(json_root, "param", json_param); - //param + //param层 cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString(cloudpath)); cJSON_AddNullToObject(json_param, "localfile_name"); @@ -246,16 +246,16 @@ void SendWebAPI_del(const string strUrl, char* cloudpath, const char* code) curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); @@ -264,14 +264,14 @@ void SendWebAPI_del(const string strUrl, char* cloudpath, const char* code) curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>TestHuaweiyun Obs Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("Huaweiyun Obs failed res code: "); } diff --git a/cfg_parse/oss_aliyun.cpp b/cfg_parse/oss_aliyun.cpp index 01124c7..0c4268f 100644 --- a/cfg_parse/oss_aliyun.cpp +++ b/cfg_parse/oss_aliyun.cpp @@ -47,7 +47,7 @@ void TestOSS() aos_pool_t *pool = NULL; apr_status_t ret; - /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/ printf(">>>TestOSS ini Start"); if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { return; @@ -65,13 +65,13 @@ void TestOSS() return ; } -void PutOSS(char* File_Name,char* data) //zw޸ 2023-9-7 ossļ +void PutOSS(char* File_Name,char* data) //zw修改 2023-9-7 上送oss文件 { apr_file_t* output = NULL; aos_pool_t* pool = NULL; apr_status_t ret; - /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/ printf(">>>PutOSS ini Start"); printf(File_Name); printf(data); @@ -82,7 +82,7 @@ void PutOSS(char* File_Name,char* data) //zw printf(">>>PutOSS put Start"); - put_object_from_file_new(File_Name, data);//ʹbufferļ + put_object_from_file_new(File_Name, data);//使用buffer推送文件 printf(">>>PutOSS put End"); @@ -91,13 +91,13 @@ void PutOSS(char* File_Name,char* data) //zw return; } -void GetOSS(char* File_Name,char* savepath) //zw޸ 2023-9-7 ȡossļ +void GetOSS(char* File_Name,char* savepath) //zw修改 2023-9-7 获取oss文件 { apr_file_t* output = NULL; aos_pool_t* pool = NULL; apr_status_t ret; - /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/ printf(">>>GetOSS ini Start"); if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { return; @@ -105,7 +105,7 @@ void GetOSS(char* File_Name,char* savepath) //zw printf(">>>GetOSS put Start"); - get_object_to_file_new(File_Name,savepath);//ʹbufferļ + get_object_to_file_new(File_Name,savepath);//使用buffer推送文件 printf(">>>GetOSS put End"); @@ -120,7 +120,7 @@ void DelOSS(char* File_Name) aos_pool_t* pool = NULL; apr_status_t ret; - /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/ printf(">>>DelOSS ini Start"); if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { return; @@ -128,7 +128,7 @@ void DelOSS(char* File_Name) printf(">>>DelOSS put Start"); - delete_object_new(File_Name);//ʹbufferļ + delete_object_new(File_Name);//使用buffer推送文件 printf(">>>DelOSS put End"); @@ -194,7 +194,7 @@ void put_object_from_buffer() aos_pool_destroy(p); } -void put_object_from_buffer_new(char* File_Name,char* data)//zw޸ 2023-9-7 oss +void put_object_from_buffer_new(char* File_Name,char* data)//zw修改 2023-9-7 oss推送 { aos_pool_t* p = NULL; aos_string_t bucket; @@ -237,7 +237,7 @@ void put_object_from_file() aos_pool_t *p = NULL; aos_string_t bucket; aos_string_t object; - /* ǷʹCNAME0ʾʹá*/ + /* 是否使用了CNAME。0表示不使用。*/ int is_cname = 0; aos_table_t *headers = NULL; aos_table_t *resp_headers = NULL; @@ -246,9 +246,9 @@ void put_object_from_file() aos_status_t *s = NULL; aos_string_t file; - /* ڴڴأpoolȼapr_pool_tʵִaprС*/ + /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/ aos_pool_create(&p, NULL); - /* ʼoptionsòendpointaccess_key_idacces_key_secretis_cnamecurlȫϢ*/ + /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/ options = oss_request_options_create(p); init_sample_request_options(options, is_cname); aos_str_set(&bucket, BUCKET_NAME); @@ -274,7 +274,7 @@ void put_object_from_file_new(char* File_Name, char* path) aos_pool_t* p = NULL; aos_string_t bucket; aos_string_t object; - /* ǷʹCNAME0ʾʹá*/ + /* 是否使用了CNAME。0表示不使用。*/ int is_cname = 0; aos_table_t* headers = NULL; aos_table_t* resp_headers = NULL; @@ -283,9 +283,9 @@ void put_object_from_file_new(char* File_Name, char* path) aos_status_t* s = NULL; aos_string_t file; - /* ڴڴأpoolȼapr_pool_tʵִaprС*/ + /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/ aos_pool_create(&p, NULL); - /* ʼoptionsòendpointaccess_key_idacces_key_secretis_cnamecurlȫϢ*/ + /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/ options = oss_request_options_create(p); init_sample_request_options(options, is_cname); aos_str_set(&bucket, BUCKET_NAME); diff --git a/cfg_parse/uds_huaweiyun.cpp b/cfg_parse/uds_huaweiyun.cpp index 229f411..fdd8913 100644 --- a/cfg_parse/uds_huaweiyun.cpp +++ b/cfg_parse/uds_huaweiyun.cpp @@ -17,7 +17,7 @@ using namespace std; #include #include #include "../mms/db_interface.h" -#include "../json/cjson.h"//WW 2023-08-27json +#include "../json/cjson.h"//WW 2023-08-27新增json解析函数 #include "../include/curl/curl.h" #ifdef __cplusplus @@ -31,33 +31,33 @@ size_t req_reply(void* ptr, size_t size, size_t nmemb, void* stream) return size * nmemb; } /** -* @brief Get_Uuid json,õuuid -* @param ptr -* @param uuid ݴС -* @return int 0ɹ -1Ч -* ע⣺ݵĴС44ı +* @brief Get_Uuid 解析返回json,得到uuid +* @param ptr 需解码的数据 +* @param uuid 需解码的数据大小 +* @return int 0:成功 -1:无效参数 +* 注意:解码的数据的大小必须大于4,且是4的倍数 */ int Get_Uuid(const char* ptr, char* uuid,char* filename) { int result = 0; - cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json = cJSON_Parse((char*)ptr); //json格式序列化 cJSON* json_code; cJSON* json_data; cJSON* json_msg; if (json) { - json_code = cJSON_GetObjectItem(json, "code"); //ȡsuccess - json_msg = cJSON_GetObjectItem(json, "msg"); //ȡsuccess - json_data = cJSON_GetObjectItem(json, "data"); //ȡdata + json_code = cJSON_GetObjectItem(json, "code"); //获取success + json_msg = cJSON_GetObjectItem(json, "msg"); //获取success + json_data = cJSON_GetObjectItem(json, "data"); //获取data if (json_code && json_code->type == cJSON_Number && json_code->valueint==0) { printf("upload uds success\n"); cJSON* json_uuid; cJSON* json_filename; - json_uuid = cJSON_GetObjectItem(json_data, "storeId"); //ȡdata + json_uuid = cJSON_GetObjectItem(json_data, "storeId"); //获取data if (json_uuid && json_uuid->type == cJSON_String) { strcpy(uuid, json_uuid->valuestring); printf("read uds uuid success:%s\n", uuid); } - json_filename = cJSON_GetObjectItem(json_data, "fileName"); //ȡdata + json_filename = cJSON_GetObjectItem(json_data, "fileName"); //获取data if (json_filename && json_filename->type == cJSON_String) { strcpy(filename, json_filename->valuestring); printf("read uds filename success:%s\n", filename); @@ -82,10 +82,10 @@ int Get_Uuid(const char* ptr, char* uuid,char* filename) cJSON_Delete(json); return result; } -// ֽдļ +// 将字节数组写入文件 void Write_Byte_Array_To_File(char* local_path, char* data_array, long size) { - // ֽдļ + // 将字节数组写入文件 FILE* outFile = fopen(local_path, "wb"); if (outFile != NULL) { fwrite(data_array, sizeof(char), size, outFile); @@ -98,21 +98,21 @@ void Write_Byte_Array_To_File(char* local_path, char* data_array, long size) } void Save_File(const char* ptr, char* local_path) { - cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json = cJSON_Parse((char*)ptr); //json格式序列化 cJSON* json_success; cJSON* json_data; cJSON* json_msg; if (json) { - json_success = cJSON_GetObjectItem(json, "sucess"); //ȡsuccess - json_msg = cJSON_GetObjectItem(json, "msg"); //ȡsuccess - json_data = cJSON_GetObjectItem(json, "data"); //ȡdata + json_success = cJSON_GetObjectItem(json, "sucess"); //获取success + json_msg = cJSON_GetObjectItem(json, "msg"); //获取success + json_data = cJSON_GetObjectItem(json, "data"); //获取data if (json_success && json_success->type == cJSON_True) { printf("save uds file success\n"); if (json_data && json_data->type == cJSON_String) { - // ַ + // 计算解码后的字符串长度 long decodedLen = strlen(json_data->valuestring) * 3 / 4; char* decodedStr = (char*)malloc(decodedLen + 1); - // Base64 + // 进行Base64解码 int success = base64_decode(json_data->valuestring, strlen(json_data->valuestring), decodedStr, &decodedLen); Write_Byte_Array_To_File(local_path, decodedStr, decodedLen); free(decodedStr); @@ -136,58 +136,58 @@ int WebAPI_Uds_Upload(char* strUrl, char* loacl_path, char* uuid,char* filename) { int result = 0; printf("loaclpath: %s\n", loacl_path); - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; - //Content-TypeΪmultipart/form-data + //设置Content-Type为multipart/form-data header_list = curl_slist_append(header_list, "Content-Type: multipart/form-data"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl); - //postIJ + //设置post请求的参数 struct curl_httppost* formpost = NULL; struct curl_httppost* lastptr = NULL; - // form-dataֶ + // 添加form-data字段 curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_FILE, loacl_path, CURLFORM_END); //curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "password", CURLFORM_COPYCONTENTS, "secretpassword", CURLFORM_END); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>uds upload Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("uds upload failed res code: "); result = 0; } else { printf("uds upload success,string %s", resPost0.c_str()); - //webapiֵж + //后期添加webapi返回值判断 result=Get_Uuid(resPost0.c_str(), uuid,filename); } - // ͷԴ + // 释放资源 curl_slist_free_all(header_list); curl_formfree(formpost); } @@ -201,23 +201,23 @@ int WebAPI_Uds_Upload(char* strUrl, char* loacl_path, char* uuid,char* filename) } void WebAPI_Uds_Download(char* strUrl, char* uuid, char* local_path,char* filename) { - // curlʼ + // curl初始化 CURL* curl = curl_easy_init(); - // curlֵ + // curl返回值 CURLcode res; if (curl) { - //curlͷ + //设置curl的请求头 struct curl_slist* header_list = NULL; header_list = curl_slist_append(header_list, "Content-Type:application/json;"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - //Ӧͷ0 1 + //不接收响应头数据0代表不接收 1代表接收 curl_easy_setopt(curl, CURLOPT_HEADER, 0); - //Ϊpost + //设置请求为post请求 curl_easy_setopt(curl, CURLOPT_POST, 1); - //URLַ + //设置请求的URL地址 curl_easy_setopt(curl, CURLOPT_URL, strUrl); - //postIJ + //设置post请求的参数 cJSON* json_root = cJSON_CreateObject(); cJSON_AddItemToObject(json_root, "isWrap", cJSON_CreateString("1")); cJSON_AddItemToObject(json_root, "storeId", cJSON_CreateString(uuid)); @@ -225,30 +225,30 @@ void WebAPI_Uds_Download(char* strUrl, char* uuid, char* local_path,char* filena char* szjson = cJSON_Print(json_root); printf(">>>json %s\n", szjson); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); - //ssl֤ + //设置ssl验证 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + //CURLOPT_VERBOSE的值为1时,会显示详细的调试信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); - //ݽպд뺯 + //设置数据接收和写入函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); string resPost0; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - //óʱʱ + //设置超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); printf(">>>uds download Post in curl post\n"); - // post + // 开启post请求 res = curl_easy_perform(curl); - // Ƿɹ + // 检查请求是否成功 if (res != CURLE_OK) { printf("uds download failed res code: "); } else { printf("uds download success,string %s", resPost0.c_str()); - //webapiֵж + //后期添加webapi返回值判断 Save_File(resPost0.c_str(), local_path); } curl_slist_free_all(header_list); diff --git a/include/rocketmq/SimpleProducer.h b/include/rocketmq/SimpleProducer.h index d02db6b..22a066f 100644 --- a/include/rocketmq/SimpleProducer.h +++ b/include/rocketmq/SimpleProducer.h @@ -1,11 +1,11 @@ #ifdef __cplusplus #include "../json/mms_json_inter.h" -#include "../include/rocketmq/CProducer.h" -#include "../include/rocketmq/CMessage.h" -#include "../include/rocketmq/CSendResult.h" +#include "../rocketmq/CProducer.h" +#include "../rocketmq/CMessage.h" +#include "../rocketmq/CSendResult.h" -#include "../include/rocketmq/CPushConsumer.h" +#include "../rocketmq/CPushConsumer.h" #include diff --git a/json/create_json.cpp b/json/create_json.cpp index 9254dc5..99590b3 100644 --- a/json/create_json.cpp +++ b/json/create_json.cpp @@ -10,18 +10,18 @@ #include #include #include -#include //C++ STLlist -#include //C++ STLmap +#include //C++ STL的list +#include //C++ STL的map #include -#include //zw޸ 2023-08-22 洢ݺ -#include //zw޸ 2023-08-22 洢ݺ +#include //zw修改 2023-08-22 存储数据合理性相关属性 +#include //zw修改 2023-08-22 存储数据合理性相关属性 -#include "mms_json_inter.h" //jsonͷļ -#include "../mms/db_interface.h" //jsonͷļ -#include "../mms/rdb_client.h" //̨˸ýӿ +#include "mms_json_inter.h" //json头文件 +#include "../mms/db_interface.h" //json头文件 +#include "../mms/rdb_client.h" //台账更新引用接口 -//lnk20241031ϴļ +//lnk20241031用于上传和下载文件 #include "../json/cjson.h" ///////////////////////////////////////////////////lnk2024-10-21//////////////////////////////////////////////////////// extern void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr); @@ -44,133 +44,133 @@ extern int FILE_FLAG; //lnk20250214 extern int isdelta_flag; -//Kafkaඨ-------------------------------------------------------------/* -class CEventData //SOE¼ +//江苏Kafka发送数据类定义-------------------------------------------------------------/* +class CEventData //SOE事件类 { public: - int nDataType; //澯SOE¼ - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - QString triggerFlag; //澯SOE¼ָ - int nIndex; //ÿ·LineInfoֵеλ - QString DO; //ݶ - QString DA; // - QString strFullName; //ݶ $ + int nDataType; //告警SOE事件类型 + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + QString triggerFlag; //告警SOE事件触发指标名称 + int nIndex; //数据在每条线路LineInfo值数组中的位置 + QString DO; //数据对象名 + QString DA; //数据属性名 + QString strFullName; //数据对象名 $ 数据属性名 }; -class CDataValue //ֵ +class CDataValue //数据值类 { public: - QString strName; // - float fValue; //ֵ - bool bIsValue; //Ƿֵɹʶ - int nIndex; //ÿ·LineInfoֵеλ - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - QString DO; //ݶ - QString DA; // - QString strFullName; //ݶ $ - QString strCoefficient; //ϵ(ַ) - float fCoefficient; //ϵ() - QString strOffset; //ʼƫ(ַ) - int iOffset; //ʼƫ() = յԺʼ - װʵʼ - bool bIsAngle; //Ƕȱ־ WW 2018-06-28 - bool bPlt; //ʱʶtrue-ʱ false-ʱ - QString BaseFlag; //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown - QString LimitUp; //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown - QString LimitDown; //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + QString strName; //数据名 + float fValue; //数据值 + bool bIsValue; //数据是否赋值成功标识 + int nIndex; //数据在每条线路LineInfo值数组中的位置 + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + QString DO; //数据对象名 + QString DA; //数据属性名 + QString strFullName; //数据对象名 $ 数据属性名 + QString strCoefficient; //数据系数(字符型) + float fCoefficient; //数据系数(浮点型) + QString strOffset; //起始序号偏移量(字符型) + int iOffset; //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号 + bool bIsAngle; //角度标志 WW 2018-06-28 + bool bPlt; //长时闪变标识:true-长时闪变 false-短时闪变 + QString BaseFlag; //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown + QString LimitUp; //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown + QString LimitDown; //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown CDataValue() { - fCoefficient = 1.0f; //ϵ() - iOffset = 0; //ʼƫ() - bIsAngle = false; //ǽǶȱ־ - bPlt = false; //ʱʶ + fCoefficient = 1.0f; //数据系数(浮点型) + iOffset = 0; //起始序号偏移量(整型) + bIsAngle = false; //非角度标志 + bPlt = false; //短时闪变标识 } }; -class CSequence //(ABCT) +class CSequence //相别(A、B、C、T)类 { public: - QString strSValue; //ֵ 7ABC8T - QString strSeq; // ABCT - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - list DataValueList; //ֵ + QString strSValue; //相别值 例:7:ABC三项,8:T相 + QString strSeq; //相别 例:A、B、C、T + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + list DataValueList; //数据值链表 }; -class CItem // +class CItem //数据项类 { public: - QString strItemName; // - QString strItemValue; //ֵ - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - list SequenceList; // + QString strItemName; //数据项名 + QString strItemValue; //数据项值 + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + list SequenceList; //相别链表 }; -class CMonitor // +class CMonitor //监测点类 { public: - QString strMonitor; // - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - list ItemList; // + QString strMonitor; //监测点名 + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + list ItemList; //数据项链表 }; -class CDataType // +class CDataType //数据类型类 { public: - int iDataType; //ֵ1-̬ 2- 3-̬ - QString type; //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - int BaseFlag1; //zw޸ 2023-8-25 ¼ܸ - int BaseFlag0; //zw޸ 2023-8-25 ¼ǻݸ - list MonitorList; // - list SOEList; //SOE¼ + int iDataType; //数据类型值:1-稳态 2-闪变 3-暂态 + QString type; //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + int BaseFlag1; //zw修改 2023-8-25 记录基础数据总个数 + int BaseFlag0; //zw修改 2023-8-25 记录非基础数据个数 + list MonitorList; //监测点链表 + list SOEList; //SOE事件链表 }; -class CTopic //Kafka Producer +class CTopic //Kafka Producer发送主题类 { public: - QString strTopic; //Kafka Producerֵ - list DataTypeList; // + QString strTopic; //Kafka Producer发送主题值 + list DataTypeList; //数据类型链表 }; -class XmlConfig //zw޸ 2023 - 8 - 14 xml +class XmlConfig //zw修改 2023 - 8 - 14 增加xml解析的配置类 { public: - QString WavePhasicFlag; //Ƿ 0- 1- Flag=0 ABCóһFlag=1ABCʵ + QString WavePhasicFlag; //是否分相 0-不分相 1-分相 如果Flag=0 A,B,C配置成一样,如果Flag=1,A,B,C根据实际配置 QString WavePhasicA; QString WavePhasicB; QString WavePhasicC; - QString UnitOfTimeUnit; //̬¼¼λ0 - 1 - - QString ValueOfTimeUnit; //ֵʱ䣺UTC-UTCʱ beijing-ʱ - QString WaveTimeFlag; //¼ļʱ䣺UTC-UTCʱ beijing-ʱ - QString IEDname; //PQMonitor - QString LDevicePrefix; //PQM - list SOEList; //SOE澯¼ + QString UnitOfTimeUnit; //暂态事件持续事件单位:0 - 毫秒 1 - 秒 + QString ValueOfTimeUnit; //上送值的时间:UTC-UTC时间 beijing-北京时间 + QString WaveTimeFlag; //录波文件的时间:UTC-UTC时间 beijing-北京时间 + QString IEDname; //例:PQMonitor + QString LDevicePrefix; //例:PQM + list SOEList; //SOE告警事件链表 }; -class XmlDataBase //zw޸ 2023-8-30 ӽݿģͱ +class XmlDataBase //zw修改 2023-8-30 增加解析数据库模型表数据类 { public: - QString MODEL_ID;//ģͱ guid - QString TMNL_TYPE;//նͺ - QString TMNL_FACTORY;//ն˳ - QString FILE_PATH;//Զģļ· lnk2024-10-28 - QString FILE_NAME;//ossļ洢· - QDateTime datetime;//ʱ ʱ + QString MODEL_ID;//模型编码 guid + QString TMNL_TYPE;//终端型号 + QString TMNL_FACTORY;//终端厂家 + QString FILE_PATH;//远端模型文件路径 lnk2024-10-28 + QString FILE_NAME;//oss文件存储路径 + QDateTime datetime;//更新时间 时间戳 }; -class MP_RATIONALITY //zw޸ 2023 - 8 - 22 ݲԼ¼ +class MP_RATIONALITY //zw修改 2023 - 8 - 22 增加数据不合理性记录类 { public: - double fValue;//zw޸ 2023-08-22 һμ¼IJֵ - QDateTime dtvalue;//zw޸ 2023-08-22 һμ¼IJֵʱ - int over_time;//zw޸ 2023-08-22 ü¼Բִֵ + double fValue;//zw修改 2023-08-22 第一次记录的不合理数值 + QDateTime dtvalue;//zw修改 2023-08-22 第一次记录的不合理数值出现时间 + int over_time;//zw修改 2023-08-22 该记录属性不合理数值出现次数 }; -class Mn_Timespan //zw޸ 2023-08-29 ʱ +class Mn_Timespan //zw修改 2023-08-29 时间间隔保存类 { public: - QList timespan;//ʱ + QList timespan;//时间戳队列 int msspan; Mn_Timespan() @@ -179,68 +179,68 @@ public: } }; -class Xmldata //zw޸ 2023-08-30 +class Xmldata //zw修改 2023-08-30 { public: - XmlDataBase xmlbase;//xmlݿ - XmlConfig xmlcfg;//‰xmlڵ - list topicList; //Kafka + XmlDataBase xmlbase;//xml数据库数据 + XmlConfig xmlcfg;//新増的xml节点解析数据 + list topicList; //Kafka发送主题链表 bool updataflag = true; }; //-------------------------------------------------------------------------------------*/ -//Ѷñ +//主程序已定义该变量 extern int FILE_FLAG; -QMutex kafka_data_list_mutex; //Kafka -QList kafka_data_list; //kafka +QMutex kafka_data_list_mutex; //Kafka发送数据锁 +QList kafka_data_list; //kafka发送数据链表 -QMutex oss_data_list_mutex; //oss zw -QList oss_data_list; //oss zw +QMutex oss_data_list_mutex; //oss发送数据锁 zw新增 +QList oss_data_list; //oss发送数据链表 zw新增 //-------------------------------------------------------------------------------------*/ -QMap data_timespan_list;//zw޸ 2023 - 8 - 29 ʱ +QMap data_timespan_list;//zw修改 2023 - 8 - 29 计算时间间隔 -QMap xmlinfo_list;//zw޸ ͺŶӦxml-ݿ Ľڵ kafka -XmlConfig xmlcfg;//zw޸ 2023 - 8 - 14 ‰xmlڵ -list topicList; //Kafka +QMap xmlinfo_list;//zw修改 保存所有型号对应的xml数据-数据库数据 新增的节点解析数据 kafka发送链表 +XmlConfig xmlcfg;//zw修改 2023 - 8 - 14 新増xml节点解析的数据 +list topicList; //Kafka发送主题链表 -int inited = false; //JiangSu_Config.xmlǷʼʶ +int inited = false; //JiangSu_Config.xml是否初始化标识 -XmlConfig xmlcfg2;//lnk2024 - 8 - 13 ‰xmlڵ -list topicList2; //lnk2024-8-14Kafka -QMap xmlinfo_list2;//lnk2024-8-14 ͺŶӦxml-ݿ Ľڵ kafka +XmlConfig xmlcfg2;//lnk2024 - 8 - 13 新増角型xml节点解析的数据 +list topicList2; //lnk2024-8-14角型Kafka发送主题链表 +QMap xmlinfo_list2;//lnk2024-8-14 保存角型所有型号对应的xml数据-数据库数据 新增的节点解析数据 kafka发送链表 -extern int isdelta_flag;//lnk2024-8-16 ͽ߱־ +extern int isdelta_flag;//lnk2024-8-16 角型接线标志 -///////////////////////////////////////////////lnk20241021滻webӿ////////////////////////////////// +///////////////////////////////////////////////lnk20241021替换web接口////////////////////////////////// void connectlog_pgsql(char* id,char* datetime,int status); -///////////////////////////////////////////////lnk20241021滻webӿ////////////////////////////////// +///////////////////////////////////////////////lnk20241021替换web接口////////////////////////////////// -//lnk2024-8-16 ͽ -bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QString path) //JiangSu_Config.xmlļ +//lnk2024-8-16 适配角型接线 +bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QString path) //解析JiangSu_Config.xml配置文件 { - //ע#7#ͨͨ 8421룬8-CP95 4-Сֵ 2-ֵ 1-ƽֵ - // %2,50%ͨͨгݣ÷Χ룬һֱʾгʼţڶг - // SEQ=ֵ8421 8-T 4-C 2-B 1-A - //עtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ 11-ʵʱSOE¼ - QString strPhasic[4] = { "A", "B", "C", "T" }; //ö (A-T) - QString strLine[4] = { "AB", "BC", "CA", "T" }; //lnk2024-8-14ö (AB-T) - int nStart = 1, nEnd = 1; //гֹ - QString strValueTemp; //ʱгַ %0,49% %2,50% + //注:①#7#代表通配符,用于通配数据类型 采用8421码,8-CP95 4-最小值 2-最大值 1-平均值 + // ②%2,50%代表通配符,用于通配谐波数据,采用范围编码,第一个数字表示谐波起始号,第二个数字谐波结束号 + // ③SEQ=后面的值采用8421码 8-T 4-C 2-B 1-A + //注:type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 11-实时SOE事件 + QString strPhasic[4] = { "A", "B", "C", "T" }; //数组枚举 相别(A-T) + QString strLine[4] = { "AB", "BC", "CA", "T" }; //lnk2024-8-14数组枚举 角型相别(AB-T) + int nStart = 1, nEnd = 1; //谐波起、止次数 + QString strValueTemp; //临时存放谐波次数字符串 例:%0,49% 或 %2,50% - //JiangSu_Config.xmlļ - //QString xml_dir = QString("D:/")+QString("PQD-9k/config/"); //·ȡxmlʧܣ˴þ· zl 2018-11-14 15:43:34 - QDomDocument doc; //½QDomDocumentһXMLĵ + //加载JiangSu_Config.xml配置文件 + //QString xml_dir = QString("D:/")+QString("PQD-9k/config/"); //相对路径读取xml失败,此处改用绝对路径! zl 2018-11-14 15:43:34 + QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档 if ("not define" == path) { - QString xml_dir = QString("../") + QString("etc/"); //Linuxµ· + QString xml_dir = QString("../") + QString("etc/"); //Linux下调试路径 QFile file(xml_dir + JSON_CONFIG_FN); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { return 0; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { file.close(); return 0; @@ -252,11 +252,11 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt QString tmppath; tmppath.append("/FeProject/dat/").append(path).append(".xml"); QFile file(tmppath); - if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //以只读方式打开xml { return 0; } - if (!doc.setContent(&file)) //ļݶdoc + if (!doc.setContent(&file)) //将文件内容读到doc中 { file.close(); return 0; @@ -264,127 +264,127 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt file.close(); cout << "define xml" << endl; } - //xmlļݶdoc - QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" - QDomElement docElem = doc.documentElement(); //ظڵԪ - QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" - while (!n.isNull()) //Topicڵ㲻Ϊ + //将xml文件内容读到doc中 + QDomNode firstNode = doc.firstChild(); //根节点"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //返回根节点元素 + QDomNode n = docElem.firstChild(); //获得doc的第一个节点,即"Topic" + while (!n.isNull()) //如果Topic节点不为空 { if (n.isElement()) { - QDomElement e = n.toElement(); //תΪԪ - QString strTag = e.tagName(); //Topicڵ + QDomElement e = n.toElement(); //将其转换为元素 + QString strTag = e.tagName(); //Topic节点 - if ("Topic" == strTag)//zw޸ 2023 - 8 - 14 ж topicڵڵĽ + if ("Topic" == strTag)//zw修改 2023 - 8 - 14 增加判断 将topic节点和其他节点的解析分离 { - CTopic* topic = new CTopic(); //ָ - topic->strTopic = e.attribute("name"); // - ctopiclist->push_back(topic); // Kafka + CTopic* topic = new CTopic(); //发送主题类指针 + topic->strTopic = e.attribute("name"); //发送主题名 + ctopiclist->push_back(topic); //添加 Kafka发送主题链表 - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown - if ("Topic" == strTag && ("HISDATA" == topic->strTopic || "RTDATA" == topic->strTopic)) //ٶȡTopicHISDATARTDATA--------------------------------------------------- + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown + if ("Topic" == strTag && ("HISDATA" == topic->strTopic || "RTDATA" == topic->strTopic)) //①读取Topic,HISDATA、RTDATA主题--------------------------------------------------- { - QDomNodeList list = e.childNodes(); //ԪTopicӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - CDataType* dt = new CDataType(); //ָ - dt->iDataType = node.toElement().attribute("value").toInt(); //ֵ(1-ʵʱ/ʷ̬2-ʵʱ/ʷ䡢3-ʵʱ/ʷ̬4-̬5-䡢6-̬) - dt->type = node.toElement().attribute("type"); //ȼ + CDataType* dt = new CDataType(); //数据类型指针 + dt->iDataType = node.toElement().attribute("value").toInt(); //数据类型值(1-实时/历史稳态、2-实时/历史闪变、3-实时/历史暂态、4-补招稳态、5-补招闪变、6-补招暂态) + dt->type = node.toElement().attribute("type"); //参数等级 dt->BaseFlag0 = 0; dt->BaseFlag1 = 0; - topic->DataTypeList.push_back(dt); // + topic->DataTypeList.push_back(dt); //添加 数据类型链表 - QString strTag2 = node.toElement().tagName(); //DataTypeڵ - if ("DataType" == strTag2) //ڶȡDataType + QString strTag2 = node.toElement().tagName(); //DataType节点 + if ("DataType" == strTag2) //②读取数据类型DataType { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 Monitor列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) { - CMonitor* mt = new CMonitor(); //ָ - mt->strMonitor = node2.toElement().attribute("name"); // עֵҪRptлȡ - mt->type = node2.toElement().attribute("type"); //ȼ - dt->MonitorList.push_back(mt); // + CMonitor* mt = new CMonitor(); //监测点类型指针 + mt->strMonitor = node2.toElement().attribute("name"); //监测点名称 注:该值需要从Rpt解析中获取监测点号 + mt->type = node2.toElement().attribute("type"); //参数等级 + dt->MonitorList.push_back(mt); //添加 监测点链表 - QString strTag3 = node2.toElement().tagName(); //Monitorڵ - if ("Monitor" == strTag3) //۶ȡMonitor + QString strTag3 = node2.toElement().tagName(); //Monitor节点 + if ("Monitor" == strTag3) //③读取监测点Monitor { - QDomNodeList list3 = node2.childNodes(); //ԪMonitorӽڵб - for (int i3 = 0; i3 < list3.count(); i3++) // Itemб + QDomNodeList list3 = node2.childNodes(); //获得元素Monitor的所有子节点的列表 + for (int i3 = 0; i3 < list3.count(); i3++) //遍历 Item列表 { QDomNode node3 = list3.at(i3); //node3 if (node3.isElement()) { - CItem* it = new CItem(); //ָ - it->strItemName = node3.toElement().attribute("name"); //FLAGTIMEVIPQ - it->type = node3.toElement().attribute("type"); //ȼ - if ("FLAG" == it->strItemName) //޳(1޳0޳Ĭ޳) - it->strItemValue = node3.toElement().attribute("value"); //ֵ - mt->ItemList.push_back(it); // + CItem* it = new CItem(); //数据项类指针 + it->strItemName = node3.toElement().attribute("name"); //FLAG、TIME、V、I、PQ + it->type = node3.toElement().attribute("type"); //参数等级 + if ("FLAG" == it->strItemName) //剔除标记(1:不剔除,0:剔除,默认剔除) + it->strItemValue = node3.toElement().attribute("value"); //数据项值 + mt->ItemList.push_back(it); //添加 数据项链表 - QString strTag4 = node3.toElement().tagName(); //Itemڵ - if ("Item" == strTag4) //ܶȡItem + QString strTag4 = node3.toElement().tagName(); //Item节点 + if ("Item" == strTag4) //④读取数据项Item { - QDomNodeList list4 = node3.childNodes(); //ԪItemӽڵб - for (int i4 = 0; i4 < list4.count(); i4++) // Sequenceб + QDomNodeList list4 = node3.childNodes(); //获得元素Item的所有子节点的列表 + for (int i4 = 0; i4 < list4.count(); i4++) //遍历 Sequence列表 { QDomNode node4 = list4.at(i4); //node4 if (node4.isElement()) { - QString strPhase = node4.toElement().attribute("value"); // - if ((!xml_flag || "V" != it->strItemName) && "7" == strPhase) //-ٶȡABC //lnk2024-8-14 ж + QString strPhase = node4.toElement().attribute("value"); //相别 + if ((!xml_flag || "V" != it->strItemName) && "7" == strPhase) //⑤-①读取ABC三相数据 //lnk2024-8-14 角型判断 { - for (int n = 0; n < 3; n++) // (ABC) + for (int n = 0; n < 3; n++) //遍历 相别(ABC三相) { - CSequence* sq = new CSequence(); //ABCָ - sq->strSValue = node4.toElement().attribute("value"); //ֵ(7ABCࡢ8T) - sq->type = node4.toElement().attribute("type"); //ȼ - sq->strSeq = strPhasic[n]; //ֵ ABC - it->SequenceList.push_back(sq); // + CSequence* sq = new CSequence(); //ABC三相相别类指针 + sq->strSValue = node4.toElement().attribute("value"); //相别值(7:ABC三相、8:T相) + sq->type = node4.toElement().attribute("type"); //参数等级 + sq->strSeq = strPhasic[n]; //相别赋值 例:A、B、C + it->SequenceList.push_back(sq); //添加 相别链表 - QString strTag5 = node4.toElement().tagName(); //Sequenceڵ - if ("Sequence" == strTag5) //ݶȡSequence + QString strTag5 = node4.toElement().tagName(); //Sequence节点 + if ("Sequence" == strTag5) //⑤读取相别Sequence { - QDomNodeList list5 = node4.childNodes(); //ԪSequenceӽڵб - for (int i5 = 0; i5 < list5.count(); i5++) // ABCValueб + QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表 + for (int i5 = 0; i5 < list5.count(); i5++) //遍历 ABC三相Value列表 { QDomNode node5 = list5.at(i5); //node5 if (node5.isElement()) { - QDomElement e_Value = node5.toElement(); //תΪԪ - QString strTag6 = e_Value.tagName(); //Sequence DataValueӽڵ - if ("Value" == strTag6) //޶ȡABCValue + QDomElement e_Value = node5.toElement(); //将其转换为元素 + QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点 + if ("Value" == strTag6) //⑥读取ABC三相Value { - QString strDVName = e_Value.attribute("name"); // - QString strDAName = e_Value.attribute("DA"); // + QString strDVName = e_Value.attribute("name"); //数据名 + QString strDAName = e_Value.attribute("DA"); //数据属性名 - if (strDAName.indexOf("l_phs*") >= 0){ //DA"l_phs*"//lnk20250221νҲԽPPV + if (strDAName.indexOf("l_phs*") >= 0){ //DA包含"l_phs*"//lnk20250221星形接线也可以接受PPV strDAName = strDAName.replace("l_phs", "phs"); strDAName = strDAName.replace("*", strLine[n]); - } //DA*滻Ϊ(ABBCCA) phsAB$cVal$mag$f + } //将DA相别*替换为具体相别(AB、BC、CA) 例:phsAB$cVal$mag$f - else if (strDAName.indexOf("phs*") >= 0) {//DA"phs*" - strDAName = strDAName.replace("*", sq->strSeq);} //DA*滻Ϊ(ABC) phsA$cVal$mag$f + else if (strDAName.indexOf("phs*") >= 0) {//DA包含"phs*" + strDAName = strDAName.replace("*", sq->strSeq);} //将DA相别*替换为具体相别(A、B、C) 例:phsA$cVal$mag$f - //-гݶȡ(ABC)------------------------------------- - if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //% DA%- V_%0,49%_MAX + //⑥-①谐波数据读取(ABC三相)------------------------------------- + if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //数据名包含% 且 DA包含%- 例:V_%0,49%_MAX { QStringList strHarm1 = strDVName.split('%'); - if (strHarm1.count() >= 2) //V_ | 0,49 | _MAX + if (strHarm1.count() >= 2) //例:V_ | 0,49 | _MAX { - strValueTemp = "%" + strHarm1.at(1) + "%"; //%0,49% - QStringList strHarm2 = strHarm1.at(1).split(','); //0,49 + strValueTemp = "%" + strHarm1.at(1) + "%"; //例:%0,49% + QStringList strHarm2 = strHarm1.at(1).split(','); //例:0,49 if (strHarm2.count() >= 2) { - nStart = (strHarm2.at(0)).toInt(); //гʼ 0 - nEnd = (strHarm2.at(1)).toInt(); //г 49 + nStart = (strHarm2.at(0)).toInt(); //谐波起始次数 例:0 + nEnd = (strHarm2.at(1)).toInt(); //谐波结束次数 例:49 } } @@ -392,23 +392,23 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt QStringList strDAList1 = substring.split('-'); int strDAoffset = (strDAList1.at(1)).toInt(); - for (int i = nStart; i <= nEnd; i++) // ABCг + for (int i = nStart; i <= nEnd; i++) //遍历 ABC三相谐波次数 { - QString strDVNameTemp = strDVName; //ʱ - QString strDANameTemp = strDAName; //ʱ - CDataValue* dv1 = new CDataValue(); //ABCгֵָ - dv1->type = e_Value.attribute("type"); //ȼ + QString strDVNameTemp = strDVName; //临时 数据名 + QString strDANameTemp = strDAName; //临时 数据属性名 + CDataValue* dv1 = new CDataValue(); //ABC三相谐波数据值类指针 + dv1->type = e_Value.attribute("type"); //参数等级 if (e_Value.attributes().contains("Coefficient")) { - dv1->strCoefficient = e_Value.attribute("Coefficient"); //ϵ(ַ) - dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //ϵ() + dv1->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型) + dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) } - dv1->strOffset = e_Value.attribute("Offset"); //ʼƫ(ַ) - dv1->iOffset = e_Value.attribute("Offset").toInt(); //ʼƫ() = յԺʼ - װʵʼ - dv1->DO = e_Value.attribute("DO"); //ݶ - dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //%0,49%滻Ϊ SI_%0,49%ΪSI_1 - dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //DA%-2滻Ϊ phs*Har[1]$mag$f + dv1->strOffset = e_Value.attribute("Offset"); //起始序号偏移量(字符型) + dv1->iOffset = e_Value.attribute("Offset").toInt(); //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号 + dv1->DO = e_Value.attribute("DO"); //数据对象名 + dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //将数据名中%0,49%替换为具体数字 例:SI_%0,49%变为SI_1 + dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //将DA中%-2替换为具体数字 例:phs*Har[1]$mag$f - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown if (e_Value.attributes().contains("BaseFlag")) { dv1->BaseFlag = e_Value.attribute("BaseFlag"); @@ -440,27 +440,27 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt { dv1->LimitDown = "not define"; } - if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //ݶΪ + if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //数据对象名和数据属性名均不为空 dv1->strFullName = dv1->DO + "$" + dv1->DA; else dv1->strFullName = "not define"; - sq->DataValueList.push_back(dv1); // (ABC) - } //ABCг + sq->DataValueList.push_back(dv1); //添加 数据链表(ABC三相) + } //遍历ABC三相谐波次数 结束 } - else //-ڷгݶȡ(ABC)------------------------------- + else //⑥-②非谐波数据读取(ABC三相)------------------------------- { - CDataValue* dv2 = new CDataValue(); //ABCгֵָ - dv2->strName = e_Value.attribute("name"); // - dv2->type = e_Value.attribute("type"); //ȼ + CDataValue* dv2 = new CDataValue(); //ABC三相非谐波数据值类指针 + dv2->strName = e_Value.attribute("name"); //数据名 + dv2->type = e_Value.attribute("type"); //参数等级 if (e_Value.attributes().contains("Coefficient")) { - dv2->strCoefficient = e_Value.attribute("Coefficient"); //ϵ(ַ) - dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //ϵ() + dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型) + dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) } - dv2->DO = e_Value.attribute("DO"); //ݶ - dv2->DA = strDAName; // + dv2->DO = e_Value.attribute("DO"); //数据对象名 + dv2->DA = strDAName; //数据属性名 - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown if (e_Value.attributes().contains("BaseFlag")) { dv2->BaseFlag = e_Value.attribute("BaseFlag"); @@ -492,63 +492,63 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt { dv2->LimitDown = "not define"; } - if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //ʱʶ - dv2->bPlt = true; //ʱʶ + if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //长时闪变标识 + dv2->bPlt = true; //长时闪变标识 else - dv2->bPlt = false; //ʱ + dv2->bPlt = false; //短时闪变 或 其他数据 - if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //ݶΪ + if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空 dv2->strFullName = dv2->DO + "$" + dv2->DA; else dv2->strFullName = "not define"; - sq->DataValueList.push_back(dv2); // (ABC) + sq->DataValueList.push_back(dv2); //添加 数据链表(ABC三相) } - } //ȡABCValue - } //жnode5ΪԪ - } //ABCValueб - } // ABC + } //读取ABC三相Value 结束 + } //判断node5为元素 结束 + } //遍历ABC三相Value列表 结束 + } //遍历 ABC三相 结束 } - } //-ٶȡABC + } //⑤-①读取ABC三相数据 结束 - if (xml_flag && "V" == it->strItemName && "112" == strPhase) //lnk2024-8-13 + if (xml_flag && "V" == it->strItemName && "112" == strPhase) //lnk2024-8-13角型 { - for (int n = 0; n < 3; n++) // (ABBCCA) + for (int n = 0; n < 3; n++) //遍历 相别(AB、BC、CA三相) { - CSequence* sq = new CSequence(); //ABBCCAָ - sq->strSValue = node4.toElement().attribute("value"); //ֵ(7ABCࡢ112:AB,BC,CA 8T) - sq->type = node4.toElement().attribute("type"); //ȼ - sq->strSeq = strLine[n]; //ֵ ABBCCA - it->SequenceList.push_back(sq); // + CSequence* sq = new CSequence(); //AB、BC、CA三相别类指针 + sq->strSValue = node4.toElement().attribute("value"); //相别值(7:ABC三相、112:线AB,BC,CA 8:T相) + sq->type = node4.toElement().attribute("type"); //参数等级 + sq->strSeq = strLine[n]; //相别赋值 例:AB、BC、CA + it->SequenceList.push_back(sq); //添加 相别链表 - QString strTag5 = node4.toElement().tagName(); //Sequenceڵ - if ("Sequence" == strTag5) //ݶȡSequence + QString strTag5 = node4.toElement().tagName(); //Sequence节点 + if ("Sequence" == strTag5) //⑤读取相别Sequence { - QDomNodeList list5 = node4.childNodes(); //ԪSequenceӽڵб - for (int i5 = 0; i5 < list5.count(); i5++) // ABBCCAValueб + QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表 + for (int i5 = 0; i5 < list5.count(); i5++) //遍历 AB、BC、CA三相Value列表 { QDomNode node5 = list5.at(i5); //node5 if (node5.isElement()) { - QDomElement e_Value = node5.toElement(); //תΪԪ - QString strTag6 = e_Value.tagName(); //Sequence DataValueӽڵ - if ("Value" == strTag6) //޶ȡABBCCAValue + QDomElement e_Value = node5.toElement(); //将其转换为元素 + QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点 + if ("Value" == strTag6) //⑥读取AB、BC、CA三相Value { - QString strDVName = e_Value.attribute("name"); // - QString strDAName = e_Value.attribute("DA"); // - if (strDAName.indexOf("phs*") >= 0) //DA"phs*" - strDAName = strDAName.replace("*", sq->strSeq); //DA*滻Ϊ(ABBCCA) phsAB$cVal$mag$f - //-гݶȡ(ABBCCA)------------------------------------- - if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //% DA%- V_%0,49%_MAX + QString strDVName = e_Value.attribute("name"); //数据名 + QString strDAName = e_Value.attribute("DA"); //数据属性名 + if (strDAName.indexOf("phs*") >= 0) //DA包含"phs*" + strDAName = strDAName.replace("*", sq->strSeq); //将DA相别*替换为具体相别(AB、BC、CA) 例:phsAB$cVal$mag$f + //⑥-①谐波数据读取(AB、BC、CA三相)------------------------------------- + if (strDVName.indexOf("%") >= 0 && strDAName.indexOf("%-") >= 0) //数据名包含% 且 DA包含%- 例:V_%0,49%_MAX { QStringList strHarm1 = strDVName.split('%'); - if (strHarm1.count() >= 2) //%0,49% + if (strHarm1.count() >= 2) //例:%0,49% { - strValueTemp = "%" + strHarm1.at(1) + "%"; //%0,49% - QStringList strHarm2 = strHarm1.at(1).split(','); //0,49 + strValueTemp = "%" + strHarm1.at(1) + "%"; //例:%0,49% + QStringList strHarm2 = strHarm1.at(1).split(','); //例:0,49 if (strHarm2.count() >= 2) { - nStart = (strHarm2.at(0)).toInt(); //гʼ 0 - nEnd = (strHarm2.at(1)).toInt(); //г 49 + nStart = (strHarm2.at(0)).toInt(); //谐波起始次数 例:0 + nEnd = (strHarm2.at(1)).toInt(); //谐波结束次数 例:49 } } @@ -556,28 +556,28 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt QStringList strDAList1 = substring.split('-'); int strDAoffset = (strDAList1.at(1)).toInt(); - for (int i = nStart; i <= nEnd; i++) // ABBCCAг + for (int i = nStart; i <= nEnd; i++) //遍历 AB、BC、CA三相谐波次数 { - QString strDVNameTemp = strDVName; //ʱ - QString strDANameTemp = strDAName;//ʱ - CDataValue* dv1 = new CDataValue(); //ABBCCAгֵָ - dv1->type = e_Value.attribute("type"); //ȼ + QString strDVNameTemp = strDVName; //临时 数据名 + QString strDANameTemp = strDAName;//临时 数据属性名 + CDataValue* dv1 = new CDataValue(); //AB、BC、CA三相谐波数据值类指针 + dv1->type = e_Value.attribute("type"); //参数等级 if (e_Value.attributes().contains("Coefficient")) { - dv1->strCoefficient = e_Value.attribute("Coefficient"); //ϵ(ַ) - dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //ϵ() + dv1->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型) + dv1->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) } - dv1->strOffset = e_Value.attribute("Offset"); //ʼƫ(ַ) - dv1->iOffset = e_Value.attribute("Offset").toInt(); //ʼƫ() = յԺʼ - װʵʼ - dv1->DO = e_Value.attribute("DO"); //ݶ + dv1->strOffset = e_Value.attribute("Offset"); //起始序号偏移量(字符型) + dv1->iOffset = e_Value.attribute("Offset").toInt(); //起始序号偏移量(整型) = 江苏电科院臻迪数据项起始序号 - 装置数据项实际起始序号 + dv1->DO = e_Value.attribute("DO"); //数据对象名 std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << dv1->DO.toUtf8().constData() << std::endl; //lnk ppv + std::cout << dv1->DO.toUtf8().constData() << std::endl; //lnk 输出ppv std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //%0,49%滻Ϊ SI_%0,49%ΪSI_1 - dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //DA%-2滻Ϊ phs*Har[1]$mag$f + dv1->strName = strDVNameTemp.replace(strValueTemp, QString::number(i + e_Value.attribute("Offset").toInt())); //将数据名中%0,49%替换为具体数字 例:SI_%0,49%变为SI_1 + dv1->DA = strDANameTemp.replace(substring, QString::number(i - strDAoffset)); //将DA中%-2替换为具体数字 例:phs*Har[1]$mag$f - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown if (e_Value.attributes().contains("BaseFlag")) { dv1->BaseFlag = e_Value.attribute("BaseFlag"); @@ -609,31 +609,31 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt { dv1->LimitDown = "not define"; } - if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //ݶΪ + if (!dv1->DO.isEmpty() && !dv1->DA.isEmpty()) //数据对象名和数据属性名均不为空 dv1->strFullName = dv1->DO + "$" + dv1->DA; else dv1->strFullName = "not define"; - sq->DataValueList.push_back(dv1); // (ABBCCA) - } //ABCг + sq->DataValueList.push_back(dv1); //添加 数据链表(AB、BC、CA三相) + } //遍历ABC三相谐波次数 结束 } - else //-ڷгݶȡ(ABBCCA)------------------------------- + else //⑥-②非谐波数据读取(AB、BC、CA三相)------------------------------- { - CDataValue* dv2 = new CDataValue(); //ABCгֵָ - dv2->strName = e_Value.attribute("name"); // - dv2->type = e_Value.attribute("type"); //ȼ + CDataValue* dv2 = new CDataValue(); //ABC三相非谐波数据值类指针 + dv2->strName = e_Value.attribute("name"); //数据名 + dv2->type = e_Value.attribute("type"); //参数等级 if (e_Value.attributes().contains("Coefficient")) { - dv2->strCoefficient = e_Value.attribute("Coefficient"); //ϵ(ַ) - dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //ϵ() + dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型) + dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) } - dv2->DO = e_Value.attribute("DO"); //ݶ - dv2->DA = strDAName; // + dv2->DO = e_Value.attribute("DO"); //数据对象名 + dv2->DA = strDAName; //数据属性名 std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << dv2->DO.toUtf8().constData() << std::endl; //lnk ppv + std::cout << dv2->DO.toUtf8().constData() << std::endl; //lnk 输出ppv std::cout << "!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!!!!!ppv!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown if (e_Value.attributes().contains("BaseFlag")) { dv2->BaseFlag = e_Value.attribute("BaseFlag"); @@ -665,55 +665,55 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt { dv2->LimitDown = "not define"; } - if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //ʱʶ - dv2->bPlt = true; //ʱʶ + if (!e_Value.attribute("PltFlag").isEmpty() && e_Value.attribute("PltFlag") == "True") //长时闪变标识 + dv2->bPlt = true; //长时闪变标识 else - dv2->bPlt = false;//ʱ + dv2->bPlt = false;//短时闪变 或 其他数据 - if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //ݶΪ + if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空 dv2->strFullName = dv2->DO + "$" + dv2->DA; else dv2->strFullName = "not define"; - sq->DataValueList.push_back(dv2); // (ABBCCA) + sq->DataValueList.push_back(dv2); //添加 数据链表(AB、BC、CA三相) } - } //ȡABBCCAValue - }//жnode5ΪԪ - } //ABBCCAValueб - } // ABBCCA + } //读取AB、BC、CA三相Value 结束 + }//判断node5为元素 结束 + } //遍历AB、BC、CA三相Value列表 结束 + } //遍历 AB、BC、CA三相 结束 } - }//-ٶȡABBCCA + }//⑤-①读取AB、BC、CA三相数据 结束 - if ("8" == strPhase) //-ڶȡT + if ("8" == strPhase) //⑤-②读取T相数据 { - CSequence* sq = new CSequence(); //Tָ - sq->strSValue = node4.toElement().attribute("value"); //ֵ - sq->type = node4.toElement().attribute("type"); //ȼ - sq->strSeq = strPhasic[3]; //ֵ - it->SequenceList.push_back(sq); // (T) + CSequence* sq = new CSequence(); //T相相别类指针 + sq->strSValue = node4.toElement().attribute("value"); //相别值 + sq->type = node4.toElement().attribute("type"); //参数等级 + sq->strSeq = strPhasic[3]; //相别赋值 + it->SequenceList.push_back(sq); //添加 相别链表(T相) - QDomNodeList list5 = node4.childNodes(); //ԪSequenceӽڵб - for (int i5 = 0; i5 < list5.count(); i5++) // TValueб + QDomNodeList list5 = node4.childNodes(); //获得元素Sequence的所有子节点的列表 + for (int i5 = 0; i5 < list5.count(); i5++) //遍历 T相Value列表 { QDomNode node5 = list5.at(i5); //node5 if (node5.isElement()) { - QDomElement e_Value = node5.toElement(); //תΪԪ - QString strTag6 = e_Value.tagName(); //Sequence DataValueӽڵ - if ("Value" == strTag6) //޶ȡTValue + QDomElement e_Value = node5.toElement(); //将其转换为元素 + QString strTag6 = e_Value.tagName(); //相别Sequence下 所有DataValue子节点 + if ("Value" == strTag6) //⑥读取T相Value { - //-гݶȡ(T) עTûг - //-ڷгݶȡ(T) - CDataValue* dv2 = new CDataValue(); //Tгֵָ - dv2->strName = e_Value.attribute("name"); // - dv2->type = e_Value.attribute("type"); //ȼ + //⑥-①谐波数据读取(T相) 注:T相没有谐波数据 + //⑥-②非谐波数据读取(T相) + CDataValue* dv2 = new CDataValue(); //T相非谐波数据值类指针 + dv2->strName = e_Value.attribute("name"); //数据名 + dv2->type = e_Value.attribute("type"); //参数等级 if (e_Value.attributes().contains("Coefficient")) { - dv2->strCoefficient = e_Value.attribute("Coefficient"); //ϵ(ַ) - dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //ϵ() + dv2->strCoefficient = e_Value.attribute("Coefficient"); //数据系数(字符型) + dv2->fCoefficient = e_Value.attribute("Coefficient").toFloat(); //数据系数(浮点型) } - dv2->DO = e_Value.attribute("DO"); //ݶ - dv2->DA = e_Value.attribute("DA"); // + dv2->DO = e_Value.attribute("DO"); //数据对象名 + dv2->DA = e_Value.attribute("DA"); //数据属性名 - //zw޸ 2023 - 8 - 14 Ϊʷݲ Valueڵָ-BaseFlag LimitUp LimitDown + //zw修改 2023 - 8 - 14 为历史数据部分 Value节点新增指标-BaseFlag LimitUp LimitDown if (e_Value.attributes().contains("BaseFlag")) { dv2->BaseFlag = e_Value.attribute("BaseFlag"); @@ -746,79 +746,79 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt dv2->LimitDown = "not define"; } - if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //ݶΪ + if (!dv2->DO.isEmpty() && !dv2->DA.isEmpty()) //数据对象名和数据属性名均不为空 dv2->strFullName = dv2->DO + "$" + dv2->DA; else dv2->strFullName = "not define"; - sq->DataValueList.push_back(dv2); // (ABC) - } //ȡTValue - } //жnode5ΪԪ - } //TValueб - } //-ڶȡT - } //жnode4ΪԪ - } //Sequenceб - } //ȡItem - } //жnode3ΪԪ - } //Itemб - } //ȡMonitorڵ - } //жnode2ΪԪ - } //Monitorб - } //ȡDataType - } //жnodeΪԪ - } //DataTypeб - } //ȡTopicڵHISDATARTDATA - else if ("Topic" == strTag && "RTDATASOE" == topic->strTopic) //SOE¼------------------------------------------------------- + sq->DataValueList.push_back(dv2); //添加 数据链表(ABC三相) + } //读取T相Value 结束 + } //判断node5为元素 结束 + } //遍历T相Value列表 结束 + } //⑤-②读取T相数据 结束 + } //判断node4为元素 结束 + } //遍历Sequence列表 结束 + } //读取数据项Item 结束 + } //判断node3为元素 结束 + } //遍历Item列表 结束 + } //读取Monitor节点 结束 + } //判断node2为元素 结束 + } //遍历Monitor列表 结束 + } //读取数据类型DataType 结束 + } //判断node为元素 结束 + } //遍历DataType列表 结束 + } //读取Topic节点HISDATA、RTDATA 结束 + else if ("Topic" == strTag && "RTDATASOE" == topic->strTopic) //SOE事件------------------------------------------------------- { - QDomNodeList list = e.childNodes(); //ԪTopicӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - CDataType* dt = new CDataType(); //ָ - dt->iDataType = node.toElement().attribute("value").toInt(); //ֵ(1-̬SOE2-SOE3-̬SOE) - dt->type = node.toElement().attribute("type"); //ȼ - topic->DataTypeList.push_back(dt); // + CDataType* dt = new CDataType(); //数据类型类指针 + dt->iDataType = node.toElement().attribute("value").toInt(); //数据类型值(1-稳态SOE、2-闪变SOE、3-暂态SOE) + dt->type = node.toElement().attribute("type"); //参数等级 + topic->DataTypeList.push_back(dt); //添加 数据类型链表 - QString strTag2 = node.toElement().tagName(); //DataTypeڵ - if ("DataType" == strTag2) //ڶȡDataType + QString strTag2 = node.toElement().tagName(); //DataType节点 + if ("DataType" == strTag2) //②读取数据类型DataType { - QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб - for (int i2 = 0; i2 < list2.count(); i2++) // SOEб + QDomNodeList list2 = node.childNodes(); //获得元素DataType的所有子节点的列表 + for (int i2 = 0; i2 < list2.count(); i2++) //遍历 SOE列表 { QDomNode node2 = list2.at(i2); //node2 if (node2.isElement()) { - CEventData* ed = new CEventData(); //SOE¼ָ - ed->triggerFlag = node2.toElement().attribute("TriggerFlag"); //SOEʶ - ed->DO = node2.toElement().attribute("DO"); //ݶ - ed->DA = node2.toElement().attribute("DA"); // - ed->type = node2.toElement().attribute("type"); //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //ݶΪ + CEventData* ed = new CEventData(); //SOE事件类指针 + ed->triggerFlag = node2.toElement().attribute("TriggerFlag"); //SOE触发标识 + ed->DO = node2.toElement().attribute("DO"); //数据对象名 + ed->DA = node2.toElement().attribute("DA"); //数据属性名 + ed->type = node2.toElement().attribute("type"); //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //数据对象名和数据属性名均不为空 ed->strFullName = ed->DO + "$" + ed->DA; else ed->strFullName = "not define"; - dt->SOEList.push_back(ed); // SOE¼ - } //жnode2ΪԪ - } //SOEб - } //ȡDataTypeڵ - } //жnodeΪԪ - } //DataTypeб - } //TopicڵRTDATASOE + dt->SOEList.push_back(ed); //添加 SOE事件链表 + } //判断node2为元素 结束 + } //遍历SOE列表 结束 + } //读取数据类型DataType节点 结束 + } //判断node为元素 结束 + } //遍历DataType列表 结束 + } //Topic节点RTDATASOE 结束 else if ("Topic" == strTag && "SOEDATA" == topic->strTopic) { - QDomNodeList list = e.childNodes(); //ԪTopicӽڵб - for (int i = 0; i < list.count(); i++) // DataTypeб + QDomNodeList list = e.childNodes(); //获得元素Topic的所有子节点的列表 + for (int i = 0; i < list.count(); i++) //遍历 DataType列表 { QDomNode node = list.at(i); //node1 if (node.isElement()) { - CEventData* ed = new CEventData(); //SOE¼ָ - ed->triggerFlag = node.toElement().attribute("name"); //SOE - ed->DO = node.toElement().attribute("DO"); //ݶ - ed->DA = node.toElement().attribute("DA"); // - ed->type = node.toElement().attribute("type"); //ȼtypeͣ0-DataType 1- 2-޳ 3-ʱ̣ 4- 5-λ 6-ֵ 9-ʵʱSOE¼ - if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //ݶΪ + CEventData* ed = new CEventData(); //SOE事件类指针 + ed->triggerFlag = node.toElement().attribute("name"); //SOE名称 + ed->DO = node.toElement().attribute("DO"); //数据对象名 + ed->DA = node.toElement().attribute("DA"); //数据属性名 + ed->type = node.toElement().attribute("type"); //参数等级type类型:0-DataType 1-监测点 2-剔除标记 3-发生时刻,毫秒 4-数据链表 5-相位 6-值索引 9-实时SOE事件 + if (!ed->DO.isEmpty() && !ed->DA.isEmpty()) //数据对象名和数据属性名均不为空 ed->strFullName = ed->DO + "$" + ed->DA; else ed->strFullName = "not define"; @@ -828,11 +828,11 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt } } } - if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + if ("ReportMap" == strTag)//zw修改 2023 - 8 - 15 增加判断 将触发报告的解析移至XML 原配置RptLogCfg.ini取消 { } - if ("Topic" != strTag && "ReportMap" != strTag)//zw޸ 2023 - 8 - 14 ж ֽڵ + if ("Topic" != strTag && "ReportMap" != strTag)//zw修改 2023 - 8 - 14 增加判断 新增部分节点解析 { if ("WavePhasic" == strTag) { @@ -868,20 +868,20 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt } } - } //жnΪԪ + } //判断n为元素 结束 - n = n.nextSibling();//ȡһֵܽڵ(HISDATA > RTDATA > RTDATASOE) - } //while (!n.isNull) + n = n.nextSibling();//获取下一个兄弟节点(HISDATA —> RTDATA —> RTDATASOE) + } //while (!n.isNull) 结束 return true; } /// -/// czy 2023-11-23 jsonװüƵ,ӡǰ̨ +/// czy 2023-11-23 测试json的装置间隔频,打印前台 /// -/// 1,2,3interval -/// 1,2,3interval +/// 1是,2是,3是填入计算的interval +/// 1是,2是,3是填入计算的interval void print_interval(int flag,int interval) { if (flag == 1) { cout << "interval!!dont't contain mp_id ,interval=1" << endl; @@ -898,7 +898,7 @@ void print_interval(int flag,int interval) { } /// -/// czy kafkajsonнߵѹתѹ +/// czy kafka的json中将线电压转成相电压 /// /// /// @@ -917,13 +917,13 @@ QString line_to_phasic(QString qstrSeq) { } } -//20250214ӽͽߴ -int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //jsonɺ zw޸ 2023-8-11 jsonṹ Ŀǰʷ̬ +//20250214添加角型接线处理 +int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json生成函数 zw修改 2023-8-11 调整传送json结构 目前仅限历史稳态数据 { list ctopic_list; - ////lnk2024-8-15 ,ͽ - if (strcmp(v_wiring_type, "0") == 0) //lnk2024-8-15 ͽ + ////lnk2024-8-15 区分星型,角型接线 + if (strcmp(v_wiring_type, "0") == 0) //lnk2024-8-15 星型接线 { cout << "1 report v_wiring_type is" << v_wiring_type << endl; if (xmlinfo_list.contains(data->dev_type)) { @@ -935,7 +935,7 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json ctopic_list = topicList; } } - else //lnk2024-8-15 ͽ + else //lnk2024-8-15 角型接线 { cout << "2 report v_wiring_type is" << v_wiring_type << endl; if (xmlinfo_list2.contains(data->dev_type)) { @@ -951,116 +951,116 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json bool shortjumpflag = false; bool longjumpflag = false; - //zw޸ end - if (!inited) //ʼ JiangSu_Config.xml + //zw修改 end + if (!inited) //初始化 JiangSu_Config.xml { inited = true; } - if (NULL == data) //jsonƴӲָΪ + if (NULL == data) //json拼接参数类指针为空 return 0; - if (100 == data->func_type) //һ̬/ͳ > MMS_Client + if (100 == data->func_type) //一、稳态/统计数据 ——> MMS_Client { list::iterator tp = ctopic_list.begin(); - while (tp != ctopic_list.end()) //ٱ Kafka + while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表 { CTopic* pTopic = *tp++; - if ("HISDATA" == pTopic->strTopic) //TopicHISDATA + if ("HISDATA" == pTopic->strTopic) //Topic等于HISDATA { - list::iterator dt = pTopic->DataTypeList.begin(); //ڱ DataTypeList + list::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList while (dt != pTopic->DataTypeList.end()) { - bool isJump = false; //Ƿ()ѭ + bool isJump = false; //是否跳出(整个数据类型)循环 CDataType* pDataType = *dt++; - if (2 == pDataType->iDataType) //-ʷ------------------------------------------------------------ + if (2 == pDataType->iDataType) //②-②历史短闪变数据------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "PST"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "PST"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - long long time_sec; //ʱ() - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʷ "02" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + long long time_sec; //时间戳(秒) + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:历史闪变 "02" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList int countflag = 0, num = 0; while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - //////////////////////////////////////////////////////////lnk20250306Ϊ⣬FLAG - if ("FLAG" == pItem->strItemName) //޳"FLAG"ֹsqִָ + //////////////////////////////////////////////////////////lnk20250306为了数据入库,构造数据添加FLAG + if ("FLAG" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //ƴ json޳ǣ1޳0޳Ĭ޳ + KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记,1不剔除,0剔除,默认剔除 continue; } ////////////////////////////////////////////////////////// - if ("TIME" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ - time_sec = data->time / 1000; //ʱ() + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 + time_sec = data->time / 1000; //时间戳(秒) continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json F + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 num = num + pSequence->DataValueList.size(); while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 { countflag++; continue; } - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ + isJump = false; //跳出本层循环 countflag++; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; } try { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) } catch (exception& e) { - cout << "ʷֵƴjsonԭ: " << e.what() << endl; + cout << "历史闪变数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -1069,124 +1069,124 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"02\" " << num << endl; cout << KafkaData.strText.toAscii().data() << endl; if (countflag < num) { - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 shortjumpflag = true; } - } //-ʷݽ-------------------------------- + } //②-②历史闪变数据解析结束!-------------------------------- - //20241204ӦΪ3 - if (3 == pDataType->iDataType) //-ʷ------------------------------------------------------------ + //20241204长闪变类型应该为3 + if (3 == pDataType->iDataType) //②-②历史长闪变数据------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "PLT"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "PLT"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - long long time_sec; //ʱ() - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʷ "02" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + long long time_sec; //时间戳(秒) + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:历史闪变 "02" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList int countflag = 0,num = 0; while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - //////////////////////////////////////////////////////////lnk20250306Ϊ⣬FLAG - if ("FLAG" == pItem->strItemName) //޳"FLAG"ֹsqִָ + //////////////////////////////////////////////////////////lnk20250306为了数据入库,构造数据添加FLAG + if ("FLAG" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //ƴ json޳ǣ1޳0޳Ĭ޳ + KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记,1不剔除,0剔除,默认剔除 continue; } ////////////////////////////////////////////////////////// - if ("TIME" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ - time_sec = data->time / 1000; //ʱ() + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 + time_sec = data->time / 1000; //时间戳(秒) continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json F + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //ƴ json ABC - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相 + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 num = num + pSequence->DataValueList.size(); while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 { countflag++; continue; } - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ + isJump = false; //跳出本层循环 countflag++; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; } try { - if (0 == time_sec % 7200) //2Сʱʱ + if (0 == time_sec % 7200) //2小时间隔,长时闪变 { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) } } catch (exception& e) { - cout << "ʷֵƴjsonԭ: " << e.what() << endl; + cout << "历史闪变数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -1195,110 +1195,110 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 cout<< countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"04\" " << num << endl; cout << KafkaData.strText.toAscii().data() << endl; if (countflag < num && 0 == time_sec % 7200) { - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 longjumpflag = true; } if (longjumpflag == true || shortjumpflag == true) { return 1; } - } //-ʷݽ-------------------------------- + } //②-②历史闪变数据解析结束!-------------------------------- - if (1 == pDataType->iDataType) //-ʷ̬----------------------------------------------------------- + if (1 == pDataType->iDataType) //②-①历史稳态数据----------------------------------------------------------- { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "HISDATA"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "HISDATA"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10,QChar('0'))); //ƴ json ʷ̬ "01" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10,QChar('0'))); //拼接 json数据类型 例:历史稳态 "01" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("FLAG" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("FLAG" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //ƴ json޳ǣ1޳0޳Ĭ޳ + KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记,1不剔除,0剔除,默认剔除 continue; } - if ("TIME" == pItem->strItemName) //޳"TIME"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"TIME",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //拼接 json发生时刻,毫秒 if (!data_timespan_list.contains(data->mp_id)) { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻,毫秒 } else if (data_timespan_list[data->mp_id]->msspan == 0) { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻,毫秒 } else { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //拼接 json发生时刻,毫秒 } continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json VIPQ + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ - //zw޸ 2023-8-28 ƥ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + isJump = false; //跳出本层循环 + //zw修改 2023-8-28 不匹配数据添加 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; @@ -1306,32 +1306,32 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json try { - if (pDataValue->strFullName.indexOf("$ang$f") != -1) //61850кǵĶ + if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义 { - double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //Ƕֵ(-180 ~ 180) + double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度) dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) } else { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) } } catch (exception& e) { - cout << "ʷֵ̬ƴjsonԭ: " << e.what() << endl; + cout << "历史稳态数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -1340,132 +1340,132 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-ʷ̬ݽ-------------------------------- - } //DataTypeList - } // HISDATA - } //TopicList - } //һ + return 1; //结束该函数,停止后续代码执行 + } //②-①历史稳态数据解析结束!-------------------------------- + } //DataTypeList 结束 + } //遍历 HISDATA 结束! + } //TopicList 结束 + } //一、结束 - if (200 == data->func_type) //3/ʵʱ > MMS_Assist + if (200 == data->func_type) //二、3秒数据/实时数据 ——> MMS_Assist { list::iterator tp = ctopic_list.begin(); - while (tp != ctopic_list.end()) //ٱ Kafka + while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表 { CTopic* pTopic = *tp++; - if ("RTDATA" == pTopic->strTopic) //TopicRTDATA------------------------------------------------------------ + if ("RTDATA" == pTopic->strTopic) //Topic等于RTDATA------------------------------------------------------------ { - list::iterator dt = pTopic->DataTypeList.begin(); //ڱ DataTypeList + list::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList while (dt != pTopic->DataTypeList.end()) { - bool isJump = false; //Ƿ()ѭ + bool isJump = false; //是否跳出(整个数据类型)循环 CDataType* pDataType = *dt++; - if (1 == pDataType->iDataType) //-ʵʱ3s-------------------------------------------------------------- + if (1 == pDataType->iDataType) //②-①实时3s数据-------------------------------------------------------------- { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATA"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATA"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʵʱ̬ "01" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:实时稳态 "01" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("FLAG" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("FLAG" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"FLAG\":\"%1\", ").arg(data->flag)); //ƴ json޳ǣ1޳0޳Ĭ޳ + KafkaData.strText.append(QString("\"FLAG\":\"%1\", ").arg(data->flag)); //拼接 json剔除标记,1不剔除,0剔除,默认剔除 continue; } - if ("TIME" == pItem->strItemName) //޳"TIME"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"TIME",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json VIPQ + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//确认字典里不含有该key { - isJump = true; //ѭ + isJump = true; //跳出本层循环 break; } try { - if (pDataValue->strFullName.indexOf("$ang$f") != -1) //61850кǵĶ + if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义 { - double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //Ƕֵ(-180 ~ 180) + double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度) dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) } else { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) } } catch (exception& e) { - cout << "ʵʱ3sֵƴjsonԭ: " << e.what() << endl; + cout << "实时3s数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -1474,406 +1474,406 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-ʵʱ3sݽ---------------------------------- + return 1; //结束该函数,停止后续代码执行 + } //②-①实时3s数据解析结束!---------------------------------- - if (2 == pDataType->iDataType) //-ʵʱ----------------------------------------------------------- + if (2 == pDataType->iDataType) //②-②实时闪变数据----------------------------------------------------------- { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATA"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATA"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - long long time_sec; //ʱ() - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʵʱ "02" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + long long time_sec; //时间戳(秒) + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:实时闪变 "02" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("TIME" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ - time_sec = data->time / 1000; //ʱ() + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 + time_sec = data->time / 1000; //时间戳(秒) continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json F + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName) && pDataValueBegin->strName == pDataValue->strName)//确认字典里不含有该key { - isJump = true; //ѭ + isJump = true; //跳出本层循环 break; } try { - if (!pDataValue->bPlt) //ʱ + if (!pDataValue->bPlt) //短时闪变 { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) } - else //ʱ + else //长时闪变 { - if (0 == time_sec % 7200) //2Сʱʱ + if (0 == time_sec % 7200) //2小时间隔,长时闪变 { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) } } } catch (exception& e) { - cout << "ʵʱֵƴjsonԭ: " << e.what() << endl; + cout << "实时闪变数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-ʵʱݽ-------------------------------- - } //DataTypeList - } // RTDATA + return 1; //结束该函数,停止后续代码执行 + } //②-②实时闪变数据解析结束!-------------------------------- + } //DataTypeList 结束 + } //遍历 RTDATA 结束! - if ("RTDATASOE" == pTopic->strTopic) //TopicRTDATASOE---------------------------------------------------------- + if ("RTDATASOE" == pTopic->strTopic) //Topic等于RTDATASOE---------------------------------------------------------- { - list::iterator dt = pTopic->DataTypeList.begin(); //ڱ DataTypeList + list::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList while (dt != pTopic->DataTypeList.end()) { - int triggerCount = 0; //SOEʶ + int triggerCount = 0; //SOE触发标识计数 CDataType* pDataType = *dt++; - if (1 == pDataType->iDataType) //-SOE̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-①SOE稳态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE稳态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE̬¼--------------------------------- + return 1; //结束该函数,停止后续代码执行 + } //②-①SOE稳态事件解析结束!--------------------------------- - if (1 == pDataType->iDataType) //-SOE̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-②SOE暂态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE暂态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE̬¼--------------------------------- + return 1; //结束该函数,停止后续代码执行 + } //②-②SOE暂态事件解析结束!--------------------------------- - if (1 == pDataType->iDataType) //-SOE״̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-③SOE状态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE״̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE状态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE״̬¼--------------------------------- - } //DataTypeList - } // RTDATASOE - } //TopicList - } // + return 1; //结束该函数,停止后续代码执行 + } //②-③SOE状态事件解析结束!--------------------------------- + } //DataTypeList 结束 + } //遍历 RTDATASOE 结束! + } //TopicList 结束 + } //二、结束 - if (400 == data->func_type || 500 == data->func_type || 600 == data->func_type || 700 == data->func_type) //ʷ > MMS_Recall + if (400 == data->func_type || 500 == data->func_type || 600 == data->func_type || 700 == data->func_type) //三、补招历史数据 ——> MMS_Recall { list::iterator tp = ctopic_list.begin(); - while (tp != ctopic_list.end()) //ٱ Kafka + while (tp != ctopic_list.end()) //①遍历 Kafka发送主题链表 { CTopic* pTopic = *tp++; - if ("HISDATA" == pTopic->strTopic) //TopicHISDATA---------------------------------------------------------- + if ("HISDATA" == pTopic->strTopic) //Topic等于HISDATA---------------------------------------------------------- { - list::iterator dt = pTopic->DataTypeList.begin(); //ڱ DataTypeList + list::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList while (dt != pTopic->DataTypeList.end()) { - bool isJump = false; //Ƿ()ѭ + bool isJump = false; //是否跳出(整个数据类型)循环 CDataType* pDataType = *dt++; - if (2 == pDataType->iDataType) //-ʷ------------------------------------------------------------ + if (2 == pDataType->iDataType) //②-②历史短闪变数据------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "PST"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "PST"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - long long time_sec; //ʱ() - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʷ "02" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + long long time_sec; //时间戳(秒) + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:历史闪变 "02" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList int countflag = 0, num = 0; while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("TIME" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ - time_sec = data->time / 1000; //ʱ() + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 + time_sec = data->time / 1000; //时间戳(秒) continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json F + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //ƴ json ABC - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相 + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 num = num + pSequence->DataValueList.size(); while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 { countflag++; continue; } - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ + isJump = false; //跳出本层循环 countflag++; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; } try { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\",").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) } catch (exception& e) { - cout << "ʷֵƴjsonԭ: " << e.what() << endl; + cout << "历史闪变数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -1882,117 +1882,117 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"02\" " << num << endl; cout << KafkaData.strText.toAscii().data() << endl; if (countflag < num) { - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 shortjumpflag = true; } - } //-ʷݽ-------------------------------- + } //②-②历史闪变数据解析结束!-------------------------------- - //20241204ӦΪ3 - if (3 == pDataType->iDataType) //-ʷ------------------------------------------------------------ + //20241204长闪变类型应该为3 + if (3 == pDataType->iDataType) //②-②历史长闪变数据------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "PLT"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "PLT"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - long long time_sec; //ʱ() - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʷ "02" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + long long time_sec; //时间戳(秒) + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:历史闪变 "02" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList int countflag = 0, num = 0; while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("TIME" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ̣ - time_sec = data->time / 1000; //ʱ() + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻,毫秒 + time_sec = data->time / 1000; //时间戳(秒) continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json F + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 F - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //ƴ json ABC - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C相 + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 num = num + pSequence->DataValueList.size(); while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 { countflag++; continue; } - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ + isJump = false; //跳出本层循环 countflag++; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; } try { - if (0 == time_sec % 7200) //2Сʱʱ + if (0 == time_sec % 7200) //2小时间隔,长时闪变 { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(角度值) } } catch (exception& e) { - cout << "ʷֵƴjsonԭ: " << e.what() << endl; + cout << "历史闪变数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -2001,109 +2001,109 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 cout << countflag << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!send name=\"DATA_TYPE\" value=\"04\" " << num << endl; cout << KafkaData.strText.toAscii().data() << endl; if (countflag < num && 0 == time_sec % 7200) { - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 longjumpflag = true; } if (longjumpflag == true || shortjumpflag == true) { return 1; } - //return 1; //úִֹͣ - } //-ʷݽ-------------------------------- + //return 1; //结束该函数,停止后续代码执行 + } //②-②历史闪变数据解析结束!-------------------------------- - if (1 == pDataType->iDataType) //-ʷ̬----------------------------------------------------------- + if (1 == pDataType->iDataType) //②-①历史稳态数据----------------------------------------------------------- { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "HISDATA"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "HISDATA"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //ƴ json ʷ̬ "01" - KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));// "1100" + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\" ").arg(pDataType->iDataType, 2, 10, QChar('0'))); //拼接 json数据类型 例:历史稳态 "01" + KafkaData.strText.append(QString(", \"Monitor\":\"%1\" ").arg(data->mp_id));//例:监测点 "1100" - list::iterator mt = pDataType->MonitorList.begin(); //۱ MonitorList + list::iterator mt = pDataType->MonitorList.begin(); //③遍历 MonitorList while (mt != pDataType->MonitorList.end()) { CMonitor* pMonitor = *mt++; - KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //ƴ json + KafkaData.strText.append(QString(", \"%1\":{").arg("Value")); //拼接 json监测点 - list::iterator it = pMonitor->ItemList.begin(); //ܱ ItemList - list::iterator itEnd = pMonitor->ItemList.end(); //ItemListһֵԪ + list::iterator it = pMonitor->ItemList.begin(); //④遍历 ItemList + list::iterator itEnd = pMonitor->ItemList.end(); //ItemList链表最后一个数据值元素 while (it != pMonitor->ItemList.end()) { CItem* pItem = *it++; - if ("FLAG" == pItem->strItemName) //޳"FLAG"ֹsqִָ + if ("FLAG" == pItem->strItemName) //剔除"FLAG",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //ƴ json޳ǣ1޳0޳Ĭ޳ + KafkaData.strText.append(QString("\"FLAG\":%1, ").arg(data->flag)); //拼接 json剔除标记,1不剔除,0剔除,默认剔除 continue; } - if ("TIME" == pItem->strItemName) //޳"TIME"ֹsqִָ + if ("TIME" == pItem->strItemName) //剔除"TIME",防止sq相别出现错误指针 { - KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"TIME\":%1, ").arg(data->time)); //拼接 json发生时刻,毫秒 if (!data_timespan_list.contains(data->mp_id)) { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻,毫秒 } else if (data_timespan_list[data->mp_id]->msspan == 0) { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(3)); //拼接 json发生时刻,毫秒 } else { - KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //ƴ jsonʱ̣ + KafkaData.strText.append(QString("\"interval\":%1, ").arg(data_timespan_list[data->mp_id]->msspan)); //拼接 json发生时刻,毫秒 } continue; } - KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //ƴ json VIPQ + KafkaData.strText.append(QString("\"%1\":{").arg(pItem->strItemName)); //拼接 json数据项 V、I、PQ - list::iterator sq = pItem->SequenceList.begin(); //ݱ SequenceList - list::iterator sqEnd = pItem->SequenceList.end(); //SequenceListһֵԪ + list::iterator sq = pItem->SequenceList.begin(); //⑤遍历 SequenceList + list::iterator sqEnd = pItem->SequenceList.end(); //SequenceList链表最后一个数据值元素 while (sq != pItem->SequenceList.end()) { CSequence* pSequence = *sq++; - //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //ƴ json ABCT - KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //ƴ json ABCT + //KafkaData.strText.append(QString("{\"SEQ\":\"%1\", ").arg(pSequence->strSeq)); //拼接 json相别 A、B、C、T相 + KafkaData.strText.append(QString("\"%1\":{ ").arg(line_to_phasic(pSequence->strSeq))); //拼接 json相别 A、B、C、T相 - list::iterator dv = pSequence->DataValueList.begin(); //ޱ DataValueList + list::iterator dv = pSequence->DataValueList.begin(); //⑥遍历 DataValueList CDataValue* pDataValueBegin = *dv; - list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueListһֵԪ + list::iterator dvEnd = pSequence->DataValueList.end(); //DataValueList链表最后一个数据值元素 while (dv != pSequence->DataValueList.end()) { CDataValue* pDataValue = *dv++; - if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pDataValue->strFullName || "not define" == pDataValue->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pDataValue->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pDataValue->strFullName))//确认字典里不含有该key { - isJump = false; //ѭ - //zw޸ 2023-8-28 ƥ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //ƴ + isJump = false; //跳出本层循环 + //zw修改 2023-8-28 不匹配数据添加 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":%2, ").arg(pDataValue->strName).arg("null")); //拼接 else - KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //ƴ + KafkaData.strText.append(QString("\"%1\":%2 ").arg(pDataValue->strName).arg("null")); //拼接 continue; @@ -2111,32 +2111,32 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json try { - if (pDataValue->strFullName.indexOf("$ang$f") != -1) //61850кǵĶ + if (pDataValue->strFullName.indexOf("$ang$f") != -1) //查找61850属性名中含有相角的定义 { - double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //Ƕֵ(-180 ~ 180) + double dAngleTemp = data->mms_str_map.value(pDataValue->strFullName); //角度值(-180度 ~ 180度) dAngleTemp = dAngleTemp > 180.0f ? dAngleTemp - 360.0f : dAngleTemp; - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //ƴ jsonֵ(Ƕֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dAngleTemp, 10, 6))); //拼接 json数据值(角度值) } else { - double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //ӿ * ϵ - if (dv != dvEnd) //ǵһֵԪ - KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + double dTemp = data->mms_str_map.value(pDataValue->strFullName) * pDataValue->fCoefficient; //接口数据 * 系数 + if (dv != dvEnd) //非单相最后一个数据值元素 + KafkaData.strText.append(QString("\"%1\":\"%2\", ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) else - KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //ƴ jsonֵ(ǽǶֵ) + KafkaData.strText.append(QString("\"%1\":\"%2\" ").arg(pDataValue->strName).arg(QString::number(dTemp, 10, 6))); //拼接 json数据值(非角度值) } } catch (exception& e) { - cout << "ʷֵ̬ƴjsonԭ: " << e.what() << endl; + cout << "历史稳态数据值拼接json错误,原因: " << e.what() << endl; return false; } - } //DataValueList + } //DataValueList 结束 if (!KafkaData.strText.isEmpty()) { if (KafkaData.strText[KafkaData.strText.length() - 1] == ',') { @@ -2145,202 +2145,202 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json cout << "KafkaData.strText = KafkaData.strText.chopped(1) " << endl; } } - if (isJump) break; //ѭ - if (sq != sqEnd) //ABCTһԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (sq != sqEnd) //非A、B、C、T最后一个相别元素 + KafkaData.strText.append("}, "); //拼接 json相别结尾 else - KafkaData.strText.append("}"); //ƴ jsonβ - } //SequenceList + KafkaData.strText.append("}"); //拼接 json相别结尾 + } //SequenceList 结束 - if (isJump) break; //ѭ - if (it != itEnd) // VIPQһjsonԪ - KafkaData.strText.append("}, "); //ƴ jsonβ + if (isJump) break; //跳出循环 + if (it != itEnd) //非 V、I、PQ最后一个json数据项元素 + KafkaData.strText.append("}, "); //拼接 json数据项结尾 else - KafkaData.strText.append("}}"); //ƴ jsonβ - } //ItemList - if (isJump) break; //ѭ - } //MonitorList - if (isJump) continue; //ѭ - KafkaData.strText.append("}"); //ƴ json̬ݽβ + KafkaData.strText.append("}}"); //拼接 json数据项结尾 + } //ItemList 结束 + if (isJump) break; //跳出循环 + } //MonitorList 结束 + if (isJump) continue; //跳出本数据类型循环 + KafkaData.strText.append("}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-ʷ̬ݽ-------------------------------- - } //DataTypeList - } // HISDATA + return 1; //结束该函数,停止后续代码执行 + } //②-①历史稳态数据解析结束!-------------------------------- + } //DataTypeList 结束 + } //遍历 HISDATA 结束! - if ("RTDATASOE" == pTopic->strTopic) //TopicRTDATASOE---------------------------------------------------------- + if ("RTDATASOE" == pTopic->strTopic) //Topic等于RTDATASOE---------------------------------------------------------- { - list::iterator dt = pTopic->DataTypeList.begin(); //ڱ DataTypeList + list::iterator dt = pTopic->DataTypeList.begin(); //②遍历 DataTypeList while (dt != pTopic->DataTypeList.end()) { - int triggerCount = 0; //SOEʶ + int triggerCount = 0; //SOE触发标识计数 CDataType* pDataType = *dt++; - if (1 == pDataType->iDataType) //-SOE̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-①SOE稳态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE稳态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE̬¼--------------------------------- + return 1; //结束该函数,停止后续代码执行 + } //②-①SOE稳态事件解析结束!--------------------------------- - if (1 == pDataType->iDataType) //-SOE̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-②SOE暂态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE暂态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE̬¼--------------------------------- + return 1; //结束该函数,停止后续代码执行 + } //②-②SOE暂态事件解析结束!--------------------------------- - if (1 == pDataType->iDataType) //-SOE״̬¼------------------------------------------------------------ + if (1 == pDataType->iDataType) //②-③SOE状态事件------------------------------------------------------------ { - Ckafka_data_t KafkaData; //kafkaݽṹ - KafkaData.monitor_id = data->monitorId; //ID + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 + KafkaData.monitor_id = data->monitorId; //监测点ID KafkaData.mp_id = data->mp_id; - KafkaData.strTopic = "RTDATASOE"; //kafka - KafkaData.strText = ""; //kafka͵jsonַ + KafkaData.strTopic = "RTDATASOE"; //kafka发送主题 + KafkaData.strText = ""; //kafka发送的json字符串 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //ƴ json - KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //ƴ jsonʱ() - KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //ƴ json + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append(QString("\"DATA_TYPE\":\"%1\", ").arg(pDataType->iDataType)); //拼接 json数据类型 + KafkaData.strText.append(QString("\"TIME\":\"%1\", ").arg(data->time)); //拼接 json发生时刻(毫秒) + KafkaData.strText.append(QString("\"%1\":[").arg(data->mp_id)); //拼接 json监测点号 - list::iterator ed = pDataType->SOEList.begin(); //۱ SOEList - list::iterator edEnd = pDataType->SOEList.end(); //SOEListβԪ + list::iterator ed = pDataType->SOEList.begin(); //③遍历 SOEList + list::iterator edEnd = pDataType->SOEList.end(); //SOEList尾元素 while (ed != pDataType->SOEList.end()) { CEventData* pEventData = *ed++; - if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //ݶ $ ƴΪ + if ("NOT DEFINE" == pEventData->strFullName || "not define" == pEventData->strFullName) //数据对象名 $ 数据属性名 即:拼接名为空 continue; - if (!data->mms_str_map.contains(pEventData->strFullName))//ȷֵﲻиkey + if (!data->mms_str_map.contains(pEventData->strFullName))//确认字典里不含有该key continue; try { double dTemp = data->mms_str_map.value(pEventData->strFullName); - if (dTemp >= 0.9) //SOE¼ + if (dTemp >= 0.9) //SOE事件发生 { - if (0 == triggerCount) //SOEʶ + if (0 == triggerCount) //SOE触发标识计数 { - KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ - triggerCount++; //SOEʶ + KafkaData.strText.append(QString("\"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 + triggerCount++; //SOE触发标识计数 } else - KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //ƴ json SOEʶ + KafkaData.strText.append(QString(", \"%1\" ").arg(pEventData->triggerFlag)); //拼接 json SOE触发标识 } } catch (exception& e) { - cout << "SOE״̬¼ƴjsonԭ: " << e.what() << endl; + cout << "SOE状态事件拼接json错误,原因: " << e.what() << endl; return false; } - } //SOEList - KafkaData.strText.append("]}"); //ƴ json̬ݽβ + } //SOEList 结束 + KafkaData.strText.append("]}"); //拼接 json稳态数据结尾 - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 - return 1; //úִֹͣ - } //-SOE״̬¼--------------------------------- - } //DataTypeList - } // RTDATASOE - } //TopicList - } // + return 1; //结束该函数,停止后续代码执行 + } //②-③SOE状态事件解析结束!--------------------------------- + } //DataTypeList 结束 + } //遍历 RTDATASOE 结束! + } //TopicList 结束 + } //三、结束 return 1; } @@ -2358,20 +2358,20 @@ void processGGIO_start_data_end(char* mp_id,char* fullname,double v,long long ti QString Full_name; Full_name.append(fullname); - Ckafka_data_t KafkaData; //kafkaݽṹ + Ckafka_data_t KafkaData; //kafka发送数据结构类对象 KafkaData.monitor_id = monitor_id; KafkaData.mp_id = mp_id; - KafkaData.strTopic = "Alm"; //kafka + KafkaData.strTopic = "Alm"; //kafka发送主题 - KafkaData.strText.append("{"); //ƴ jsonʼ - KafkaData.strText.append("\"DATA_TYPE\":\"05\", "); //ƴ - KafkaData.strText.append(QString("\"Monitor\":\"%1\", ").arg(mp_id)); //ƴ json - KafkaData.strText.append(QString("\"Value\":{")); //ƴ json - KafkaData.strText.append(QString("\"FLAG\":%1,").arg(1)); //ƴ ޳ - KafkaData.strText.append(QString("\"TIME\":%1,").arg(time)); //ƴ ʱ - KafkaData.strText.append(QString("\"SOE\":[")); //ƴ SOE + KafkaData.strText.append("{"); //拼接 json起始 + KafkaData.strText.append("\"DATA_TYPE\":\"05\", "); //拼接 数据类型 + KafkaData.strText.append(QString("\"Monitor\":\"%1\", ").arg(mp_id)); //拼接 json监测点 + KafkaData.strText.append(QString("\"Value\":{")); //拼接 json监测点 + KafkaData.strText.append(QString("\"FLAG\":%1,").arg(1)); //拼接 剔除标记 + KafkaData.strText.append(QString("\"TIME\":%1,").arg(time)); //拼接 时间 + KafkaData.strText.append(QString("\"SOE\":[")); //拼接 SOE - list::iterator ed = c_xmlcfg.SOEList.begin(); //۱ SOEList + list::iterator ed = c_xmlcfg.SOEList.begin(); //③遍历 SOEList while (ed != c_xmlcfg.SOEList.end()) { CEventData* pEventData = *ed++; @@ -2382,18 +2382,18 @@ void processGGIO_start_data_end(char* mp_id,char* fullname,double v,long long ti } } - KafkaData.strText.append(QString("]")); //ƴ SOE - KafkaData.strText.append("}"); //ƴ value - KafkaData.strText.append("}"); //ƴ json + KafkaData.strText.append(QString("]")); //拼接 SOE结束 + KafkaData.strText.append("}"); //拼接 value结束 + KafkaData.strText.append("}"); //拼接 json结束 printf("transfer json ggio data: %s==%s \n", KafkaData.strText.toStdString().c_str(), fullname); - kafka_data_list_mutex.lock(); // - kafka_data_list.append(KafkaData); // kafka - kafka_data_list_mutex.unlock(); // + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(KafkaData); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 } -//zw޸ 2023-8-31 list дxmlݿϢ ģͱ նͺ ն˳ oss洢· ʱ -//lnk޸ 2024-10-28 ȥն˳ңԶģļ· +//zw修改 2023-8-31 新增或更新list队列 写入xml数据库信息 模型编码 终端型号 终端厂家 oss存储路径 时间 +//lnk修改 2024-10-28 去掉终端厂家,换成远端模型文件路径 //void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* TMNL_FACTORY, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second) void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second) { @@ -2409,33 +2409,33 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char filepath.append(FILE_PATH); name.append(FILE_NAME); - //lnk20241125 + //调试用lnk20241125 cout << "setxmldatabase:" << TMNL_TYPE << endl; - if (!xmlinfo_list.contains(type))//նбû鵽 + if (!xmlinfo_list.contains(type))//在终端类型列表中没查到 { - Xmldata* config = new Xmldata(); //ûҵͲµն͵б + Xmldata* config = new Xmldata(); //没找到就插个新的终端类型到列表中 xmlinfo_list.insert(type, config); - //lnk20241125 + //调试用lnk20241125 cout << "xmlinfo_list insert type:" << type.toStdString() << endl; } - else//鵽͸¸ + else//查到就更新覆盖 { - //lnk20241125 + //调试用lnk20241125 cout << "xmlinfo_list type contain:" << type.toStdString() << endl; QDateTime time(QDate(year, month, day), QTime(hour, minute, second)); - if (xmlinfo_list[type]->xmlbase.datetime == time) { //նͺŸ±־ͺŴ󣬵ʵõӳļһ߸ԭӳļܳ⡣ݿ¼ͺźӳļʱҪע - xmlinfo_list[type]->updataflag = false; //ʱֵһ˵ûи£ǰҵвʱֵÿζ + if (xmlinfo_list[type]->xmlbase.datetime == time) { //终端型号更新标志,如果新增的型号错误,导致实际用的映射文件不一样,或者覆盖了原来的映射文件这里可能出问题。数据库在录入型号和映射文件时要注意 + xmlinfo_list[type]->updataflag = false; //时间值一样说明是没有更新,当前业务中不包含时间值,所以每次都会更新 } else { xmlinfo_list[type]->updataflag = true; } - //lnk20250208ʹִ + //lnk20250208如果类型存在则不再往下执行 } - //lnk20250208ӦǸǶ׷ + //lnk20250208这里应该是覆盖而不是追加 //xmlinfo_list[type]->xmlbase.MODEL_ID.append(id); //xmlinfo_list[type]->xmlbase.TMNL_TYPE.append(type); //xmlinfo_list[type]->xmlbase.FILE_PATH.append(filepath); @@ -2449,7 +2449,7 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char xmlinfo_list[type]->xmlbase.datetime = time; cout << "##################################isdelta_flag is " << isdelta_flag << endl; - /*lnk2024-8-14 isdelta_flag ѡxmllist*/ + /*lnk2024-8-14 根据isdelta_flag 选择xmllist*/ if (isdelta_flag) { cout << "xmllist2 create" << endl; if (!xmlinfo_list2.contains(type)) @@ -2479,38 +2479,38 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char memset(file_name, 0, 256); sprintf(file_name, "%s", FILE_NAME); QString Qsavename; - Qsavename.append("/FeProject/dat/").append(id).append(".xml"); //ر· + Qsavename.append("/FeProject/dat/").append(id).append(".xml"); //本地保存路径 char save_name[256]; memset(save_name, 0, 256); sprintf(save_name, "%s", Qsavename.toAscii().data()); cout << file_name << "!!!!!!!!!!!!!!!!!!!!!!!!!!" << save_name << endl; - //20241028 lnk 滻Ϊļwebӿ - //ļؽӿڲ - //ӿʾhttp://192.168.1.125:10215/file/download?filePath=/path/xxx.txt - // webȡļ + //20241028 lnk 替换为文件下载web接口 + //构造文件下载接口参数 + //接口示例http://192.168.1.125:10215/file/download?filePath=/path/xxx.txt + // 调用web获取文件内容 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::cout << "fullpath" << fullPath << std::endl; SendJsonAPI_web(WEB_FILEDOWNLOAD, fullPath.c_str(), "", &fileContent); if (fileContent != NULL) { - // ļ + // 创建并打开文件 - // - //std::ofstream outFile(downpath, std::ios::binary);//Ƶķʽ + //测试 + //std::ofstream outFile(downpath, std::ios::binary);//二进制的方式打开 - std::ofstream outFile(save_name, std::ios::out);//ıģʽ + std::ofstream outFile(save_name, std::ios::out);//文本模式打开 if (outFile.is_open()) { - // ļдļ + // 将文件流写入文件 outFile.write(fileContent, strlen(fileContent)); outFile.close(); std::cout << "File saved successfully!" << std::endl; @@ -2518,24 +2518,24 @@ void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* FILE_PATH, char std::cerr << "Error: Unable to open file for writing." << std::endl; } - // ͷŷڴ + // 释放分配的内存 free(fileContent); } else { std::cerr << "Error: Unable to download file." << std::endl; } } -//zw޸ 2023-9-4 ȡװͶӦxmlļ +//zw修改 2023-9-4 读取装置类型对应的xml文件 void Set_xml_nodeinfo() { - //޶ӦxmlļʱĬϽ - if (!inited) //ʼ JiangSu_Config.xml + //配置无对应xml文件时的默认解析配置 + if (!inited) //初始化 JiangSu_Config.xml { QString path; path.append("not define"); - ParseXMLConfig2(0, &xmlcfg, &topicList, path); // ParseXMLConfig() JiangSu_Config.xmlļ + ParseXMLConfig2(0, &xmlcfg, &topicList, path); //调用 ParseXMLConfig() 解析JiangSu_Config.xml配置文件 if (isdelta_flag) { - ParseXMLConfig2(1, &xmlcfg2, &topicList2, path); //lnk2024-8-13ͽ + ParseXMLConfig2(1, &xmlcfg2, &topicList2, path); //lnk2024-8-13角型接线 } inited = true; } @@ -2552,7 +2552,7 @@ void Set_xml_nodeinfo() ParseXMLConfig2(0,&(value2->xmlcfg), &(value2->topicList), value2->xmlbase.MODEL_ID); } } - //lnk2024-8-14 ѡͽ + //lnk2024-8-14 选择角型接线 if (isdelta_flag) { for (QMap::iterator it3 = xmlinfo_list2.begin(); it3 != xmlinfo_list2.end(); ++it3) { @@ -2570,23 +2570,23 @@ void Set_xml_nodeinfo() } } -//zw޸ 2023-9-4 ȡxml· +//zw修改 2023-9-4 获取xml路径 char* Get_xmlpath(char* devtype) { QString type; type.append(devtype); - //lnk20241125 + //调试用lnk20241125 std::cout << type.toStdString() << std::endl; if (xmlinfo_list.contains(devtype) && - xmlinfo_list[devtype] != NULL && // ȼָǷΪ - !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isNull() && // ȷ QString NULL - !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isEmpty() && // ȷַΪ - xmlinfo_list[devtype]->xmlbase.MODEL_ID.trimmed().length() >= 4) { //ȷmodelidlnk20250313 + xmlinfo_list[devtype] != NULL && // 先检查指针是否为空 + !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isNull() && // 确保 QString 不是 NULL + !xmlinfo_list[devtype]->xmlbase.MODEL_ID.isEmpty() && // 确保字符串不为空 + xmlinfo_list[devtype]->xmlbase.MODEL_ID.trimmed().length() >= 4) { //确保modelid存在lnk20250313 cout << "!!!!!!!!!! xmlinfo_list.contains(devtype) == 1 !!!!!!!!!!!" << endl; - QByteArray byteArray = xmlinfo_list[devtype]->xmlbase.MODEL_ID.toLocal8Bit();//ױ,һҪȷmodelidlnk20250313 - char* charArray = new char[byteArray.size()+1];//ڴʱ+1ֹڴй©lnk20250305 + QByteArray byteArray = xmlinfo_list[devtype]->xmlbase.MODEL_ID.toLocal8Bit();//易崩溃点,一定要确保modelid存在lnk20250313 + char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305 memcpy(charArray, byteArray.data(), byteArray.size()); charArray[byteArray.size()] = '\0'; return charArray; @@ -2596,7 +2596,7 @@ char* Get_xmlpath(char* devtype) return NULL; } } -//zw޸ 2023-9-5 ȡIEDģ +//zw修改 2023-9-5 获取IED模型 char* Get_IED(char* devtype) { QString type; @@ -2604,7 +2604,7 @@ char* Get_IED(char* devtype) if (xmlinfo_list.contains(type) && xmlinfo_list[type] != NULL) { cout << "!!!!!!!!!! Get_IED xmlinfo_list.contains(devtype) == 1 !!!!!!!!!!!" << endl; - // ȷ xmlcfg Աǿ + // 确保 xmlcfg 及其成员非空 if (xmlinfo_list[type]->xmlcfg.IEDname.isNull() || xmlinfo_list[type]->xmlcfg.LDevicePrefix.isNull()) { cout << "Error: IEDname or LDevicePrefix is NULL in Get_IED!" << endl; return NULL; @@ -2622,7 +2622,7 @@ char* Get_IED(char* devtype) return NULL; } - // ڴ棬ȷ㹻Сȫ + // 分配内存,确保足够大小并安全拷贝 char* charArray = new char[byteArray.size() + 1]; if (!charArray) { cout << "Error: Memory allocation failed!" << endl; @@ -2630,7 +2630,7 @@ char* Get_IED(char* devtype) } memcpy(charArray, byteArray.data(), byteArray.size()); - charArray[byteArray.size()] = '\0'; // ȷַ '\0' β + charArray[byteArray.size()] = '\0'; // 确保字符串以 '\0' 结尾 return charArray; } @@ -2642,7 +2642,7 @@ char* Get_IED(char* devtype) ied.append(xmlcfg.LDevicePrefix); ied.append("%d"); QByteArray byteArray = ied.toLocal8Bit(); - char* charArray = new char[byteArray.size()+1];//ڴʱ+1ֹڴй©lnk20250305 + char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305 memcpy(charArray, byteArray.data(), byteArray.size()); charArray[byteArray.size()] = '\0'; return charArray; @@ -2652,14 +2652,14 @@ char* Get_LDevice(char* devtype) { QString type; type.append(devtype); - if (xmlinfo_list.contains(type) && xmlinfo_list[type] != NULL) { // ȷʹҲΪ + if (xmlinfo_list.contains(type) && xmlinfo_list[type] != NULL) { // 确保类型存在且不为空 if (xmlinfo_list[type]->xmlcfg.LDevicePrefix.isNull() || xmlinfo_list[type]->xmlcfg.LDevicePrefix.isEmpty()) { cout << "Error: LDevicePrefix is NULL or empty in Get_IED!" << endl; return NULL; } QString ied; - ied.append(xmlinfo_list[type]->xmlcfg.LDevicePrefix); // ʹýбնǰ׺ + ied.append(xmlinfo_list[type]->xmlcfg.LDevicePrefix); // 使用解析列表的终端前缀 ied.append("%d"); QByteArray byteArray = ied.toLocal8Bit(); @@ -2669,7 +2669,7 @@ char* Get_LDevice(char* devtype) return NULL; } - // ڴ棬ȷ㹻С + // 分配内存,确保足够大小 char* charArray = new char[byteArray.size() + 1]; if (!charArray) { cout << "Error: Memory allocation failed!" << endl; @@ -2677,17 +2677,17 @@ char* Get_LDevice(char* devtype) } memcpy(charArray, byteArray.data(), byteArray.size()); - charArray[byteArray.size()] = '\0'; // ȷַ '\0' β + charArray[byteArray.size()] = '\0'; // 确保字符串以 '\0' 结尾 return charArray; } else { QString ied; - ied.append(xmlcfg.LDevicePrefix);//ʹĬϽõնǰ׺ + ied.append(xmlcfg.LDevicePrefix);//使用默认解析配置的终端前缀 ied.append("%d"); QByteArray byteArray = ied.toLocal8Bit(); - char* charArray = new char[byteArray.size()+1];//ڴʱ+1ֹڴй©lnk20250305 + char* charArray = new char[byteArray.size()+1];//分配内存时+1防止内存泄漏lnk20250305 memcpy(charArray, byteArray.data(), byteArray.size()); charArray[byteArray.size()] = '\0'; return charArray; @@ -2699,14 +2699,14 @@ char* Get_LDevice(char* devtype) ///////////////////////////////////////////////////lnk2024-10-21//////////////////////////////////////////////////////// void handleCommentResponse(const std::string& response) { - // JSON Ӧ + // 解析 JSON 响应 cJSON* json_data = cJSON_Parse(response.c_str()); if (json_data == NULL) { std::cerr << "Error parsing response: " << cJSON_GetErrorPtr() << std::endl; return; } - // ȡֶ + // 提取字段 cJSON* codeItem = cJSON_GetObjectItem(json_data, "code"); cJSON* msgItem = cJSON_GetObjectItem(json_data, "msg"); cJSON* dataItem = cJSON_GetObjectItem(json_data, "data"); @@ -2714,7 +2714,7 @@ void handleCommentResponse(const std::string& response) { if (codeItem) { std::string code = codeItem->valuestring; - // Ϣ + // 输出信息 std::cout << "Response Code: " << code << std::endl; std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found"; @@ -2724,7 +2724,7 @@ void handleCommentResponse(const std::string& response) { std::cerr << "Error: Missing expected fields in JSON response." << std::endl; } - // ͷ JSON + // 释放 JSON 对象 cJSON_Delete(json_data); } @@ -2732,21 +2732,21 @@ std::string boolToString(bool value) { return value ? "1" : "0"; } -//Ρʱ״̬lnk202411-4 +//添加入参、时间和状态lnk202411-4 void connectlog_pgsql(char* id,char* datetime,int status) { - //Ӧ + //创建响应接收 char* ptr=NULL; - // JSON + // 创建 JSON 对象 cJSON* jsonObject = cJSON_CreateObject(); if (jsonObject == NULL) { std::cerr << "Failed to create JSON object." << std::endl; return; } - // ֶε JSON + // 添加字段到 JSON 对象 cJSON* id_item = cJSON_CreateString(id); if (!id_item) { std::cerr << "Failed to create 'id' string." << std::endl; @@ -2763,8 +2763,8 @@ void connectlog_pgsql(char* id,char* datetime,int status) } cJSON_AddItemToObject(jsonObject, "date", datetime_item); - char statusStr[12]; // 㹻һź '\0' - sprintf(statusStr, "%d", status);// ʹ sprintf int תΪַ + char statusStr[12]; // 足够容纳一个整数(包括负号和 '\0') + sprintf(statusStr, "%d", status);// 使用 sprintf 将 int 转换为字符串 cJSON* status_item = cJSON_CreateString(statusStr); if (!status_item) { @@ -2784,61 +2784,61 @@ void connectlog_pgsql(char* id,char* datetime,int status) - //ʹmq + //使用mq Ckafka_data_t connect_info; connect_info.strTopic = QString::fromStdString(G_CONNECT_TOPIC); connect_info.strText = QString::fromStdString(std::string(jsonString)); - if(g_node_id == STAT_DATA_BASE_NODE_ID){//̬ϴ - kafka_data_list_mutex.lock(); // - kafka_data_list.append(connect_info); // kafka - kafka_data_list_mutex.unlock(); // + if(g_node_id == STAT_DATA_BASE_NODE_ID){//稳态才上传 + kafka_data_list_mutex.lock(); //加锁 + kafka_data_list.append(connect_info); //添加 kafka发送链表 + kafka_data_list_mutex.unlock(); //解锁 } - // ͷڴ + // 释放内存 cJSON_Delete(jsonObject); - free(jsonString); // cJSON_PrintUnformattedʹmallocڴ + free(jsonString); // cJSON_PrintUnformatted使用malloc分配内存 } -//lnk202411-5 ̬ݲʹkafkaͣijhttpӿ -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////̬¼ļ -// ⲿҪԭСܡĸ +//lnk202411-5 暂态数据不再使用kafka发送,改成http接口 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件 +// 下面这部分是你要在原函数中“插入的新增功能”所需的辅助函数 // ***************************************************************************************** -// ȡָĿ¼ļϢ(ļ޸ʱ䡢С)ԱɾжļܴС +// 获取指定目录下所有文件的信息(文件名、修改时间、大小),以便后续做删除或判断文件总大小 struct FileInfo { std::string fileName; - time_t modTime; // ϴ޸ʱ - long long fileSize; // ļС + time_t modTime; // 上次修改时间 + long long fileSize; // 文件大小 }; -// ɨĿ¼ȡĿ¼ͨļϢ +// 扫描目录,获取该目录下所有普通文件的信息 static void getDirectoryFilesInfo(const std::string &dirPath, std::vector &fileList) { DIR* dp = opendir(dirPath.c_str()); if (!dp) { std::cerr << "Failed to get info from : " << dirPath << std::endl; - return; // ʧֱӷ + return; // 打开失败则直接返回 } struct dirent* entry = NULL; while ((entry = readdir(dp)) != NULL) { - // . .. + // 跳过 . 和 .. if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } - // ƴ· + // 拼出完整路径 std::string fullPath = dirPath + entry->d_name; - // ȡļϢ + // 获取文件信息 struct stat st; if (stat(fullPath.c_str(), &st) == 0) { if (S_ISREG(st.st_mode)) { FileInfo fi; - fi.fileName = fullPath; // · - fi.modTime = st.st_mtime; // ޸ʱ - fi.fileSize = (long long)st.st_size; // ļС + fi.fileName = fullPath; // 包含路径 + fi.modTime = st.st_mtime; // 修改时间 + fi.fileSize = (long long)st.st_size; // 文件大小 fileList.push_back(fi); } @@ -2847,8 +2847,8 @@ static void getDirectoryFilesInfo(const std::string &dirPath, std::vector fileList; getDirectoryFilesInfo(dirPath, fileList); - // ܴС + // 计算总大小 long long totalSize = 0; for (size_t i = 0; i < fileList.size(); ++i) { totalSize += fileList[i].fileSize; } - // ֵɾϵǸ + // 如果超过阈值,则删除最老的那个 if (totalSize > maxBytes && !fileList.empty()) { - // ޸ʱ(޸ʱ)ǰ + // 按修改时间升序排序,最老(修改时间最早)的排在最前面 std::sort(fileList.begin(), fileList.end(), - // C++98 ıȽд + // C++98 的比较写法 static_cast( - // ʹlambdaúָ - // ȽϺ + // 不能使用lambda,用函数指针 + // 比较函数 (bool (*)(const FileInfo&, const FileInfo&))[] (const FileInfo &a, const FileInfo &b) { return a.modTime < b.modTime; } ) ); - // ɾһ(ϵļ) + // 删掉第一个(最老的文件) remove(fileList[0].fileName.c_str()); } } -// ɨĿ¼µļζȡͣͳɹɾļͲɹ +// 扫描目录下的离线文件,依次读取并发送;若发送成功则删除该文件,发送不成功则保留 static void scanAndResendOfflineFiles(const std::string &dirPath) { - // ȡĿ¼ļϢ + // 获取目录下所有文件信息 std::vector fileList; std::cout << "getDirectoryFilesInfo" << std::endl; getDirectoryFilesInfo(dirPath, fileList); std::cout << "send every file" << std::endl; - // ļط + // 逐个文件尝试重发 for (size_t i = 0; i < fileList.size(); ++i) { - // ȡļ(֮ǰ JSON) + // 读取文件内容(即之前存的 JSON) FILE* fp = fopen(fileList[i].fileName.c_str(), "r"); if (!fp) { std::cerr << " fail to open exsist file " << fileList[i].fileName << std::endl; continue; } - // ȡڴ + // 读取到内存 std::string jsonContent; char buf[1024]; while (!feof(fp)) { @@ -2954,20 +2954,20 @@ static void scanAndResendOfflineFiles(const std::string &dirPath) std::cout << "send jsonContent" << jsonContent << std::endl; - // Է - char* ptr = NULL; // շ + // 尝试发送 + char* ptr = NULL; // 接收返回 SendJsonAPI_web(WEB_EVENT, "", jsonContent.c_str(), &ptr); if (ptr != NULL) { cJSON* j_r = cJSON_Parse(ptr); if (j_r == NULL) { std::cout << "old file send fail" << std::endl; - // ʾӦΪɹĿҪɼӸϸж + // 表示有响应,则可视为成功;根据项目需要可加更精细的判断 handleCommentResponse(std::string(ptr)); } else{ std::cout << "old file send success,remove it" << std::endl; - // ɾļ + // 删除文件 remove(fileList[i].fileName.c_str()); free(j_r); @@ -2975,7 +2975,7 @@ static void scanAndResendOfflineFiles(const std::string &dirPath) } else { - // ʧܣļԱ´ + // 发送失败,保留文件,以便下次重试 std::cout << "old file send fail" << std::endl; } free(ptr); @@ -2992,17 +2992,17 @@ std::string FormatTimeForFilename(const std::string& timeStr) { } return result; } -// ======================== ԭȵĺ ======================== +// ======================== 原先的函数 ======================== int transfer_json_qvvr_data(unsigned int func_type, int monitor_id, double mag, double dur, long long start_tm, long long end_tm, int dis_kind, char* uuid_cfg,char* uuid_dat, char* mp_id,char* Qvvr_rptname,char* devtype) { - // ԭ߼κθĶ + // 原本的逻辑,不做任何改动 // --------------------------------------------------------------- XmlConfig c_xmlcfg; if (xmlinfo_list.contains(devtype)) { - c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;//ӳ + c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;//查找映射 } else { c_xmlcfg = xmlcfg; @@ -3051,26 +3051,26 @@ char* mp_id,char* Qvvr_rptname,char* devtype) } char* json_string = cJSON_Print(root); - printf("%s\n", json_string); // JSON ַ + printf("%s\n", json_string); // 输出 JSON 字符串 - // ͵̬ӿ + // 发送到暂态接口 char* ptr = NULL; SendJsonAPI_web(WEB_EVENT, "", json_string, &ptr); - // ================ ¹ ========================= - // ********** ܿʼ ********** + // ================ 插入新功能 ========================= + // ********** 新增功能开始 ********** if(ptr != NULL) { cJSON* j_r = cJSON_Parse(ptr); - // ʧ(j_r == NULL)ѵǰ json ָĿ¼(/FeProject/dat/qvvr/) + // 如果发送失败(j_r == NULL),则把当前 json 存入指定目录(/FeProject/dat/qvvr/) if (j_r == NULL) { std::cout << "qvvr send fail ,store in local" << std::endl; - // 1) ȼ/FeProject/dat/qvvr/Ŀ¼ļСǷ񳬹 10Mɾϵһļ + // 1) 先检查/FeProject/dat/qvvr/目录文件大小是否超过 10M,若超过则删除最老的一个文件 std::string qvvrDir = "/FeProject/dat/qvvr/"; checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024); - // 2) json Ϊļļ: mp_id-start_time_str-dis_kind.txt - // 磺 502-2025-04-02 15:25:30.123-3.txt (ʾ) + // 2) 将此条 json 存为文件,文件名: mp_id-start_time_str-dis_kind.txt + // 例如: 502-2025-04-02 15:25:30.123-3.txt (仅示例) std::string fileName = qvvrDir; fileName += mp_id; fileName += "-"; @@ -3082,42 +3082,42 @@ char* mp_id,char* Qvvr_rptname,char* devtype) fileName += buf; fileName += ".txt"; - // json_string дļ + // 把 json_string 写入文件 writeJsonToFile(fileName.c_str(), json_string); } else{ free(j_r); - // + //后续处理 } } - // ۴˴ηͳɹʧܣҪɨ/FeProject/dat/qvvr/Ŀ¼µļط + // 无论此次发送成功或失败,都要扫描/FeProject/dat/qvvr/目录下的文件并尝试依次重发 if(1) { std::string qvvrDir = "/FeProject/dat/qvvr/"; scanAndResendOfflineFiles(qvvrDir); } - // ********** ܽ ********** + // ********** 新增功能结束 ********** - // ԭ߼η + // 下面继续原逻辑,不动,处理本次发送 if (ptr != NULL) { std::cout << "current qvvr handle response" << std::endl; handleCommentResponse(std::string(ptr)); free(ptr); } else { - // ptr Ϊ NULL ־¼ + // 处理 ptr 为 NULL 的情况,例如日志记录或错误处理 std::cout << "Error: Received NULL response" << std::endl; - // ͷڴ + // 释放内存 cJSON_Delete(root); free(json_string); return 0; } - // ͷڴ + // 释放内存 cJSON_Delete(root); free(json_string); return 1; } -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////̬¼ļ +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件 void qvvr_test() { @@ -3139,25 +3139,25 @@ void comflag_test() ///////////////////////////////////////////////////lnk2024-10-21//////////////////////////////////////////////////////// void clearXmlConfigAndTopicList(Xmldata* data) { - // XmlConfig - data->xmlcfg = XmlConfig(); // ͨ¸ֵ xmlcfg + // 清空 XmlConfig + data->xmlcfg = XmlConfig(); // 通过重新赋值重置 xmlcfg - // topicList + // 清空 topicList list::iterator it; for (it = data->topicList.begin(); it != data->topicList.end(); ++it) { - delete *it; // ͷڴ + delete *it; // 释放内存 } - data->topicList.clear(); // + data->topicList.clear(); // 清空链表 } -//4-ӳļ////////////////////////////// +//4-配置映射文件////////////////////////////// void Set_xml_nodeinfo_one(char* dev_type) { bool ret = false; - if(xmlinfo_list[QString::fromUtf8(dev_type)] != NULL){ //ԭѴ͵Ľڵ - if(xmlinfo_list[QString::fromUtf8(dev_type)]->updataflag == true){ //Ҫ + if(xmlinfo_list[QString::fromUtf8(dev_type)] != NULL){ //原来已存在这个类型的节点 + if(xmlinfo_list[QString::fromUtf8(dev_type)]->updataflag == true){ //需要更新 - //xmlcfgtopicListɾ + //将这个点的xmlcfg和topicList删除 clearXmlConfigAndTopicList(xmlinfo_list[QString::fromUtf8(dev_type)]); ret = ParseXMLConfig2(0,&(xmlinfo_list[QString::fromUtf8(dev_type)]->xmlcfg), &(xmlinfo_list[QString::fromUtf8(dev_type)]->topicList), xmlinfo_list[QString::fromUtf8(dev_type)]->xmlbase.MODEL_ID); @@ -3171,12 +3171,12 @@ void Set_xml_nodeinfo_one(char* dev_type) else{ std::cout << "xmlinfo_list not contain this devtype" << std::endl; } - //ӽ + //添加角形 if(isdelta_flag){ - if(xmlinfo_list2[QString::fromUtf8(dev_type)] != NULL){ //ԭѴ͵Ľڵ - if(xmlinfo_list2[QString::fromUtf8(dev_type)]->updataflag == true){ //Ҫ + if(xmlinfo_list2[QString::fromUtf8(dev_type)] != NULL){ //原来已存在这个类型的节点 + if(xmlinfo_list2[QString::fromUtf8(dev_type)]->updataflag == true){ //需要更新 - //xmlcfgtopicListɾ + //将这个点的xmlcfg和topicList删除 clearXmlConfigAndTopicList(xmlinfo_list2[QString::fromUtf8(dev_type)]); ret = ParseXMLConfig2(1,&(xmlinfo_list2[QString::fromUtf8(dev_type)]->xmlcfg), &(xmlinfo_list2[QString::fromUtf8(dev_type)]->topicList), xmlinfo_list2[QString::fromUtf8(dev_type)]->xmlbase.MODEL_ID); diff --git a/json/mms_json_inter.h b/json/mms_json_inter.h index 17bb8cf..c4ca673 100644 --- a/json/mms_json_inter.h +++ b/json/mms_json_inter.h @@ -22,46 +22,46 @@ #include -#define STAT_DATA_BASE_NODE_ID 100 //̬ͳ -#define THREE_SECS_DATA_BASE_NODE_ID 200 // ݡʵʱ -#define SOE_COMTRADE_BASE_NODE_ID 300 // soe ¼ -#define HIS_DATA_BASE_NODE_ID 400 //ʷ +#define STAT_DATA_BASE_NODE_ID 100 //稳态、统计数据 +#define THREE_SECS_DATA_BASE_NODE_ID 200 // 三秒数据、实时数据 +#define SOE_COMTRADE_BASE_NODE_ID 300 // soe 录波 +#define HIS_DATA_BASE_NODE_ID 400 //历史、补招 -class json_block_data //jsonƴӲ +class json_block_data //json拼接参数类 { public: - int monitorId; //ID - int func_type; //Ӧ(#define궨100 400)ѡ - int flag; //޳ǣ1޳0޳Ĭ޳ Ρ˲δ·װôȡ2018-11-21 19:32:38 - long long time; //ʱ() - double voltage_level; //CZY 2023-08-23 ѹȼ(double) - QString mp_id; //charͼ - QString dev_type;//豸 + int monitorId; //监测点ID + int func_type; //对应(#define宏定义中100 — 400)功能选项 + int flag; //剔除标记,1不剔除,0剔除,默认剔除 ——————问下王巍,此参数如何从线路装置处获取???2018-11-21 19:32:38 + long long time; //时间戳(毫秒) + double voltage_level; //CZY 2023-08-23 电压等级(翻译后的double类型) + QString mp_id; //char型监测点 + QString dev_type;//设备类型 - QMap mms_str_map; //ֵ(61850, ֵ) + QMap mms_str_map; //数据值(61850数据属性名, 数据值) }; -class Ckafka_data_t //kafkaݽṹ +class Ckafka_data_t //kafka发送数据结构类 { public: - int monitor_id; //ID - QString strTopic; //kafkatopic - QString strText; //kafka͵jsonַ - QString mp_id; //charid + int monitor_id; //监测点ID + QString strTopic; //kafka发送topic + QString strText; //kafka发送的json字符串 + QString mp_id; //char类型id }; -class oss_data_t //ossͷݽṹ zw 2023-9-22 +class oss_data_t //oss推送发送数据结构类 zw 2023-9-22 新增 { public: - QString filename; //Ʊ· - QString savename; //ر· - QString data; // + QString filename; //云保存路径 + QString savename; //本地保存路径 + QString data; //保存的数据 - //־ͨò - QString log_name; //նidid - QString id; //նidid - QString time; //ʱ + //日志通用参数 + QString log_name; //终端id或监测点id + QString id; //终端id或监测点id + QString time; //时间 int base_mat_num; int adv_mat_num; int base_act_num; @@ -69,7 +69,7 @@ public: int list_num; }; -int transfer_json_block_data(char v_wiring_type[], json_block_data* data);//lnk2024-8-16Ӳ +int transfer_json_block_data(char v_wiring_type[], json_block_data* data);//lnk2024-8-16添加参数 #endif /* __cplusplus */ @@ -80,8 +80,8 @@ extern "C" { int transfer_json_qvvr_data(unsigned int func_type,int monitor_id,double mag,double dur,long long start_tm,long long end_tm,int dis_kind, char* uuid_cfg, char* uuid_dat, char* mp_id, char* Qvvr_rptname, char* devtype); void processGGIO_start_data_end(char* mp_id, char* fullname, double v,long long time,char* devtype,int monitor_id); -void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* TMNL_FACTORY, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second);//zw޸ ú -void Set_xml_nodeinfo();//zw޸ +void Set_xml_databaseinfo(char* MODEL_ID, char* TMNL_TYPE, char* TMNL_FACTORY, char* FILE_NAME, int year, int month, int day, int hour, int minute, int second);//zw修改 新增调用函数 +void Set_xml_nodeinfo();//zw修改 char* Get_xmlpath(char* devtype); char* Get_IED(char* devtype); char* Get_LDevice(char* devtype); diff --git a/json/save2json.cpp b/json/save2json.cpp index befb130..5680f95 100644 --- a/json/save2json.cpp +++ b/json/save2json.cpp @@ -24,19 +24,21 @@ using namespace std; #include #include #include -#include //CZY 2023-08-17 WW 202331317:21:02 ӶICD֧ +#include //CZY 2023-08-17 WW 2023年3月13日17:21:02 增加多ICD支持 #include #include +#include "../log4cplus/log4.h"//lnk添加log4 + #include "../mms/db_interface.h" #include "../json/save2json.h" #include "../json/mms_json_inter.h" #include "kafka_producer.h" -#include "../include/rocketmq/CPushConsumer.h" +#include "../rocketmq/CPushConsumer.h" #include -#include "../json/cjson.h" //json -#include //xml -#include //xml +#include "../json/cjson.h" //解json +#include //创建xml +#include //创建xml bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int limit,std::string type); extern int recall_json_handle(const char* jstr); extern std::string intToString(int number); @@ -46,6 +48,10 @@ extern pthread_mutex_t mtx;//lnk20250115 #ifdef __cplusplus extern "C" { + +//解决编译lnk20250509 +#define thisFileName __FILE__ + #include "../mms/rdb_client.h" #include "node.h"//lnk20241223 #include "mvl_defs.h" @@ -74,16 +80,16 @@ extern QMutex oss_data_list_mutex; extern QList oss_data_list; extern int FILE_FLAG; KafkaSendThread myThrd; -//WW 2023-08-22 ݿ̺߳WebSokcet߳ -WebSocketThread socketThrd; //Web Socket߳ +//WW 2023-08-22 增加数据库线程和WebSokcet线程 +WebSocketThread socketThrd; //Web Socket线程类对象 -WebhttpThread webhttpThrd; //Web http߳ lnk202411 -httpThread httpThrd; //Web http߳ lnk202411 -mqconsumerThread mqconsumerThrd;//mq߳lnk20241213 +WebhttpThread webhttpThrd; //Web http线程类对象 lnk202411 +httpThread httpThrd; //Web http线程类对象 lnk202411 +mqconsumerThread mqconsumerThrd;//mq消费者线程lnk20241213 -OnTimerThread onTimerThrd;//ʱ߳ +OnTimerThread onTimerThrd;//定时线程 -extern int g_iSqlListSize; //SqlִԪظ עSqlԪس˸ԪƳ +extern int g_iSqlListSize; //Sql执行语句链表允许最大元素个数 注:Sql链表中元素超过此个数,多出元素需移除! extern int FILE_FLAG; extern int SEND_FLAG; extern char* BROKER_LIST; @@ -95,10 +101,10 @@ extern char* TOPIC_ALARM; extern char* TOPIC_SNG; extern char* TOPIC_RTDATA;//lnk20241220 extern char* UDS_UPLOAD_URL; -extern char g_onlyIP[255]; //ֱijIPΪ +extern char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 //WW 2023-08-22 end -//lnk20241216mq +//lnk20241216添加mq消费者 extern std::string G_MQCONSUMER_IPPORT;//rocketmq ip+port extern std::string G_MQCONSUMER_TOPIC_RT;//topie_realtimedata extern std::string G_MQCONSUMER_TAG_RT;//tag @@ -129,39 +135,52 @@ bool showinshellflag =false; const int MAX_LIST_SIZE = 16; static QMap > real_data_report_map; -static QMap json_data_map;//CZY 2023-08-17 ww 202331317:23:17չMapڱ· -static QMap json_flicker_data_map;//CZY 2023-09-11 չMapڱ· -static QMap json_pst_data_map;//CZY 2023-09-11 չMapڱ· +static QMap json_data_map;//CZY 2023-08-17 ww 2023年3月13日17:23:17扩展Map,用于保存各条线路的数据 +static QMap json_flicker_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据 +static QMap json_pst_data_map;//CZY 2023-09-11 展Map,用于保存各条线路的闪变数据 + +bool is_blank(const std::string& str) +{ + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + { + if (!std::isspace(*it)) { + return false; + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////// int urcbRealDataHasReceived(int dev_index, LD_info_t* LD_info, long long Time) { QList& ts_list = real_data_report_map[LD_info->line_id]; - bool bFind = ts_list.contains(Time); //ʵʱʱ + bool bFind = ts_list.contains(Time); //实时数据时间链表 if (bFind == false) { ts_list.append(Time); if (ts_list.size() > MAX_LIST_SIZE) ts_list.removeFirst(); - //lnk20241223ÿյһʵʱݾͼһ + //lnk20241223每收到一次实时数据就检查一下数量 int real_report_count = 0; real_report_count = get_real_report_count(LD_info); - // + //调试 std::cout << "real_report_count is" << real_report_count << std::endl; std::cout << "mp limit is" << LD_info->limit << std::endl; if(real_report_count >= LD_info->limit){ std::cout << "real_report_count reach limit!!!"<< std::endl; - //delete.xml + //生成delete.xml if (!createXmlFile(dev_index, LD_info->line_id, 0, 0, 0,"delete")) { std::cerr << "Failed to create delete XML file!!!." << std::endl; } } - return 0; //ûظ + return 0; //没有重复数据 } else - return 1; //ظ + return 1; //有重复数据 } ////////////////////////////////////////////////////////////////////////// @@ -247,7 +266,7 @@ void add_stat_kafka_json_log(char* log_str) } ////////////////////////////////////////////////////////////////////////// -/*rocketmqlnk10-10*/ +/*新增rocketmq发送数据lnk10-10*/ void my_rocketmq_send(Ckafka_data_t& data) { static std::string topic; @@ -303,7 +322,7 @@ void my_rocketmq_send(Ckafka_data_t& data) } if (g_onlyIP[0] != 0) { - //ģʽ + //单例模式 add_sng_log(data.strText.toAscii().data()); } @@ -450,7 +469,7 @@ void my_datahub_send(Ckafka_data_t& data) } if (g_onlyIP[0] != 0) { - //ģʽ + //单例模式 add_sng_log(data.strText.toAscii().data()); } @@ -466,7 +485,7 @@ void concatenate_and_separate(char str1[], char str2[], QString* result) { void KafkaSendThread::run() { - //߳̿ʼlnk20241211 + //线程开始创建生产者lnk20241211 InitializeProducer(); printf("\nKafkaSendThread::run() is called ...... \n\n"); @@ -486,19 +505,19 @@ void KafkaSendThread::run() static uint32_t count = 0; printf("BEGIN my_kafka_send no.%i -------->>>>>>>>>>>> %s \n", count, 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); } - else if (SEND_FLAG == 2)//datahub + else if (SEND_FLAG == 2)//datahub推送 { my_datahub_send(data); } - else if (SEND_FLAG == 3)//rocketmqlnk10-11 + else if (SEND_FLAG == 3)//rocketmq推送lnk10-11 { my_rocketmq_send(data); } - else //δ Ĭmq + else //未配置 默认mq推送 { my_rocketmq_send(data); } @@ -507,7 +526,7 @@ void KafkaSendThread::run() QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); } - //lnk20250225־ + /*//lnk20250225添加日志上送 Ckafka_data_t log_send; log_send.strTopic = QString::fromStdString(G_LOG_TOPIC); bool log_gotten; @@ -515,68 +534,68 @@ void KafkaSendThread::run() if(!showinshellflag){ if (debugOutputEnabled) { - // normalOutputEnabled warnOutputEnabled Ϊ 0 errorOutputEnabled Ϊ 1ȡ errorList - // errorList + // 如果 normalOutputEnabled 和 warnOutputEnabled 都为 0,且 errorOutputEnabled 为 1,取 errorList 输出 + // 处理 errorList 的输出 pthread_mutex_lock(&debugListMutex); if (!debugList.empty()) { log_gotten = true; - log_send.strText = QString::fromStdString(debugList.front());//ȷlistȷ - // ǷΪַȥհַǷΪգ + log_send.strText = QString::fromStdString(debugList.front());//请确保list正确 + // 检查是否为空字符串(去掉空白字符后是否为空) if (log_send.strText.trimmed().isEmpty()) { - debugList.pop_front(); // ֱӶ־ - log_gotten = false; // ûлȡЧ־ + debugList.pop_front(); // 直接丢弃这条日志 + log_gotten = false; // 标记没有获取到有效日志 } else { - debugList.pop_front(); // ֻзǿհַŻ + debugList.pop_front(); // 只有非空白字符串才会真正返回 } } pthread_mutex_unlock(&debugListMutex); } else if (normalOutputEnabled) { - // normalOutputEnabled Ϊ 1ȴ normalList ȡ - // normalList + // 如果 normalOutputEnabled 为 1,优先从 normalList 获取输出 + // 处理 normalList 的输出 pthread_mutex_lock(&normalListMutex); if (!normalList.empty()) { log_gotten = true; log_send.strText = QString::fromStdString(normalList.front()); - // ǷΪַȥհַǷΪգ + // 检查是否为空字符串(去掉空白字符后是否为空) if (log_send.strText.trimmed().isEmpty()) { - normalList.pop_front(); // ֱӶ־ - log_gotten = false; // ûлȡЧ־ + normalList.pop_front(); // 直接丢弃这条日志 + log_gotten = false; // 标记没有获取到有效日志 } else { - normalList.pop_front(); // ֻзǿհַŻ + normalList.pop_front(); // 只有非空白字符串才会真正返回 } } pthread_mutex_unlock(&normalListMutex); } else if (warnOutputEnabled) { - // normalOutputEnabled Ϊ 0 warnOutputEnabled Ϊ 1ȴ warnList ȡ - // warnList + // 如果 normalOutputEnabled 为 0,且 warnOutputEnabled 为 1,优先从 warnList 获取输出 + // 处理 warnList 的输出 pthread_mutex_lock(&warnListMutex); if (!warnList.empty()) { log_gotten = true; log_send.strText = QString::fromStdString(warnList.front()); - // ǷΪַȥհַǷΪգ + // 检查是否为空字符串(去掉空白字符后是否为空) if (log_send.strText.trimmed().isEmpty()) { - warnList.pop_front(); // ֱӶ־ - log_gotten = false; // ûлȡЧ־ + warnList.pop_front(); // 直接丢弃这条日志 + log_gotten = false; // 标记没有获取到有效日志 } else { - warnList.pop_front(); // ֻзǿհַŻ + warnList.pop_front(); // 只有非空白字符串才会真正返回 } } pthread_mutex_unlock(&warnListMutex); } else if (errorOutputEnabled) { - // normalOutputEnabled warnOutputEnabled Ϊ 0 errorOutputEnabled Ϊ 1ȡ errorList - // errorList + // 如果 normalOutputEnabled 和 warnOutputEnabled 都为 0,且 errorOutputEnabled 为 1,取 errorList 输出 + // 处理 errorList 的输出 pthread_mutex_lock(&errorListMutex); if (!errorList.empty()) { log_gotten = true; log_send.strText = QString::fromStdString(errorList.front()); - // ǷΪַȥհַǷΪգ + // 检查是否为空字符串(去掉空白字符后是否为空) if (log_send.strText.trimmed().isEmpty()) { - errorList.pop_front(); // ֱӶ־ - log_gotten = false; // ûлȡЧ־ + errorList.pop_front(); // 直接丢弃这条日志 + log_gotten = false; // 标记没有获取到有效日志 } else { - errorList.pop_front(); // ֻзǿհַŻ + errorList.pop_front(); // 只有非空白字符串才会真正返回 } } pthread_mutex_unlock(&errorListMutex); @@ -586,28 +605,28 @@ void KafkaSendThread::run() if (log_gotten) { static uint32_t count = 0; my_rocketmq_send(log_send); - } + }*/ - QThread::msleep(1); // CPU תlnk20250326 + QThread::msleep(10); // 避免 CPU 空转lnk20250326 } - //߳̽ݻ + //线程结束摧毁生产者 ShutdownAndDestroyProducer();//lnk20241211 } -//lnk20241213в/////////////////////////////////////////////////////////////////////////////////////////////// -// ȡ 'data' 鲢Ϊµ JSON ַ ( std::string) +//lnk20241213补招部分/////////////////////////////////////////////////////////////////////////////////////////////// +// 提取 'data' 数组并返回为新的 JSON 字符串 (返回 std::string) std::string extractDataJson(const char* inputJson) { - // JSON ַ + // 解析输入 JSON 字符串 cJSON* root = cJSON_Parse(inputJson); if (root == NULL) { std::cerr << "Error parsing JSON" << std::endl; return ""; } - // ȡ "messageBody" + // 提取 "messageBody" 部分 cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody"); if (messageJson == NULL || messageJson->type != cJSON_String) { std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl; @@ -615,7 +634,7 @@ std::string extractDataJson(const char* inputJson) { return ""; } - // messageBody е JSON ַ + // 解析 messageBody 中的 JSON 字符串 const char* messageBodyStr = messageJson->valuestring; if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) { std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl; @@ -623,14 +642,24 @@ std::string extractDataJson(const char* inputJson) { return ""; } - cJSON* messageBody = cJSON_Parse(messageBodyStr); // messageBody ַ + cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串 if (messageBody == NULL) { std::cerr << "Failed to parse 'messageBody' JSON." << std::endl; cJSON_Delete(root); return ""; } - // ȡ "data" + /*//添加guid + // 提取 "guid" 部分 + cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid"); + if (guidstr == NULL || data->type != cJSON_String) { + std::cerr << "'guid' is missing or is not an array" << std::endl; + cJSON_Delete(root); + return ""; + } + //guid回复*/ + + // 提取 "data" 部分 cJSON* data = cJSON_GetObjectItem(messageBody, "data"); if (data == NULL || data->type != cJSON_Array) { std::cerr << "'data' is missing or is not an array" << std::endl; @@ -638,16 +667,16 @@ std::string extractDataJson(const char* inputJson) { return ""; } - // µ JSON ֻ "data" - cJSON* newJson = cJSON_CreateArray(); // һµ + // 创建新的 JSON 数组对象,只包含 "data" 部分 + cJSON* newJson = cJSON_CreateArray(); // 创建一个新的数组 - // "data" еԪӵ + // 将 "data" 数组中的元素逐个添加到新数组中 cJSON* dataItem = NULL; cJSON_ArrayForEach(dataItem, data) { cJSON_AddItemToArray(newJson, cJSON_Duplicate(dataItem, 1)); } - // µ JSON תΪַ + // 将新的 JSON 数组转换为字符串 char* newJsonString = cJSON_Print(newJson); if (newJsonString == NULL) { std::cerr << "Error printing new JSON" << std::endl; @@ -656,28 +685,28 @@ std::string extractDataJson(const char* inputJson) { return ""; } - // תΪ std::string + // 转换为 std::string 类型 std::string result(newJsonString); - // ڴ + // 清理内存 free(newJsonString); cJSON_Delete(root); cJSON_Delete(newJson); - return result; // std::string ͵Ľ + return result; // 返回 std::string 类型的结果 } -//ʵʱݲ////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ȡ JSON Ϣеֶ +//实时数据部分////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 提取 JSON 消息中的相关字段 bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::string& line, bool& realData, bool& soeData, int& limit) { - // JSON + // 解析 JSON 数据 cJSON* root = cJSON_Parse(body.c_str()); if (root == NULL) { std::cerr << "Failed to parse JSON message." << std::endl; return false; } - // ȡ "messageBody" + // 提取 "messageBody" 部分 cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody"); if (messageJson == NULL || messageJson->type != cJSON_String) { std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl; @@ -685,7 +714,7 @@ bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::st return false; } - // messageBody е JSON ַ + // 解析 messageBody 中的 JSON 字符串 const char* messageBodyStr = messageJson->valuestring; if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) { std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl; @@ -693,37 +722,45 @@ bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::st return false; } - cJSON* messageBody = cJSON_Parse(messageBodyStr); // messageBody ַ + cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串 if (messageBody == NULL) { std::cerr << "Failed to parse 'messageBody' JSON." << std::endl; cJSON_Delete(root); return false; } - // ȡֶ + // 提取字段 cJSON* devSeriesItem = cJSON_GetObjectItem(messageBody, "devSeries"); cJSON* lineItem = cJSON_GetObjectItem(messageBody, "line"); cJSON* realDataItem = cJSON_GetObjectItem(messageBody, "realData"); cJSON* soeDataItem = cJSON_GetObjectItem(messageBody, "soeData"); cJSON* limitItem = cJSON_GetObjectItem(messageBody, "limit"); + //添加guid + //cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid"); + //if(guidstr)std::string guid = guidstr->valuestring; + if (devSeriesItem && lineItem && realDataItem && soeDataItem && limitItem) { devSeries = devSeriesItem->valuestring; line = lineItem->valuestring; realData = realDataItem->valueint; soeData = soeDataItem->valueint; limit = limitItem->valueint; + + //回复消息 + //guid + } else { std::cerr << "Missing expected fields in JSON message." << std::endl; cJSON_Delete(root); return false; } - cJSON_Delete(root); // JSON + cJSON_Delete(root); // 清理 JSON 对象 return true; } -// XML ݵĺ½ɾ +// 构造 XML 内容的函数新建和删除 std::string createnewXmlContent(int devindex, int mpindex, bool realData, bool soeData, int limit) { std::ostringstream xmlContent; @@ -758,13 +795,13 @@ std::string createdeleteXmlContent(int devindex, int mpindex) return xmlContent.str(); } -// д XML ݵļĺ +// 写入 XML 内容到文件的函数 bool writeToFile(const std::string& filePath, const std::string& xmlContent) { - // ļд XML - std::ofstream outFile(filePath.c_str()); // ʹ c_str() תΪ const char* + // 打开文件流以写入 XML 内容 + std::ofstream outFile(filePath.c_str()); // 使用 c_str() 转换为 const char* if (outFile.is_open()) { - outFile << xmlContent; // д + outFile << xmlContent; // 写入内容 outFile.close(); std::cout << "XML file created at: " << filePath << std::endl; return true; @@ -774,7 +811,7 @@ bool writeToFile(const std::string& filePath, const std::string& xmlContent) } } -// дµ XML ļ +// 创建并写入新的 XML 文件的主函数 bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int limit,std::string type) { std::string xmlContent = ""; @@ -782,18 +819,18 @@ bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int l std::string filePath = ""; if(type == "new"){ - // XML + // 构造 XML 内容 xmlContent = createnewXmlContent(devindex, mpindex, realData, soeData, limit); - // ļ· + // 设置文件路径 directory = "../etc/trigger3s/"; filePath = directory + "newtrigger.xml"; } else if(type == "delete"){ - // XML + // 构造 XML 内容 xmlContent = createdeleteXmlContent(devindex, mpindex); - // ļ· + // 设置文件路径 directory = "../etc/trigger3s/"; filePath = directory + "deletetrigger.xml"; } @@ -803,63 +840,63 @@ bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int l } - // Ŀ¼ڣ + // 创建目录(如果不存在) if (system(("mkdir -p " + directory).c_str()) != 0) { std::cerr << "Failed to create directory: " << directory << std::endl; return false; } - // XML дļ + // 将 XML 内容写入文件 return writeToFile(filePath, xmlContent); } //////////////////////////////////////////////////////////////////////////////////////////////////////////// -//lnk20250108̸² +//lnk20250108进程更新部分 -// ڹرս̼Ķ˿ -extern int server_socket; //Web Socketʵ +// 用于关闭进程监听的端口 +extern int server_socket; //Web Socket服务端实例 void close_listening_socket() { if (server_socket != -1) { - // رsocket + // 关闭socket close(server_socket); std::cout << "Server socket closed successfully!" << std::endl; - server_socket = -1; // server_socket + server_socket = -1; // 重置 server_socket } else { std::cout << "No server socket to close!" << std::endl; } } -//Уipʽ +//用于校验ip格式 bool isValidIP(const std::string &ip) { std::vector parts; std::stringstream ss(ip); std::string part; - // ʹ "." Ϊָ IP ַָɸ + // 使用 "." 作为分隔符将 IP 地址分割成各部分 while (getline(ss, part, '.')) { parts.push_back(part); } - // IP ַ 4 + // IP 地址必须有 4 部分 if (parts.size() != 4) { return false; } - // УÿһǷΪϷ 0 255 ֮ + // 校验每一部分是否为合法的数字且在 0 到 255 之间 for (size_t i = 0; i < parts.size(); ++i) { - // УÿǷΪ + // 校验每部分是否为数字 for (size_t j = 0; j < parts[i].size(); ++j) { if (!isdigit(parts[i][j])) { return false; } } - // תΪǷЧΧ + // 转换为整数并检查是否在有效范围内 int num = atoi(parts[i].c_str()); if (num < 0 || num > 255) { return false; } - // Ƿǰ㣨 01001 ȣ + // 检查是否有前导零(如 01、001 等) if (parts[i].length() > 1 && parts[i][0] == '0') { return false; } @@ -868,60 +905,60 @@ bool isValidIP(const std::string &ip) { return true; } -//ִнűƽ +//执行脚本控制进程 void execute_bash(string fun,int process_num,string type) { - // Ϊ char 㹻Ŀռ + // 为 char 数组分配足够的空间 char p_num_str[20]; - // ʹ sprintf ת + // 使用 sprintf 转换 std::sprintf(p_num_str, "%d", process_num); - const char* script = "/FeProject/bin/set_process.sh";//ʹsetsidֹ˿ռ + const char* script = "/FeProject/bin/set_process.sh";//使用setsid防止端口占用 const char* param1 = fun.c_str(); const char* param2 = p_num_str; const char* param3 = type.c_str(); - // + // 构造完整的命令 char command[256]; snprintf(command, sizeof(command), "%s %s %s %s &", script, param1, param2, param3); std::cout << "command:" << command <type != cJSON_String) { std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl; @@ -929,7 +966,7 @@ void parse_set(const std::string& json_str) { return ; } - // messageBody е JSON ַ + // 解析 messageBody 中的 JSON 字符串 const char* messageBodyStr = messageJson->valuestring; if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) { std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl; @@ -937,14 +974,25 @@ void parse_set(const std::string& json_str) { return; } - cJSON* messageBody = cJSON_Parse(messageBodyStr); // messageBody ַ + cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串 if (messageBody == NULL) { std::cerr << "Failed to parse 'messageBody' JSON." << std::endl; cJSON_Delete(root); return ; } - // ȡ code ֶ + // 获取 guid 字段 + cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid"); + if (guidstr == nullptr) { + std::cout << "Missing 'guid' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + // 根据 guid 字段回复消息 + std::string guid = guidstr->valuestring; + + // 获取 code 字段 cJSON* code = cJSON_GetObjectItem(messageBody, "code"); if (code == nullptr) { std::cout << "Missing 'code' in JSON." << std::endl; @@ -952,104 +1000,131 @@ void parse_set(const std::string& json_str) { return; } - cJSON* index = cJSON_GetObjectItem(messageBody, "index"); - if (index == nullptr) { - std::cout << "Missing 'index' in JSON." << std::endl; + // 根据 code 字段值执行不同的解析逻辑 + std::string code_str = code->valuestring; + + cJSON* processNo = cJSON_GetObjectItem(messageBody, "processNo"); + if (processNo == nullptr) { + std::cout << "Missing 'processNo' in JSON." << std::endl; cJSON_Delete(root); return; } - //жDzԼ̺ţ - int index_value = index->valueint; - //string index_value_str = index->valuestring; - //int index_value = StringToInt(index_value_str); + //判断是不是自己进程号: + int index_value = processNo->valueint; - //̺Ϊ0Ľ̴пϢ + cJSON* funtion = cJSON_GetObjectItem(messageBody, "fun"); + if (funtion == nullptr) { + std::cout << "Missing 'fun' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string fun = funtion->valuestring; + + cJSON* front = cJSON_GetObjectItem(messageBody, "frontType"); + if (front == nullptr) { + std::cout << "Missing 'frontType' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string frontType = front->valuestring; + + //进程号为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; cJSON_Delete(root); return; } - //̺Ϊ0߽̺ƥ + //进程号为0或者进程号匹配上 std::cout << "msg index:"<< index_value <<" self index:" << g_front_seg_index << std::endl; - // code ִֵֶвͬĽ߼ - std::string code_str = code->valuestring; if (code_str == "set_process") { - if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){ - std::cout << "cfg_stat_data process" << g_front_seg_index <<" handle this msg" << std::endl; - // set_process - cJSON* data = cJSON_GetObjectItem(messageBody, "data"); - if (data != nullptr && data->type == cJSON_Array) { - int data_size = cJSON_GetArraySize(data); - for (int i = 0; i < data_size; i++) { - cJSON* item = cJSON_GetArrayItem(data, i); + cJSON* num = cJSON_GetObjectItem(messageBody, "processNum"); + if (num == nullptr) { + std::cout << "Missing 'processNum' in JSON." << std::endl; + cJSON_Delete(root); + return; + } - std::string fun = cJSON_GetObjectItem(item, "fun")->valuestring; - int processNum = cJSON_GetObjectItem(item, "processNum")->valueint; - std::string frontType = cJSON_GetObjectItem(item, "frontType")->valuestring; + int processNum = num->valueint; + + //校验数据 + if((fun == "reset" || fun == "add") && + (processNum >=1 && processNum < 10) && + (frontType == "stat" || frontType == "recall" || frontType == "all")){ + + if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){ + + // 调用执行脚本函数 + if(fun == "reset"){ + close_listening_socket(); + } + execute_bash(fun, processNum, frontType); + + //脚本在3秒后执行 + //回复消息 + + //上送日志 - //У - if((fun == "reset" || fun == "add") && - (processNum >=1 && processNum < 10) && - (frontType == "stat" || frontType == "recall" || frontType == "all")){ - // ִнű - if(fun == "reset"){ - close_listening_socket(); - } - execute_bash(fun, processNum, frontType); - std::cout << "!!!!!!!!!!!!!!!! execute mark:" << i << " !!!!!!!!!!!!!!!" <type == cJSON_Array) { - int data_size = cJSON_GetArraySize(data); - for (int i = 0; i < data_size; i++) { - cJSON* item = cJSON_GetArrayItem(data, i); - std::string fun = cJSON_GetObjectItem(item, "fun")->valuestring?cJSON_GetObjectItem(item, "fun")->valuestring:"NULL"; - std::string ip = cJSON_GetObjectItem(item, "ip")->valuestring?cJSON_GetObjectItem(item, "ip")->valuestring:"NULL"; - std::string frontType = cJSON_GetObjectItem(item, "frontType")->valuestring?cJSON_GetObjectItem(item, "frontType")->valuestring:"NULL"; - cJSON *index_item = cJSON_GetObjectItem(item, "proindex"); - int proindex = 0; // Ĭֵ - if (index_item != NULL && index_item->type == cJSON_Number) { - proindex = index_item->valueint; - } + cJSON* onlyip = cJSON_GetObjectItem(messageBody, "ip"); + if (onlyip == nullptr) { + std::cout << "Missing 'ip' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string ip = onlyip->valuestring; - std::cout << "proindex is :" << proindex <valueint; - //У - if((fun == "start" || fun == "delete") && - isValidIP(ip) && - (frontType == "stat" || frontType == "recall" || frontType == "3s" || frontType == "comtrade") && - (proindex >= 10 && proindex < 100)){ //õĽ̺Ӧô10С100 - execute_bash_debug(fun, ip, frontType,proindex); - std::cout << "!!!!!!!!!!!!!!!! execute mark:" << i << " !!!!!!!!!!!!!!!" <= 10 && proindex < 100)){ //单连测试用的进程号应该大于10小于100 + execute_bash_debug(fun, ip, frontType,proindex); + } + else{ + std::cout << "param is not executable" <" << std::endl; indentLevel++; + // 添加 guid 节点 + add_indent(xmlStream, indentLevel); + xmlStream << "" << guid << "" << std::endl; + if (code_str == "ledger_modify" || code_str == "add_terminal") { - // modify + // 如果是 modify 类型 if (code_str == "ledger_modify") { add_indent(xmlStream, indentLevel); xmlStream << "" << std::endl; @@ -1099,7 +1178,7 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat indentLevel++; } - // ݲ + // 添加数据部分 add_indent(xmlStream, indentLevel); xmlStream << "" << std::endl; indentLevel++; @@ -1147,7 +1226,7 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat add_indent(xmlStream, indentLevel); xmlStream << "" << json_data.dev_key << "" << std::endl; - // monitorData + // monitorData 部分 for (int i = 0; json_data.line[i].monitor_id[0] != '\0'; i++) { const monitor& monitor = json_data.line[i]; @@ -1188,7 +1267,7 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat add_indent(xmlStream, indentLevel); xmlStream << "" << std::endl; - // modify add ǩ + // 结束 modify 或 add 标签 if (code_str == "ledger_modify") { indentLevel--; add_indent(xmlStream, indentLevel); @@ -1203,7 +1282,7 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat } } else if (code_str == "delete_terminal") { - // delete + // 如果是 delete 类型 add_indent(xmlStream, indentLevel); xmlStream << "" << std::endl; indentLevel++; @@ -1228,38 +1307,38 @@ std::string prepare_update(const std::string& code_str, const terminal& json_dat return ""; } - // ڵ + // 结束根节点 indentLevel--; add_indent(xmlStream, indentLevel); xmlStream << "" << std::endl; - return xmlStream.str(); // ع XML ַ + return xmlStream.str(); // 返回构造的 XML 字符串 } -// stringַתΪ +// 函数:将string字符串转换为整数 int StringToInt(const std::string& str) { std::stringstream ss(str); int number; - ss >> number; // ַжȡ + ss >> number; // 从字符串流中读取整数 - // Ƿתɹ + // 检查是否转换成功 if (ss.fail()) { std::cerr << "Conversion failed!" << std::endl; - return 0; // ѡ񷵻һʶʧֵܵ-1 + return 0; // 或者你可以选择返回一个标识失败的值,如-1 } return number; } -// JSON ִַӦ +// 解析 JSON 字符串并执行相应操作 void parse_log(const std::string& json_str) { - // JSON ַ + // 解析 JSON 字符串 cJSON* root = cJSON_Parse(json_str.c_str()); if (root == nullptr) { std::cout << "Error parsing JSON." << std::endl; return; } - // ȡ "messageBody" + // 提取 "messageBody" 部分 cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody"); if (messageJson == NULL || messageJson->type != cJSON_String) { std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl; @@ -1267,7 +1346,7 @@ void parse_log(const std::string& json_str) { return ; } - // messageBody е JSON ַ + // 解析 messageBody 中的 JSON 字符串 const char* messageBodyStr = messageJson->valuestring; if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) { std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl; @@ -1275,14 +1354,25 @@ void parse_log(const std::string& json_str) { return; } - cJSON* messageBody = cJSON_Parse(messageBodyStr); // messageBody ַ + cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串 if (messageBody == NULL) { std::cerr << "Failed to parse 'messageBody' JSON." << std::endl; cJSON_Delete(root); return ; } - // ȡ code ֶ + // 获取 guid 字段 + cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid"); + if (guidstr == nullptr) { + std::cout << "Missing 'guid' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + // 根据 guid 字段回复消息 + std::string guid = guidstr->valuestring; + + // 获取 code 字段 cJSON* code = cJSON_GetObjectItem(messageBody, "code"); if (code == nullptr) { std::cout << "Missing 'code' in JSON." << std::endl; @@ -1290,103 +1380,120 @@ void parse_log(const std::string& json_str) { return; } - cJSON* index = cJSON_GetObjectItem(messageBody, "index"); - if (index == nullptr) { - std::cout << "Missing 'index' in JSON." << std::endl; + // 根据 code 字段值执行不同的解析逻辑 + std::string code_str = code->valuestring; + + //获取进程号 + cJSON* process = cJSON_GetObjectItem(messageBody, "processNo"); + if (process == nullptr) { + std::cout << "Missing 'processNo' in JSON." << std::endl; cJSON_Delete(root); return; } - //жDzԼ̺ţ - int index_value = index->valueint; - //string index_value_str = index->valuestring; - //int index_value = StringToInt(index_value_str); + //判断是不是自己进程号: + int processNo = process->valueint; + // 获取 id 字段 + cJSON* idstr = cJSON_GetObjectItem(messageBody, "id"); + if (idstr == nullptr) { + std::cout << "Missing 'id' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string id = idstr->valuestring; - //̺Ϊ0Ľ̴̨˸Ϣ - if (index_value != g_front_seg_index) { - std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl; + // 获取 level 字段 + cJSON* levelstr = cJSON_GetObjectItem(messageBody, "level"); + if (levelstr == nullptr) { + std::cout << "Missing 'level' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string level = levelstr->valuestring; + + // 获取 grade 字段 + cJSON* gradestr = cJSON_GetObjectItem(messageBody, "grade"); + if (gradestr == nullptr) { + std::cout << "Missing 'grade' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string grade = gradestr->valuestring; + + // 获取 logtype 字段 + cJSON* logtypestr = cJSON_GetObjectItem(messageBody, "logtype"); + if (logtypestr == nullptr) { + std::cout << "Missing 'logtype' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string logtype = logtypestr->valuestring; + + // 获取 frontType 字段 + cJSON* frontTypestr = cJSON_GetObjectItem(messageBody, "frontType"); + if (frontTypestr == nullptr) { + std::cout << "Missing 'frontType' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + std::string frontType = frontTypestr->valuestring; + + //进程号为0的进程处理所有台账更新消息 + if (processNo != g_front_seg_index) { + std::cout << "msg index:"<< processNo <<"doesnt match self index:" << g_front_seg_index << std::endl; cJSON_Delete(root); return; } - //̺ƥ - std::cout << "msg index:"<< index_value <<" self index:" << g_front_seg_index << std::endl; - - // code ִֵֶвͬĽ߼ - std::string code_str = code->valuestring; - - if (code_str == "set_log") { - - // set_process - cJSON* data = cJSON_GetObjectItem(messageBody, "data"); - if (data != nullptr && data->type == cJSON_Array) { - int data_size = cJSON_GetArraySize(data); - for (int i = 0; i < data_size; i++) { - cJSON* item = cJSON_GetArrayItem(data, i); - std::string fun = cJSON_GetObjectItem(item, "fun")->valuestring; - std::string level = cJSON_GetObjectItem(item, "level")->valuestring; - std::string frontType = cJSON_GetObjectItem(item, "frontType")->valuestring; - //У - if(frontType == subdir){ - if(fun == "open"){ - if (level == "ERROR"){ - // ô - redirectErrorOutput(true); - } - else if (level == "WARN"){ - // ø澯 - redirectWarnOutput(true); - redirectErrorOutput(true); - } - else if (level == "NORMAL"){ - // ͨ - redirectNormalOutput(true); - redirectErrorOutput(true); - redirectWarnOutput(true); - } - else if (level == "DEBUG"){ - // debug (ֻ浽 debugListʾն) - redirectDebugOutput(true); - redirectErrorOutput(true); - redirectWarnOutput(true); - redirectNormalOutput(true); - } - else{ - std::cout << "level error" <type != cJSON_String) { std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl; @@ -1394,7 +1501,7 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { return ; } - // messageBody е JSON ַ + // 解析 messageBody 中的 JSON 字符串 const char* messageBodyStr = messageJson->valuestring; if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) { std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl; @@ -1402,14 +1509,14 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { return; } - cJSON* messageBody = cJSON_Parse(messageBodyStr); // messageBody ַ + cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串 if (messageBody == NULL) { std::cerr << "Failed to parse 'messageBody' JSON." << std::endl; cJSON_Delete(root); return ; } - // ȡ code ֶ + // 获取 code 字段 cJSON* code = cJSON_GetObjectItem(messageBody, "code"); if (code == nullptr) { std::cout << "Missing 'code' in JSON." << std::endl; @@ -1417,34 +1524,49 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { return; } - cJSON* index = cJSON_GetObjectItem(messageBody, "index"); - if (index == nullptr) { - std::cout << "Missing 'index' in JSON." << std::endl; - cJSON_Delete(root); - return; - } + // 根据 code 字段值执行不同的解析逻辑 + std::string code_str = code->valuestring; - //жDzԼ̺ţ - int index_value = index->valueint; + //获取进程号 + cJSON* process = cJSON_GetObjectItem(messageBody, "processNo"); + if (process == nullptr) { + std::cout << "Missing 'processNo' in JSON." << std::endl; + cJSON_Delete(root); + return; + } - //̺Ϊ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; + //判断是不是自己进程号: + int process_No = process->valueint; + + // 获取 guid 字段 + cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid"); + if (guidstr == nullptr) { + std::cout << "Missing 'guid' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + // 根据 guid 字段回复消息 + std::string guid = guidstr->valuestring; + + //进程号为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; cJSON_Delete(root); return; } - //̺Ϊ0߽̺ƥ - std::cout << "msg index:"<< index_value <<" self index:" << g_front_seg_index << std::endl; + //进程号为0或者进程号匹配上 + std::cout << "msg index:"<< process_No <<" self index:" << g_front_seg_index << std::endl; - // code ִֵֶвͬĽ߼ - std::string code_str = code->valuestring; + //匹配后响应收到台账更新消息 + //guid if (code_str == "add_terminal" || code_str == "ledger_modify") { - std::cout << "add or update ledger" <type == cJSON_Array) { int data_size = cJSON_GetArraySize(data); @@ -1452,7 +1574,7 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { cJSON* item = cJSON_GetArrayItem(data, i); terminal json_data; - // terminal_dev + // 填充 terminal_dev 的数据 cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id if (id && id->type == cJSON_String) std::strncpy(json_data.terminal_id, id->valuestring, sizeof(json_data.terminal_id) - 1); @@ -1513,8 +1635,8 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { else std::strncpy(json_data.dev_series, "N/A", sizeof(json_data.dev_series) - 1); - //lnk20250210̨˽̺ - cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNoתΪַ + //lnk20250210台账进程号 + cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNo转为字符串 if (processNo && processNo->type == cJSON_Number) snprintf(json_data.processNo, sizeof(json_data.processNo), "%d", processNo->valueint); else strncpy(json_data.processNo, "N/A", sizeof(json_data.processNo) - 1); @@ -1536,12 +1658,12 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { else std::strncpy(json_data.timestamp, "N/A", sizeof(json_data.timestamp) - 1); - // monitorData 䵽 line + // monitorData 解析,填充到 line 数组中 cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData"); if (monitorData != nullptr && monitorData->type == cJSON_Array) { int monitorData_size = cJSON_GetArraySize(monitorData); - for (int j = 0; j < monitorData_size && j < 10; j++) { // 10 + for (int j = 0; j < monitorData_size && j < 10; j++) { // 最多 10 个监测点 cJSON* monitor_item = cJSON_GetArrayItem(monitorData, j); monitor monitor_data; @@ -1585,7 +1707,7 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { std::strncpy(monitor_data.timestamp, json_data.timestamp, sizeof(monitor_data.timestamp) - 1); std::strncpy(monitor_data.terminal_code, json_data.terminal_code, sizeof(monitor_data.terminal_code) - 1); - // 䵽 line + // 填充到 line 数组 json_data.line[j] = monitor_data; } @@ -1593,14 +1715,14 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { print_terminal(&json_data); - // ׼ XML ݲдļ - std::string xmlContent = prepare_update(code_str, json_data); + // 准备 XML 内容并写入文件 + std::string xmlContent = prepare_update(code_str, json_data,guid);//添加guid20250506 if (xmlContent != "") { std::cout << "write to xml in /FeProject/etc/ledger_update" <type == cJSON_Array) { int data_size = cJSON_GetArraySize(data); for (int i = 0; i < data_size; i++) { cJSON* item = cJSON_GetArrayItem(data, i); - // ֻ id ֶ + // 只解析 id 字段 cJSON* id = cJSON_GetObjectItem(item, "id"); if (id != nullptr) { terminal json_data; std::strncpy(json_data.terminal_id, cJSON_GetObjectItem(item, "id")->valuestring, sizeof(json_data.terminal_id) - 1); - // ׼ XML ݲдļ - std::string xmlContent = prepare_update(code_str, json_data); + // 准备 XML 内容并写入文件 + std::string xmlContent = prepare_update(code_str, json_data,guid);//添加guid20250506 if(xmlContent != ""){ char nodeid[20]; - std::sprintf(nodeid, "%u", g_node_id); // "%u" unsigned int + std::sprintf(nodeid, "%u", g_node_id); // "%u" 用于 unsigned int std::string nodeid_str(nodeid); std::string frontindex_str = intToString(g_front_seg_index); std::string file_name = output_dir + "/" + nodeid_str + "_" + frontindex_str + "_" + json_data.terminal_id + "_delete_terminal.xml"; - writeToFile(file_name, xmlContent); + writeToFile(file_name, xmlContent); //写文件加上guid,读文件 } } } @@ -1647,7 +1769,7 @@ void parse_control(const std::string& json_str, const std::string& output_dir) { std::cout << "code_str error" < subscriptions; - // ʼ1 //lnk20241230ֻʵʱ̻ᶩʵʱtopicʵʱtopicĽ޷ʵʱ + // 初始化消费者1 //lnk20241230只有实时进程会订阅实时topic,不订阅实时topic的进程无法触发实时数据 if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID){ subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RT, G_MQCONSUMER_TAG_RT, myMessageCallbackrtdata)); } - // ʼ2 //н̶ᶩ̨˸topic̵̨ͬܽ˲ܻӰ + // 初始化消费者2 //所有进程都会订阅台账更新topic,不同功能进程的台账不能互相影响 subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_UD, G_MQCONSUMER_TAG_UD, myMessageCallbackupdate)); - // ʼ3 //lnk20241230ֻвн̻ᶩIJtopicIJtopicĽ޷ + // 初始化消费者3 //lnk20241230只有补招进程会订阅补招topic,不订阅补招topic的进程无法触发补招数据 if(g_node_id == RECALL_HIS_DATA_BASE_NODE_ID){ subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RC, G_MQCONSUMER_TAG_RC, myMessageCallbackrecall)); } - // ʼ4 //lnk20250108ֻ̬1ᶩĿtopicĿtopicĽ޷ + // 初始化消费者4 //lnk20250108只有稳态进程1会订阅控制topic,不订阅控制topic的进程无法触发进程重置 if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){ subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_SET, G_MQCONSUMER_TAG_SET, myMessageCallbackset)); } - // ʼ5 //н̶ᶩ־topic̵ͬܽ־ͲܻӰ + // 初始化消费者5 //所有进程都会订阅日志上送topic,不同功能进程的日志上送不能互相影响 subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_LOG, G_MQCONSUMER_TAG_LOG, myMessageCallbacklog)); try { @@ -1933,7 +2058,7 @@ void mqconsumerThread::run() std::cerr << "Exception during consumerUD setup: " << e.what() << std::endl; } - // У߻ͨصϢ + // 程序运行中,消费者会通过回调处理消息 std::cout << "Consumer is running. " << std::endl; } @@ -1946,109 +2071,109 @@ double get_voltage_level(char voltage_level_char[]) { switch (n) { - case 1://6V + case 1://交流6V return 0.006; - case 2://12V + case 2://交流12V return 0.012; - case 3://24V + case 3://交流24V return 0.024; - case 4://36V + case 4://交流36V return 0.036; - case 5://48V + case 5://交流48V return 0.048; - case 6://110V + case 6://交流110V return 0.11; - case 7://220V + case 7://交流220V return 0.22; - case 8://380V400V + case 8://交流380V(含400V) return 0.38; - case 9://660V + case 9://交流660V return 0.66; - case 10://1000V1140V + case 10://交流1000V(含1140V) return 1; - case 11://600V + case 11://交流600V return 0.6; - case 12://750V + case 12://交流750V return 0.75; - case 13://1500V + case 13://交流1500V return 1.5; - case 14://2000V + case 14://交流2000V return 2.0; - case 15://2500V + case 15://交流2500V return 2.5; - case 20://3kV + case 20://交流3kV return 3; - case 21://6kV + case 21://交流6kV return 6; - case 22://10kV + case 22://交流10kV return 10; - case 23://15.75kV + case 23://交流15.75kV return 15.75; - case 24://20kV + case 24://交流20kV return 20; - case 25://35kV + case 25://交流35kV return 35; - case 30://66kV + case 30://交流66kV return 66; - case 31://72.5kV + case 31://交流72.5kV return 72.5; - case 32://110kV + case 32://交流110kV return 110; - case 33://220kV + case 33://交流220kV return 220; - case 34://330kV + case 34://交流330kV return 330; - case 35://500kV + case 35://交流500kV return 500; - case 36://750kV + case 36://交流750kV return 750; - case 37://1000kV + case 37://交流1000kV return 1000; - case 51://ֱ6V + case 51://直流6V return 0.006; - case 52://ֱ12V + case 52://直流12V return 0.012; - case 53://ֱ24V + case 53://直流24V return 0.024; - case 54://ֱ36V + case 54://直流36V return 0.036; - case 55://ֱ48V + case 55://直流48V return 0.048; - case 56://ֱ110V + case 56://直流110V return 0.11; - case 60://ֱ220V + case 60://直流220V return 0.22; - case 70://ֱ600V + case 70://直流600V return 0.6; - case 71://ֱ750V + case 71://直流750V return 0.75; - case 72://ֱ1500V + case 72://直流1500V return 1.5; - case 73://ֱ3000V + case 73://直流3000V return 3.0; - case 76://ֱ35kV + case 76://直流35kV return 35; - case 77://ֱ30kV + case 77://直流30kV return 30; - case 78://ֱ50kV + case 78://直流50kV return 50; - case 80://ֱ120kV + case 80://直流120kV return 120; - case 81://ֱ125kV + case 81://直流125kV return 125; - case 82://ֱ400kV + case 82://直流400kV return 400; - case 83://ֱ500kV + case 83://直流500kV return 500; - case 84://ֱ660kV + case 84://直流660kV return 660; - case 85://ֱ800kV + case 85://直流800kV return 800; - case 86://ֱ1000kV + case 86://直流1000kV return 1000; - case 87://ֱ200kV + case 87://直流200kV return 200; - case 88://ֱ320kV + case 88://直流320kV。 return 320; default: return 0; @@ -2085,10 +2210,10 @@ void try_start_mqconsumer_thread() ///////////////////////////////////////////////////////////////////////// json_block_data json_blkd; -//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ -//json_block_data json_blkd; //jsonƴӲ,ԭеһݶڶICD»ݴλ -//ǽݷLDInfoṹд洢֤һ·һjsonƴӲ -void init_json_block_data(char mp_id[], char voltage_level[], int flicker_flag)//WW 202331316:38:41 ICD޸ +//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 +//json_block_data json_blkd; //json拼接参数类对象,原有的一个数据对象,在多ICD下会出现数据错位问题 +//解决方案是将此数据放入LDInfo结构中存储,保证一条线路一个json拼接参数类对象 +void init_json_block_data(char mp_id[], char voltage_level[], int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改 { json_block_data* pdata; @@ -2124,34 +2249,34 @@ void init_json_block_data(char mp_id[], char voltage_level[], int flicker_flag)/ tmp.append(mp_id); pdata->mp_id = tmp; pdata->func_type = g_node_id; - //flag Ʒʣ 쳣1 0 - pdata->flag = 0; // //޳ǣ1޳0޳Ĭ޳ + //flag 是品质, 异常送1, 正常送0 + pdata->flag = 0; // //剔除标记,1不剔除,0剔除,默认剔除 pdata->mms_str_map.clear(); pdata->voltage_level = get_voltage_level(voltage_level); //CZY 2023-08-23 add voltage_level } -int json_block_create_start(char voltage_level[], char monid_char[], int flicker_flag, char temcode[], int line_id)//WW 202331316:38 : 41 ICD޸ +int json_block_create_start(char voltage_level[], char monid_char[], int flicker_flag, char temcode[], int line_id)//WW 2023年3月13日16:38 : 41 多ICD修改 { try_start_kafka_thread(); init_json_block_data(monid_char, voltage_level, flicker_flag); json_block_data* pdata; if (flicker_flag == 1) { - if (!json_flicker_data_map.contains(monid_char))//δ鵽 + if (!json_flicker_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_flicker_data_map.value(monid_char); } else if (flicker_flag == 0) { - if (!json_data_map.contains(monid_char))//δ鵽 + if (!json_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_data_map.value(monid_char); } else if (flicker_flag == 2) { - if (!json_pst_data_map.contains(monid_char))//δ鵽 + if (!json_pst_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_pst_data_map.value(monid_char); } @@ -2178,23 +2303,23 @@ int json_block_create_start(char voltage_level[], char monid_char[], int flicker } -int json_block_create_time(char monid_char[], long long Time, int flicker_flag)//WW 202331316:38:41 ICD޸ +int json_block_create_time(char monid_char[], long long Time, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改 { json_block_data* pdata; if (flicker_flag == 1) { - if (!json_flicker_data_map.contains(monid_char))//δ鵽 + if (!json_flicker_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_flicker_data_map.value(monid_char); } else if (flicker_flag == 0) { - if (!json_data_map.contains(monid_char))//δ鵽 + if (!json_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_data_map.value(monid_char); } else if (flicker_flag == 2) { - if (!json_pst_data_map.contains(monid_char))//δ鵽 + if (!json_pst_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_pst_data_map.value(monid_char); } @@ -2206,23 +2331,23 @@ int json_block_create_time(char monid_char[], long long Time, int flicker_flag)/ } -int json_block_create_flag(char monid_char[], int flag, int flicker_flag)//WW 202331316:38:41 ICD޸ +int json_block_create_flag(char monid_char[], int flag, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改 { json_block_data* pdata; if (flicker_flag == 1) { - if (!json_flicker_data_map.contains(monid_char))//δ鵽 + if (!json_flicker_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_flicker_data_map.value(monid_char); } else if (flicker_flag == 0) { - if (!json_data_map.contains(monid_char))//δ鵽 + if (!json_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_data_map.value(monid_char); } else if (flicker_flag == 2) { - if (!json_pst_data_map.contains(monid_char))//δ鵽 + if (!json_pst_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_pst_data_map.value(monid_char); } @@ -2235,23 +2360,23 @@ int json_block_create_flag(char monid_char[], int flag, int flicker_flag)//WW 20 -int json_block_create_data(char monid_char[], char* mms_str, double v, int flicker_flag)//WW 202331316:38:41 ICD޸ +int json_block_create_data(char monid_char[], char* mms_str, double v, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改 { json_block_data* pdata; if (flicker_flag == 1) { - if (!json_flicker_data_map.contains(monid_char))//δ鵽 + if (!json_flicker_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_flicker_data_map.value(monid_char); } else if (flicker_flag == 0) { - if (!json_data_map.contains(monid_char))//δ鵽 + if (!json_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_data_map.value(monid_char); } else if (flicker_flag == 2) { - if (!json_pst_data_map.contains(monid_char))//δ鵽 + if (!json_pst_data_map.contains(monid_char))//未查到数据 return 0; pdata = json_pst_data_map.value(monid_char); } @@ -2267,12 +2392,12 @@ int json_block_create_data(char monid_char[], char* mms_str, double v, int flick } -//lnk2024-8-16ӽ߲ -int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag)//WW 202331316:38:41 ICD޸ +//lnk2024-8-16添加接线参数 +int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改 { json_block_data* pdata; if (flicker_flag == 1) { - if (!json_flicker_data_map.contains(monid_char))//δ鵽 + if (!json_flicker_data_map.contains(monid_char))//未查到数据 { printf("---------- json_block_create_end: mp_id= %s json_flicker_data_map can't find MonitorId----------\n", monid_char); return 1; @@ -2281,7 +2406,7 @@ int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_f } else if (flicker_flag == 0) { - if (!json_data_map.contains(monid_char))//δ鵽 + if (!json_data_map.contains(monid_char))//未查到数据 { printf("---------- json_block_create_end: mp_id= %s json_data_map can't find MonitorId----------\n", monid_char); return 1; @@ -2290,7 +2415,7 @@ int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_f } else if (flicker_flag == 2) { - if (!json_pst_data_map.contains(monid_char))//δ鵽 + if (!json_pst_data_map.contains(monid_char))//未查到数据 { printf("---------- json_block_create_end: mp_id= %s json_pst_data_map can't find MonitorId----------\n", monid_char); return 1; @@ -2315,7 +2440,7 @@ int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_f printf("---------- json_block_create_end: pdata->mms_str_map.count() == 0 ----------\n"); return 1; } - //lnk2024-8-16ӽ߲ + //lnk2024-8-16添加接线参数 int ret = transfer_json_block_data(v_wiring_type, pdata); if (pdata != NULL) @@ -2419,29 +2544,29 @@ void try_start_http_thread() //lnk20241202 int try_start_mqtest_thread(int argc, char *argv[]) { - //ʹü򵥵ѭ̣߳һappִѭ̣߳ҿ - //װqtӡ + //不使用简单的循环线程,而是启动一个app,不仅执行循环线程,而且可以连接输入 + //安装qt打印 qInstallMsgHandler(myQtMsgHandler); QCoreApplication a(argc, argv); - // QThread Worker + // 创建 QThread 和 Worker 对象 QThread *thread = new QThread(); Worker *worker = new Worker(); - // Worker ƶ QThread + // 将 Worker 对象移动到 QThread 中 worker->moveToThread(thread); - // źźͲ + // 连接信号和槽 QObject::connect(thread, SIGNAL(started()), worker, SLOT(startServer())); QObject::connect(worker, SIGNAL(serverError()), thread, SLOT(quit())); QObject::connect(worker, SIGNAL(serverError()), worker, SLOT(deleteLater())); QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - // ߳ + // 启动线程 thread->start(); - // ȷӦ˳ʱ߳Ҳȷ˳ + // 确保在应用退出时,线程也能正确退出 QObject::connect(&a, SIGNAL(aboutToQuit()), thread, SLOT(quit())); return a.exec(); @@ -2458,10 +2583,10 @@ void try_start_ontimer_thread() //WW 2023-08-22 end /////////////////////////////////////////// -//ZW 2024-01-31 ģʽŻ -static QMap mvl_type_ctrl_map;//ZW 2024-01-31 ڱ浥λȡģ -static int mvl_type_ctrl_map_size;// -//donameӦģ +//ZW 2024-01-31 补招数据模式优化 +static QMap mvl_type_ctrl_map;//ZW 2024-01-31 用于保存单次获取的模型 +static int mvl_type_ctrl_map_size;//计数 +//添加doname对应的数据模型 void add_mvl_type_ctrl(char doname[], int ctrl) { if (!mvl_type_ctrl_map.contains(doname)) @@ -2470,7 +2595,7 @@ void add_mvl_type_ctrl(char doname[], int ctrl) } } -//ɾmapģ +//删除map中所有数据模型 void del_mvl_type_ctrl() { for (QMap::iterator it = mvl_type_ctrl_map.begin(); it != mvl_type_ctrl_map.end(); ++it) { @@ -2485,7 +2610,7 @@ int get_mvl_type_ctrl_map_size() { return mvl_type_ctrl_map.count(); } -//ҶӦdonameģǷmap +//查找对应doname的数据模型是否存在map中 int sel_mvl_type_ctrl_flag(char doname[]) { if (mvl_type_ctrl_map.contains(doname)) diff --git a/json/save2json.h b/json/save2json.h index 542d4f2..303f82e 100644 --- a/json/save2json.h +++ b/json/save2json.h @@ -32,8 +32,8 @@ extern "C" { #include //lnk20250106 -#include "../include/rocketmq/SimpleProducer.h" -//־ +#include "../rocketmq/SimpleProducer.h" +//日志功能 #include "../cfg_parse/custom_printf.h"//lnk20250225 #include #include @@ -63,7 +63,7 @@ class KafkaSendThread : public QThread protected: void run(); }; -//WW 2023-08-22 ݿ̺߳WebSocket߳ +//WW 2023-08-22 增加数据库线程和WebSocket线程 class WebSocketThread : public QThread { @@ -96,21 +96,21 @@ void doMonitorTaskmain(void); } #endif -// ====================== Telnet ====================== -// Telnet ֽ: +// ====================== Telnet 常量定义 ====================== +// Telnet 命令字节: #define IAC 255 // Interpret As Command #define DONT 254 #define TELDO 253 #define WONT 252 #define WILL 251 -// Telnet ѡ: -#define TELOPT_ECHO 1 // +// Telnet 选项常量: +#define TELOPT_ECHO 1 // 回显 #define TELOPT_SUPPRESS_GO_AHEAD 3 // SGA -#define TELOPT_LINEMODE 34 // ģʽ +#define TELOPT_LINEMODE 34 // 行模式 /** - * @brief WorkerࣺTelnet߼ + * @brief Worker类:包含启动服务器、处理Telnet交互等逻辑 */ class Worker : public QObject { @@ -130,7 +130,7 @@ public: } ~Worker() { - // ʱͷ + // 清理定时器和服务器 stopServer(); } @@ -141,19 +141,19 @@ public: public slots: /** - * @brief + * @brief 启动服务器 */ void startServer() { if (server) { qDebug() << "Server is already running!"; - return; // ֹظ + return; // 防止重复启动服务器 } - // QTcpServer ź + // 创建 QTcpServer 并设置信号与槽 server = new QTcpServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); - // Լ˿ + // 尝试监听端口 if (!server->listen(QHostAddress::Any, TEST_PORT)) { std::cout << "Server failed to start!" << std::endl; qDebug() << "Server failed to start!"; @@ -164,15 +164,15 @@ public slots: qDebug() << QString("Server is running on port %1").arg(TEST_PORT); } - // ʱ + // 创建并启动定时器 timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(doPeriodicTask())); - timer->start(60000); // ÿ60봥һ + timer->start(60000); // 每60秒触发一次 - // һں滻̵߳ļ + // 开启另一个周期函数用来替换主线程的监控 QTimer *monitorTimer = new QTimer(this); connect(monitorTimer, SIGNAL(timeout()), this, SLOT(doMonitorTask())); - monitorTimer->start(1000); // ÿ1봥һ + monitorTimer->start(1000); // 每1秒触发一次 std::cout << "Timer started, event loop running in thread: " << QThread::currentThreadId() << std::endl; @@ -180,10 +180,10 @@ public slots: } /** - * @brief ֹͣ + * @brief 停止服务器 */ void stopServer() { - // ֹͣԴ + // 停止服务器并清理资源 if (server) { server->close(); delete server; @@ -191,7 +191,7 @@ public slots: qDebug() << "Server stopped."; } - // ֹͣʱ + // 停止定时器 if (timer) { timer->stop(); delete timer; @@ -201,7 +201,7 @@ public slots: } /** - * @brief TEST_NUM + * @brief 设置TEST_NUM */ void setTestNum(int num) { QMutexLocker locker(&mutex); @@ -217,7 +217,7 @@ public slots: private slots: /** - * @brief ʱ + * @brief 定时任务 */ void doPeriodicTask() { QMutexLocker locker(&mutex); @@ -232,14 +232,14 @@ private slots: } /** - * @brief + * @brief 监控任务 */ void doMonitorTask() { doMonitorTaskmain(); } /** - * @brief ¿ͻʱ + * @brief 当有新客户端连接时处理 */ void onNewConnection() { if (!server) return; @@ -248,24 +248,24 @@ private slots: qDebug() << "New connection established!"; std::cout << "New connection established!\n"; - // readyRead / disconnected + // 绑定 readyRead / disconnected connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); connect(clientSocket, SIGNAL(disconnected()), clientSocket, SLOT(deleteLater())); - // Telnet Э + // 发送 Telnet 协商 sendTelnetNegotiation(clientSocket); - // ͻӭϢʾ + // 发送欢迎信息和提示符 if (clientSocket) { std::cout << "clientSocket OK\n"; clientSocket->write("\r\x1B[K"); clientSocket->write("Welcome to the test shell. Type 'help' for available commands.\r\n"); - printPrompt(clientSocket); // ͳһӡʾ + printPrompt(clientSocket); // 统一打印提示符 } } /** - * @brief ͻ˷͵Telnet + * @brief 处理客户端发送的Telnet数据 */ void onReadyRead() { QTcpSocket *clientSocket = qobject_cast(sender()); @@ -278,22 +278,22 @@ private slots: for (int i = 0; i < data.size(); ++i) { unsigned char c = static_cast(data[i]); - // ⵽ IAC(255)˵ Telnet Эָ + // 如果检测到 IAC(255),说明是 Telnet 协商指令 if (c == IAC) { - // TELDO/DONT/WILL/WONT + option + // 简单跳过 TELDO/DONT/WILL/WONT + option if (i + 1 < data.size()) { unsigned char cmd = static_cast(data[i+1]); if (cmd == TELDO || cmd == DONT || cmd == WILL || cmd == WONT) { - i += 2; // 2ֽ + i += 2; // 跳过这2字节 } else { - // (IAC SB)˴һֽ + // 遇到其它情况(比如IAC SB),此处仅简单跳过一个字节 i += 1; } } continue; } - // 1) '`' ˳ viewlog ping + // 1) 处理 '`' 退出 viewlog 和ping if (c == '`') { std::cout << "Received '`' from shell socket! Exiting viewlog...\n"; if (activeClient == clientSocket) { @@ -306,29 +306,29 @@ private slots: return; } - // 2) سУִ + // 2) 回车换行:执行命令 if (c == '\r' || c == '\n') { if (!currentCommand.isEmpty()) { - // ӵʷ + // 加到历史 if (commandHistory.isEmpty() || commandHistory.last() != currentCommand) { commandHistory.append(currentCommand); } historyIndex = commandHistory.size(); - // ִʱǰհ + // 执行命令时,忽略前后空白 //QString trimmedCmd = currentCommand.trimmed(); currentCommand.remove(0, 1); processCommand(currentCommand, clientSocket); currentCommand.clear(); } else { - // => ӡµʾ + // 空行 => 仅打印新的提示符 printPrompt(clientSocket); } continue; } - // 3) + // 3) 方向键 if (c == '\x1b') { if (i + 2 < data.size() && data[i+1] == '[') { char arrow = data[i+2]; @@ -342,22 +342,22 @@ private slots: continue; } - // ʾ̶Ϊ "> "ʾΪ2 + // 假设提示符固定为 "> ",提示符长度为2 const int promptLength = 1; - // 4) ˸ + // 4) 退格键 if (c == '\x7f' || c == '\b') { - // currentCommand ijȴʾʱɾַ + // 仅当 currentCommand 的长度大于提示符长度时,允许删除字符 if (currentCommand.length() > promptLength) { currentCommand.chop(1); - // ˸ "\b \b" Ļһַ + // 回显退格:用 "\b \b" 来擦除屏幕上最后一个字符 clientSocket->write("\b \b"); clientSocket->flush(); } continue; } - // 5) ַͨ + // 5) 普通字符 currentCommand.append(static_cast(c)); clientSocket->write((const char*)&c, 1); clientSocket->flush(); @@ -368,10 +368,10 @@ signals: void serverError(); private: - // ========== Telnet Э̺ ========== + // ========== Telnet 协商函数 ========== void sendTelnetNegotiation(QTcpSocket *socket) { - // WILL ECHO / WILL SUPPRESS-GO-AHEAD / DONT LINEMODE + // 发送 WILL ECHO / WILL SUPPRESS-GO-AHEAD / DONT LINEMODE static const unsigned char will_echo[3] = { IAC, WILL, TELOPT_ECHO }; static const unsigned char will_sga[3] = { IAC, WILL, TELOPT_SUPPRESS_GO_AHEAD }; static const unsigned char dont_linemode[3] = { IAC, DONT, TELOPT_LINEMODE }; @@ -383,7 +383,7 @@ private: } /** - * @brief ӡʾͳһʹ\r\nУҴӡ"> " + * @brief 打印提示符:统一使用\r\n换行,并且打印"> "于行首 */ void printPrompt(QTcpSocket *clientSocket) { @@ -392,13 +392,13 @@ private: } /** - * @brief ִһѱtrimmed + * @brief 执行一条命令(已被trimmed) */ void processCommand(const QString &cmd, QTcpSocket *clientSocket) { qDebug() << "Received command:" << cmd; std::cout << "Received command: " << cmd.toStdString() << "\n"; - // + // 命令解析 if (cmd == "help") { QString helpText = "Available commands:\r\n"; helpText += "TEST_NUM= - Set the TEST_NUM\r\n"; @@ -539,19 +539,19 @@ private: clientSocket->flush(); } - // 󣬴ӡʾ + // 命令处理结束后,打印提示符 printPrompt(clientSocket); } /** - * @brief ϼͷʷ + * @brief 上箭头:历史命令回溯 */ void handleUpArrow(QTcpSocket *clientSocket) { if (!commandHistory.isEmpty() && historyIndex > 0) { historyIndex--; currentCommand = commandHistory[historyIndex]; - // У\rص + \x1B[K + // 清行:\r回到行首 + \x1B[K清除光标后文字 clientSocket->write("\r\x1B[K> "); clientSocket->write(currentCommand.toUtf8()); clientSocket->flush(); @@ -559,7 +559,7 @@ private: } /** - * @brief ¼ͷʷǰ + * @brief 下箭头:历史命令前进 */ void handleDownArrow(QTcpSocket *clientSocket) { if (!commandHistory.isEmpty() && historyIndex < commandHistory.size() - 1) { @@ -585,14 +585,14 @@ private: int TEST_NUM; QMutex mutex; - // ʷ - QList commandHistory; // 洢ʷ - int historyIndex; // ǰʷ - QString currentCommand; // ǰ + // 历史命令相关 + QList commandHistory; // 存储历史命令 + int historyIndex; // 当前历史命令索引 + QString currentCommand; // 当前正在输入的命令 - // viewlog + // viewlog 相关 bool stopViewLog; - //ping + //ping相关 bool g_stopTelnetTest; QTcpSocket* activeClient; }; @@ -606,7 +606,7 @@ protected: }; -class OnTimerThread : public QThread//ʱ߳ +class OnTimerThread : public QThread//定时线程 { protected: void run(); @@ -617,10 +617,10 @@ protected: extern "C" { #endif -//lnk20250106̨˽ṹ +//lnk20250106添加台账结构 typedef struct terminal terminal; typedef struct monitor monitor; -struct monitor // ̨ +struct monitor // 监测点台账 { char monitor_id[64]; char terminal_code[64]; @@ -632,8 +632,11 @@ struct monitor // char status[255]; }; -struct terminal // ն̨ +struct terminal // 终端台账 { + + char guid[128]; + char terminal_id[64]; char terminal_code[64]; char org_name[64]; @@ -644,11 +647,11 @@ struct terminal // char dev_type[64]; char dev_key[255]; char dev_series[255]; - char processNo[64]; //lnk20250210̺ + char processNo[64]; //lnk20250210进程号 char addr_str[64]; char port[64]; char timestamp[64]; - monitor line[10]; // 10 + monitor line[10]; // 最多 10 个监测点 }; diff --git a/log4cplus/appender.h b/log4cplus/appender.h new file mode 100644 index 0000000..972359a --- /dev/null +++ b/log4cplus/appender.h @@ -0,0 +1,340 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: appender.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_APPENDER_HEADER_ +#define LOG4CPLUS_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace log4cplus { + + + namespace helpers + { + + class Properties; + + } + + + /** + * This class is used to "handle" errors encountered in an {@link + * log4cplus::Appender}. + */ + class LOG4CPLUS_EXPORT ErrorHandler + { + public: + ErrorHandler (); + virtual ~ErrorHandler() = 0; + virtual void error(const log4cplus::tstring& err) = 0; + virtual void reset() = 0; + }; + + + class LOG4CPLUS_EXPORT OnlyOnceErrorHandler + : public ErrorHandler + { + public: + // Ctor + OnlyOnceErrorHandler(); + virtual ~OnlyOnceErrorHandler (); + virtual void error(const log4cplus::tstring& err); + virtual void reset(); + + private: + bool firstTime; + }; + + + /** + * Extend this class for implementing your own strategies for printing log + * statements. + * + *

Properties

+ *
+ * + *
layout
+ *
This property specifies message layout used by + * Appender. + * \sa Layout + *
+ * + *
filters
+ *
This property specifies possibly multiple filters used by + * Appender. Each of multple filters and its properties is under a + * numbered subkey of filters key. E.g.: + * filters.1=log4cplus::spi::LogLevelMatchFilter. Filter + * subkey numbers must be consecutive.
+ * + *
Threshold
+ *
This property specifies log level threshold. Events with + * lower log level than the threshold will not be logged by + * appender.
+ * + *
UseLockFile
+ *
Set this property to true if you want your output + * through this appender to be synchronized between multiple + * processes. When this property is set to true then log4cplus + * uses OS specific facilities (e.g., lockf()) to + * provide inter-process locking. With the exception of + * FileAppender and its derived classes, it is also necessary to + * provide path to a lock file using the LockFile + * property. + * \sa FileAppender + *
+ * + *
LockFile
+ *
This property specifies lock file, file used for + * inter-process synchronization of log file access. The property + * is only used when UseLockFile is set to true. Then it + * is mandatory. + * \sa FileAppender + *
+ * + *
AsyncAppend
+ *
Set this property to true if you want all appends using + * this appender to be done asynchronously. Default is false.
+ * + *
+ */ + class LOG4CPLUS_EXPORT Appender + : public virtual log4cplus::helpers::SharedObject + { + public: + // Ctor + Appender(); + Appender(const log4cplus::helpers::Properties & properties); + + // Dtor + virtual ~Appender(); + + /** + * This function is for derived appenders to call from their + * destructors. All classes derived from `Appender` class + * _must_ call this function from their destructors. It + * ensures that appenders will get properly closed during + * shutdown by call to `close()` function before they are + * destroyed. + */ + void destructorImpl(); + + // Methods + /** + * Release any resources allocated within the appender such as file + * handles, network connections, etc. + * + * It is a programming error to append to a closed appender. + */ + virtual void close() = 0; + + /** + * Check if this appender is in closed state. + */ + bool isClosed() const; + + /** + * This method performs threshold checks and invokes filters before + * delegating actual logging to the subclasses specific {@link + * #append} method. + */ + void syncDoAppend(const log4cplus::spi::InternalLoggingEvent& event); + + /** + * This method performs book keeping related to asynchronous logging + * and executes `syncDoAppend()` to do the actual logging. + */ + + void asyncDoAppend(const log4cplus::spi::InternalLoggingEvent& event); + + /** + * This function checks `async` flag. It either executes + * `syncDoAppend()` directly or enqueues its execution to thread pool + * thread. + */ + void doAppend(const log4cplus::spi::InternalLoggingEvent& event); + + /** + * Get the name of this appender. The name uniquely identifies the + * appender. + */ + virtual log4cplus::tstring getName(); + + /** + * Set the name of this appender. The name is used by other + * components to identify this appender. + */ + virtual void setName(const log4cplus::tstring& name); + + /** + * Set the {@link ErrorHandler} for this Appender. + */ + virtual void setErrorHandler(std::unique_ptr eh); + + /** + * Return the currently set {@link ErrorHandler} for this + * Appender. + */ + virtual ErrorHandler* getErrorHandler(); + + /** + * Set the layout for this appender. Note that some appenders have + * their own (fixed) layouts or do not use one. For example, the + * SocketAppender ignores the layout set here. + */ + virtual void setLayout(std::unique_ptr layout); + + /** + * Returns the layout of this appender. The value may be NULL. + * + * This class owns the returned pointer. + */ + virtual Layout* getLayout(); + + /** + * Set the filter chain on this Appender. + */ + void setFilter(log4cplus::spi::FilterPtr f); + + /** + * Get the filter chain on this Appender. + */ + log4cplus::spi::FilterPtr getFilter() const; + + /** + * Add filter at the end of the filters chain. + */ + void addFilter (log4cplus::spi::FilterPtr f); + + /** + * Add filter at the end of the filters chain. + */ + void addFilter (std::function< + spi::FilterResult (const log4cplus::spi::InternalLoggingEvent &)>); + + /** + * Returns this appenders threshold LogLevel. See the {@link + * #setThreshold} method for the meaning of this option. + */ + LogLevel getThreshold() const { return threshold; } + + /** + * Set the threshold LogLevel. All log events with lower LogLevel + * than the threshold LogLevel are ignored by the appender. + * + * In configuration files this option is specified by setting the + * value of the Threshold option to a LogLevel + * string, such as "DEBUG", "INFO" and so on. + */ + void setThreshold(LogLevel th) { threshold = th; } + + /** + * Check whether the message LogLevel is below the appender's + * threshold. If there is no threshold set, then the return value is + * always true. + */ + bool isAsSevereAsThreshold(LogLevel ll) const { + return ((ll != NOT_SET_LOG_LEVEL) && (ll >= threshold)); + } + + /** + * This method waits for all events that are being asynchronously + * logged to finish. + */ + void waitToFinishAsyncLogging(); + + protected: + // Methods + /** + * Subclasses of Appender should implement this + * method to perform actual logging. + * @see doAppend method. + */ + virtual void append(const log4cplus::spi::InternalLoggingEvent& event) = 0; + + tstring & formatEvent (const log4cplus::spi::InternalLoggingEvent& event) const; + + // Data + /** The layout variable does not need to be set if the appender + * implementation has its own layout. */ + std::unique_ptr layout; + + /** Appenders are named. */ + log4cplus::tstring name; + + /** There is no LogLevel threshold filtering by default. */ + LogLevel threshold; + + /** The first filter in the filter chain. Set to null + * initially. */ + log4cplus::spi::FilterPtr filter; + + /** It is assumed and enforced that errorHandler is never null. */ + std::unique_ptr errorHandler; + + //! Optional system wide synchronization lock. + std::unique_ptr lockFile; + + //! Use lock file for inter-process synchronization of access + //! to log file. + bool useLockFile; + + //! Asynchronous append. + bool async; +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::atomic in_flight; + std::mutex in_flight_mutex; + std::condition_variable in_flight_condition; +#endif + + /** Is this appender closed? */ + bool closed; + + private: +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + void subtract_in_flight(); +#endif + }; + + /** This is a pointer to an Appender. */ + typedef helpers::SharedObjectPtr SharedAppenderPtr; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_APPENDER_HEADER_ diff --git a/log4cplus/asyncappender.h b/log4cplus/asyncappender.h new file mode 100644 index 0000000..1a5439a --- /dev/null +++ b/log4cplus/asyncappender.h @@ -0,0 +1,110 @@ +// -*- C++ -*- +// Module: Log4cplus +// File: asyncappender.h +// Created: 1/2009 +// Author: Vaclav Haisman +// +// +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// + +/** @file */ + +#ifndef LOG4CPLUS_ASYNCAPPENDER_H +#define LOG4CPLUS_ASYNCAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#ifndef LOG4CPLUS_SINGLE_THREADED + +#include +#include +#include +#include + + +namespace log4cplus +{ + + +/** + This `Appender` is a wrapper to which other appenders can be attached. The + attached appendres are then appended to from a separate thread which reads + events appended to this appender from a queue. + +

Properties

+
+ +
QueueLimit
+
Events queue size limit. Default is 100.
+ + +
Appender
+
`Appender` and its properties to use as sink for logged events.
+ + +
+ + \sa helpers::AppenderAttachableImpl + */ +class LOG4CPLUS_EXPORT AsyncAppender + : public Appender + , public helpers::AppenderAttachableImpl +{ +public: + AsyncAppender (SharedAppenderPtr const & app, unsigned max_len); + AsyncAppender (helpers::Properties const &); + virtual ~AsyncAppender (); + + virtual void close (); + +protected: + virtual void append (spi::InternalLoggingEvent const &); + + void init_queue_thread (unsigned); + + thread::AbstractThreadPtr queue_thread; + thread::QueuePtr queue; + +private: + AsyncAppender (AsyncAppender const &); + AsyncAppender & operator = (AsyncAppender const &); +}; + + +typedef helpers::SharedObjectPtr AsyncAppenderPtr; + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_SINGLE_THREADED + +#endif // LOG4CPLUS_ASYNCAPPENDER_H diff --git a/log4cplus/boost/deviceappender.hxx b/log4cplus/boost/deviceappender.hxx new file mode 100644 index 0000000..eb41edf --- /dev/null +++ b/log4cplus/boost/deviceappender.hxx @@ -0,0 +1,201 @@ +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_BOOST_DEVICEAPPENDER_HXX +#define LOG4CPLUS_BOOST_DEVICEAPPENDER_HXX + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + + +namespace log4cplus +{ + + +namespace device_appender_detail +{ + + +template +struct device_type_traits +{ + typedef T & device_type; + + static + device_type + unwrap (device_type x) + { + return x; + } +}; + + +template +struct device_type_traits > +{ + typedef boost::shared_ptr device_type; + + static + T & + unwrap (device_type const & ptr) + { + return *ptr; + } +}; + + +} // namespace device_appender_detail + + +template +class DeviceAppender + : public Appender +{ +public: + typedef device_appender_detail::device_type_traits device_traits; + typedef typename device_traits::device_type device_type; + + template + DeviceAppender (D & d, bool close_device = true) + : device (d) + , close_flag (close_device) + { } + + template + DeviceAppender (boost::shared_ptr const & d, bool close_device = true) + : device (d) + , close_flag (close_device) + { } + + template + DeviceAppender (D & d, const helpers::Properties & props) + : Appender (props) + , device (d) + { + if (props.exists (LOG4CPLUS_TEXT ("CloseDevice"))) + close_flag = true; + else + close_flag = false; + } + + template + DeviceAppender (boost::shared_ptr const & d, + const helpers::Properties & props) + : Appender (props) + , device (d) + { + if (props.exists (LOG4CPLUS_TEXT ("CloseDevice"))) + close_flag = true; + else + close_flag = false; + } + + virtual + ~DeviceAppender () + { } + + virtual + void + close () + { + if (close_flag) + boost::iostreams::close (device_traits::unwrap (device)); + } + +protected: + virtual + void + append (log4cplus::spi::InternalLoggingEvent const & event) + { + tstring & str = formatEvent (event); + boost::iostreams::write (device_traits::unwrap (device), + str.c_str (), str.size ()); + } + + device_type device; + bool close_flag; + +private: + DeviceAppender (DeviceAppender const &); + DeviceAppender & operator = (DeviceAppender const &); +}; + + +template +inline +SharedAppenderPtr +make_device_appender (T & d, bool close_device = true) +{ + SharedAppenderPtr app (new DeviceAppender (d, close_device)); + return app; +} + + +template +inline +SharedAppenderPtr +make_device_appender (T & d, const helpers::Properties & props) +{ + SharedAppenderPtr app (new DeviceAppender (d, props)); + return app; +} + + +template +inline +SharedAppenderPtr +make_device_appender_sp (boost::shared_ptr const & p, + bool close_device = true) +{ + SharedAppenderPtr app ( + new DeviceAppender > (p, close_device)); + return app; +} + + +template +inline +SharedAppenderPtr +make_device_appender_sp (boost::shared_ptr const & p, + const helpers::Properties & props) +{ + SharedAppenderPtr app ( + new DeviceAppender > (p, props)); + return app; +} + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_BOOST_DEVICEAPPENDER_HXX diff --git a/log4cplus/callbackappender.h b/log4cplus/callbackappender.h new file mode 100644 index 0000000..0c61bed --- /dev/null +++ b/log4cplus/callbackappender.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +// Copyright (C) 2015-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +/** @file */ + +#ifndef LOG4CPLUS_CALLBACK_APPENDER_HEADER_ +#define LOG4CPLUS_CALLBACK_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus { + +/** +* Send log events to a C function callback. +*/ +class LOG4CPLUS_EXPORT CallbackAppender + : public Appender { +public: + CallbackAppender(); + CallbackAppender(log4cplus_log_event_callback_t callback, void * cookie); + CallbackAppender(const log4cplus::helpers::Properties&); + + virtual ~CallbackAppender(); + virtual void close(); + + void setCookie(void *); + void setCallback(log4cplus_log_event_callback_t); + +protected: + virtual void append(const log4cplus::spi::InternalLoggingEvent& event); + +private: + log4cplus_log_event_callback_t callback; + void * cookie; + + // Disallow copying of instances of this class + CallbackAppender(const CallbackAppender&) = delete; + CallbackAppender& operator=(const CallbackAppender&) = delete; +}; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_CALLBACK_APPENDER_HEADER_ diff --git a/log4cplus/clfsappender.h b/log4cplus/clfsappender.h new file mode 100644 index 0000000..e764315 --- /dev/null +++ b/log4cplus/clfsappender.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +// Module: Log4cplus +// File: clfsappender.h +// Created: 5/2012 +// Author: Vaclav Zeman +// +// +// Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// + +/** @file */ + +#ifndef LOG4CPLUS_CLFSAPPENDER_H +#define LOG4CPLUS_CLFSAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +#if defined (LOG4CPLUS_CLFSAPPENDER_BUILD_DLL) +# if defined (INSIDE_LOG4CPLUS_CLFSAPPENDER) +# define LOG4CPLUS_CLFSAPPENDER_EXPORT __declspec(dllexport) +# else +# define LOG4CPLUS_CLFSAPPENDER_EXPORT __declspec(dllimport) +# endif +#else +# define LOG4CPLUS_CLFSAPPENDER_EXPORT +#endif + + +namespace log4cplus +{ + + +class LOG4CPLUS_CLFSAPPENDER_EXPORT CLFSAppender + : public Appender +{ +public: + CLFSAppender (tstring const & logname, unsigned long logsize, + unsigned long buffersize); + explicit CLFSAppender (helpers::Properties const &); + virtual ~CLFSAppender (); + + virtual void close (); + + static void registerAppender (); + +protected: + virtual void append (spi::InternalLoggingEvent const &); + + void init (tstring const & logname, unsigned long logsize, + unsigned long buffersize); + + struct Data; + + Data * data; + +private: + CLFSAppender (CLFSAppender const &); + CLFSAppender & operator = (CLFSAppender const &); +}; + + +typedef helpers::SharedObjectPtr CLFSAppenderPtr; + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_CLFSAPPENDER_H diff --git a/log4cplus/clogger.h b/log4cplus/clogger.h new file mode 100644 index 0000000..b8b2a43 --- /dev/null +++ b/log4cplus/clogger.h @@ -0,0 +1,126 @@ +// -*- C -*- +/** + * Module: Log4CPLUS + * File: clogger.h + * Created: 01/2011 + * Author: Jens Rehsack + * + * + * Copyright 2011-2017 Jens Rehsack & Tad E. Smith + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file + * This header defines the C API for log4cplus and the logging macros. */ + +#ifndef LOG4CPLUS_CLOGGERHEADER_ +#define LOG4CPLUS_CLOGGERHEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +// TODO UNICDE capable + +typedef void * log4cplus_logger_t; +typedef log4cplus_logger_t logger_t; + +typedef int log4cplus_loglevel_t; +typedef log4cplus_loglevel_t loglevel_t; + +#define L4CP_OFF_LOG_LEVEL 60000 +#define L4CP_FATAL_LOG_LEVEL 50000 +#define L4CP_ERROR_LOG_LEVEL 40000 +#define L4CP_WARN_LOG_LEVEL 30000 +#define L4CP_INFO_LOG_LEVEL 20000 +#define L4CP_DEBUG_LOG_LEVEL 10000 +#define L4CP_TRACE_LOG_LEVEL 0 +#define L4CP_ALL_LOG_LEVEL TRACE_LOG_LEVEL +#define L4CP_NOT_SET_LOG_LEVEL -1 + +#ifdef UNICODE +typedef wchar_t log4cplus_char_t; +#else +typedef char log4cplus_char_t; +#endif // UNICODE + +#if ! defined (LOG4CPLUS_TEXT) +#ifdef UNICODE +# define LOG4CPLUS_TEXT2(STRING) L##STRING +#else +# define LOG4CPLUS_TEXT2(STRING) STRING +#endif // UNICODE +#define LOG4CPLUS_TEXT(STRING) LOG4CPLUS_TEXT2(STRING) +#endif // LOG4CPLUS_TEXT + +LOG4CPLUS_EXPORT void * log4cplus_initialize(void); +LOG4CPLUS_EXPORT int log4cplus_deinitialize(void * initializer); + +LOG4CPLUS_EXPORT int log4cplus_file_configure(const log4cplus_char_t *pathname); +LOG4CPLUS_EXPORT int log4cplus_file_reconfigure(const log4cplus_char_t *pathname); +LOG4CPLUS_EXPORT int log4cplus_str_configure(const log4cplus_char_t *config); +LOG4CPLUS_EXPORT int log4cplus_str_reconfigure(const log4cplus_char_t *config); +LOG4CPLUS_EXPORT int log4cplus_basic_configure(void); +LOG4CPLUS_EXPORT int log4cplus_basic_reconfigure(int logToStdErr); +LOG4CPLUS_EXPORT void log4cplus_shutdown(void); + +LOG4CPLUS_EXPORT int log4cplus_logger_exists(const log4cplus_char_t *name); +LOG4CPLUS_EXPORT int log4cplus_logger_is_enabled_for( + const log4cplus_char_t *name, log4cplus_loglevel_t ll); + +LOG4CPLUS_EXPORT int log4cplus_logger_log(const log4cplus_char_t *name, + log4cplus_loglevel_t ll, const log4cplus_char_t *msgfmt, ...) + LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 4); + +LOG4CPLUS_EXPORT int log4cplus_logger_log_str(const log4cplus_char_t *name, + log4cplus_loglevel_t ll, const log4cplus_char_t *msg); + +LOG4CPLUS_EXPORT int log4cplus_logger_force_log(const log4cplus_char_t *name, + log4cplus_loglevel_t ll, const log4cplus_char_t *msgfmt, ...) + LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 4); + +LOG4CPLUS_EXPORT int log4cplus_logger_force_log_str(const log4cplus_char_t *name, + log4cplus_loglevel_t ll, const log4cplus_char_t *msg); + +//! CallbackAppender callback type. +typedef void (* log4cplus_log_event_callback_t)(void * cookie, + log4cplus_char_t const * message, log4cplus_char_t const * loggerName, + log4cplus_loglevel_t ll, log4cplus_char_t const * thread, + log4cplus_char_t const * thread2, + unsigned long long timestamp_secs, unsigned long timestamp_usecs, + log4cplus_char_t const * file, log4cplus_char_t const * function, int line); + +LOG4CPLUS_EXPORT int log4cplus_add_callback_appender( + const log4cplus_char_t * logger, log4cplus_log_event_callback_t callback, + void * cookie); + +// Custom LogLevel +LOG4CPLUS_EXPORT int log4cplus_add_log_level(unsigned int ll, + const log4cplus_char_t *ll_name); +LOG4CPLUS_EXPORT int log4cplus_remove_log_level(unsigned int ll, + const log4cplus_char_t *ll_name); + +#ifdef __cplusplus +} +#endif + +#endif /*?LOG4CPLUS_CLOGGERHEADER_*/ diff --git a/log4cplus/config.h.cmake.in b/log4cplus/config.h.cmake.in new file mode 100644 index 0000000..2bf4342 --- /dev/null +++ b/log4cplus/config.h.cmake.in @@ -0,0 +1,335 @@ +/* include/log4cplus/config.h.in. Generated from configure.in by autoheader. */ + +#ifndef LOG4CPLUS_CONFIG_H + +#define LOG4CPLUS_CONFIG_H + +/* Defined if the compiler supports C99 style variadic macros with + __VA_ARGS__. */ +/* #undef HAS_C99_VARIADIC_MACROS */ + +/* Defined if the compiler supports GNU style variadic macros. */ +/* #undef HAS_GNU_VARIADIC_MACROS */ + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `ftime' function. */ +#cmakedefine HAVE_FTIME 1 + +/* */ +#cmakedefine HAVE_GETADDRINFO 1 + +/* */ +#cmakedefine HAVE_GETHOSTBYNAME_R 1 + +/* Define to 1 if you have the `getpid' function. */ +#cmakedefine HAVE_GETPID 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `gmtime_r' function. */ +#cmakedefine HAVE_GMTIME_R 1 + +/* Define to 1 if you have the `htonl' function. */ +#cmakedefine HAVE_HTONL 1 + +/* Define to 1 if you have the `htons' function. */ +#cmakedefine HAVE_HTONS 1 + +/* Define to 1 if you have the `iconv' function. */ +#cmakedefine HAVE_ICONV 1 + +/* Define to 1 if you have the `iconv_close' function. */ +#cmakedefine HAVE_ICONV_CLOSE 1 + +/* Define to 1 if you have the `iconv_open' function. */ +#cmakedefine HAVE_ICONV_OPEN 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `advapi32' library (-ladvapi32). */ +#cmakedefine HAVE_LIBADVAPI32 1 + +/* Define to 1 if you have the `libiconv' function. */ +/* #undef HAVE_LIBICONV */ + +/* Define to 1 if you have the `libiconv_close' function. */ +/* #undef HAVE_LIBICONV_CLOSE */ + +/* Define to 1 if you have the `libiconv_open' function. */ +/* #undef HAVE_LIBICONV_OPEN */ + +/* Define to 1 if you have the `kernel32' library (-lkernel32). */ +#cmakedefine HAVE_LIBKERNEL32 1 + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#cmakedefine HAVE_LIBNSL 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +#cmakedefine HAVE_LIBRT 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#cmakedefine HAVE_LIBSOCKET 1 + +/* Define to 1 if you have the `ws2_32' library (-lws2_32). */ +#cmakedefine HAVE_LIBWS2_32 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#cmakedefine HAVE_LOCALTIME_R 1 + +/* Define to 1 if you have the `lstat' function. */ +#cmakedefine HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `ntohl' function. */ +#cmakedefine HAVE_NTOHL 1 + +/* Define to 1 if you have the `ntohs' function. */ +#cmakedefine HAVE_NTOHS 1 + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the `stat' function. */ +#cmakedefine HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vfprintf_s' function. */ +#cmakedefine HAVE_VFPRINTF_S 1 + +/* Define to 1 if you have the `vfwprintf_s' function. */ +#cmakedefine HAVE_VFWPRINTF_S 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsprintf_s' function. */ +#cmakedefine HAVE_VSPRINTF_S 1 + +/* Define to 1 if you have the `vswprintf_s' function. */ +#cmakedefine HAVE_VSWPRINTF_S 1 + +/* Define to 1 if you have the `_vsnprintf' function. */ +#cmakedefine HAVE__VSNPRINTF 1 + +/* Define to 1 if you have the `_vsnprintf_s' function. */ +#cmakedefine HAVE__VSNPRINTF_S 1 + +/* Define to 1 if you have the `_vsnwprintf_s' function. */ +#cmakedefine HAVE__VSNWPRINTF_S 1 + +/* Defined if the compiler supports __FUNCTION__ macro. */ +#cmakedefine HAVE___FUNCTION___MACRO 1 + +/* Defined if the compiler supports __PRETTY_FUNCTION__ macro. */ +#cmakedefine HAVE___PRETTY_FUNCTION___MACRO 1 + +/* Defined if the compiler provides __sync_add_and_fetch(). */ +#cmakedefine HAVE___SYNC_ADD_AND_FETCH 1 + +/* Defined if the compiler provides __sync_sub_and_fetch(). */ +#cmakedefine HAVE___SYNC_SUB_AND_FETCH 1 + +/* Defined for --enable-debugging builds. */ +#undef LOG4CPLUS_DEBUGGING + +/* Defined if the compiler understands __declspec(dllimport) or + __attribute__((visibility("default"))) construct. */ +#define LOG4CPLUS_DECLSPEC_EXPORT @LOG4CPLUS_DECLSPEC_EXPORT@ + +/* Defined if the compiler understands __declspec(dllexport) or construct. */ +#define LOG4CPLUS_DECLSPEC_IMPORT @LOG4CPLUS_DECLSPEC_IMPORT@ /**/ + +/* */ +#cmakedefine LOG4CPLUS_HAVE_CLOCK_GETTIME 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ENAMETOOLONG 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ERRNO_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_FTIME 1 + +/* */ +#define LOG4CPLUS_HAVE_FUNCTION_MACRO 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GETADDRINFO 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GETHOSTBYNAME_R 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GETPID 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GETTID 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GETTIMEOFDAY 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_GMTIME_R 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_HTONL 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_HTONS 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ICONV 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ICONV_CLOSE 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ICONV_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_ICONV_OPEN 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_LIMITS_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_LOCALTIME_R 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_LSTAT 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_NETDB_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_NETINET_IN_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_NETINET_TCP_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_NTOHL 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_NTOHS 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_PRETTY_FUNCTION_MACRO 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_STAT 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_STDARG_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_STDIO_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_STDLIB_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYSLOG_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_SOCKET_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_STAT_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_SYSCALL_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_TIMEB_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_TIME_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_SYS_TYPES_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_TIME_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_UNISTD_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_VFPRINTF_S 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_VFWPRINTF_S 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_VSNPRINTF 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_VSPRINTF_S 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_VSWPRINTF_S 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE_WCHAR_H 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE__VSNPRINTF 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE__VSNPRINTF_S 1 + +/* */ +#cmakedefine LOG4CPLUS_HAVE__VSNWPRINTF_S 1 + +/* Define if this is a single-threaded library. */ +#undef LOG4CPLUS_SINGLE_THREADED + +/* */ +#undef LOG4CPLUS_USE_PTHREADS + +/* Define for compilers/standard libraries that support more than just the "C" + locale. */ +#undef LOG4CPLUS_WORKING_LOCALE + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to 1 if you have the ANSI C header files. Seems to be unused*/ +#cmakedefine STDC_HEADERS 1 + +/* Define to int if undefined. */ +#cmakedefine socklen_t int + +#endif // LOG4CPLUS_CONFIG_H diff --git a/log4cplus/config.h.in b/log4cplus/config.h.in new file mode 100644 index 0000000..9e62eb6 --- /dev/null +++ b/log4cplus/config.h.in @@ -0,0 +1,471 @@ +/* include/log4cplus/config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef LOG4CPLUS_CONFIG_H + +#define LOG4CPLUS_CONFIG_H + +/* define if the compiler supports basic C++11 syntax */ +#undef HAVE_CXX11 + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the `fcntl' function. */ +#undef HAVE_FCNTL + +/* Define to 1 if you have the `flock' function. */ +#undef HAVE_FLOCK + +/* Define to 1 if you have the `ftime' function. */ +#undef HAVE_FTIME + +/* Define to 1 if the system has the `constructor' function attribute */ +#undef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR + +/* Define to 1 if the system has the `constructor_priority' function attribute + */ +#undef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR_PRIORITY + +/* */ +#undef HAVE_GETADDRINFO + +/* */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `getpid' function. */ +#undef HAVE_GETPID + +/* Define to 1 if you have the `gmtime_r' function. */ +#undef HAVE_GMTIME_R + +/* Define to 1 if you have the `htonl' function. */ +#undef HAVE_HTONL + +/* Define to 1 if you have the `htons' function. */ +#undef HAVE_HTONS + +/* Define to 1 if you have the `iconv' function. */ +#undef HAVE_ICONV + +/* Define to 1 if you have the `iconv_close' function. */ +#undef HAVE_ICONV_CLOSE + +/* Define to 1 if you have the `iconv_open' function. */ +#undef HAVE_ICONV_OPEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `advapi32' library (-ladvapi32). */ +#undef HAVE_LIBADVAPI32 + +/* Define to 1 if you have the `libiconv' function. */ +#undef HAVE_LIBICONV + +/* Define to 1 if you have the `libiconv_close' function. */ +#undef HAVE_LIBICONV_CLOSE + +/* Define to 1 if you have the `libiconv_open' function. */ +#undef HAVE_LIBICONV_OPEN + +/* Define to 1 if you have the `kernel32' library (-lkernel32). */ +#undef HAVE_LIBKERNEL32 + +/* Define to 1 if you have the `oleaut32' library (-loleaut32). */ +#undef HAVE_LIBOLEAUT32 + +/* Define to 1 if you have the `ws2_32' library (-lws2_32). */ +#undef HAVE_LIBWS2_32 + +/* Define to 1 if you have the `localtime_r' function. */ +#undef HAVE_LOCALTIME_R + +/* Define to 1 if you have the `lockf' function. */ +#undef HAVE_LOCKF + +/* Define to 1 if you have the `lstat' function. */ +#undef HAVE_LSTAT + +/* Define to 1 if you have the `mbstowcs' function. */ +#undef HAVE_MBSTOWCS + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `ntohl' function. */ +#undef HAVE_NTOHL + +/* Define to 1 if you have the `ntohs' function. */ +#undef HAVE_NTOHS + +/* Define to 1 if you have the `OutputDebugStringW' function. */ +#undef HAVE_OUTPUTDEBUGSTRINGW + +/* Define to 1 if you have the `pipe' function. */ +#undef HAVE_PIPE + +/* Define to 1 if you have the `pipe2' function. */ +#undef HAVE_PIPE2 + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + +/* If available, contains the Python version number currently in use. */ +#undef HAVE_PYTHON + +/* Define to 1 if you have the `shutdown' function. */ +#undef HAVE_SHUTDOWN + +/* Define to 1 if you have the `stat' function. */ +#undef HAVE_STAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Defined if the compiler understands __thread or __declspec(thread) + construct. */ +#undef HAVE_TLS_SUPPORT + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the `init_priority' variable attribute */ +#undef HAVE_VAR_ATTRIBUTE_INIT_PRIORITY + +/* Define to 1 if you have the `vfprintf_s' function. */ +#undef HAVE_VFPRINTF_S + +/* Define to 1 if you have the `vfwprintf_s' function. */ +#undef HAVE_VFWPRINTF_S + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `vsnwprintf' function. */ +#undef HAVE_VSNWPRINTF + +/* Define to 1 if you have the `vsprintf_s' function. */ +#undef HAVE_VSPRINTF_S + +/* Define to 1 if you have the `vswprintf_s' function. */ +#undef HAVE_VSWPRINTF_S + +/* Define to 1 if you have the `wcstombs' function. */ +#undef HAVE_WCSTOMBS + +/* Define to 1 if you have the `_vsnprintf' function. */ +#undef HAVE__VSNPRINTF + +/* Define to 1 if you have the `_vsnprintf_s' function. */ +#undef HAVE__VSNPRINTF_S + +/* Define to 1 if you have the `_vsnwprintf' function. */ +#undef HAVE__VSNWPRINTF + +/* Define to 1 if you have the `_vsnwprintf_s' function. */ +#undef HAVE__VSNWPRINTF_S + +/* Defined if the compiler supports __FUNCTION__ macro. */ +#undef HAVE___FUNCTION___MACRO + +/* Defined if the compiler supports __func__ symbol. */ +#undef HAVE___FUNC___SYMBOL + +/* Defined if the compiler supports __PRETTY_FUNCTION__ macro. */ +#undef HAVE___PRETTY_FUNCTION___MACRO + +/* Defined for --enable-debugging builds. */ +#undef LOG4CPLUS_DEBUGGING + +/* Defined if the compiler understands __declspec(dllimport) or + __attribute__((visibility("default"))) or __global construct. */ +#undef LOG4CPLUS_DECLSPEC_EXPORT + +/* Defined if the compiler understands __declspec(dllimport) or + __attribute__((visibility("default"))) or __global construct. */ +#undef LOG4CPLUS_DECLSPEC_IMPORT + +/* Defined if the compiler understands __attribute__((visibility("hidden"))) + or __hidden construct. */ +#undef LOG4CPLUS_DECLSPEC_PRIVATE + +/* */ +#undef LOG4CPLUS_HAVE_ARPA_INET_H + +/* */ +#undef LOG4CPLUS_HAVE_ENAMETOOLONG + +/* */ +#undef LOG4CPLUS_HAVE_ERRNO_H + +/* */ +#undef LOG4CPLUS_HAVE_FCNTL + +/* */ +#undef LOG4CPLUS_HAVE_FCNTL_H + +/* */ +#undef LOG4CPLUS_HAVE_FLOCK + +/* */ +#undef LOG4CPLUS_HAVE_FTIME + +/* */ +#undef LOG4CPLUS_HAVE_FUNCTION_MACRO + +/* */ +#undef LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR + +/* */ +#undef LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR_PRIORITY + +/* */ +#undef LOG4CPLUS_HAVE_FUNC_SYMBOL + +/* */ +#undef LOG4CPLUS_HAVE_GETADDRINFO + +/* */ +#undef LOG4CPLUS_HAVE_GETHOSTBYNAME_R + +/* */ +#undef LOG4CPLUS_HAVE_GETPID + +/* */ +#undef LOG4CPLUS_HAVE_GETTID + +/* */ +#undef LOG4CPLUS_HAVE_GMTIME_R + +/* */ +#undef LOG4CPLUS_HAVE_HTONL + +/* */ +#undef LOG4CPLUS_HAVE_HTONS + +/* */ +#undef LOG4CPLUS_HAVE_ICONV + +/* */ +#undef LOG4CPLUS_HAVE_ICONV_CLOSE + +/* */ +#undef LOG4CPLUS_HAVE_ICONV_H + +/* */ +#undef LOG4CPLUS_HAVE_ICONV_OPEN + +/* */ +#undef LOG4CPLUS_HAVE_LIMITS_H + +/* */ +#undef LOG4CPLUS_HAVE_LOCALTIME_R + +/* */ +#undef LOG4CPLUS_HAVE_LOCKF + +/* */ +#undef LOG4CPLUS_HAVE_LSTAT + +/* */ +#undef LOG4CPLUS_HAVE_MBSTOWCS + +/* */ +#undef LOG4CPLUS_HAVE_NETDB_H + +/* */ +#undef LOG4CPLUS_HAVE_NETINET_IN_H + +/* */ +#undef LOG4CPLUS_HAVE_NETINET_TCP_H + +/* */ +#undef LOG4CPLUS_HAVE_NTOHL + +/* */ +#undef LOG4CPLUS_HAVE_NTOHS + +/* */ +#undef LOG4CPLUS_HAVE_OUTPUTDEBUGSTRING + +/* */ +#undef LOG4CPLUS_HAVE_PIPE + +/* */ +#undef LOG4CPLUS_HAVE_PIPE2 + +/* */ +#undef LOG4CPLUS_HAVE_POLL + +/* */ +#undef LOG4CPLUS_HAVE_POLL_H + +/* */ +#undef LOG4CPLUS_HAVE_PRETTY_FUNCTION_MACRO + +/* */ +#undef LOG4CPLUS_HAVE_SHUTDOWN + +/* */ +#undef LOG4CPLUS_HAVE_STAT + +/* */ +#undef LOG4CPLUS_HAVE_STDARG_H + +/* */ +#undef LOG4CPLUS_HAVE_STDIO_H + +/* */ +#undef LOG4CPLUS_HAVE_STDLIB_H + +/* */ +#undef LOG4CPLUS_HAVE_SYSLOG_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_FILE_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_SOCKET_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_STAT_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_SYSCALL_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TIMEB_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TIME_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TYPES_H + +/* */ +#undef LOG4CPLUS_HAVE_TIME_H + +/* */ +#undef LOG4CPLUS_HAVE_TLS_SUPPORT + +/* */ +#undef LOG4CPLUS_HAVE_UNISTD_H + +/* */ +#undef LOG4CPLUS_HAVE_VAR_ATTRIBUTE_INIT_PRIORITY + +/* */ +#undef LOG4CPLUS_HAVE_VFPRINTF_S + +/* */ +#undef LOG4CPLUS_HAVE_VFWPRINTF_S + +/* */ +#undef LOG4CPLUS_HAVE_VSNPRINTF + +/* */ +#undef LOG4CPLUS_HAVE_VSNWPRINTF + +/* */ +#undef LOG4CPLUS_HAVE_VSPRINTF_S + +/* */ +#undef LOG4CPLUS_HAVE_VSWPRINTF_S + +/* */ +#undef LOG4CPLUS_HAVE_WCHAR_H + +/* */ +#undef LOG4CPLUS_HAVE_WCSTOMBS + +/* */ +#undef LOG4CPLUS_HAVE__VSNPRINTF + +/* */ +#undef LOG4CPLUS_HAVE__VSNPRINTF_S + +/* */ +#undef LOG4CPLUS_HAVE__VSNWPRINTF + +/* */ +#undef LOG4CPLUS_HAVE__VSNWPRINTF_S + +/* Define if this is a single-threaded library. */ +#undef LOG4CPLUS_SINGLE_THREADED + +/* */ +#undef LOG4CPLUS_THREAD_LOCAL_VAR + +/* */ +#undef LOG4CPLUS_USE_PTHREADS + +/* Define when iconv() is available. */ +#undef LOG4CPLUS_WITH_ICONV + +/* Defined to enable unit tests. */ +#undef LOG4CPLUS_WITH_UNIT_TESTS + +/* Define for C99 compilers/standard libraries that support more than just the + "C" locale. */ +#undef LOG4CPLUS_WORKING_C_LOCALE + +/* Define for compilers/standard libraries that support more than just the "C" + locale. */ +#undef LOG4CPLUS_WORKING_LOCALE + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Defined to the actual TLS support construct. */ +#undef TLS_SUPPORT_CONSTRUCT + +/* Substitute for socklen_t */ +#undef socklen_t + +#endif // LOG4CPLUS_CONFIG_H diff --git a/log4cplus/config.hxx b/log4cplus/config.hxx new file mode 100644 index 0000000..99e5156 --- /dev/null +++ b/log4cplus/config.hxx @@ -0,0 +1,217 @@ +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_CONFIG_HXX +#define LOG4CPLUS_CONFIG_HXX + +#if defined (_WIN32) +# include +#elif (defined(__MWERKS__) && defined(__MACOS__)) +# include +#else +# include +#endif + +# if ! defined (LOG4CPLUS_WORKING_LOCALE) \ + && ! defined (LOG4CPLUS_WORKING_C_LOCALE) \ + && ! defined (LOG4CPLUS_WITH_ICONV) +# define LOG4CPLUS_POOR_MANS_CHCONV +#endif + +#ifndef LOG4CPLUS_DECLSPEC_EXPORT +#define LOG4CPLUS_DECLSPEC_EXPORT /* empty */ +#endif + +#ifndef LOG4CPLUS_DECLSPEC_IMPORT +#define LOG4CPLUS_DECLSPEC_IMPORT /* empty */ +#endif + +#ifndef LOG4CPLUS_DECLSPEC_PRIVATE +#define LOG4CPLUS_DECLSPEC_PRIVATE /* empty */ +#endif + +#define LOG4CPLUS_PRIVATE LOG4CPLUS_DECLSPEC_PRIVATE + +#if !defined(_WIN32) +# define LOG4CPLUS_USE_BSD_SOCKETS +# if !defined(LOG4CPLUS_SINGLE_THREADED) +# define LOG4CPLUS_USE_PTHREADS +# endif +# if defined (INSIDE_LOG4CPLUS) +# define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_EXPORT +# else +# define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_IMPORT +# endif // defined (INSIDE_LOG4CPLUS) + +#endif // !_WIN32 + +#if defined (LOG4CPLUS_INLINES_ARE_EXPORTED) \ + && defined (LOG4CPLUS_BUILD_DLL) +# define LOG4CPLUS_INLINE_EXPORT inline +#else +# define LOG4CPLUS_INLINE_EXPORT +#endif + +#if defined (UNICODE) +# if defined (_MSC_VER) && _MSC_VER >= 1400 +# define LOG4CPLUS_FSTREAM_ACCEPTS_WCHAR_T +# endif +# if defined (_MSC_VER) && _MSC_VER >= 1600 +# define LOG4CPLUS_HAVE_CODECVT_UTF8_FACET +# define LOG4CPLUS_HAVE_CODECVT_UTF16_FACET +# endif +#endif + +// C++11 stuff + +#if ! defined (__has_feature) +//! __has_feature(X) is Clangs way for testing features. +//! Define it to 0 if it does not exist. +# define __has_feature(X) 0 +#endif + +#if __has_feature (cxx_noexcept) \ + || (defined (__GNUC__) \ + && (__GNUC__ > 4 \ + || __GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \ + || (defined (_MSC_VER) && _MSC_VER >= 1900) +# define LOG4CPLUS_NOEXCEPT noexcept +# define LOG4CPLUS_NOEXCEPT_FALSE noexcept(false) +#else +# define LOG4CPLUS_NOEXCEPT /* empty */ +# define LOG4CPLUS_NOEXCEPT_FALSE /* empty */ +#endif + +#if ! defined (UNICODE) && defined (__GNUC__) && __GNUC__ >= 3 +# define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, format_index, first_arg_index) \ + __attribute__ ((format (archetype, format_index, first_arg_index))) +#else +# define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, fmt_index, first_arg_index) \ + /* empty */ +#endif + +#if defined (__GNUC__) \ + && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) \ + && ! defined (__INTEL_COMPILER) \ + && ! defined (__CUDACC__) +# define LOG4CPLUS_CALLER_FILE() __builtin_FILE () +# define LOG4CPLUS_CALLER_LINE() __builtin_LINE () +# define LOG4CPLUS_CALLER_FUNCTION() __builtin_FUNCTION () +#else +# define LOG4CPLUS_CALLER_FILE() (nullptr) +# define LOG4CPLUS_CALLER_LINE() (-1) +# define LOG4CPLUS_CALLER_FUNCTION() (nullptr) +#endif + +#if defined (__GNUC__) && __GNUC__ >= 3 +# define LOG4CPLUS_ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +# define LOG4CPLUS_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# define LOG4CPLUS_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) +# define LOG4CPLUS_BUILTIN_EXPECT(exp, c) __builtin_expect ((exp), (c)) +#else +# if ! defined (LOG4CPLUS_ATTRIBUTE_NORETURN) +# define LOG4CPLUS_ATTRIBUTE_NORETURN /* empty */ +# endif +# define LOG4CPLUS_ATTRIBUTE_PURE /* empty */ +# define LOG4CPLUS_ATTRIBUTE_DEPRECATED /* empty */ +# define LOG4CPLUS_BUILTIN_EXPECT(exp, c) (exp) +#endif + +#define LOG4CPLUS_LIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 1) +#define LOG4CPLUS_UNLIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 0) + +#if defined (_MSC_VER) \ + || (defined (__BORLANDC__) && __BORLANDC__ >= 0x0650) \ + || (defined (__COMO__) && __COMO_VERSION__ >= 400) /* ??? */ \ + || (defined (__DMC__) && __DMC__ >= 0x700) /* ??? */ \ + || (defined (__clang__) && __clang_major__ >= 3) \ + || (defined (__GNUC__) && (__GNUC__ >= 4 \ + || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))) +# define LOG4CPLUS_HAVE_PRAGMA_ONCE +# pragma once +#endif + +#if defined (LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR_PRIORITY) +# define LOG4CPLUS_CONSTRUCTOR_FUNC(prio) \ + __attribute__ ((__constructor__ ((prio)))) +#elif defined (LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR) +# define LOG4CPLUS_CONSTRUCTOR_FUNC(prio) \ + __attribute__ ((__constructor__)) +#else +# define LOG4CPLUS_CONSTRUCTOR_FUNC(prio) /* empty */ +#endif + +#if defined (LOG4CPLUS_HAVE_VAR_ATTRIBUTE_INIT_PRIORITY) +# define LOG4CPLUS_INIT_PRIORITY(prio) \ + __attribute__ ((__init_priority__ ((prio)))) +#else +# define LOG4CPLUS_INIT_PRIORITY(prio) /* empty */ +#endif + +#define LOG4CPLUS_INIT_PRIORITY_BASE (65535 / 2) + +#include + +#if defined (LOG4CPLUS_SINGLE_THREADED) +#define LOG4CPLUS_THREADED(x) +#else +#define LOG4CPLUS_THREADED(x) x +#endif + +#if defined(__cplusplus) +#include + +namespace log4cplus +{ + +//! Per thread cleanup function. Users should call this function before +//! a thread ends its execution. It frees resources allocated in thread local +//! storage. It is important only for multi-threaded static library builds +//! of log4cplus and user threads. In all other cases the clean up is provided +//! automatically by other means. +LOG4CPLUS_EXPORT void threadCleanup (); + +//! Initializes log4cplus. +//! +//! \note using `log4cplus::Initializer` is preferred +LOG4CPLUS_EXPORT void initialize (); + +//! Deinitializes log4cplus. +//! +//! \note using `log4cplus::Initializer` is preferred +LOG4CPLUS_EXPORT void deinitialize (); + +//! Set thread pool size. +LOG4CPLUS_EXPORT void setThreadPoolSize (std::size_t pool_size); + +//! Set behaviour on full thread pool queue. Default is to block. +LOG4CPLUS_EXPORT void setThreadPoolBlockOnFull (bool block); + +//! Set thread pool queue size limit. +LOG4CPLUS_EXPORT void setThreadPoolQueueSizeLimit (std::size_t queue_size_limit); + +} // namespace log4cplus + +#endif + +#endif // LOG4CPLUS_CONFIG_HXX diff --git a/log4cplus/config/defines.hxx.in b/log4cplus/config/defines.hxx.in new file mode 100644 index 0000000..3c80749 --- /dev/null +++ b/log4cplus/config/defines.hxx.in @@ -0,0 +1,247 @@ +#ifndef LOG4CPLUS_CONFIG_DEFINES_HXX +#define LOG4CPLUS_CONFIG_DEFINES_HXX + +/* */ +#undef LOG4CPLUS_HAVE_SYSLOG_H + +/* */ +#undef LOG4CPLUS_HAVE_ARPA_INET_H + +/* */ +#undef LOG4CPLUS_HAVE_NETINET_IN_H + +/* */ +#undef LOG4CPLUS_HAVE_NETINET_TCP_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TIMEB_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TIME_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_TYPES_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_STAT_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_SYSCALL_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_FILE_H + +/* */ +#undef LOG4CPLUS_HAVE_TIME_H + +/* */ +#undef LOG4CPLUS_HAVE_SYS_SOCKET_H + +/* */ +#undef LOG4CPLUS_HAVE_NETDB_H + +/* */ +#undef LOG4CPLUS_HAVE_UNISTD_H + +/* */ +#undef LOG4CPLUS_HAVE_FCNTL_H + +/* */ +#undef LOG4CPLUS_HAVE_STDARG_H + +/* */ +#undef LOG4CPLUS_HAVE_STDIO_H + +/* */ +#undef LOG4CPLUS_HAVE_STDLIB_H + +/* */ +#undef LOG4CPLUS_HAVE_ERRNO_H + +/* */ +#undef LOG4CPLUS_HAVE_WCHAR_H + +/* */ +#undef LOG4CPLUS_HAVE_ICONV_H + +/* */ +#undef LOG4CPLUS_HAVE_LIMITS_H + +/* */ +#undef LOG4CPLUS_HAVE_FTIME + +/* */ +#undef LOG4CPLUS_HAVE_GETADDRINFO + +/* */ +#undef LOG4CPLUS_HAVE_GETHOSTBYNAME_R + +/* */ +#undef LOG4CPLUS_HAVE_GETPID + +/* */ +#undef LOG4CPLUS_HAVE_GMTIME_R + +/* */ +#undef LOG4CPLUS_HAVE_HTONL + +/* */ +#undef LOG4CPLUS_HAVE_HTONS + +/* */ +#undef LOG4CPLUS_HAVE_LOCALTIME_R + +/* */ +#undef LOG4CPLUS_HAVE_LSTAT + +/* */ +#undef LOG4CPLUS_HAVE_FCNTL + +/* */ +#undef LOG4CPLUS_HAVE_LOCKF + +/* */ +#undef LOG4CPLUS_HAVE_FLOCK + +/* */ +#undef LOG4CPLUS_HAVE_NTOHL + +/* */ +#undef LOG4CPLUS_HAVE_NTOHS + +/* Define to 1 if you have the `shutdown' function. */ +#undef LOG4CPLUS_HAVE_SHUTDOWN + +/* */ +#undef LOG4CPLUS_HAVE_PIPE + +/* */ +#undef LOG4CPLUS_HAVE_PIPE2 + +/* */ +#undef LOG4CPLUS_HAVE_POLL + +/* */ +#undef LOG4CPLUS_HAVE_POLL_H + +/* */ +#undef LOG4CPLUS_HAVE_STAT + +/* Define if this is a single-threaded library. */ +#undef LOG4CPLUS_SINGLE_THREADED + +/* */ +#undef LOG4CPLUS_USE_PTHREADS + +/* Define for compilers/standard libraries that support more than just the "C" + locale. */ +#undef LOG4CPLUS_WORKING_LOCALE + +/* Define for C99 compilers/standard libraries that support more than just the + "C" locale. */ +#undef LOG4CPLUS_WORKING_C_LOCALE + +/* Define to int if undefined. */ +#undef socklen_t + +/* Defined for --enable-debugging builds. */ +#undef LOG4CPLUS_DEBUGGING + +/* Defined if the compiler understands __declspec(dllexport) or + __attribute__((visibility("default"))) construct. */ +#undef LOG4CPLUS_DECLSPEC_EXPORT + +/* Defined if the compiler understands __declspec(dllimport) or + __attribute__((visibility("default"))) construct. */ +#undef LOG4CPLUS_DECLSPEC_IMPORT + +/* Defined if the compiler understands + __attribute__((visibility("hidden"))) construct. */ +#undef LOG4CPLUS_DECLSPEC_PRIVATE + +/* */ +#undef LOG4CPLUS_HAVE_TLS_SUPPORT + +/* */ +#undef LOG4CPLUS_THREAD_LOCAL_VAR + +/* Defined if the host OS provides ENAMETOOLONG errno value. */ +#undef LOG4CPLUS_HAVE_ENAMETOOLONG + +/* */ +#undef LOG4CPLUS_HAVE_VSNPRINTF + +/* Define to 1 if you have the `vsnwprintf' function. */ +#undef LOG4CPLUS_HAVE_VSNWPRINTF + +/* Define to 1 if you have the `_vsnwprintf' function. */ +#undef LOG4CPLUS_HAVE__VSNWPRINTF + +/* */ +#undef LOG4CPLUS_HAVE__VSNPRINTF + +/* Define to 1 if you have the `vfprintf_s' function. */ +#undef LOG4CPLUS_HAVE_VFPRINTF_S + +/* Define to 1 if you have the `vfwprintf_s' function. */ +#undef LOG4CPLUS_HAVE_VFWPRINTF_S + +/* Define to 1 if you have the `vsprintf_s' function. */ +#undef LOG4CPLUS_HAVE_VSPRINTF_S + +/* Define to 1 if you have the `vswprintf_s' function. */ +#undef LOG4CPLUS_HAVE_VSWPRINTF_S + +/* Define to 1 if you have the `_vsnprintf_s' function. */ +#undef LOG4CPLUS_HAVE__VSNPRINTF_S + +/* Define to 1 if you have the `_vsnwprintf_s' function. */ +#undef LOG4CPLUS_HAVE__VSNWPRINTF_S + +/* Defined if the compiler supports __FUNCTION__ macro. */ +#undef LOG4CPLUS_HAVE_FUNCTION_MACRO + +/* Defined if the compiler supports __PRETTY_FUNCTION__ macro. */ +#undef LOG4CPLUS_HAVE_PRETTY_FUNCTION_MACRO + +/* Defined if the compiler supports __func__ symbol. */ +#undef LOG4CPLUS_HAVE_FUNC_SYMBOL + +/* Define to 1 if you have the `mbstowcs' function. */ +#undef LOG4CPLUS_HAVE_MBSTOWCS + +/* Define to 1 if you have the `wcstombs' function. */ +#undef LOG4CPLUS_HAVE_WCSTOMBS + +/* Define to 1 if you have Linux style syscall(SYS_gettid). */ +#undef LOG4CPLUS_HAVE_GETTID + +/* Define when iconv() is available. */ +#undef LOG4CPLUS_WITH_ICONV + +/* Define to 1 if you have the `iconv' function. */ +#undef LOG4CPLUS_HAVE_ICONV + +/* Define to 1 if you have the `iconv_close' function. */ +#undef LOG4CPLUS_HAVE_ICONV_CLOSE + +/* Define to 1 if you have the `iconv_open' function. */ +#undef LOG4CPLUS_HAVE_ICONV_OPEN + +/* Define to 1 if you have the `OutputDebugString' function. */ +#undef LOG4CPLUS_HAVE_OUTPUTDEBUGSTRING + +/* Define to 1 if the system has the `constructor' function attribute + with priority */ +#undef LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR_PRIORITY + +/* Define to 1 if the system has the `constructor' function attribute */ +#undef LOG4CPLUS_HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR + +/* Define to 1 if the system has the `init_priority' variable attribute */ +#undef LOG4CPLUS_HAVE_VAR_ATTRIBUTE_INIT_PRIORITY + +/* Defined to enable unit tests. */ +#undef LOG4CPLUS_WITH_UNIT_TESTS + +#endif // LOG4CPLUS_CONFIG_DEFINES_HXX diff --git a/log4cplus/config/macosx.h b/log4cplus/config/macosx.h new file mode 100644 index 0000000..3f793c5 --- /dev/null +++ b/log4cplus/config/macosx.h @@ -0,0 +1,37 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: config-macosx.h +// Created: 7/2003 +// Author: Christopher R. Bailey +// +// +// Copyright 2003-2017 Christopher R. Bailey +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_CONFIG_MACOSX_HEADER_ +#define LOG4CPLUS_CONFIG_MACOSX_HEADER_ + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if (defined(__APPLE__) || (defined(__MWERKS__) && defined(__MACOS__))) + +#define LOG4CPLUS_HAVE_GETTIMEOFDAY 1 +#define socklen_t int + +#endif // MACOSX +#endif // LOG4CPLUS_CONFIG_MACOSX_HEADER_ diff --git a/log4cplus/config/win32.h b/log4cplus/config/win32.h new file mode 100644 index 0000000..5d3a0b4 --- /dev/null +++ b/log4cplus/config/win32.h @@ -0,0 +1,194 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: config-win32.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_CONFIG_WIN32_HEADER_ +#define LOG4CPLUS_CONFIG_WIN32_HEADER_ + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (__MINGW32__) || defined (__MINGW64__) +# include <_mingw.h> +#endif + +#ifdef _WIN32 + +#if (defined (_MSC_VER) && _MSC_VER > 1400) \ + || (defined (__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 3) +# define LOG4CPLUS_HAVE_INTRIN_H +#endif + +// Time related functions and headers. +#define LOG4CPLUS_HAVE_TIME_H +#define LOG4CPLUS_HAVE_SYS_TIMEB_H +#define LOG4CPLUS_HAVE_FTIME +#if defined (_MSC_VER) || defined (__BORLANDC__) +#define LOG4CPLUS_HAVE_GMTIME_S +#endif + +// Use Winsock on Windows. +#define LOG4CPLUS_USE_WINSOCK + +// Enable Win32DebugAppender +#define LOG4CPLUS_HAVE_OUTPUTDEBUGSTRING + +// Enable Win32ConsoleAppender. +#define LOG4CPLUS_HAVE_WIN32_CONSOLE + +#define LOG4CPLUS_HAVE_SYS_TYPES_H +#define LOG4CPLUS_HAVE_SYS_LOCKING_H +#define LOG4CPLUS_HAVE_FCNTL_H +#define LOG4CPLUS_HAVE_IO_H +#define LOG4CPLUS_HAVE_STDIO_H +#define LOG4CPLUS_HAVE_WCHAR_H +#define LOG4CPLUS_HAVE_STDARG_H +#define LOG4CPLUS_HAVE_STDLIB_H +#define LOG4CPLUS_HAVE_ERRNO_H +#define LOG4CPLUS_HAVE_SYS_STAT_H +#define LOG4CPLUS_HAVE_TIME_H +#define LOG4CPLUS_HAVE_STDLIB_H +#define LOG4CPLUS_HAVE_DIRECT_H + +// MSVC has both and so does MinGW. +#define LOG4CPLUS_HAVE_VSNPRINTF +#define LOG4CPLUS_HAVE__VSNPRINTF +#define LOG4CPLUS_HAVE__VSNWPRINTF + +// Limit the use of foo_s() functions to builds using Visual Studio +// 2005 and its run time library. In MinGW land, limit the foo_s() +// functions to MinGw-w64 toolchain and __MSVCRT_VERSION__ >= 0x0900. +#if (defined (_MSC_VER) && _MSC_VER >= 1400) \ + || (defined (__MSVCRT_VERSION__) && __MSVCRT_VERSION__ >= 0x0900 \ + && defined (__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 2) +// MS secure versions of vprintf(). +# define LOG4CPLUS_HAVE_VSPRINTF_S +# define LOG4CPLUS_HAVE_VSWPRINTF_S + +// MS secure versions of vfprintf(). +# define LOG4CPLUS_HAVE_VFPRINTF_S +# define LOG4CPLUS_HAVE_VFWPRINTF_S + +// MS secure versions of vsnprintf(). +# define LOG4CPLUS_HAVE_VSNPRINTF_S +# define LOG4CPLUS_HAVE__VSNPRINTF_S +# define LOG4CPLUS_HAVE__VSNWPRINTF_S + +// MS secure version of _tsopen(). +# define LOG4CPLUS_HAVE__TSOPEN_S +#endif + +#if defined (_MSC_VER) && _MSC_VER >= 1400 +// MS printf-like functions supporting positional parameters. +# define LOG4CPLUS_HAVE__VSPRINTF_P +# define LOG4CPLUS_HAVE__VSWPRINTF_P +#endif + +#if defined (_MSC_VER) +# define LOG4CPLUS_HAVE_LOCALTIME_S +#endif + +#define LOG4CPLUS_HAVE__TSOPEN + +#define LOG4CPLUS_DLLMAIN_HINSTANCE HINSTANCE +#define LOG4CPLUS_HAVE_NT_EVENT_LOG + +// log4cplus_EXPORTS is used by the CMake build system. DLL_EXPORT is +// used by the autotools build system. +#if (defined (log4cplus_EXPORTS) || defined (log4cplusU_EXPORTS) \ + || (defined (DLL_EXPORT) && defined (INSIDE_LOG4CPLUS))) \ + && ! defined (LOG4CPLUS_STATIC) +# undef LOG4CPLUS_BUILD_DLL +# define LOG4CPLUS_BUILD_DLL +#endif + +#if ! defined (LOG4CPLUS_BUILD_DLL) +# undef LOG4CPLUS_STATIC +# define LOG4CPLUS_STATIC +#endif + +#if defined (LOG4CPLUS_STATIC) && defined (LOG4CPLUS_BUILD_DLL) +# error LOG4CPLUS_STATIC and LOG4CPLUS_BUILD_DLL cannot be defined both. +#endif + +#if defined (LOG4CPLUS_BUILD_DLL) +# if defined (INSIDE_LOG4CPLUS) +# define LOG4CPLUS_EXPORT __declspec(dllexport) +# else +# define LOG4CPLUS_EXPORT __declspec(dllimport) +# endif +#else +# define LOG4CPLUS_EXPORT +#endif + +#ifndef LOG4CPLUS_SINGLE_THREADED +# define LOG4CPLUS_USE_WIN32_THREADS +#endif + +#if defined(_MSC_VER) + // Warning about: identifier was truncated to '255' characters in the debug information +# pragma warning( disable : 4786 ) + // Warning about: needs to have dll-interface to be used by clients of class +# pragma warning( disable : 4251 ) + +# define LOG4CPLUS_INLINES_ARE_EXPORTED + +# if _MSC_VER >= 1400 +# define LOG4CPLUS_WORKING_LOCALE +# define LOG4CPLUS_HAVE_FUNCTION_MACRO +# define LOG4CPLUS_HAVE_FUNCSIG_MACRO +# define LOG4CPLUS_ATTRIBUTE_NORETURN __declspec(noreturn) +# endif +#endif + +#if defined (__GNUC__) +# undef LOG4CPLUS_INLINES_ARE_EXPORTED +# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define LOG4CPLUS_HAVE_PRETTY_FUNCTION_MACRO +# define LOG4CPLUS_HAVE_FUNC_SYMBOL +# endif +// This has worked for some versions of MinGW with GCC 4.7+ but it +// appears to be broken again in 4.8.x. Thus, we disable this for GCC +// completely forever. +// +//# define LOG4CPLUS_INLINES_ARE_EXPORTED +# define LOG4CPLUS_HAVE_FUNCTION_MACRO +# if defined (__MINGW32__) +# define LOG4CPLUS_WORKING_C_LOCALE +# endif +#endif + +#if defined (__BORLANDC__) && __BORLANDC__ >= 0x0650 +# define LOG4CPLUS_HAVE_FUNCTION_MACRO +#endif // __BORLANDC__ + +#if ! defined (LOG4CPLUS_DISABLE_DLL_RUNTIME_WARNING) +# if defined (LOG4CPLUS_STATIC) && defined (_MSC_VER) && ! defined (_DLL) +# pragma message("You are not using DLL C run time library. " \ + "You must call log4cplus::initialize() once before " \ + "you use any other log4cplus API.") +# endif +#endif + +#endif // _WIN32 +#endif // LOG4CPLUS_CONFIG_WIN32_HEADER_ diff --git a/log4cplus/config/windowsh-inc-full.h b/log4cplus/config/windowsh-inc-full.h new file mode 100644 index 0000000..bff5925 --- /dev/null +++ b/log4cplus/config/windowsh-inc-full.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: windowsh-inc.h +// Created: 9/2018 +// Author: Vaclav Haisman +// +// +// Copyright (C) 2018, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// NOTE: This file is a fragment intentionally left without include guards. + +#if defined (_WIN32) +#include +#include +#include +#if defined (LOG4CPLUS_HAVE_INTRIN_H) +#include +#endif +#endif + +// NOTE: This file is a fragment intentionally left without include guards. diff --git a/log4cplus/config/windowsh-inc.h b/log4cplus/config/windowsh-inc.h new file mode 100644 index 0000000..0ed1c50 --- /dev/null +++ b/log4cplus/config/windowsh-inc.h @@ -0,0 +1,159 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: windowsh-inc.h +// Created: 4/2010 +// Author: Vaclav Zeman +// +// +// Copyright (C) 2010-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// NOTE: This file is a fragment intentionally left without include guards. + +#if defined (_WIN32) +#undef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN + +#undef NOGDICAPMASKS +#define NOGDICAPMASKS + +#undef NOVIRTUALKEYCODES +#define NOVIRTUALKEYCODES + +#undef NOWINMESSAGES +#define NOWINMESSAGES + +#undef NOWINSTYLES +#define NOWINSTYLES + +#undef NOSYSMETRICS +#define NOSYSMETRICS + +#undef NOMENUS +#define NOMENUS + +#undef NOICONS +#define NOICONS + +#undef NOKEYSTATES +#define NOKEYSTATES + +#undef NOSYSCOMMANDS +#define NOSYSCOMMANDS + +#undef NORASTEROPS +#define NORASTEROPS + +#undef NOSHOWWINDOW +#define NOSHOWWINDOW + +#undef NOATOM +#define NOATOM + +#undef NOCLIPBOARD +#define NOCLIPBOARD + +#undef NOCOLOR +#define NOCOLOR + +#undef NOCTLMGR +#define NOCTLMGR + +#undef NODRAWTEXT +#define NODRAWTEXT + +#undef NOGDI +#define NOGDI + +#undef NOKERNEL +#define NOKERNEL + +#undef NOUSER +#define NOUSER + +#undef NONLS +#define NONLS + +#undef NOMB +#define NOMB + +#undef NOMEMMGR +#define NOMEMMGR + +#undef NOMETAFILE +#define NOMETAFILE + +#undef NOMINMAX +#define NOMINMAX + +#undef NOMSG +#define NOMSG + +#undef NOOPENFILE +#define NOOPENFILE + +#undef NOSCROLL +#define NOSCROLL + +#undef NOSERVICE +#define NOSERVICE + +#undef NOSOUND +#define NOSOUND + +#undef NOTEXTMETRIC +#define NOTEXTMETRIC + +#undef NOWH +#define NOWH + +#undef NOWINOFFSETS +#define NOWINOFFSETS + +#undef NOCOMM +#define NOCOMM + +#undef NOKANJI +#define NOKANJI + +#undef NOHELP +#define NOHELP + +#undef NOPROFILER +#define NOPROFILER + +#undef NODEFERWINDOWPOS +#define NODEFERWINDOWPOS + +#undef NOMCX +#define NOMCX + +#include +#include +#include +#if defined (LOG4CPLUS_HAVE_INTRIN_H) +#include +#endif +#endif + +// NOTE: This file is a fragment intentionally left without include guards. diff --git a/log4cplus/configurator.h b/log4cplus/configurator.h new file mode 100644 index 0000000..0120325 --- /dev/null +++ b/log4cplus/configurator.h @@ -0,0 +1,389 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: configurator.h +// Created: 3/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_CONFIGURATOR_HEADER_ +#define LOG4CPLUS_CONFIGURATOR_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +#include + + +namespace log4cplus +{ + class Hierarchy; + + + /** + * Provides configuration from an external file. See configure() for + * the expected format. + * + * All option values admit variable substitution. For + * example, if userhome environment property is set to + * /home/xyz and the File option is set to the string + * ${userhome}/test.log, then File option will be + * interpreted as the string /home/xyz/test.log. + * + * The syntax of variable substitution is similar to that of UNIX + * shells. The string between an opening "${" and + * closing "}" is interpreted as a key. Its value is + * searched in the environment properties. The corresponding value replaces + * the ${variableName} sequence. + * + * Configuration files also recognize include + * file.properties directive that allow composing + * configuration from multiple files. There is no cyclic includes + * detection mechanism to stop unbound recursion. + */ + class LOG4CPLUS_EXPORT PropertyConfigurator + { + public: + enum PCFlags + { + fRecursiveExpansion = (1 << 0) + , fShadowEnvironment = (1 << 1) + , fAllowEmptyVars = (1 << 2) + + // These encoding related options occupy 2 bits of the flags + // and are mutually exclusive. These flags are synchronized with + // PFlags in Properties. + + , fEncodingShift = 3 + , fEncodingMask = 0x3 + , fUnspecEncoding = (0 << fEncodingShift) +#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE) + , fUTF8 = (1 << fEncodingShift) +#endif +#if (defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) || defined (_WIN32)) \ + && defined (UNICODE) + , fUTF16 = (2 << fEncodingShift) +#endif +#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE) + , fUTF32 = (3 << fEncodingShift) +#endif + , fThrow = (1 << 5) + }; + + // ctor and dtor + PropertyConfigurator(const log4cplus::tstring& propertyFile, + Hierarchy& h = Logger::getDefaultHierarchy(), unsigned flags = 0); + PropertyConfigurator(const log4cplus::helpers::Properties& props, + Hierarchy& h = Logger::getDefaultHierarchy(), unsigned flags = 0); + PropertyConfigurator(log4cplus::tistream& propertyStream, + Hierarchy& h = Logger::getDefaultHierarchy(), unsigned flags = 0); + virtual ~PropertyConfigurator(); + + /** + * This method eliminates the need to create a temporary + * PropertyConfigurator to configure log4cplus. + * It is equivalent to the following:
+ * + * PropertyConfigurator config("filename"); + * config.configure(); + * + */ + static void doConfigure(const log4cplus::tstring& configFilename, + Hierarchy& h = Logger::getDefaultHierarchy(), unsigned flags = 0); + + /** + * Read configuration from a file. The existing configuration is + * not cleared nor reset. If you require a different behavior, + * then call {@link Hierarchy::resetConfiguration + * resetConfiguration} method before calling + * doConfigure. + * + * The configuration file consists of statements in the format + * key=value. The syntax of different configuration + * elements are discussed below. + * + *

Appender configuration

+ * + * Appender configuration syntax is: + *
+         * # For appender named appenderName, set its class.
+         * # Note: The appender name can contain dots.
+         * log4cplus.appender.appenderName=fully.qualified.name.of.appender.class
+         *
+         * # Set appender specific options.
+         * log4cplus.appender.appenderName.option1=value1
+         * ...
+         * log4cplus.appender.appenderName.optionN=valueN
+         * 
+ * + * For each named appender you can configure its {@link Layout}. The + * syntax for configuring an appender's layout is: + *
+         * log4cplus.appender.appenderName.layout=fully.qualified.name.of.layout.class
+         * log4cplus.appender.appenderName.layout.option1=value1
+         * ....
+         * log4cplus.appender.appenderName.layout.optionN=valueN
+         * 
+ * + *

Configuring loggers

+ * + * The syntax for configuring the root logger is: + *
+         * log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...
+         * 
+ * + * This syntax means that an optional LogLevel value can + * be supplied followed by appender names separated by commas. + * + * The LogLevel value can consist of the string values FATAL, + * ERROR, WARN, INFO, DEBUG or a custom LogLevel value. + * + * If a LogLevel value is specified, then the root LogLevel is set + * to the corresponding LogLevel. If no LogLevel value is specified, + * then the root LogLevel remains untouched. + * + * The root logger can be assigned multiple appenders. + * + * Each appenderName (separated by commas) will be added to + * the root logger. The named appender is defined using the + * appender syntax defined above. + * + * For non-root loggers the syntax is almost the same: + *
+         * log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...
+         * 
+ * + * The meaning of the optional LogLevel value is discussed above + * in relation to the root logger. In addition however, the value + * INHERITED can be specified meaning that the named logger should + * inherit its LogLevel from the logger hierarchy. + * + * By default loggers inherit their LogLevel from the + * hierarchy. However, if you set the LogLevel of a logger and + * later decide that that logger should inherit its LogLevel, then + * you should specify INHERITED as the value for the LogLevel value. + * + * Similar to the root logger syntax, each appenderName + * (separated by commas) will be attached to the named logger. + * + * See the appender + * additivity rule in the user manual for the meaning of the + * additivity flag. + * + * The user can override any of the {@link + * Hierarchy#disable} family of methods by setting the a key + * "log4cplus.disableOverride" to true or any value other + * than false. As in
log4cplus.disableOverride=true 
+ * + *

Global configuration

+ * + *
    + *
  • Property
    log4cplus.threadPoolSize
    can be used to adjust + * size of log4cplus' internal thread pool.
  • + *
  • Property
    log4cplus.threadPoolBlockOnFull
    can be + * used to change behaviour of the thread pool when its queue is full. + * The default value is
    true
    , to block the thread until + * there is a space in the queue. Setting this property to + *
    false
    makes the thread pool not to block when it is full. + * The items that could not be inserted are dropped instead.
  • + *
  • Property
    log4cplus.threadPoolQueueSizeLimit
    can be used to + * set thread pool queue size limit.
  • + *
+ * + *

Example

+ * + * An example configuration is given below. + * + *
+         *
+         * # Set options for appender named "A1".
+         * # Appender "A1" will be a SyslogAppender
+         * log4cplus.appender.A1=log4cplus::SyslogAppender
+         *
+         * # The syslog daemon resides on www.abc.net
+         * log4cplus.appender.A1.SyslogHost=www.abc.net
+         *
+         * # A1's layout is a PatternLayout, using the conversion pattern
+         * # %r %-5p %c{2} %M.%L %x - %m\n. Thus, the log output will
+         * # include # the relative time since the start of the application in
+         * # milliseconds, followed by the LogLevel of the log request,
+         * # followed by the two rightmost components of the logger name,
+         * # followed by the callers method name, followed by the line number,
+         * # the nested disgnostic context and finally the message itself.
+         * # Refer to the documentation of {@link PatternLayout} for further information
+         * # on the syntax of the ConversionPattern key.
+         * log4cplus.appender.A1.layout=log4cplus::PatternLayout
+         * log4cplus.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
+         *
+         * # Set options for appender named "A2"
+         * # A2 should be a RollingFileAppender, with maximum file size of 10 MB
+         * # using at most one backup file. A2's layout is TTCC, using the
+         * # ISO8061 date format with context printing enabled.
+         * log4cplus.appender.A2=log4cplus::RollingFileAppender
+         * log4cplus.appender.A2.MaxFileSize=10MB
+         * log4cplus.appender.A2.MaxBackupIndex=1
+         * log4cplus.appender.A2.layout=log4cplus::TTCCLayout
+         * log4cplus.appender.A2.layout.ContextPrinting=true
+         * log4cplus.appender.A2.layout.DateFormat=ISO8601
+         *
+         * # Root logger set to DEBUG using the A2 appender defined above.
+         * log4cplus.rootLogger=DEBUG, A2
+         *
+         * # Logger definitions:
+         * # The SECURITY logger inherits is LogLevel from root. However, it's output
+         * # will go to A1 appender defined above. It's additivity is non-cumulative.
+         * log4cplus.logger.SECURITY=INHERIT, A1
+         * log4cplus.additivity.SECURITY=false
+         *
+         * # Only warnings or above will be logged for the logger "SECURITY.access".
+         * # Output will go to A1.
+         * log4cplus.logger.SECURITY.access=WARN
+         *
+         *
+         * # The logger "class.of.the.day" inherits its LogLevel from the
+         * # logger hierarchy.  Output will go to the appender's of the root
+         * # logger, A2 in this case.
+         * log4cplus.logger.class.of.the.day=INHERIT
+         * 
+ * + * Refer to the setOption method in each Appender and + * Layout for class specific options. + * + * Use the # character at the beginning of a line + * for comments. + */ + virtual void configure(); + + /** + * \return The return value is reference to Properties + * container of properties with the "log4cplus." + * prefix removed and references to other properties and/or + * environment variables expanded. + */ + log4cplus::helpers::Properties const & getProperties () const; + + /** + * \return The return value is a reference to log4cplus::tstring + * containing filename of properties source file. It will be + * string "UNAVAILABLE" if the PropertyConfigurator instance has been + * constructed using one of the other constructors that do not take + * filename as parameter. + */ + log4cplus::tstring const & getPropertyFilename () const; + + protected: + // Methods + void init(); // called by the ctor + void reconfigure(); + void replaceEnvironVariables(); + void configureLoggers(); + void configureLogger(log4cplus::Logger logger, const log4cplus::tstring& config); + void configureAppenders(); + void configureAdditivity(); + + virtual Logger getLogger(const log4cplus::tstring& name); + virtual void addAppender(Logger &logger, log4cplus::SharedAppenderPtr& appender); + + // Types + typedef std::map AppenderMap; + + // Data + Hierarchy& h; + log4cplus::tstring propertyFilename; + log4cplus::helpers::Properties properties; + AppenderMap appenders; + unsigned flags; + + private: + // Disable copy + PropertyConfigurator(const PropertyConfigurator&); + PropertyConfigurator& operator=(PropertyConfigurator&); + }; + + + + /** + * Use this class to quickly configure the package. For file based + * configuration see PropertyConfigurator. BasicConfigurator + * automatically attaches ConsoleAppender to + * rootLogger, with output going to standard output, + * using DEBUG LogLevel value. The additional parameter + * logToStdErr may redirect the output to standard error. + */ + class LOG4CPLUS_EXPORT BasicConfigurator : public PropertyConfigurator { + public: + // ctor and dtor + BasicConfigurator(Hierarchy& h = Logger::getDefaultHierarchy(), + bool logToStdErr = false); + virtual ~BasicConfigurator(); + + /** + * This method eliminates the need to create a temporary + * BasicConfigurator object to configure log4cplus. + * It is equivalent to the following:
+ *
+         * BasicConfigurator config;
+         * config.configure();
+         * 
+ */ + static void doConfigure(Hierarchy& h = Logger::getDefaultHierarchy(), + bool logToStdErr = false); + + //! Property name for disable override. + static log4cplus::tstring const DISABLE_OVERRIDE_KEY; + + private: + // Disable copy + BasicConfigurator(const BasicConfigurator&); + BasicConfigurator& operator=(BasicConfigurator&); + }; + + +#if !defined(LOG4CPLUS_SINGLE_THREADED) + // Forward Declarations + class ConfigurationWatchDogThread; + + + class LOG4CPLUS_EXPORT ConfigureAndWatchThread { + public: + // ctor and dtor + ConfigureAndWatchThread(const log4cplus::tstring& propertyFile, + unsigned int millis = 60 * 1000); + virtual ~ConfigureAndWatchThread(); + + private: + // Disallow copying of instances of this class + ConfigureAndWatchThread(const ConfigureAndWatchThread&); + ConfigureAndWatchThread& operator=(const ConfigureAndWatchThread&); + + // Data + ConfigurationWatchDogThread * watchDogThread; + }; +#endif + +} // end namespace log4cplus + +#endif // LOG4CPLUS_CONFIGURATOR_HEADER_ diff --git a/log4cplus/consoleappender.h b/log4cplus/consoleappender.h new file mode 100644 index 0000000..3da24c8 --- /dev/null +++ b/log4cplus/consoleappender.h @@ -0,0 +1,105 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: consoleappender.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_CONSOLE_APPENDER_HEADER_ +#define LOG4CPLUS_CONSOLE_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +namespace log4cplus { + /** + * ConsoleAppender appends log events to std::cout or + * std::cerr using a layout specified by the + * user. The default target is std::cout. + * + *

Properties

+ *
+ *
logToStdErr
+ *
When it is set true, the output stream will be + * std::cerr instead of std::cout.
+ * + *
ImmediateFlush
+ *
When it is set true, output stream will be flushed after + * each appended event.
+ * + *
Locale
+ *
This property specifies a locale name that will be imbued + * into output stream. Locale can be specified either by system + * specific locale name, e.g., en_US.UTF-8, or by one of + * four recognized keywords: GLOBAL, DEFAULT + * (which is an alias for GLOBAL), USER and + * CLASSIC. When specified locale is not available, + * GLOBAL is used instead. It is possible to register + * additional locale keywords by registering an instance of + * spi::LocaleFactory in + * spi::LocaleFactoryRegistry. + * \sa spi::getLocaleFactoryRegistry(). + * + * Note: if Locale is set, ImmediateFlush will + * be set to true automatically. + *
+ * + *
+ * \sa Appender + */ + class LOG4CPLUS_EXPORT ConsoleAppender : public Appender { + public: + // Ctors + ConsoleAppender(bool logToStdErr = false, bool immediateFlush = false); + ConsoleAppender(const log4cplus::helpers::Properties & properties); + + // Dtor + ~ConsoleAppender(); + + // Methods + virtual void close(); + + //! This mutex is used by ConsoleAppender and helpers::LogLog + //! classes to synchronize output to console. + static log4cplus::thread::Mutex const & getOutputMutex(); + + protected: + virtual void append(const spi::InternalLoggingEvent& event); + + // Data + bool logToStdErr; + /** + * Immediate flush means that the underlying output stream + * will be flushed at the end of each append operation. + */ + bool immediateFlush; + + std::unique_ptr locale; + }; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_CONSOLE_APPENDER_HEADER_ + diff --git a/log4cplus/exception.h b/log4cplus/exception.h new file mode 100644 index 0000000..7531edb --- /dev/null +++ b/log4cplus/exception.h @@ -0,0 +1,56 @@ +// Copyright (C) 2023, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_EXCEPTION_HXX +#define LOG4CPLUS_EXCEPTION_HXX + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus +{ + +/** + * \brief Exception class thrown by LogLog. + * \sa helpers::LogLog + * + */ +class LOG4CPLUS_EXPORT exception : public std::runtime_error +{ +public: + exception (tstring const &); + exception (exception const &); + exception & operator=(exception const &); + virtual ~exception (); +}; + +} // namespace log4cplus + +#endif // LOG4CPLUS_EXCEPTION_HXX \ No newline at end of file diff --git a/log4cplus/fileappender.h b/log4cplus/fileappender.h new file mode 100644 index 0000000..36f6d35 --- /dev/null +++ b/log4cplus/fileappender.h @@ -0,0 +1,428 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: fileappender.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_FILE_APPENDER_HEADER_ +#define LOG4CPLUS_FILE_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + + +namespace log4cplus +{ + + /** + * Base class for Appenders writing log events to a file. + * It is constructed with uninitialized file object, so all + * classes derived from FileAppenderBase _must_ call init() method. + * + *

Properties

+ *
+ *
File
+ *
This property specifies output file name.
+ * + *
ImmediateFlush
+ *
When it is set true, output stream will be flushed after + * each appended event.
+ * + *
Append
+ *
When it is set true, output file will be appended to + * instead of being truncated at opening.
+ * + *
ReopenDelay
+ *
This property sets a delay after which the appender will try + * to reopen log file again, after last logging failure. + *
+ * + *
BufferSize
+ *
Non-zero value of this property sets up buffering of output + * stream using a buffer of given size. + *
+ * + *
UseLockFile
+ *
Set this property to true if you want your output + * to go into a log file shared by multiple processes. When this + * property is set to true then log4cplus uses OS specific + * facilities (e.g., lockf()) to provide + * inter-process file locking. + * \sa Appender + *
+ * + *
LockFile
+ *
This property specifies lock file, file used for + * inter-process synchronization of log file access. When this + * property is not specified, the value is derived from + * File property by addition of ".lock" suffix. The + * property is only used when UseLockFile is set to true. + * \sa Appender + *
+ * + *
Locale
+ *
This property specifies a locale name that will be imbued + * into output stream. Locale can be specified either by system + * specific locale name, e.g., en_US.UTF-8, or by one of + * four recognized keywords: GLOBAL, DEFAULT + * (which is an alias for GLOBAL), USER and + * CLASSIC. When specified locale is not available, + * GLOBAL is used instead. It is possible to register + * additional locale keywords by registering an instance of + * spi::LocaleFactory in + * spi::LocaleFactoryRegistry. + * \sa spi::getLocaleFactoryRegistry() + *
+ * + *
CreateDirs
+ *
Set this property to true if you want to create + * missing directories in path leading to log file and lock file. + *
+ * + *
TextMode
+ *
Set this property to Binary if the underlying stream should + * not translate EOLs to OS specific character sequence. The default value + * is Text and the underlying stream will be opened in text + * mode.
+ *
+ */ + class LOG4CPLUS_EXPORT FileAppenderBase : public Appender { + public: + // Methods + virtual void close(); + + //! Redefine default locale for output stream. It may be a good idea to + //! provide UTF-8 locale in case UNICODE macro is defined. + virtual std::locale imbue(std::locale const& loc); + + //! \returns Locale imbued in fstream. + virtual std::locale getloc () const; + + protected: + // Ctors + FileAppenderBase(const log4cplus::tstring& filename, + std::ios_base::openmode mode = std::ios_base::trunc, + bool immediateFlush = true, + bool createDirs = false); + FileAppenderBase(const log4cplus::helpers::Properties& properties, + std::ios_base::openmode mode = std::ios_base::trunc); + + void init(); + + virtual void append(const spi::InternalLoggingEvent& event); + + virtual void open(std::ios_base::openmode mode); + bool reopen(); + + // Data + /** + * Immediate flush means that the underlying writer or output stream + * will be flushed at the end of each append operation. Immediate + * flush is slower but ensures that each append request is actually + * written. If immediateFlush is set to + * false, then there is a good chance that the last few + * logs events are not actually written to persistent media if and + * when the application crashes. + * + * The immediateFlush variable is set to + * true by default. + */ + bool immediateFlush; + + /** + * When this variable is true, FileAppender will try to create + * missing directories in path leading to log file. + * + * The `createDirs` variable is set to `false` by default. + */ + bool createDirs; + + /** + * When any append operation fails, reopenDelay says + * for how many seconds the next attempt to re-open the log file and + * resume logging will be delayed. If reopenDelay is zero, + * each failed append operation will cause log file to be re-opened. + * By default, reopenDelay is 1 second. + */ + int reopenDelay; + + unsigned long bufferSize; + std::unique_ptr buffer; + + log4cplus::tofstream out; + log4cplus::tstring filename; + log4cplus::tstring localeName; + log4cplus::tstring lockFileName; + std::ios_base::openmode fileOpenMode; + + log4cplus::helpers::Time reopen_time; + + private: + // Disallow copying of instances of this class + FileAppenderBase(const FileAppenderBase&); + FileAppenderBase& operator=(const FileAppenderBase&); + }; + + + /** + * Appends log events to a file. + * + *

Properties

+ *

It has no properties additional to {@link FileAppenderBase}. + */ + class LOG4CPLUS_EXPORT FileAppender : public FileAppenderBase { + public: + // Ctors + FileAppender(const log4cplus::tstring& filename, + std::ios_base::openmode mode = std::ios_base::trunc, + bool immediateFlush = true, + bool createDirs = false); + FileAppender(const log4cplus::helpers::Properties& properties, + std::ios_base::openmode mode = std::ios_base::trunc); + + // Dtor + virtual ~FileAppender(); + + protected: + void init(); + }; + + typedef helpers::SharedObjectPtr SharedFileAppenderPtr; + + + + /** + * RollingFileAppender extends FileAppender to backup the log + * files when they reach a certain size. + * + *

Properties

+ *

Properties additional to {@link FileAppender}'s properties: + * + *

+ *
MaxFileSize
+ *
This property specifies maximal size of output file. The + * value is in bytes. It is possible to use MB and + * KB suffixes to specify the value in megabytes or + * kilobytes instead.
+ * + *
MaxBackupIndex
+ *
This property limits the number of backup output + * files; e.g. how many log.1, log.2 etc. files + * will be kept.
+ *
+ */ + class LOG4CPLUS_EXPORT RollingFileAppender : public FileAppender { + public: + // Ctors + RollingFileAppender(const log4cplus::tstring& filename, + long maxFileSize = 10*1024*1024, // 10 MB + int maxBackupIndex = 1, + bool immediateFlush = true, + bool createDirs = false); + RollingFileAppender(const log4cplus::helpers::Properties& properties); + + // Dtor + virtual ~RollingFileAppender(); + + protected: + virtual void append(const spi::InternalLoggingEvent& event); + void rollover(bool alreadyLocked = false); + + // Data + long maxFileSize; + int maxBackupIndex; + + private: + LOG4CPLUS_PRIVATE void init(long maxFileSize, int maxBackupIndex); + }; + + + typedef helpers::SharedObjectPtr + SharedRollingFileAppenderPtr; + + + enum DailyRollingFileSchedule { MONTHLY, WEEKLY, DAILY, + TWICE_DAILY, HOURLY, MINUTELY}; + + /** + * DailyRollingFileAppender extends {@link FileAppender} so that the + * underlying file is rolled over at a user chosen frequency. + * + *

Properties

+ *

Properties additional to {@link FileAppender}'s properties: + * + *

+ *
Schedule
+ *
This property specifies rollover schedule. The possible + * values are MONTHLY, WEEKLY, DAILY, + * TWICE_DAILY, HOURLY and + * MINUTELY.
+ * + *
MaxBackupIndex
+ *
This property limits how many backup files are kept per + * single logging period; e.g. how many log.2009-11-07.1, + * log.2009-11-07.2 etc. files are kept.
+ * + *
RollOnClose
+ *
This property specifies whether to rollover log files upon + * shutdown. By default it's set to true to retain compatibility + * with legacy code, however it may lead to undesired behaviour + * as described in the github issue #120.
+ * + *
DatePattern
+ *
This property specifies filename suffix pattern to use for + * periodical backups of the logfile. The patern should be in + * format supported by {@link log4cplus::helpers::Time::getFormatterTime()}. + * Please notice that the format of the pattern is similar but not identical + * to the one used for this option in the corresponding Log4J class. + * If the property isn't specified a reasonable default for a given + * schedule type is used.
+ * + *
+ */ + class LOG4CPLUS_EXPORT DailyRollingFileAppender : public FileAppender { + public: + // Ctors + DailyRollingFileAppender(const log4cplus::tstring& filename, + DailyRollingFileSchedule schedule = DAILY, + bool immediateFlush = true, + int maxBackupIndex = 10, + bool createDirs = false, + bool rollOnClose = true, + const log4cplus::tstring& datePattern = log4cplus::tstring()); + DailyRollingFileAppender(const log4cplus::helpers::Properties& properties); + + // Dtor + virtual ~DailyRollingFileAppender(); + + // Methods + virtual void close(); + + protected: + virtual void append(const spi::InternalLoggingEvent& event); + void rollover(bool alreadyLocked = false); + log4cplus::helpers::Time calculateNextRolloverTime(const log4cplus::helpers::Time& t) const; + log4cplus::tstring getFilename(const log4cplus::helpers::Time& t) const; + + // Data + DailyRollingFileSchedule schedule; + log4cplus::tstring scheduledFilename; + log4cplus::helpers::Time nextRolloverTime; + int maxBackupIndex; + bool rollOnClose; + log4cplus::tstring datePattern; + + private: + LOG4CPLUS_PRIVATE void init(DailyRollingFileSchedule schedule); + }; + + typedef helpers::SharedObjectPtr + SharedDailyRollingFileAppenderPtr; + + + /** + * TimeBasedRollingFileAppender extends {@link FileAppenderBase} so that + * the underlying file is rolled over at a user chosen frequency while also + * keeping in check a total maximum number of produced files. + * + *

Properties

+ *

Properties additional to {@link FileAppenderBase}'s properties: + * + *

+ * + *
FilenamePattern
+ *
The mandatory fileNamePattern property defines the name of the + * rolled-over (archived) log files. Its value should consist of the name + * of the file, plus a suitably placed %d conversion specifier. The %d + * conversion specifier may contain a date-and-time pattern as specified by + * the java's SimpleDateFormat. The rollover period is inferred from the + * value of fileNamePattern.
+ * + *
MaxHistory
+ *
The optional maxHistory property controls the maximum number of + * archive files to keep, deleting older files.
+ * + *
CleanHistoryOnStart
+ *
If set to true, archive removal will be executed on appender start + * up. By default this property is set to false.
+ * + *
RollOnClose
+ *
This property specifies whether to rollover log files upon + * shutdown. By default it's set to true to retain compatibility + * with legacy code, however it may lead to undesired behaviour + * as described in the github issue #120.
+ * + *
+ */ + class LOG4CPLUS_EXPORT TimeBasedRollingFileAppender : public FileAppenderBase { + public: + // Ctors + TimeBasedRollingFileAppender(const tstring& filename = LOG4CPLUS_TEXT(""), + const tstring& filenamePattern = LOG4CPLUS_TEXT("%d.log"), + int maxHistory = 10, + bool cleanHistoryOnStart = false, + bool immediateFlush = true, + bool createDirs = false, + bool rollOnClose = true); + TimeBasedRollingFileAppender(const helpers::Properties& properties); + + // Dtor + ~TimeBasedRollingFileAppender(); + + protected: + void append(const spi::InternalLoggingEvent& event); + void open(std::ios_base::openmode mode); + void close(); + void rollover(bool alreadyLocked = false); + void clean(helpers::Time time); + helpers::Time::duration getRolloverPeriodDuration() const; + helpers::Time calculateNextRolloverTime(const helpers::Time& t) const; + + // Data + tstring filenamePattern; + DailyRollingFileSchedule schedule; + tstring scheduledFilename; + int maxHistory; + bool cleanHistoryOnStart; + log4cplus::helpers::Time lastHeartBeat; + log4cplus::helpers::Time nextRolloverTime; + bool rollOnClose; + + private: + LOG4CPLUS_PRIVATE void init(); + }; + + typedef helpers::SharedObjectPtr + SharedTimeBasedRollingFileAppenderPtr; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_FILE_APPENDER_HEADER_ diff --git a/log4cplus/fstreams.h b/log4cplus/fstreams.h new file mode 100644 index 0000000..a7dcd66 --- /dev/null +++ b/log4cplus/fstreams.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: fstreams.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_FSTREAMS_HEADER_ +#define LOG4CPLUS_FSTREAMS_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus +{ + + +typedef std::basic_ofstream tofstream; +typedef std::basic_ifstream tifstream; + +//! \def LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(X) +//! \brief Expands into expression that picks the right type for +//! std::fstream file name parameter. +#if defined (LOG4CPLUS_FSTREAM_ACCEPTS_WCHAR_T) && defined (UNICODE) +# define LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(X) (X) +#else +# define LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(X) (LOG4CPLUS_TSTRING_TO_STRING(X)) +#endif + + +} + +#endif // LOG4CPLUS_FSTREAMS_HEADER_ diff --git a/log4cplus/helpers/appenderattachableimpl.h b/log4cplus/helpers/appenderattachableimpl.h new file mode 100644 index 0000000..52ed096 --- /dev/null +++ b/log4cplus/helpers/appenderattachableimpl.h @@ -0,0 +1,119 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: appenderattachableimpl.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_APPENDER_ATTACHABLE_IMPL_HEADER_ +#define LOG4CPLUS_HELPERS_APPENDER_ATTACHABLE_IMPL_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +#include +#include + + +namespace log4cplus { + namespace helpers { + + /** + * This Interface is for attaching Appenders to objects. + */ + class LOG4CPLUS_EXPORT AppenderAttachableImpl + : public log4cplus::spi::AppenderAttachable + { + public: + // Data + thread::Mutex appender_list_mutex; + + // Ctors + AppenderAttachableImpl(); + + // Dtor + virtual ~AppenderAttachableImpl(); + + // Methods + /** + * Add an appender. If the appender is already in the list in + * won't be added again. + */ + virtual void addAppender(SharedAppenderPtr newAppender); + + /** + * Get all previously added appenders as an vectory. + */ + virtual SharedAppenderPtrList getAllAppenders(); + + /** + * Look for an attached appender named as name. + * + * Return the appender with that name if in the list. Return null + * otherwise. + */ + virtual SharedAppenderPtr getAppender(const log4cplus::tstring& name); + + /** + * Remove all previously added appenders. + */ + virtual void removeAllAppenders(); + + /** + * Remove the appender passed as parameter from the list of appenders. + */ + virtual void removeAppender(SharedAppenderPtr appender); + + /** + * Remove the appender with the name passed as parameter from the + * list of appenders. + */ + virtual void removeAppender(const log4cplus::tstring& name); + + /** + * Call the doAppend method on all attached appenders. + */ + int appendLoopOnAppenders(const spi::InternalLoggingEvent& event) const; + + protected: + // Types + typedef std::vector ListType; + + // Data + /** Array of appenders. */ + ListType appenderList; + + private: + AppenderAttachableImpl(AppenderAttachableImpl const &); + AppenderAttachableImpl & operator = (AppenderAttachableImpl const &); + }; // end class AppenderAttachableImpl + + } // end namespace helpers +} // end namespace log4cplus + +#endif // LOG4CPLUS_HELPERS_APPENDER_ATTACHABLE_IMPL_HEADER_ + diff --git a/log4cplus/helpers/connectorthread.h b/log4cplus/helpers/connectorthread.h new file mode 100644 index 0000000..6df3ce5 --- /dev/null +++ b/log4cplus/helpers/connectorthread.h @@ -0,0 +1,107 @@ +// -*- C++ -*- +// Copyright (C) 2013-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_HELPERS_CONNECTORTHREAD_H +#define LOG4CPLUS_HELPERS_CONNECTORTHREAD_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + +namespace log4cplus { namespace helpers { + + +class LOG4CPLUS_EXPORT ConnectorThread; + +//! Interface implemented by users of ConnectorThread. +class LOG4CPLUS_EXPORT IConnectorThreadClient +{ +protected: + virtual ~IConnectorThreadClient (); + + //! \return Mutex for synchronization between ConnectorThread and + //! its client object. This is usually SharedObject::access_mutex. + virtual thread::Mutex const & ctcGetAccessMutex () const = 0; + + //! \return Socket variable in ConnectorThread client to maintain. + virtual helpers::Socket & ctcGetSocket () = 0; + + //! \return ConnectorThread client's function returning connected + //! socket. + virtual helpers::Socket ctcConnect () = 0; + + //! Sets connected flag to true in ConnectorThread's client. + virtual void ctcSetConnected () = 0; + + friend class LOG4CPLUS_EXPORT ConnectorThread; +}; + + +//! This class is used by SocketAppender and (remote) SysLogAppender +//! to provide asynchronous re-connection. +class LOG4CPLUS_EXPORT ConnectorThread + : public thread::AbstractThread +{ +public: + //! \param client reference to ConnectorThread's client object + ConnectorThread (IConnectorThreadClient & client); + virtual ~ConnectorThread (); + + virtual void run(); + + //! Call this function to terminate ConnectorThread. The function + //! sets `exit_flag` and then triggers `trigger_ev` to wake up the + //! ConnectorThread. + void terminate (); + + //! This function triggers (`trigger_ev`) connection check and + //! attempt to re-connect a broken connection, when necessary. + void trigger (); + +protected: + //! reference to ConnectorThread's client + IConnectorThreadClient & ctc; + + //! This event is the re-connection trigger. + thread::ManualResetEvent trigger_ev; + + //! When this variable set to true when ConnectorThread is signaled to + bool exit_flag; +}; + + +} } // namespace log4cplus { namespace helpers { + +#endif // ! defined (LOG4CPLUS_SINGLE_THREADED) + +#endif // LOG4CPLUS_HELPERS_CONNECTORTHREAD_H diff --git a/log4cplus/helpers/eventcounter.h b/log4cplus/helpers/eventcounter.h new file mode 100644 index 0000000..be9f192 --- /dev/null +++ b/log4cplus/helpers/eventcounter.h @@ -0,0 +1,91 @@ +// -*- C++ -*- +// +// Copyright (C) 2024, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_HELPERS_EVENTCOUNTER_H +#define LOG4CPLUS_HELPERS_EVENTCOUNTER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + + +namespace log4cplus { + +namespace helpers { + +class LOG4CPLUS_EXPORT BaseEventCounter +{ +public: + BaseEventCounter (); + virtual ~BaseEventCounter (); + + virtual std::size_t record_event (); + +protected: + std::atomic event_count {0}; +}; + + +class LOG4CPLUS_EXPORT SteadyClockGate + : public BaseEventCounter +{ +public: + using Clock = std::chrono::steady_clock; + using Duration = Clock::duration; + using TimePoint = std::chrono::time_point; + + struct LOG4CPLUS_EXPORT Info + { + ~Info (); + + std::size_t count; + Duration time_span; + }; + + SteadyClockGate (SteadyClockGate::Duration pause_duraiton); + virtual ~SteadyClockGate (); + + bool latch_open (Info &); + +private: + log4cplus::thread::SimpleMutex mtx; + Duration const pause_duration; + TimePoint timeout_point; + TimePoint prev_timeout_point; +}; + + +} // namespace helpers + +} // namespace log4cplus + +#endif // LOG4CPLUS_HELPERS_EVENTCOUNTER_H diff --git a/log4cplus/helpers/fileinfo.h b/log4cplus/helpers/fileinfo.h new file mode 100644 index 0000000..88004ee --- /dev/null +++ b/log4cplus/helpers/fileinfo.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +// +// Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#if ! defined (LOG4CPLUS_HELPERS_FILEINFO_H) +#define LOG4CPLUS_HELPERS_FILEINFO_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#ifdef LOG4CPLUS_HAVE_SYS_TYPES_H +#include +#endif + + +namespace log4cplus { namespace helpers { + +//! FileInfo structure is OS independent abstraction of the +//! stat() function. +struct LOG4CPLUS_EXPORT FileInfo +{ + helpers::Time mtime; + bool is_link; + off_t size; +}; + + +//! OS independent abstraction of stat() function. +LOG4CPLUS_EXPORT int getFileInfo (FileInfo * fi, tstring const & name); + + +} } // namespace log4cplus { namespace helpers { + +#endif // LOG4CPLUS_HELPERS_FILEINFO_H diff --git a/log4cplus/helpers/lockfile.h b/log4cplus/helpers/lockfile.h new file mode 100644 index 0000000..3856dcd --- /dev/null +++ b/log4cplus/helpers/lockfile.h @@ -0,0 +1,69 @@ +// -*- C++ -*- +// +// Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#if ! defined (LOG4CPLUS_HELPERS_LOCKFILE_H) +#define LOG4CPLUS_HELPERS_LOCKFILE_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus { namespace helpers { + + +class LOG4CPLUS_EXPORT LockFile +{ +public: + LockFile (tstring const & lock_file, bool create_dirs = false); + ~LockFile (); + + void lock () const; + void unlock () const; + +private: + void open (int) const; + void close () const; + + struct Impl; + + tstring lock_file_name; + Impl * data; + bool create_dirs; +}; + + +typedef log4cplus::thread::SyncGuard LockFileGuard; + + +} } // namespace log4cplus { namespace helpers { + + +#endif // LOG4CPLUS_HELPERS_LOCKFILE_H diff --git a/log4cplus/helpers/loglog.h b/log4cplus/helpers/loglog.h new file mode 100644 index 0000000..4f92ef8 --- /dev/null +++ b/log4cplus/helpers/loglog.h @@ -0,0 +1,145 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loglog.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_LOGLOG +#define LOG4CPLUS_HELPERS_LOGLOG + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + + +namespace log4cplus { + namespace helpers { + + /** + * This class used to output log statements from within the log4cplus package. + * + * Log4cplus components cannot make log4cplus logging calls. However, it is + * sometimes useful for the user to learn about what log4cplus is + * doing. You can enable log4cplus internal logging by defining the + * log4cplus.configDebug variable. + * + * All log4cplus internal debug calls go to cout + * where as internal error messages are sent to + * cerr. All internal messages are prepended with + * the string "log4clus: ". + */ + class LOG4CPLUS_EXPORT LogLog + { + public: + //! Return type of getLogLog(). + typedef LogLog * Ptr; + + /** + * Returns a reference to the LogLog singleton. + */ + static Ptr getLogLog(); + + + /** + * Allows to enable/disable log4cplus internal logging. + */ + void setInternalDebugging(bool enabled); + + /** + * In quite mode no LogLog generates strictly no output, not even + * for errors. + * + * @param quietMode A true for not + */ + void setQuietMode(bool quietMode); + + /** + * This method is used to output log4cplus internal debug + * statements. Output goes to std::cout. + */ + void debug(const log4cplus::tstring& msg) const; + void debug(tchar const * msg) const; + + /** + * This method is used to output log4cplus internal error + * statements. There is no way to disable error + * statements. Output goes to + * std::cerr. Optionally, this method can + * throw std::runtime_error exception too. + */ + void error(const log4cplus::tstring& msg, bool throw_flag = false) const; + void error(tchar const * msg, bool throw_flag = false) const; + + /** + * This method is used to output log4cplus internal warning + * statements. There is no way to disable warning statements. + * Output goes to std::cerr. + */ + void warn(const log4cplus::tstring& msg) const; + void warn(tchar const * msg) const; + + // Public ctor and dtor to be used only by internal::DefaultContext. + LogLog(); + virtual ~LogLog(); + + private: + enum TriState + { + TriUndef = -1, + TriFalse, + TriTrue + }; + + template + LOG4CPLUS_PRIVATE + void logging_worker (tostream & os, + bool (LogLog:: * cond) () const, tchar const *, + StringType const &, bool throw_flag = false) const; + + LOG4CPLUS_PRIVATE static void set_tristate_from_env (TriState *, + tchar const * envvar); + + LOG4CPLUS_PRIVATE bool get_quiet_mode () const; + LOG4CPLUS_PRIVATE bool get_not_quiet_mode () const; + LOG4CPLUS_PRIVATE bool get_debug_mode () const; + + // Data + mutable TriState debugEnabled; + mutable TriState quietMode; + thread::Mutex mutex; + + LOG4CPLUS_PRIVATE LogLog(const LogLog&); + LOG4CPLUS_PRIVATE LogLog & operator = (LogLog const &); + }; + + LOG4CPLUS_EXPORT LogLog & getLogLog (); + + } // end namespace helpers +} // end namespace log4cplus + + +#endif // LOG4CPLUS_HELPERS_LOGLOG + diff --git a/log4cplus/helpers/pointer.h b/log4cplus/helpers/pointer.h new file mode 100644 index 0000000..d9ccfd4 --- /dev/null +++ b/log4cplus/helpers/pointer.h @@ -0,0 +1,210 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: pointer.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// Note: Some of this code uses ideas from "More Effective C++" by Scott +// Myers, Addison Wesley Longmain, Inc., (c) 1996, Chapter 29, pp. 183-213 +// + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_POINTERS_HEADER_ +#define LOG4CPLUS_HELPERS_POINTERS_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#if ! defined (LOG4CPLUS_SINGLE_THREADED) +#include +#endif + + +namespace log4cplus { + namespace helpers { + + /****************************************************************************** + * Class SharedObject (from pp. 204-205) * + ******************************************************************************/ + + class LOG4CPLUS_EXPORT SharedObject + { + public: + void addReference() const LOG4CPLUS_NOEXCEPT; + void removeReference() const; + + protected: + // Ctor + SharedObject() + : access_mutex() + , count__(0) + { } + + SharedObject(const SharedObject&) + : access_mutex() + , count__(0) + { } + + SharedObject(SharedObject &&) + : access_mutex() + , count__(0) + { } + + // Dtor + virtual ~SharedObject(); + + // Operators + SharedObject& operator=(const SharedObject&) LOG4CPLUS_NOEXCEPT { return *this; } + SharedObject& operator=(SharedObject &&) LOG4CPLUS_NOEXCEPT { return *this; } + + public: + thread::Mutex access_mutex; + + private: +#if defined (LOG4CPLUS_SINGLE_THREADED) + typedef unsigned count_type; +#else + typedef std::atomic count_type; +#endif + mutable count_type count__; + }; + + + /****************************************************************************** + * Template Class SharedObjectPtr (from pp. 203, 206) * + ******************************************************************************/ + template + class SharedObjectPtr + { + public: + // Ctor + explicit + SharedObjectPtr(T* realPtr = 0) LOG4CPLUS_NOEXCEPT + : pointee(realPtr) + { + addref (); + } + + SharedObjectPtr(const SharedObjectPtr& rhs) LOG4CPLUS_NOEXCEPT + : pointee(rhs.pointee) + { + addref (); + } + + SharedObjectPtr(SharedObjectPtr && rhs) LOG4CPLUS_NOEXCEPT + : pointee (std::move (rhs.pointee)) + { + rhs.pointee = 0; + } + + SharedObjectPtr & operator = (SharedObjectPtr && rhs) LOG4CPLUS_NOEXCEPT + { + rhs.swap (*this); + return *this; + } + + // Dtor + ~SharedObjectPtr() + { + if (pointee) + pointee->removeReference(); + } + + // Operators + bool operator==(const SharedObjectPtr& rhs) const + { return (pointee == rhs.pointee); } + bool operator!=(const SharedObjectPtr& rhs) const + { return (pointee != rhs.pointee); } + bool operator==(const T* rhs) const { return (pointee == rhs); } + bool operator!=(const T* rhs) const { return (pointee != rhs); } + T* operator->() const {assert (pointee); return pointee; } + T& operator*() const {assert (pointee); return *pointee; } + + SharedObjectPtr& operator=(const SharedObjectPtr& rhs) + { + return this->operator = (rhs.pointee); + } + + SharedObjectPtr& operator=(T* rhs) + { + SharedObjectPtr (rhs).swap (*this); + return *this; + } + + // Methods + T* get() const { return pointee; } + + void swap (SharedObjectPtr & other) LOG4CPLUS_NOEXCEPT + { + std::swap (pointee, other.pointee); + } + + typedef T * (SharedObjectPtr:: * unspec_bool_type) () const; + operator unspec_bool_type () const + { + return pointee ? &SharedObjectPtr::get : 0; + } + + bool operator ! () const + { + return ! pointee; + } + + private: + // Methods + void addref() const LOG4CPLUS_NOEXCEPT + { + if (pointee) + pointee->addReference(); + } + + // Data + T* pointee; + }; + + + //! Boost `intrusive_ptr` helpers. + //! @{ + inline + void + intrusive_ptr_add_ref (SharedObject const * so) + { + so->addReference(); + } + + inline + void + intrusive_ptr_release (SharedObject const * so) + { + so->removeReference(); + } + //! @} + + } // end namespace helpers +} // end namespace log4cplus + + +#endif // LOG4CPLUS_HELPERS_POINTERS_HEADER_ diff --git a/log4cplus/helpers/property.h b/log4cplus/helpers/property.h new file mode 100644 index 0000000..fa81bc3 --- /dev/null +++ b/log4cplus/helpers/property.h @@ -0,0 +1,172 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: property.h +// Created: 2/2002 +// Author: Tad E. Smith +// +// +// Copyright 2002-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_PROPERTY_HEADER_ +#define LOG4CPLUS_HELPERS_PROPERTY_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + + +namespace log4cplus { + namespace helpers { + + //! \sa log4cplus::PropertyConfigurator + class LOG4CPLUS_EXPORT Properties { + public: + enum PFlags + { + // These encoding related options occupy 2 bits of the flags + // and are mutually exclusive. These flags are synchronized + // with PCFlags in PropertyConfigurator. + + fEncodingShift = 3 + , fEncodingMask = 0x3 + , fUnspecEncoding = (0 << fEncodingShift) +#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE) + , fUTF8 = (1 << fEncodingShift) +#endif +#if (defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) || defined (_WIN32)) \ + && defined (UNICODE) + , fUTF16 = (2 << fEncodingShift) +#endif +#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE) + , fUTF32 = (3 << fEncodingShift) +#endif + , fThrow = (1 << 5) + }; + + Properties(); + explicit Properties(log4cplus::tistream& input); + explicit Properties(const log4cplus::tstring& inputFile, unsigned flags = 0); + virtual ~Properties(); + + // constants + static const tchar PROPERTIES_COMMENT_CHAR; + + // methods + /** + * Tests to see if key can be found in this map. + */ + bool exists(const log4cplus::tstring& key) const; + bool exists(tchar const * key) const; + + /** + * Returns the number of entries in this map. + */ + std::size_t size() const + { + return data.size(); + } + + /** + * Searches for the property with the specified key in this property + * list. If the key is not found in this property list, the default + * property list, and its defaults, recursively, are then checked. + * The method returns null if the property is not found. + */ + log4cplus::tstring const & getProperty(const log4cplus::tstring& key) const; + log4cplus::tstring const & getProperty(tchar const * key) const; + + /** + * Searches for the property with the specified key in this property + * list. If the key is not found in this property list, the default + * property list, and its defaults, recursively, are then checked. + * The method returns the default value argument if the property is + * not found. + */ + log4cplus::tstring getProperty(const log4cplus::tstring& key, + const log4cplus::tstring& defaultVal) const; + + /** + * Returns all the keys in this property list. + */ + std::vector propertyNames() const; + + /** + * Inserts value into this map indexed by key. + */ + void setProperty(const log4cplus::tstring& key, const log4cplus::tstring& value); + + /** + * Removed the property index by key from this map. + */ + bool removeProperty(const log4cplus::tstring& key); + + /** + * Returns a subset of the "properties" whose keys start with + * "prefix". The returned "properties" have "prefix" trimmed from + * their keys. + */ + Properties getPropertySubset(const log4cplus::tstring& prefix) const; + + bool getInt (int & val, log4cplus::tstring const & key) const; + bool getUInt (unsigned & val, log4cplus::tstring const & key) const; + bool getLong (long & val, log4cplus::tstring const & key) const; + bool getULong (unsigned long & val, log4cplus::tstring const & key) const; + bool getBool (bool & val, log4cplus::tstring const & key) const; + bool getString (log4cplus::tstring & val, log4cplus::tstring const & key) const; + + protected: + // Types + typedef std::map StringMap; + + // Methods + void init(log4cplus::tistream& input); + + // Data + StringMap data; + unsigned flags; + + private: + template + log4cplus::tstring const & get_property_worker ( + StringType const & key) const; + + template + bool get_type_val_worker (ValType & val, + log4cplus::tstring const & key) const; + }; + + + class LogLog; + + + bool + substVars (tstring & dest, const tstring & val, + Properties const & props, LogLog& loglog, + unsigned flags); + } // end namespace helpers + +} + + +#endif // LOG4CPLUS_HELPERS_PROPERTY_HEADER_ diff --git a/log4cplus/helpers/queue.h b/log4cplus/helpers/queue.h new file mode 100644 index 0000000..113d695 --- /dev/null +++ b/log4cplus/helpers/queue.h @@ -0,0 +1,158 @@ +// -*- C++ -*- +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_HELPERS_QUEUE_H +#define LOG4CPLUS_HELPERS_QUEUE_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + +#include +#include +#include +#include + + +namespace log4cplus { namespace thread { + + +//! Single consumer, multiple producers queue. +class LOG4CPLUS_EXPORT Queue + : public virtual helpers::SharedObject +{ +public: + //! Type of the state flags field. + typedef unsigned flags_type; + + //! Queue storage type. + typedef std::deque queue_storage_type; + + explicit Queue (unsigned len = 100); + virtual ~Queue (); + + // Producers' methods. + + //! Puts event ev into queue, sets QUEUE flag and + //! sets internal event object into signaled state. If the EXIT + //! flags is already set upon entering the function, nothing is + //! inserted into the queue. The function can block on internal + //! semaphore if the queue has reached maximal allowed + //! length. Calling thread is unblocked either by consumer thread + //! removing item from queue or by any other thread calling + //! signal_exit(). + //! + //! \param ev spi::InternalLoggingEvent to be put into the queue. + //! \return Flags. + flags_type put_event (spi::InternalLoggingEvent const & ev); + + //! Sets EXIT flag and DRAIN flag and sets internal event object + //! into signaled state. + //! \param drain If true, DRAIN flag will be set, otherwise unset. + //! \return Flags, ERROR_BIT can be set upon error. + flags_type signal_exit (bool drain = true); + + // Consumer's methods. + + //! The get_events() function is used by queue's consumer. It + //! fills buf argument and sets EVENT flag in return + //! value. If EXIT flag is already set in flags member upon + //! entering the function then depending on DRAIN flag it either + //! fills buf argument or does not fill the argument, + //! if the queue is non-empty. The function blocks by waiting for + //! internal event object to be signaled if the queue is empty, + //! unless EXIT flag is set. The calling thread is unblocked when + //! items are added into the queue or when exit is signaled using + //! the signal_exit() function. + //! + //! + //! Upon error, return value has one of the error flags set. + //! + //! \param buf Pointer to storage of spi::InternalLoggingEvent + //! instances to be filled from queue. + //! \return Flags. + flags_type get_events (queue_storage_type * buf); + + //! Possible state flags. + enum Flags + { + //! EVENT flag is set in return value of get_event() call if + //! the ev argument is filled with event from the queue. + EVENT = 0x0001, + + //! QUEUE flag is set by producers when they put item into the + //! queue. + QUEUE = 0x0002, + + //! EXIT flag is set by signal_exit() call, signaling that the + //! queue worker thread should end itself. + EXIT = 0x0004, + + //! When DRAIN flag is set together with EXIT flag, the queue + //! worker thread will first drain the queue before exiting. + DRAIN = 0x0008, + + //! ERROR_BIT signals error. + ERROR_BIT = 0x0010, + + //! ERROR_AFTER signals error that has occurred after queue has + //! already been touched. + ERROR_AFTER = 0x0020 + }; + +protected: + //! Queue storage. + queue_storage_type queue; + + //! Mutex protecting queue and flags. + Mutex mutex; + + //! Event on which consumer can wait if it finds queue empty. + ManualResetEvent ev_consumer; + + //! Semaphore that limits the queue length. + Semaphore sem; + + //! State flags. + flags_type flags; + +private: + Queue (Queue const &); + Queue & operator = (Queue const &); +}; + + +typedef helpers::SharedObjectPtr QueuePtr; + + +} } // namespace log4cplus { namespace thread { + + +#endif // LOG4CPLUS_SINGLE_THREADED + +#endif // LOG4CPLUS_HELPERS_QUEUE_H diff --git a/log4cplus/helpers/snprintf.h b/log4cplus/helpers/snprintf.h new file mode 100644 index 0000000..bf56935 --- /dev/null +++ b/log4cplus/helpers/snprintf.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_HELPERS_SNPRINTF_H +#define LOG4CPLUS_HELPERS_SNPRINTF_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + + +namespace log4cplus { namespace helpers { + + +class LOG4CPLUS_EXPORT snprintf_buf +{ +public: + snprintf_buf (); + + tchar const * print (tchar const * fmt, ...) + LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 2, 3); + + int print_va_list (tchar const * & str, tchar const * fmt, std::va_list) + LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 0); + +private: + std::vector buf; +}; + + +} } // namespace log4cplus { namespace helpers + + + +#endif // LOG4CPLUS_HELPERS_SNPRINTF_H diff --git a/log4cplus/helpers/socket.h b/log4cplus/helpers/socket.h new file mode 100644 index 0000000..1924bfe --- /dev/null +++ b/log4cplus/helpers/socket.h @@ -0,0 +1,163 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: socket.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_SOCKET_HEADER_ +#define LOG4CPLUS_HELPERS_SOCKET_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include +#include + + +namespace log4cplus { + namespace helpers { + + enum SocketState { ok, + not_opened, + bad_address, + connection_failed, + broken_pipe, + invalid_access_mode, + message_truncated, + accept_interrupted + }; + + typedef std::ptrdiff_t SOCKET_TYPE; + + extern LOG4CPLUS_EXPORT SOCKET_TYPE const INVALID_SOCKET_VALUE; + + class LOG4CPLUS_EXPORT AbstractSocket { + public: + AbstractSocket(); + AbstractSocket(SOCKET_TYPE sock, SocketState state, int err); + AbstractSocket(AbstractSocket const &) = delete; + AbstractSocket(AbstractSocket &&) LOG4CPLUS_NOEXCEPT; + virtual ~AbstractSocket() = 0; + + /// Close socket + virtual void close(); + virtual bool isOpen() const; + virtual void shutdown(); + AbstractSocket & operator = (AbstractSocket && rhs) LOG4CPLUS_NOEXCEPT; + + void swap (AbstractSocket &); + + protected: + SOCKET_TYPE sock; + SocketState state; + int err; + }; + + + + /** + * This class implements client sockets (also called just "sockets"). + * A socket is an endpoint for communication between two machines. + */ + class LOG4CPLUS_EXPORT Socket : public AbstractSocket { + public: + // ctor and dtor + Socket(); + Socket(SOCKET_TYPE sock, SocketState state, int err); + Socket(const tstring& address, unsigned short port, + bool udp = false, bool ipv6 = false); + Socket(Socket &&) LOG4CPLUS_NOEXCEPT; + virtual ~Socket(); + + Socket & operator = (Socket &&) LOG4CPLUS_NOEXCEPT; + + // methods + virtual bool read(SocketBuffer& buffer); + virtual bool write(const SocketBuffer& buffer); + virtual bool write(const std::string & buffer); + virtual bool write(std::size_t bufferCount, + SocketBuffer const * const * buffers); + + template + static bool write(Socket & socket, Args &&... args) + { + SocketBuffer const * const buffers[sizeof... (args)] { + (&args)... }; + return socket.write (sizeof... (args), buffers); + } + }; + + + + /** + * This class implements server sockets. A server socket waits for + * requests to come in over the network. It performs some operation + * based on that request, and then possibly returns a result to the + * requester. + */ + class LOG4CPLUS_EXPORT ServerSocket : public AbstractSocket { + public: + ServerSocket(unsigned short port, bool udp = false, + bool ipv6 = false, tstring const & host = tstring ()); + ServerSocket(ServerSocket &&) LOG4CPLUS_NOEXCEPT; + virtual ~ServerSocket(); + + ServerSocket & operator = (ServerSocket &&) LOG4CPLUS_NOEXCEPT; + + Socket accept(); + void interruptAccept (); + void swap (ServerSocket &); + + protected: + std::array interruptHandles; + }; + + + LOG4CPLUS_EXPORT SOCKET_TYPE openSocket(unsigned short port, bool udp, + bool ipv6, SocketState& state); + LOG4CPLUS_EXPORT SOCKET_TYPE openSocket(tstring const & host, + unsigned short port, bool udp, bool ipv6, SocketState& state); + + LOG4CPLUS_EXPORT SOCKET_TYPE connectSocket(const log4cplus::tstring& hostn, + unsigned short port, bool udp, bool ipv6, SocketState& state); + LOG4CPLUS_EXPORT SOCKET_TYPE acceptSocket(SOCKET_TYPE sock, SocketState& state); + LOG4CPLUS_EXPORT int closeSocket(SOCKET_TYPE sock); + LOG4CPLUS_EXPORT int shutdownSocket(SOCKET_TYPE sock); + + LOG4CPLUS_EXPORT long read(SOCKET_TYPE sock, SocketBuffer& buffer); + LOG4CPLUS_EXPORT long write(SOCKET_TYPE sock, + const SocketBuffer& buffer); + LOG4CPLUS_EXPORT long write(SOCKET_TYPE sock, std::size_t bufferCount, + SocketBuffer const * const * buffers); + LOG4CPLUS_EXPORT long write(SOCKET_TYPE sock, + const std::string & buffer); + + LOG4CPLUS_EXPORT tstring getHostname (bool fqdn); + LOG4CPLUS_EXPORT int setTCPNoDelay (SOCKET_TYPE, bool); + + } // end namespace helpers +} // end namespace log4cplus + +#endif // LOG4CPLUS_HELPERS_SOCKET_HEADER_ diff --git a/log4cplus/helpers/socketbuffer.h b/log4cplus/helpers/socketbuffer.h new file mode 100644 index 0000000..d58b643 --- /dev/null +++ b/log4cplus/helpers/socketbuffer.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: socketbuffer.h +// Created: 5/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_SOCKET_BUFFER_HEADER_ +#define LOG4CPLUS_HELPERS_SOCKET_BUFFER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +namespace log4cplus { +namespace helpers { + +/** + * + */ +class LOG4CPLUS_EXPORT SocketBuffer +{ +public: + explicit SocketBuffer(std::size_t max); + virtual ~SocketBuffer(); + + char *getBuffer() const { return buffer; } + std::size_t getMaxSize() const { return maxsize; } + std::size_t getSize() const { return size; } + void setSize(std::size_t s) { size = s; } + std::size_t getPos() const { return pos; } + + unsigned char readByte(); + unsigned short readShort(); + unsigned int readInt(); + tstring readString(unsigned char sizeOfChar); + + void appendByte(unsigned char val); + void appendShort(unsigned short val); + void appendInt(unsigned int val); + void appendString(const tstring& str); + void appendBuffer(const SocketBuffer& buffer); + +private: + // Data + std::size_t maxsize; + std::size_t size; + std::size_t pos; + char *buffer; + + SocketBuffer(SocketBuffer const & rhs); + SocketBuffer& operator= (SocketBuffer const& rhs); +}; + +} // end namespace helpers +} // end namespace log4cplus + +#endif // LOG4CPLUS_HELPERS_SOCKET_HEADER_ diff --git a/log4cplus/helpers/stringhelper.h b/log4cplus/helpers/stringhelper.h new file mode 100644 index 0000000..ee825c3 --- /dev/null +++ b/log4cplus/helpers/stringhelper.h @@ -0,0 +1,271 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: stringhelper.h +// Created: 3/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_STRINGHELPER_HEADER_ +#define LOG4CPLUS_HELPERS_STRINGHELPER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include +#include + + +namespace log4cplus { + namespace helpers { + + /** + * Returns s in upper case. + */ + LOG4CPLUS_EXPORT log4cplus::tstring toUpper(const log4cplus::tstring& s); + LOG4CPLUS_EXPORT tchar toUpper(tchar); + + + /** + * Returns s in lower case. + */ + LOG4CPLUS_EXPORT log4cplus::tstring toLower(const log4cplus::tstring& s); + LOG4CPLUS_EXPORT tchar toLower(tchar); + + + /** + * Tokenize s using c as the delimiter and + * put the resulting tokens in _result. If + * collapseTokens is false, multiple adjacent delimiters + * will result in zero length tokens. + * + * Example: + *
+         *   string s = // Set string with '.' as delimiters
+         *   list tokens;
+         *   tokenize(s, '.', back_insert_iterator >(tokens));
+         * 
+ */ + template + inline + void + tokenize(const StringType& s, typename StringType::value_type c, + OutputIter result, bool collapseTokens = true) + { + typedef typename StringType::size_type size_type; + size_type const slen = s.length(); + size_type first = 0; + size_type i = 0; + for (i=0; i < slen; ++i) + { + if (s[i] == c) + { + *result = StringType (s, first, i - first); + ++result; + if (collapseTokens) + while (i+1 < slen && s[i+1] == c) + ++i; + first = i + 1; + } + } + if (first != i) + *result = StringType (s, first, i - first); + else if (! collapseTokens && first == i) + *result = StringType (); + } + + + template + struct ConvertIntegerToStringHelper; + + + template + struct ConvertIntegerToStringHelper + { + static inline + void + step1 (charType * & it, intType & value) + { + // The sign of the result of the modulo operator is + // implementation defined. That's why we work with + // positive counterpart instead. Also, in twos + // complement arithmetic the smallest negative number + // does not have positive counterpart; the range is + // asymetric. That's why we handle the case of value + // == min() specially here. + if (LOG4CPLUS_UNLIKELY ( + value == (std::numeric_limits::min) ())) + { + intType const r = value / 10; + intType const a = (-r) * 10; + intType const mod = -(a + value); + value = -r; + + *(it - 1) + = static_cast(LOG4CPLUS_TEXT('0') + mod); + --it; + } + else + value = -value; + } + + static + bool + is_negative (intType val) + { + return val < 0; + } + }; + + + template + struct ConvertIntegerToStringHelper + { + static inline + void + step1 (charType * &, intType &) + { + // This will never be called for unsigned types. + } + + static + bool + is_negative (intType) + { + return false; + } + }; + + + template + inline + void + convertIntegerToString (stringType & str, intType value) + { + typedef std::numeric_limits intTypeLimits; + typedef typename stringType::value_type charType; + typedef ConvertIntegerToStringHelper HelperType; + + charType buffer[intTypeLimits::digits10 + 2]; + const std::size_t buffer_size + = sizeof (buffer) / sizeof (charType); + + charType * it = &buffer[buffer_size]; + charType const * const buf_end = &buffer[buffer_size]; + + if (LOG4CPLUS_UNLIKELY (value == 0)) + { + --it; + *it = LOG4CPLUS_TEXT('0'); + } + else + { + bool const negative = HelperType::is_negative (value); + if (negative) + HelperType::step1 (it, value); + + for (; value != 0; --it) + { + intType mod = value % 10; + value = value / 10; + *(it - 1) = static_cast(LOG4CPLUS_TEXT('0') + + mod); + } + + if (negative) + { + --it; + *it = LOG4CPLUS_TEXT('-'); + } + } + + str.assign (static_cast(it), buf_end); + } + + + template + inline + tstring + convertIntegerToString (intType value) + { + tstring result; + convertIntegerToString (result, value); + return result; + } + + + template + inline + std::string + convertIntegerToNarrowString (intType value) + { + std::string result; + convertIntegerToString (result, value); + return result; + } + + + //! Join a list of items into a string. + template + inline + void + join_worker (tstring & result, Iterator & start, Iterator & last, + Separator const & sep) + { + if (start != last) + result = *start++; + + for (; start != last; ++start) + { + result += sep; + result += *start; + } + } + + //! Join a list of items into a string. + template + inline + void + join (tstring & result, Iterator start, Iterator last, + tstring const & sep) + { + join_worker (result, start, last, sep); + } + + //! Join a list of items into a string. + template + inline + void + join (tstring & result, Iterator start, Iterator last, + tstring::value_type sep) + { + join_worker (result, start, last, sep); + } + + + } // namespace helpers + +} // namespace log4cplus + +#endif // LOG4CPLUS_HELPERS_STRINGHELPER_HEADER_ diff --git a/log4cplus/helpers/thread-config.h b/log4cplus/helpers/thread-config.h new file mode 100644 index 0000000..0d89762 --- /dev/null +++ b/log4cplus/helpers/thread-config.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: thread-config.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_THREAD_CONFIG_HEADER_ +#define LOG4CPLUS_HELPERS_THREAD_CONFIG_HEADER_ + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (LOG4CPLUS_USE_PTHREADS) +# if defined (__APPLE__) +# define LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE +# endif + +#elif defined(LOG4CPLUS_USE_WIN32_THREADS) +# define LOG4CPLUS_USE_SRW_LOCK +//# define LOG4CPLUS_POOR_MANS_SHAREDMUTEX +# undef LOG4CPLUS_HAVE_TLS_SUPPORT +# undef LOG4CPLUS_THREAD_LOCAL_VAR +# if defined (_MSC_VER) +// The __declspec(thread) functionality is not compatible with LoadLibrary(). +// For more information why see and "Windows and TLS" note in README. +// . +# define LOG4CPLUS_HAVE_TLS_SUPPORT 1 +# define LOG4CPLUS_THREAD_LOCAL_VAR __declspec(thread) +# endif + +#elif defined(LOG4CPLUS_SINGLE_THREADED) +# undef LOG4CPLUS_HAVE_TLS_SUPPORT +# undef LOG4CPLUS_THREAD_LOCAL_VAR + +#else +# error "You Must define a Threading model" + +#endif + + +#endif // LOG4CPLUS_HELPERS_THREAD_CONFIG_HEADER_ diff --git a/log4cplus/helpers/timehelper.h b/log4cplus/helpers/timehelper.h new file mode 100644 index 0000000..40f3b42 --- /dev/null +++ b/log4cplus/helpers/timehelper.h @@ -0,0 +1,169 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: timehelper.h +// Created: 6/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HELPERS_TIME_HELPER_HEADER_ +#define LOG4CPLUS_HELPERS_TIME_HELPER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#if defined (LOG4CPLUS_HAVE_TIME_H) +#include +#endif + +#include +#include + + +namespace log4cplus { + +namespace helpers { + + +using std::time_t; +using std::tm; +namespace chrono = std::chrono; + +typedef chrono::system_clock Clock; +typedef chrono::duration Duration; +typedef chrono::time_point Time; + + +template +inline +Time +time_cast (chrono::time_point const & tp) +{ + return chrono::time_point_cast (tp); +} + + +inline +Time +now () +{ + return time_cast (Clock::now ()); +} + + +inline +Time +from_time_t (time_t t_time) +{ + return time_cast (Clock::from_time_t (t_time)); +} + + +inline +time_t +to_time_t (Time const & the_time) +{ + // This is based on . It is + // possible that to_time_t() returns rounded time and we want truncation. + + time_t time = Clock::to_time_t (the_time); + auto const rounded_time = from_time_t (time); + if (rounded_time > the_time) + --time; + + return time; +} + + +LOG4CPLUS_EXPORT Time from_struct_tm (tm * t); + + +inline +Time +truncate_fractions (Time const & the_time) +{ + return from_time_t (to_time_t (the_time)); +} + + +inline +long +microseconds_part (Time const & the_time) +{ + static_assert ((std::ratio_equal::value), + "microseconds"); + + // This is based on + return static_cast( + (the_time - from_time_t (to_time_t (the_time))).count ()); +} + + +inline +Time +time_from_parts (time_t tv_sec, long tv_usec) +{ + return from_time_t (tv_sec) + chrono::microseconds (tv_usec); +} + + +/** + * Populates tm using the gmtime() + * function. + */ + +LOG4CPLUS_EXPORT +void gmTime (tm* t, Time const &); + +/** + * Populates tm using the localtime() + * function. + */ + +LOG4CPLUS_EXPORT +void localTime (tm* t, Time const &); + +/** + * Returns a string with a "formatted time" specified by + * fmt. It used the strftime() + * function to do this. + * + * Look at your platform's strftime() documentation + * for the formatting options available. + * + * The following additional options are provided:
+ * %q - 3 character field that provides milliseconds + * %Q - 7 character field that provides fractional + * milliseconds. + */ +LOG4CPLUS_EXPORT +log4cplus::tstring getFormattedTime (log4cplus::tstring const & fmt, + Time const & the_time, bool use_gmtime = false); + + +} // namespace helpers + +} // namespace log4cplus + + +#endif // LOG4CPLUS_HELPERS_TIME_HELPER_HEADER_ diff --git a/log4cplus/hierarchy.h b/log4cplus/hierarchy.h new file mode 100644 index 0000000..80cb23c --- /dev/null +++ b/log4cplus/hierarchy.h @@ -0,0 +1,324 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: hierarchy.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HIERARCHY_HEADER_ +#define LOG4CPLUS_HIERARCHY_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include + + +namespace log4cplus { + // Forward Declarations + class HierarchyLocker; + + /** + * This class is specialized in retrieving loggers by name and + * also maintaining the logger hierarchy. + * + * The casual user should not have to deal with this class + * directly. However, if you are in an environment where + * multiple applications run in the same process, then read on. + * + * The structure of the logger hierarchy is maintained by the + * {@link #getInstance} method. The hierarchy is such that children + * link to their parent but parents do not have any pointers to their + * children. Moreover, loggers can be instantiated in any order, in + * particular descendant before ancestor. + * + * In case a descendant is created before a particular ancestor, + * then it creates a provision node for the ancestor and adds itself + * to the provision node. Other descendants of the same ancestor add + * themselves to the previously created provision node. + */ + class LOG4CPLUS_EXPORT Hierarchy + { + public: + // DISABLE_OFF should be set to a value lower than all possible + // priorities. + static const LogLevel DISABLE_OFF; + static const LogLevel DISABLE_OVERRIDE; + + // Ctors + /** + * Create a new Logger hierarchy. + */ + Hierarchy(); + + // Dtor + virtual ~Hierarchy(); + + // Methods + /** + * This call will clear all logger definitions from the internal + * hashtable. Invoking this method will irrevocably mess up the + * logger hierarchy. + * + * You should really know what you are doing before + * invoking this method. + */ + virtual void clear(); + + /** + * Returns true if the named logger exists + * (in the default hierarchy). + * + * @param name The name of the logger to search for. + */ + virtual bool exists(const log4cplus::tstring& name); + + /** + * Similar to {@link #disable(LogLevel)} except that the LogLevel + * argument is given as a log4cplus::tstring. + */ + virtual void disable(const log4cplus::tstring& loglevelStr); + + /** + * Disable all logging requests of LogLevel equal to or + * below the ll parameter p, for + * all loggers in this hierarchy. Logging requests of + * higher LogLevel then p remain unaffected. + * + * Nevertheless, if the + * BasicConfigurator::DISABLE_OVERRIDE_KEY property is set to + * true, then logging requests are evaluated as usual. + * + * The "disable" family of methods are there for speed. They + * allow printing methods such as debug, info, etc. to return + * immediately after an integer comparison without walking the + * logger hierarchy. In most modern computers an integer + * comparison is measured in nanoseconds where as a logger walk is + * measured in units of microseconds. + */ + virtual void disable(LogLevel ll); + + /** + * Disable all logging requests regardless of logger and LogLevel. + * This method is equivalent to calling {@link #disable} with the + * argument FATAL_LOG_LEVEL, the highest possible LogLevel. + */ + virtual void disableAll(); + + /** + * Disable all Debug logging requests regardless of logger. + * This method is equivalent to calling {@link #disable} with the + * argument DEBUG_LOG_LEVEL. + */ + virtual void disableDebug(); + + /** + * Disable all Info logging requests regardless of logger. + * This method is equivalent to calling {@link #disable} with the + * argument INFO_LOG_LEVEL. + */ + virtual void disableInfo(); + + /** + * Undoes the effect of calling any of {@link #disable}, {@link + * #disableAll}, {@link #disableDebug} and {@link #disableInfo} + * methods. More precisely, invoking this method sets the Logger + * class internal variable called disable to its + * default "off" value. + */ + virtual void enableAll(); + + /** + * Return a new logger instance named as the first parameter using + * the default factory. + * + * If a logger of that name already exists, then it will be + * returned. Otherwise, a new logger will be instantiated and + * then linked with its existing ancestors as well as children. + * + * @param name The name of the logger to retrieve. + */ + virtual Logger getInstance(const log4cplus::tstring& name); + + /** + * Return a new logger instance named as the first parameter using + * factory. + * + * If a logger of that name already exists, then it will be + * returned. Otherwise, a new logger will be instantiated by the + * factory parameter and linked with its existing + * ancestors as well as children. + * + * @param name The name of the logger to retrieve. + * @param factory The factory that will make the new logger instance. + */ + virtual Logger getInstance(const log4cplus::tstring& name, spi::LoggerFactory& factory); + + /** + * Returns all the currently defined loggers in this hierarchy. + * + * The root logger is not included in the returned list. + */ + virtual LoggerList getCurrentLoggers(); + + /** + * Is the LogLevel specified by level enabled? + */ + virtual bool isDisabled(LogLevel level); + + /** + * Get the root of this hierarchy. + */ + virtual Logger getRoot() const; + + /** + * Reset all values contained in this hierarchy instance to their + * default. This removes all appenders from all loggers, sets + * the LogLevel of all non-root loggers to NOT_SET_LOG_LEVEL, + * sets their additivity flag to true and sets the LogLevel + * of the root logger to DEBUG_LOG_LEVEL. Moreover, message disabling + * is set its default "off" value. + * + * Existing loggers are not removed. They are just reset. + * + * This method should be used sparingly and with care as it will + * block all logging until it is completed.

+ */ + virtual void resetConfiguration(); + + /** + * Set the default LoggerFactory instance. + */ + virtual void setLoggerFactory(std::unique_ptr factory); + + /** + * Returns the default LoggerFactory instance. + */ + virtual spi::LoggerFactory* getLoggerFactory(); + + /** + * Shutting down a hierarchy will safely close and remove + * all appenders in all loggers including the root logger. + * + * Some appenders such as SocketAppender need to be closed before the + * application exits. Otherwise, pending logging events might be + * lost. + * + * The shutdown method is careful to close nested + * appenders before closing regular appenders. This is allows + * configurations where a regular appender is attached to a logger + * and again to a nested appender. + */ + virtual void shutdown(); + + private: + // Types + typedef std::vector ProvisionNode; + typedef std::map ProvisionNodeMap; + typedef std::map LoggerMap; + + // Methods + /** + * This is the implementation of the getInstance() method. + * NOTE: This method does not lock the hashtable_mutex. + */ + LOG4CPLUS_PRIVATE + Logger getInstanceImpl(const log4cplus::tstring& name, + spi::LoggerFactory& factory); + + /** + * This is the implementation of the getCurrentLoggers(). + * NOTE: This method does not lock the hashtable_mutex. + */ + LOG4CPLUS_PRIVATE + void initializeLoggerList(LoggerList& list) const; + + /** + * This method loops through all the *potential* parents of + * logger'. There 3 possible cases: + * + * 1) No entry for the potential parent of 'logger' exists + * + * We create a ProvisionNode for this potential parent and insert + * 'logger' in that provision node. + * + * 2) There is an entry of type Logger for the potential parent. + * + * The entry is 'logger's nearest existing parent. We update logger's + * parent field with this entry. We also break from the loop + * because updating our parent's parent is our parent's + * responsibility. + * + * 3) There entry is of type ProvisionNode for this potential parent. + * + * We add 'logger' to the list of children for this potential parent. + */ + LOG4CPLUS_PRIVATE void updateParents(Logger const & logger); + + /** + * We update the links for all the children that placed themselves + * in the provision node 'pn'. The second argument 'logger' is a + * reference for the newly created Logger, parent of all the + * children in 'pn' + * + * We loop on all the children 'c' in 'pn': + * + * If the child 'c' has been already linked to a child of + * 'logger' then there is no need to update 'c'. + * + * Otherwise, we set logger's parent field to c's parent and set + * c's parent field to logger. + */ + LOG4CPLUS_PRIVATE void updateChildren(ProvisionNode& pn, + Logger const & logger); + + // Data + thread::Mutex hashtable_mutex; + std::unique_ptr defaultFactory; + ProvisionNodeMap provisionNodes; + LoggerMap loggerPtrs; + Logger root; + + int disableValue; + + bool emittedNoAppenderWarning; + + // Disallow copying of instances of this class + Hierarchy(const Hierarchy&); + Hierarchy& operator=(const Hierarchy&); + + // Friends + friend class log4cplus::spi::LoggerImpl; + friend class log4cplus::HierarchyLocker; + }; + + + LOG4CPLUS_EXPORT Hierarchy & getDefaultHierarchy (); + + +} // end namespace log4cplus + +#endif // LOG4CPLUS_HIERARCHY_HEADER_ diff --git a/log4cplus/hierarchylocker.h b/log4cplus/hierarchylocker.h new file mode 100644 index 0000000..20fa9aa --- /dev/null +++ b/log4cplus/hierarchylocker.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: hierarchylocker.h +// Created: 8/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_HIERARCHY_LOCKER_HEADER_ +#define LOG4CPLUS_HIERARCHY_LOCKER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + + +namespace log4cplus +{ + + class Hierarchy; + + + /** + * This is used to lock a Hierarchy. The dtor unlocks the Hierarchy. + */ + class LOG4CPLUS_EXPORT HierarchyLocker { + public: + // ctor & dtor + HierarchyLocker(Hierarchy& h); + ~HierarchyLocker() LOG4CPLUS_NOEXCEPT_FALSE; + + /** + * Calls the resetConfiguration() method on the locked Hierarchy. + */ + void resetConfiguration(); + + /** + * Calls the getInstance() method on the locked Hierarchy. + */ + Logger getInstance(const log4cplus::tstring& name); + + /** + * Calls the getInstance() method on the locked Hierarchy. + */ + Logger getInstance(const log4cplus::tstring& name, spi::LoggerFactory& factory); + + void addAppender(Logger &logger, log4cplus::SharedAppenderPtr& appender); + + private: + // Data + Hierarchy& h; + log4cplus::thread::MutexGuard hierarchyLocker; + LoggerList loggerList; + }; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_HIERARCHY_LOCKER_HEADER_ diff --git a/log4cplus/initializer.h b/log4cplus/initializer.h new file mode 100644 index 0000000..92245de --- /dev/null +++ b/log4cplus/initializer.h @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_INITIALIZER_HXX +#define LOG4CPLUS_INITIALIZER_HXX + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +namespace log4cplus +{ + +/** + This class helps with initialization and shutdown of log4cplus. Its + constructor calls `log4cplus::initialize()` and its destructor calls + `log4cplus::Logger::shutdown()`. Use this class as the first thing in your + `main()`. It will ensure shutdown of log4cplus at the end of + `main()`. This is particularly important on Windows, where shutdown of + standard threads outside `main()` is impossible. + */ +class LOG4CPLUS_EXPORT Initializer +{ +public: + Initializer (); + ~Initializer (); + + Initializer (Initializer const &) = delete; + Initializer (Initializer &&) = delete; + Initializer & operator = (Initializer const &) = delete; + Initializer & operator = (Initializer &&) = delete; +}; + +} // namespace log4cplus + + +#endif // LOG4CPLUS_INITIALIZER_HXX diff --git a/log4cplus/internal/customloglevelmanager.h b/log4cplus/internal/customloglevelmanager.h new file mode 100644 index 0000000..386dad0 --- /dev/null +++ b/log4cplus/internal/customloglevelmanager.h @@ -0,0 +1,151 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: customloglevelmanager.h +// Created: 12/2018 +// Author: Jens Rehsack +// Author: Václav Haisman +// +// +// Copyright (C) 2018, Jens Rehsack. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/** @file + * This header contains declaration internal to log4cplus. They must never be + * visible from user accesible headers or exported in DLL/shared library. + */ + + +#ifndef LOG4CPLUS_INTERNAL_CUSTOMLOGLEVELMANAGER_HEADER_ +#define LOG4CPLUS_INTERNAL_CUSTOMLOGLEVELMANAGER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + +#include +#include +#include + + +namespace log4cplus { + +namespace internal { + + +/** + * Custom log level manager used by C API. + */ +class CustomLogLevelManager { +protected: + log4cplus::thread::Mutex mtx; + bool pushed_methods; + std::map ll2nm; + std::map nm2ll; + +public: + CustomLogLevelManager() + : pushed_methods (false) + { } + + bool add(LogLevel ll, tstring const &nm) + { + log4cplus::thread::MutexGuard guard (mtx); + + if (! pushed_methods) + { + pushed_methods = true; + getLogLevelManager().pushToStringMethod(customToStringMethod); + getLogLevelManager().pushFromStringMethod(customFromStringMethod); + } + + auto i = ll2nm.lower_bound(ll); + if( ( i != ll2nm.end() ) && ( i->first == ll ) && ( i->second != nm ) ) + return false; + + auto j = nm2ll.lower_bound(nm); + if( ( j != nm2ll.end() ) && ( j->first == nm ) && ( j->second != ll ) ) + return false; + + // there is no else after return + ll2nm.insert( i, std::make_pair(ll, nm) ); + nm2ll.insert( j, std::make_pair(nm, ll) ); + return true; + } + + bool remove(LogLevel ll, tstring const &nm) + { + log4cplus::thread::MutexGuard guard (mtx); + + auto i = ll2nm.find(ll); + auto j = nm2ll.find(nm); + if( ( i != ll2nm.end() ) && ( j != nm2ll.end() ) && + ( i->first == j->second ) && ( i->second == j->first ) ) { + ll2nm.erase(i); + nm2ll.erase(j); + + return true; + } + + // there is no else after return + return false; + } + +protected: + tstring const & customToStringMethodWorker(LogLevel ll) + { + log4cplus::thread::MutexGuard guard (mtx); + auto i = ll2nm.find(ll); + if( i != ll2nm.end() ) + return i->second; + + return internal::empty_str; + } + + LogLevel customFromStringMethodWorker(const tstring& nm) + { + log4cplus::thread::MutexGuard guard (mtx); + auto i = nm2ll.find(nm); + if( i != nm2ll.end() ) + return i->second; + + return NOT_SET_LOG_LEVEL; + } + + LOG4CPLUS_PRIVATE static tstring const & customToStringMethod(LogLevel ll); + LOG4CPLUS_PRIVATE static LogLevel customFromStringMethod(const tstring& nm); +}; + +LOG4CPLUS_PRIVATE CustomLogLevelManager & getCustomLogLevelManager (); + +} // namespace internal + +} // namespace log4cplus + + +#endif // LOG4CPLUS_INTERNAL_CUSTOMLOGLEVELMANAGER_HEADER diff --git a/log4cplus/internal/cygwin-win32.h b/log4cplus/internal/cygwin-win32.h new file mode 100644 index 0000000..1b8ae6e --- /dev/null +++ b/log4cplus/internal/cygwin-win32.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: cygwin-win32.h +// Created: 7/2011 +// Author: Vaclav Zeman +// +// Copyright (C) 2011-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#if ! defined (LOG4CPLUS_CONFIG_CYGWIN_WIN32_H) +#define LOG4CPLUS_CONFIG_CYGWIN_WIN32_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (__CYGWIN__) + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + + +namespace log4cplus { namespace cygwin { + +unsigned long get_current_win32_thread_id (); +void output_debug_stringW (wchar_t const *); + +} } // namespace log4cplus { namespace cygwin { + + +#endif // defined (__CYGWIN__) +#endif // LOG4CPLUS_CONFIG_CYGWIN_WIN32_H diff --git a/log4cplus/internal/env.h b/log4cplus/internal/env.h new file mode 100644 index 0000000..549a89f --- /dev/null +++ b/log4cplus/internal/env.h @@ -0,0 +1,102 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: env.h +// Created: 7/2010 +// Author: Vaclav Haisman +// +// +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_INTERNAL_ENV_H +#define LOG4CPLUS_INTERNAL_ENV_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + +#if defined (_WIN32) +#include +#endif +#ifdef LOG4CPLUS_HAVE_SYS_TYPES_H +#include +#endif +#ifdef LOG4CPLUS_HAVE_UNISTD_H +#include +#endif + + +namespace log4cplus { namespace internal { + + +//! Get environment variable value. +bool get_env_var (tstring & value, tstring const & name); + +//! Get locale. +std::locale get_locale_by_name(tstring const& locale_name); + +//! Parse a string as a boolean value. +bool parse_bool (bool & val, tstring const & str); + +//! Parse a path into path components. +bool split_path (std::vector & components, std::size_t & special, + tstring const & path); + +//! Makes directories leading to file. +void make_dirs (tstring const & file_path); + +inline +#if defined (_WIN32) +DWORD +get_process_id () +{ + return GetCurrentProcessId (); +} + +#elif defined (LOG4CPLUS_HAVE_GETPID) +pid_t +get_process_id () +{ + return getpid (); +} + +#else +int +get_process_id () +{ + return 0; +} + +#endif + + +} } // namespace log4cplus { namespace internal { + + +#endif // LOG4CPLUS_INTERNAL_ENV_H diff --git a/log4cplus/internal/internal.h b/log4cplus/internal/internal.h new file mode 100644 index 0000000..2483d05 --- /dev/null +++ b/log4cplus/internal/internal.h @@ -0,0 +1,244 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: internal.h +// Created: 1/2009 +// Author: Vaclav Haisman +// +// +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/** @file + * This header contains declaration internal to log4cplus. They must never be + * visible from user accesible headers or exported in DLL/shared libray. + */ + + +#ifndef LOG4CPLUS_INTERNAL_INTERNAL_HEADER_ +#define LOG4CPLUS_INTERNAL_INTERNAL_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace log4cplus { + +namespace internal { + + +//! Canonical empty string. It is used when the need to return empty string +//! by reference arises. +extern log4cplus::tstring const empty_str; + + +struct gft_scratch_pad +{ + gft_scratch_pad (); + ~gft_scratch_pad (); + + void + reset () + { + uc_q_str_valid = false; + q_str_valid = false; + s_str_valid = false; + ret.clear (); + } + + log4cplus::tstring q_str; + log4cplus::tstring uc_q_str; + log4cplus::tstring s_str; + log4cplus::tstring ret; + log4cplus::tstring fmt; + log4cplus::tstring tmp; + std::vector buffer; + bool uc_q_str_valid; + bool q_str_valid; + bool s_str_valid; +}; + + +struct appender_sratch_pad +{ + appender_sratch_pad (); + ~appender_sratch_pad (); + + tostringstream oss; + tstring str; + std::string chstr; +}; + + +//! Per thread data. +struct per_thread_data +{ + per_thread_data (); + ~per_thread_data (); + + tstring macros_str; + tostringstream macros_oss; + tostringstream layout_oss; + DiagnosticContextStack ndc_dcs; + MappedDiagnosticContextMap mdc_map; + log4cplus::tstring thread_name; + log4cplus::tstring thread_name2; + gft_scratch_pad gft_sp; + appender_sratch_pad appender_sp; + log4cplus::tstring faa_str; + log4cplus::tstring ll_str; + spi::InternalLoggingEvent forced_log_ev; + std::FILE * fnull; + log4cplus::helpers::snprintf_buf snprintf_buf; +}; + + +per_thread_data * alloc_ptd (); + +// TLS key whose value is pointer struct per_thread_data. +extern log4cplus::thread::impl::tls_key_type tls_storage_key; + + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) \ + && defined (LOG4CPLUS_THREAD_LOCAL_VAR) + +extern LOG4CPLUS_THREAD_LOCAL_VAR per_thread_data * ptd; + + +inline +void +set_ptd (per_thread_data * p) +{ + ptd = p; +} + + +inline +per_thread_data * +get_ptd (bool alloc = true) +{ + if (LOG4CPLUS_UNLIKELY (! ptd && alloc)) + return alloc_ptd (); + + // The assert() does not belong here. get_ptd() might be called by + // cleanup code that can handle the returned NULL pointer. + //assert (ptd); + + return ptd; +} + + +#else // defined (LOG4CPLUS_THREAD_LOCAL_VAR) + + +inline +void +set_ptd (per_thread_data * p) +{ + thread::impl::tls_set_value (tls_storage_key, p); +} + + +inline +per_thread_data * +get_ptd (bool alloc = true) +{ + per_thread_data * ptd + = reinterpret_cast( + thread::impl::tls_get_value (tls_storage_key)); + + if (LOG4CPLUS_UNLIKELY (! ptd && alloc)) + return alloc_ptd (); + + return ptd; +} + + +#endif // defined (LOG4CPLUS_THREAD_LOCAL_VAR) + + +inline +tstring & +get_thread_name_str () +{ + return get_ptd ()->thread_name; +} + + +inline +tstring & +get_thread_name2_str () +{ + return get_ptd ()->thread_name2; +} + + +inline +gft_scratch_pad & +get_gft_scratch_pad () +{ + return get_ptd ()->gft_sp; +} + + +inline +appender_sratch_pad & +get_appender_sp () +{ + return get_ptd ()->appender_sp; +} + + +} // namespace internal { + + +namespace detail +{ + +LOG4CPLUS_EXPORT void clear_tostringstream (tostringstream &); + +} // namespace detail + + +} // namespace log4cplus { + + +#endif // LOG4CPLUS_INTERNAL_INTERNAL_HEADER_ diff --git a/log4cplus/internal/socket.h b/log4cplus/internal/socket.h new file mode 100644 index 0000000..058b48f --- /dev/null +++ b/log4cplus/internal/socket.h @@ -0,0 +1,219 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: socket.h +// Created: 1/2010 +// Author: Vaclav Haisman +// +// +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/** @file + * This header contains declaration internal to log4cplus. They must never be + * visible from user accesible headers or exported in DLL/shared libray. + */ + + +#ifndef LOG4CPLUS_INTERNAL_SOCKET_H_ +#define LOG4CPLUS_INTERNAL_SOCKET_H_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + +#if defined(_WIN32) +#include +#endif +#include + +#include +#ifdef LOG4CPLUS_HAVE_ERRNO_H +#include +#endif + +#ifdef LOG4CPLUS_HAVE_UNISTD_H +#include +#endif + +#if defined (LOG4CPLUS_HAVE_NETDB_H) +#include +#endif + + +namespace log4cplus { + +namespace helpers { + +#if defined(_WIN32) +typedef SOCKET os_socket_type; +os_socket_type const INVALID_OS_SOCKET_VALUE = INVALID_SOCKET; + +struct ADDRINFOT_deleter +{ + void + operator () (ADDRINFOA * ptr) const + { + FreeAddrInfoA(ptr); + } + + void + operator () (ADDRINFOW * ptr) const + { + FreeAddrInfoW(ptr); + } +}; + + +struct socket_closer +{ + void + operator () (SOCKET s) + { + if (s && s != INVALID_OS_SOCKET_VALUE) + { + DWORD const eno = WSAGetLastError(); + ::closesocket(s); + WSASetLastError(eno); + } + } +}; + + +#else +typedef int os_socket_type; +os_socket_type const INVALID_OS_SOCKET_VALUE = -1; + + +struct addrinfo_deleter +{ + void + operator () (struct addrinfo * ptr) const + { + freeaddrinfo(ptr); + } +}; + + +struct socket_closer +{ + void + operator () (os_socket_type s) + { + if (s >= 0) + { + int const eno = errno; + close(s); + errno = eno; + } + } +}; + +#endif + + +struct socket_holder +{ + os_socket_type sock; + + socket_holder() + : sock(INVALID_OS_SOCKET_VALUE) + { } + + socket_holder(os_socket_type s) + : sock(s) + { } + + ~socket_holder() + { + socket_closer()(sock); + } + + void + reset(os_socket_type s = INVALID_OS_SOCKET_VALUE) + { + if (sock != INVALID_OS_SOCKET_VALUE) + socket_closer()(sock); + + sock = s; + } + + os_socket_type + detach() + { + os_socket_type s = sock; + sock = INVALID_OS_SOCKET_VALUE; + return s; + } + + socket_holder(socket_holder &&) = delete; + socket_holder(socket_holder const &) = delete; + + socket_holder operator = (socket_holder &&) = delete; + socket_holder operator = (socket_holder const &) = delete; +}; + + +static inline +os_socket_type +to_os_socket (SOCKET_TYPE const & x) +{ + return static_cast(x); +} + + +static inline +SOCKET_TYPE +to_log4cplus_socket (os_socket_type const & x) +{ + return static_cast(x); +} + + +static inline +void +set_last_socket_error (int err) +{ + errno = err; +} + + +static inline +int +get_last_socket_error () +{ + return errno; +} + + +} // namespace helpers { + +} // namespace log4cplus { + + +#endif // LOG4CPLUS_INTERNAL_SOCKET_H_ diff --git a/log4cplus/layout.h b/log4cplus/layout.h new file mode 100644 index 0000000..a0110e4 --- /dev/null +++ b/log4cplus/layout.h @@ -0,0 +1,645 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: Layout.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_LAYOUT_HEADER_ +#define LOG4CPLUS_LAYOUT_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +#include +#include + + +namespace log4cplus { + + // Forward Declarations + namespace pattern + { + + class PatternConverter; + + } + + + namespace helpers + { + + class Properties; + + } + + + namespace spi + { + + class InternalLoggingEvent; + + } + + + /** + * This class is used to layout strings sent to an {@link + * log4cplus::Appender}. + */ + class LOG4CPLUS_EXPORT Layout + { + public: + Layout(); + Layout(const helpers::Properties& properties); + virtual ~Layout() = 0; + + virtual void formatAndAppend(log4cplus::tostream& output, + const log4cplus::spi::InternalLoggingEvent& event) = 0; + + protected: + LogLevelManager& llmCache; + + private: + // Disable copy + Layout(const Layout&); + Layout& operator=(Layout const &); + }; + + + + /** + * SimpleLayout consists of the LogLevel of the log statement, + * followed by " - " and then the log message itself. For example, + * + *
+     *         DEBUG - Hello world
+     * 
+ * + * {@link PatternLayout} offers a much more powerful alternative. + */ + class LOG4CPLUS_EXPORT SimpleLayout + : public Layout + { + public: + SimpleLayout(); + SimpleLayout(const log4cplus::helpers::Properties& properties); + virtual ~SimpleLayout(); + + virtual void formatAndAppend(log4cplus::tostream& output, + const log4cplus::spi::InternalLoggingEvent& event); + + private: + // Disallow copying of instances of this class + SimpleLayout(const SimpleLayout&); + SimpleLayout& operator=(const SimpleLayout&); + }; + + + + /** + * TTCC layout format consists of time, thread, Logger and nested + * diagnostic context information, hence the name. + * + * The time format depends on the DateFormat used. Use the + * Use_gmtime to specify whether messages should be logged + * using localtime or gmtime. There are also + * ThreadPrinting, CategoryPrefixing and + * ContextPrinting properties to turn on and off thread name, + * logger name and NDC context printing respectively. + * + * Here is an example TTCCLayout output: + * + * ~~~~ + * 1 [0x60004dca0] WARN test.TestThread <> - Thread-3 TestThread.run()- Starting... + * 1 [0x60004dca0] TRACE SlowObject - ENTER: SlowObject::doSomething() + * 2 [0x60004b030] INFO SlowObject - Actually doing something...1, 2, 3, testing...DONE + * 2 [0x60004b130] INFO SlowObject - Actually doing something... + * 2 [0x60004b030] TRACE SlowObject - EXIT: SlowObject::doSomething() + * 2 [0x60004b030] TRACE SlowObject - ENTER: SlowObject::doSomething() + * 3 [0x60004b130] INFO SlowObject - Actually doing something...1, 2, 3, testing...DONE + * 3 [0x60004cad0] INFO SlowObject - Actually doing something... + * ~~~~ + * + * The first field is the number of milliseconds elapsed since + * the start of the program. + * + * The second field is the thread outputting the log + * statement. (The value is the same as that of the `t` formatter + * for PatternLayout.) + * + * The third field is the LogLevel. + * + * The fourth field is the logger to which the statement belongs. + * + * The fifth field (just before the '-') is the nested + * diagnostic context. Note the nested diagnostic context may be + * empty as in the first two statements. The text after the '-' + * is the message of the statement. + * + * PatternLayout offers a much more flexible alternative. + */ + class LOG4CPLUS_EXPORT TTCCLayout + : public Layout + { + public: + TTCCLayout(bool use_gmtime = false, bool thread_printing = true, + bool category_prefixes = true, bool context_printing = true); + TTCCLayout(const log4cplus::helpers::Properties& properties); + virtual ~TTCCLayout(); + + virtual void formatAndAppend(log4cplus::tostream& output, + const log4cplus::spi::InternalLoggingEvent& event); + + bool getThreadPrinting() const; + void setThreadPrinting(bool); + + bool getCategoryPrefixing() const; + void setCategoryPrefixing(bool); + + bool getContextPrinting() const; + void setContextPrinting(bool); + + protected: + log4cplus::tstring dateFormat; + bool use_gmtime = false; + bool thread_printing = true; + bool category_prefixing = true; + bool context_printing = true; + + private: + // Disallow copying of instances of this class + TTCCLayout(const TTCCLayout&); + TTCCLayout& operator=(const TTCCLayout&); + }; + + + LOG4CPLUS_EXPORT helpers::Time const & getTTCCLayoutTimeBase (); + + + /** + * A flexible layout configurable with pattern string. + * + * The goal of this class is to format a InternalLoggingEvent and return + * the results as a string. The results depend on the conversion + * pattern. + * + * The conversion pattern is closely related to the conversion + * pattern of the printf function in C. A conversion pattern is + * composed of literal text and format control expressions called + * conversion specifiers. + * + * You are free to insert any literal text within the conversion + * pattern. + * + * Each conversion specifier starts with a percent sign (%%) and is + * followed by optional format modifiers and a conversion + * character. The conversion character specifies the type of + * data, e.g. Logger, LogLevel, date, thread name. The format + * modifiers control such things as field width, padding, left and + * right justification. The following is a simple example. + * + * Let the conversion pattern be `"%-5p [%t]: %m%n"` and assume + * that the log4cplus environment was set to use a PatternLayout. Then the + * statements + * + * ~~~~{.c} + * Logger root = Logger.getRoot(); + * LOG4CPLUS_DEBUG(root, "Message 1"); + * LOG4CPLUS_WARN(root, "Message 2"); + * ~~~~ + * + * would yield the output + * + * ~~~~ + * DEBUG [main]: Message 1 + * WARN [main]: Message 2 + * ~~~~ + * + * Note that there is no explicit separator between text and + * conversion specifiers. The pattern parser knows when it has reached + * the end of a conversion specifier when it reads a conversion + * character. In the example above the conversion specifier + * "%-5p" means the LogLevel of the logging event should be left + * justified to a width of five characters. + * + * The recognized conversion characters are + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Conversion CharacterEffect
bUsed to output file name component of path name. + * E.g. main.cxx from path ../../main.cxx.
cUsed to output the logger of the logging event. The + * logger conversion specifier can be optionally followed by + * precision specifier, that is a decimal constant in + * brackets. + * + * If a precision specifier is given, then only the corresponding + * number of right most components of the logger name will be + * printed. By default the logger name is printed in full. + * + * For example, for the logger name "a.b.c" the pattern + * %c{2} will output "b.c". + * + *
dUsed to output the date of the logging event in UTC. + * + * The date conversion specifier may be followed by a date format + * specifier enclosed between braces. For example, %%d{%%H:%%M:%%s} + * or %%d{%%d %%b %%Y %%H:%%M:%%s}. If no date format + * specifier is given then %%d{%%d %%m %%Y %%H:%%M:%%s} + * is assumed. + * + * The Following format options are possible: + *
    + *
  • %%a -- Abbreviated weekday name
  • + *
  • %%A -- Full weekday name
  • + *
  • %%b -- Abbreviated month name
  • + *
  • %%B -- Full month name
  • + *
  • %%c -- Standard date and time string
  • + *
  • %%d -- Day of month as a decimal(1-31)
  • + *
  • %%H -- Hour(0-23)
  • + *
  • %%I -- Hour(1-12)
  • + *
  • %%j -- Day of year as a decimal(1-366)
  • + *
  • %%m -- Month as decimal(1-12)
  • + *
  • %%M -- Minute as decimal(0-59)
  • + *
  • %%p -- Locale's equivalent of AM or PM
  • + *
  • %%q -- milliseconds as decimal(0-999) -- Log4CPLUS specific + *
  • %%Q -- fractional milliseconds as decimal(0-999.999) -- Log4CPLUS specific + *
  • %%S -- Second as decimal(0-59)
  • + *
  • %%U -- Week of year, Sunday being first day(0-53)
  • + *
  • %%w -- Weekday as a decimal(0-6, Sunday being 0)
  • + *
  • %%W -- Week of year, Monday being first day(0-53)
  • + *
  • %%x -- Standard date string
  • + *
  • %%X -- Standard time string
  • + *
  • %%y -- Year in decimal without century(0-99)
  • + *
  • %%Y -- Year including century as decimal
  • + *
  • %%Z -- Time zone name
  • + *
  • %% -- The percent sign
  • + *
+ * + * Lookup the documentation for the strftime() function + * found in the <ctime> header for more information. + *
DUsed to output the date of the logging event in local time. + * + * All of the above information applies. + *
EUsed to output the value of a given environment variable. The + * name of is supplied as an argument in brackets. If the variable does + * exist then empty string will be used. + * + * For example, the pattern %E{HOME} will output the contents + * of the HOME environment variable. + *
FUsed to output the file name where the logging request was + * issued. + * + * NOTE Unlike log4j, there is no performance penalty for + * calling this method.
hUsed to output the hostname of this system (as returned + * by gethostname(2)). + * + * NOTE The hostname is only retrieved once at + * initialization. + * + *
HUsed to output the fully-qualified domain name of this + * system (as returned by gethostbyname(2) for the hostname + * returned by gethostname(2)). + * + * NOTE The hostname is only retrieved once at + * initialization. + * + *
lEquivalent to using "%F:%L" + * + * NOTE: Unlike log4j, there is no performance penalty for + * calling this method. + * + *
LUsed to output the line number from where the logging request + * was issued. + * + * NOTE: Unlike log4j, there is no performance penalty for + * calling this method. + * + *
mUsed to output the application supplied message associated with + * the logging event.
MUsed to output function name using + * __FUNCTION__ or similar macro. + * + * NOTE The __FUNCTION__ macro is not + * standard but it is common extension provided by all compilers + * (as of 2010). In case it is missing or in case this feature + * is disabled using the + * LOG4CPLUS_DISABLE_FUNCTION_MACRO macro, %M + * expands to an empty string.
nOutputs the platform dependent line separator character or + * characters. + *
pUsed to output the LogLevel of the logging event.
rUsed to output miliseconds since program start + * of the logging event.
tUsed to output the thread ID of the thread that generated + * the logging event. (This is either `pthread_t` value returned + * by `pthread_self()` on POSIX platforms or thread ID returned + * by `GetCurrentThreadId()` on Windows.)
TUsed to output alternative name of the thread that generated the + * logging event.
iUsed to output the process ID of the process that generated the + * logging event.
xUsed to output the NDC (nested diagnostic context) associated + * with the thread that generated the logging event. + *
XUsed to output the MDC (mapped diagnostic context) + * associated with the thread that generated the logging + * event. It takes optional key parameter. Without the key + * paramter (%%X), it outputs the whole MDC map. With the key + * (%%X{key}), it outputs just the key's value. + *
"%%"The sequence "%%" outputs a single percent sign. + *
+ * + * By default the relevant information is output as is. However, + * with the aid of format modifiers it is possible to change the + * minimum field width, the maximum field width and justification. + * + * The optional format modifier is placed between the percent sign + * and the conversion character. + * + * The first optional format modifier is the left justification + * flag which is just the minus (-) character. Then comes the + * optional minimum field width modifier. This is a decimal + * constant that represents the minimum number of characters to + * output. If the data item requires fewer characters, it is padded on + * either the left or the right until the minimum width is + * reached. The default is to pad on the left (right justify) but you + * can specify right padding with the left justification flag. The + * padding character is space. If the data item is larger than the + * minimum field width, the field is expanded to accommodate the + * data. The value is never truncated. + * + * This behavior can be changed using the maximum field + * width modifier which is designated by a period followed by a + * decimal constant. If the data item is longer than the maximum + * field, then the extra characters are removed from the + * beginning of the data item and not from the end. For + * example, it the maximum field width is eight and the data item is + * ten characters long, then the first two characters of the data item + * are dropped. This behavior deviates from the printf function in C + * where truncation is done from the end. + * + * Below are various format modifier examples for the logger + * conversion specifier. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Format modifierleft justifyminimum widthmaximum widthcomment
%20cfalse20noneLeft pad with spaces if the logger name is less than 20 + * characters long. + *
%-20c true 20 none Right pad with + * spaces if the logger name is less than 20 characters long. + *
%.30cNAnone30Truncate from the beginning if the logger name is longer than 30 + * characters. + *
%20.30cfalse2030Left pad with spaces if the logger name is shorter than 20 + * characters. However, if logger name is longer than 30 characters, + * then truncate from the beginning. + *
%-20.30ctrue2030Right pad with spaces if the logger name is shorter than 20 + * characters. However, if logger name is longer than 30 characters, + * then truncate from the beginning. + *
+ * + * Below are some examples of conversion patterns. + * + *
+ * + *
"%r [%t] %-5p %c %x - %m%n" + *
This is essentially the TTCC layout. + * + *
"%-6r [%15.15t] %-5p %30.30c %x - %m%n" + * + *
Similar to the TTCC layout except that the relative time is + * right padded if less than 6 digits, thread name is right padded if + * less than 15 characters and truncated if longer and the logger + * name is left padded if shorter than 30 characters and truncated if + * longer. + * + *
+ * + * The above text is largely inspired from Peter A. Darnell and + * Philip E. Margolis' highly recommended book "C -- a Software + * Engineering Approach", ISBN 0-387-97389-3. + * + *

Properties

+ * + *
+ *
NDCMaxDepth
+ *
This property limits how many deepest NDC components will + * be printed by %%x specifier.
+ * + *
ConversionPattern
+ *
This property specifies conversion pattern.
+ *
+ * + */ + class LOG4CPLUS_EXPORT PatternLayout + : public Layout + { + public: + // Ctors and dtor + PatternLayout(const log4cplus::tstring& pattern); + PatternLayout(const log4cplus::helpers::Properties& properties); + virtual ~PatternLayout(); + + virtual void formatAndAppend(log4cplus::tostream& output, + const log4cplus::spi::InternalLoggingEvent& event); + + protected: + void init(const log4cplus::tstring& pattern, unsigned ndcMaxDepth = 0); + + // Data + log4cplus::tstring pattern; + std::vector > parsedPattern; + + private: + // Disallow copying of instances of this class + PatternLayout(const PatternLayout&); + PatternLayout& operator=(const PatternLayout&); + }; + + + +} // end namespace log4cplus + +#endif // LOG4CPLUS_LAYOUT_HEADER_ diff --git a/log4cplus/log4.h b/log4cplus/log4.h new file mode 100644 index 0000000..8e1b23e --- /dev/null +++ b/log4cplus/log4.h @@ -0,0 +1,80 @@ +#ifndef LOG4_H +#define LOG4_H + +#ifdef __cplusplus + +#include +#include + +//防止#include 里的冲突 +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif +//防止#include 里的冲突 + +#include "logger.h" +#include +#include "loggingmacros.h" + + +#define LOGTYPE_COM 1 +#define LOGTYPE_DATA 2 + +struct TypedLogger { + log4cplus::Logger logger; + int logtype; + TypedLogger(); + TypedLogger(const log4cplus::Logger& l, int t); +}; + +struct DebugSwitch { + bool debug_open; + std::set targets; + int min_level; + std::map type_enable; + + DebugSwitch(); + void open(); + void close(); + void set_target(const std::string& name); + void set_level(int level); + void enable_type(int type); + void disable_type(int type); + bool match(const std::string& logger_name, int level, int logtype); +}; + +extern std::map logger_map; +extern DebugSwitch g_debug_switch; + + + + + +log4cplus::Logger init_logger(const std::string& full_name, const std::string& file_dir, const std::string& base_file); + + +void process_log_command(const std::string& id, const std::string& level, const std::string& grade, const std::string& logtype_str); + + +void update_log_entries_countdown(); + +extern "C" { +#endif +void remove_loggers_by_terminal_id(const char* terminal_id_cstr); +void init_logger_process(); +void init_loggers(); +void init_loggers_bydevid(const char* dev_id); + +void log_debug(const char* key, const char* msg); +void log_info(const char* key, const char* msg); +void log_warn(const char* key, const char* msg); +void log_error(const char* key, const char* msg); +#ifdef __cplusplus +} +#endif + +#endif // LOG4_H diff --git a/log4cplus/log4cplus.h b/log4cplus/log4cplus.h new file mode 100644 index 0000000..e3ddb32 --- /dev/null +++ b/log4cplus/log4cplus.h @@ -0,0 +1,66 @@ +// Copyright (C) 2015-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_LOG4CPLUS_HXX +#define LOG4CPLUS_LOG4CPLUS_HXX + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined (LOG4CPLUS_WITH_UNIT_TESTS) +namespace log4cplus +{ + +LOG4CPLUS_EXPORT int unit_tests_main (int argc, char* argv[]); + +} // namespace log4cplus +#endif + +#endif // LOG4CPLUS_LOG4CPLUS_HXX diff --git a/log4cplus/log4judpappender.h b/log4cplus/log4judpappender.h new file mode 100644 index 0000000..a6422d5 --- /dev/null +++ b/log4cplus/log4judpappender.h @@ -0,0 +1,91 @@ +// -*- C++ -*- +// Module: LOG4CPLUS +// File: log4judpappender.h +// Created: 7/2012 +// Author: Siva Chandran P +// +// +// Copyright 2012-2017 Siva Chandran P +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_LOG4J_UDP_APPENDER_HEADER_ +#define LOG4CPLUS_LOG4J_UDP_APPENDER_HEADER_ + +#include +#include +#include + +namespace log4cplus { + + /** + * Sends log events as Log4j XML to a remote a log server. + * + * The Log4jUdpAppender has the following properties: + * + *
    + *
  • Remote logging is non-intrusive as far as the log event + * is concerned. In other words, the event will be logged with + * the same time stamp, NDC, location info as if it were logged + * locally by the client.
  • + * + *
  • Remote logging uses the UDP protocol.
  • + *
+ * + *

Properties

+ *
+ *
host
+ *
Remote host name to connect and send events to.
+ * + *
port
+ *
Port on remote host to send events to. Default is 5000.
+ * + *
IPv6
+ *
Boolean value specifying whether to use IPv6 (true) or IPv4 + * (false). Default value is false.
+ * + *
+ */ + class LOG4CPLUS_EXPORT Log4jUdpAppender : public Appender { + public: + // Ctors + Log4jUdpAppender(const log4cplus::tstring& host, int port, + bool ipv6 = false); + Log4jUdpAppender(const log4cplus::helpers::Properties & properties); + + // Dtor + ~Log4jUdpAppender(); + + // Methods + virtual void close(); + + protected: + void openSocket(); + virtual void append(const spi::InternalLoggingEvent& event); + + // Data + log4cplus::helpers::Socket socket; + log4cplus::tstring host; + int port; + bool ipv6 = false; + + private: + // Disallow copying of instances of this class + Log4jUdpAppender(const Log4jUdpAppender&); + Log4jUdpAppender& operator=(const Log4jUdpAppender&); + }; +} // end namespace log4cplus + +#endif // LOG4CPLUS_LOG4J_UDP_APPENDER_HEADER_ diff --git a/log4cplus/logger.h b/log4cplus/logger.h new file mode 100644 index 0000000..dbf6d11 --- /dev/null +++ b/log4cplus/logger.h @@ -0,0 +1,325 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: logger.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file + * This header defines the Logger class and the logging macros. */ + +#ifndef LOG4CPLUS_LOGGERHEADER_ +#define LOG4CPLUS_LOGGERHEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +#include + + +namespace log4cplus +{ + // Forward declarations + + class Appender; + class Hierarchy; + class HierarchyLocker; + class DefaultLoggerFactory; + + namespace spi + { + + class LoggerImpl; + + } + + + /** \typedef std::vector LoggerList + * This is a list of {@link Logger Loggers}. */ + typedef std::vector LoggerList; + + + /** + * This is the central class in the log4cplus package. One of the + * distintive features of log4cplus are hierarchical loggers and their + * evaluation. + */ + class LOG4CPLUS_EXPORT Logger + : public log4cplus::spi::AppenderAttachable + { + public: + // Static Methods + /** + * Returns true if the named logger exists + * (in the default hierarchy). + * + * @param name The name of the logger to search for. + */ + static bool exists(const log4cplus::tstring& name); + + /* + * Returns all the currently defined loggers in the default + * hierarchy. + * + * The root logger is not included in the returned + * list. + */ + static LoggerList getCurrentLoggers(); + + /** + * Return the default Hierarchy instance. + */ + static Hierarchy& getDefaultHierarchy(); + + /** + * Retrieve a logger with name name. If the named + * logger already exists, then the existing instance will be returned. + * Otherwise, a new instance is created. + * + * By default, loggers do not have a set LogLevel but inherit + * it from the hierarchy. This is one of the central features of + * log4cplus. + * + * @param name The name of the logger to retrieve. + */ + static Logger getInstance(const log4cplus::tstring& name); + + /** + * Like getInstance() except that the type of logger + * instantiated depends on the type returned by the {@link + * spi::LoggerFactory#makeNewLoggerInstance} method of the + * factory parameter. + * + * This method is intended to be used by sub-classes. + * + * @param name The name of the logger to retrieve. + * @param factory A {@link spi::LoggerFactory} implementation that will + * actually create a new Instance. + */ + static Logger getInstance(const log4cplus::tstring& name, + spi::LoggerFactory& factory); + + /** + * Return the root of the default logger hierrachy. + * + * The root logger is always instantiated and available. It's + * name is "root". + * + * Nevertheless, calling {@link #getInstance + * Logger.getInstance("root")} does not retrieve the root logger + * but a logger just under root named "root". + */ + static Logger getRoot(); + + /** + * Calling this method will safely close and remove all + * appenders in all the loggers including root contained in the + * default hierachy. + * + * Some appenders such as SocketAppender need to be closed before the + * application exits. Otherwise, pending logging events might be + * lost. + * + * The shutdown method is careful to close nested + * appenders before closing regular appenders. This is allows + * configurations where a regular appender is attached to a logger + * and again to a nested appender. + */ + static void shutdown(); + + // Non-Static Methods + /** + * If assertionVal parameter is false, then + * logs msg with FATAL_LOG_LEVEL log level. + * + * @param assertionVal Truth value of assertion condition. + * @param msg The message to print if assertion is + * false. + */ + void assertion(bool assertionVal, const log4cplus::tstring& msg) const; + + /** + * Close all attached appenders implementing the AppenderAttachable + * interface. + */ + void closeNestedAppenders() const; + + /** + * Check whether this logger is enabled for a given + * LogLevel passed as parameter. + * + * @return boolean True if this logger is enabled for ll. + */ + bool isEnabledFor(LogLevel ll) const; + + /** + * This generic form is intended to be used by wrappers. + */ + void log(LogLevel ll, const log4cplus::tstring& message, + const char* file = LOG4CPLUS_CALLER_FILE (), + int line = LOG4CPLUS_CALLER_LINE (), + const char* function = LOG4CPLUS_CALLER_FUNCTION ()) const; + + void log(spi::InternalLoggingEvent const &) const; + + /** + * This method creates a new logging event and logs the event + * without further checks. + */ + void forcedLog(LogLevel ll, const log4cplus::tstring& message, + const char* file = LOG4CPLUS_CALLER_FILE (), + int line = LOG4CPLUS_CALLER_LINE (), + const char* function = LOG4CPLUS_CALLER_FUNCTION ()) const; + + void forcedLog(spi::InternalLoggingEvent const &) const; + + /** + * Call the appenders in the hierrachy starting at + * this. If no appenders could be found, emit a + * warning. + * + * This method calls all the appenders inherited from the + * hierarchy circumventing any evaluation of whether to log or not + * to log the particular log request. + * + * @param event the event to log. + */ + void callAppenders(const spi::InternalLoggingEvent& event) const; + + /** + * Starting from this logger, search the logger hierarchy for a + * "set" LogLevel and return it. Otherwise, return the LogLevel of the + * root logger. + * + * The Logger class is designed so that this method executes as + * quickly as possible. + */ + LogLevel getChainedLogLevel() const; + + /** + * Returns the assigned LogLevel, if any, for this Logger. + * + * @return LogLevel - the assigned LogLevel, can be NOT_SET_LOG_LEVEL. + */ + LogLevel getLogLevel() const; + + /** + * Set the LogLevel of this Logger. + */ + void setLogLevel(LogLevel ll); + + /** + * Return the the {@link Hierarchy} where this Logger instance is + * attached. + */ + Hierarchy& getHierarchy() const; + + /** + * Return the logger name. + */ + log4cplus::tstring const & getName() const; + + /** + * Get the additivity flag for this Logger instance. + */ + bool getAdditivity() const; + + /** + * Set the additivity flag for this Logger instance. + */ + void setAdditivity(bool additive); + + // AppenderAttachable Methods + virtual void addAppender(SharedAppenderPtr newAppender); + + virtual SharedAppenderPtrList getAllAppenders(); + + virtual SharedAppenderPtr getAppender(const log4cplus::tstring& name); + + virtual void removeAllAppenders(); + + virtual void removeAppender(SharedAppenderPtr appender); + + virtual void removeAppender(const log4cplus::tstring& name); + + Logger () LOG4CPLUS_NOEXCEPT; + Logger(const Logger& rhs) LOG4CPLUS_NOEXCEPT; + Logger& operator=(const Logger& rhs) LOG4CPLUS_NOEXCEPT; + Logger (Logger && rhs) LOG4CPLUS_NOEXCEPT; + Logger & operator = (Logger && rhs) LOG4CPLUS_NOEXCEPT; + virtual ~Logger(); + + void swap (Logger &) LOG4CPLUS_NOEXCEPT; + + /** + * Used to retrieve the parent of this Logger in the + * Logger tree. + */ + Logger getParent() const; + + protected: + // Data + /** This is a pointer to the implementation class. */ + spi::LoggerImpl * value = nullptr; + + private: + // Ctors + /** + * This constructor created a new Logger instance + * with a pointer to a Logger implementation. + * + * You should not create loggers directly. + * + * @param ptr A pointer to the Logger implementation. This value + * cannot be NULL. + */ + Logger(spi::LoggerImpl * ptr) LOG4CPLUS_NOEXCEPT; + + // Friends + friend class log4cplus::spi::LoggerImpl; + friend class log4cplus::Hierarchy; + friend class log4cplus::HierarchyLocker; + friend class log4cplus::DefaultLoggerFactory; + }; + + + /** + * This class is used to create the default implementation of + * the Logger class. + */ + class LOG4CPLUS_EXPORT DefaultLoggerFactory : public spi::LoggerFactory { + public: + Logger makeNewLoggerInstance(const log4cplus::tstring& name, Hierarchy& h); + + protected: + virtual spi::LoggerImpl * makeNewLoggerImplInstance( + const log4cplus::tstring& name, Hierarchy& h); + }; + + +} // end namespace log4cplus + + +#endif // LOG4CPLUS_LOGGERHEADER_ diff --git a/log4cplus/loggingmacros.h b/log4cplus/loggingmacros.h new file mode 100644 index 0000000..9b8f400 --- /dev/null +++ b/log4cplus/loggingmacros.h @@ -0,0 +1,427 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loggingmacros.h +// Created: 8/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file + * This header defines the logging macros. */ + +#ifndef LOG4CPLUS_LOGGING_MACROS_HEADER_ +#define LOG4CPLUS_LOGGING_MACROS_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + + +#if defined(_MSC_VER) +#define LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + __pragma (warning (push)) \ + __pragma (warning (disable:4127)) + +#define LOG4CPLUS_RESTORE_DOWHILE_WARNING() \ + __pragma (warning (pop)) + +#else +#define LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() /* empty */ +#define LOG4CPLUS_RESTORE_DOWHILE_WARNING() /* empty */ + +#endif + +#define LOG4CPLUS_DOWHILE_NOTHING() \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { } while (0) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +#if defined(LOG4CPLUS_DISABLE_FATAL) && !defined(LOG4CPLUS_DISABLE_ERROR) +#define LOG4CPLUS_DISABLE_ERROR +#endif +#if defined(LOG4CPLUS_DISABLE_ERROR) && !defined(LOG4CPLUS_DISABLE_WARN) +#define LOG4CPLUS_DISABLE_WARN +#endif +#if defined(LOG4CPLUS_DISABLE_WARN) && !defined(LOG4CPLUS_DISABLE_INFO) +#define LOG4CPLUS_DISABLE_INFO +#endif +#if defined(LOG4CPLUS_DISABLE_INFO) && !defined(LOG4CPLUS_DISABLE_DEBUG) +#define LOG4CPLUS_DISABLE_DEBUG +#endif +#if defined(LOG4CPLUS_DISABLE_DEBUG) && !defined(LOG4CPLUS_DISABLE_TRACE) +#define LOG4CPLUS_DISABLE_TRACE +#endif + + +namespace log4cplus +{ + +namespace detail +{ + + +inline +Logger +macros_get_logger (Logger const & logger) +{ + return logger; +} + + +inline +Logger const & +macros_get_logger (Logger & logger) +{ + return logger; +} + + +inline +Logger +macros_get_logger (Logger && logger) +{ + return std::move (logger); +} + +inline +Logger +macros_get_logger (tstring const & logger) +{ + return Logger::getInstance (logger); +} + + +inline +Logger +macros_get_logger (tchar const * logger) +{ + return Logger::getInstance (logger); +} + + +LOG4CPLUS_EXPORT void clear_tostringstream (tostringstream &); + + +LOG4CPLUS_EXPORT log4cplus::tostringstream & get_macro_body_oss (); +LOG4CPLUS_EXPORT log4cplus::helpers::snprintf_buf & get_macro_body_snprintf_buf (); +LOG4CPLUS_EXPORT void macro_forced_log (log4cplus::Logger const &, + log4cplus::LogLevel, log4cplus::tstring const &, char const *, int, + char const *); +LOG4CPLUS_EXPORT void macro_forced_log (log4cplus::Logger const &, + log4cplus::LogLevel, log4cplus::tchar const *, char const *, int, + char const *); + + + +} // namespace detail + +} // namespace log4cplus + + +#undef LOG4CPLUS_MACRO_FUNCTION +#define LOG4CPLUS_MACRO_FUNCTION() nullptr +#if ! defined (LOG4CPLUS_DISABLE_FUNCTION_MACRO) +# if defined (LOG4CPLUS_HAVE_FUNCSIG_MACRO) +# undef LOG4CPLUS_MACRO_FUNCTION +# define LOG4CPLUS_MACRO_FUNCTION() __FUNCSIG__ +# elif defined (LOG4CPLUS_HAVE_PRETTY_FUNCTION_MACRO) +# undef LOG4CPLUS_MACRO_FUNCTION +# define LOG4CPLUS_MACRO_FUNCTION() __PRETTY_FUNCTION__ +# elif defined (LOG4CPLUS_HAVE_FUNCTION_MACRO) +# undef LOG4CPLUS_MACRO_FUNCTION +# define LOG4CPLUS_MACRO_FUNCTION() __FUNCTION__ +# elif defined (LOG4CPLUS_HAVE_FUNC_SYMBOL) +# undef LOG4CPLUS_MACRO_FUNCTION +# define LOG4CPLUS_MACRO_FUNCTION() __func__ +# endif +#endif + +#undef LOG4CPLUS_MACRO_FILE +#define LOG4CPLUS_MACRO_FILE() nullptr +#if ! defined (LOG4CPLUS_DISABLE_FILE_MACRO) +# undef LOG4CPLUS_MACRO_FILE +# define LOG4CPLUS_MACRO_FILE() __FILE__ +#endif + + +// Make TRACE and DEBUG log level unlikely and INFO, WARN, ERROR and +// FATAL log level likely. +#define LOG4CPLUS_MACRO_TRACE_LOG_LEVEL(pred) \ + LOG4CPLUS_UNLIKELY (pred) +#define LOG4CPLUS_MACRO_DEBUG_LOG_LEVEL(pred) \ + LOG4CPLUS_UNLIKELY (pred) +#define LOG4CPLUS_MACRO_INFO_LOG_LEVEL(pred) \ + LOG4CPLUS_LIKELY (pred) +#define LOG4CPLUS_MACRO_WARN_LOG_LEVEL(pred) \ + LOG4CPLUS_LIKELY (pred) +#define LOG4CPLUS_MACRO_ERROR_LOG_LEVEL(pred) \ + LOG4CPLUS_LIKELY (pred) +#define LOG4CPLUS_MACRO_FATAL_LOG_LEVEL(pred) \ + LOG4CPLUS_LIKELY (pred) + + +//! Dispatch to LOG4CPLUS_MACRO_LOGLEVEL_* depending on log level. +#define LOG4CPLUS_MACRO_LOGLEVEL_PRED(pred, logLevel) \ + LOG4CPLUS_MACRO_ ## logLevel (pred) + + +// Either use temporary instances of ostringstream +// and snprintf_buf, or use thread-local instances. +#if defined (LOG4CPLUS_MACRO_DISABLE_TLS) +# define LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM(var) \ + log4cplus::tostringstream var + +# define LOG4CPLUS_MACRO_INSTANTIATE_SNPRINTF_BUF(var) \ + log4cplus::helpers::snprintf_buf var + +#else +# define LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM(var) \ + log4cplus::tostringstream & var \ + = log4cplus::detail::get_macro_body_oss () + +# define LOG4CPLUS_MACRO_INSTANTIATE_SNPRINTF_BUF(var) \ + log4cplus::helpers::snprintf_buf & var \ + = log4cplus::detail::get_macro_body_snprintf_buf () + +#endif + + +#define LOG4CPLUS_MACRO_BODY(logger, logEvent, logLevel) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + log4cplus::Logger const & _l \ + = log4cplus::detail::macros_get_logger (logger); \ + if (LOG4CPLUS_MACRO_LOGLEVEL_PRED ( \ + _l.isEnabledFor (log4cplus::logLevel), logLevel)) { \ + LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM (_log4cplus_buf); \ + _log4cplus_buf << logEvent; \ + log4cplus::detail::macro_forced_log (_l, \ + log4cplus::logLevel, _log4cplus_buf.str(), \ + LOG4CPLUS_MACRO_FILE (), __LINE__, \ + LOG4CPLUS_MACRO_FUNCTION ()); \ + } \ + } while (0) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + + +#define LOG4CPLUS_MACRO_STR_BODY(logger, logEvent, logLevel) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + log4cplus::Logger const & _l \ + = log4cplus::detail::macros_get_logger (logger); \ + if (LOG4CPLUS_MACRO_LOGLEVEL_PRED ( \ + _l.isEnabledFor (log4cplus::logLevel), logLevel)) { \ + log4cplus::detail::macro_forced_log (_l, \ + log4cplus::logLevel, logEvent, \ + LOG4CPLUS_MACRO_FILE (), __LINE__, \ + LOG4CPLUS_MACRO_FUNCTION ()); \ + } \ + } while(0) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +#define LOG4CPLUS_MACRO_FMT_BODY(logger, logLevel, ...) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + log4cplus::Logger const & _l \ + = log4cplus::detail::macros_get_logger (logger); \ + if (LOG4CPLUS_MACRO_LOGLEVEL_PRED ( \ + _l.isEnabledFor (log4cplus::logLevel), logLevel)) { \ + LOG4CPLUS_MACRO_INSTANTIATE_SNPRINTF_BUF (_snpbuf); \ + log4cplus::tchar const * _logEvent \ + = _snpbuf.print (__VA_ARGS__); \ + log4cplus::detail::macro_forced_log (_l, \ + log4cplus::logLevel, _logEvent, \ + LOG4CPLUS_MACRO_FILE (), __LINE__, \ + LOG4CPLUS_MACRO_FUNCTION ()); \ + } \ + } while(0) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +/** + * @def LOG4CPLUS_TRACE(logger, logEvent) This macro creates a + * TraceLogger to log a TRACE_LOG_LEVEL message to logger + * upon entry and exiting of a method. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_TRACE) +#define LOG4CPLUS_TRACE_METHOD(logger, logEvent) \ + log4cplus::TraceLogger _log4cplus_trace_logger(logger, logEvent, \ + LOG4CPLUS_MACRO_FILE (), __LINE__, \ + LOG4CPLUS_MACRO_FUNCTION ()); +#define LOG4CPLUS_TRACE(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, TRACE_LOG_LEVEL) +#define LOG4CPLUS_TRACE_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, TRACE_LOG_LEVEL) +#define LOG4CPLUS_TRACE_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, TRACE_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_TRACE_METHOD(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_TRACE(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_TRACE_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_TRACE_FMT(logger, logFmt, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +/** + * @def LOG4CPLUS_DEBUG(logger, logEvent) This macro is used to log a + * DEBUG_LOG_LEVEL message to logger. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_DEBUG) +#define LOG4CPLUS_DEBUG(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, DEBUG_LOG_LEVEL) +#define LOG4CPLUS_DEBUG_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, DEBUG_LOG_LEVEL) +#define LOG4CPLUS_DEBUG_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, DEBUG_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_DEBUG(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_DEBUG_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_DEBUG_FMT(logger, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +/** + * @def LOG4CPLUS_INFO(logger, logEvent) This macro is used to log a + * INFO_LOG_LEVEL message to logger. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_INFO) +#define LOG4CPLUS_INFO(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, INFO_LOG_LEVEL) +#define LOG4CPLUS_INFO_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, INFO_LOG_LEVEL) +#define LOG4CPLUS_INFO_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, INFO_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_INFO(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_INFO_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_INFO_FMT(logger, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +/** + * @def LOG4CPLUS_WARN(logger, logEvent) This macro is used to log a + * WARN_LOG_LEVEL message to logger. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_WARN) +#define LOG4CPLUS_WARN(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, WARN_LOG_LEVEL) +#define LOG4CPLUS_WARN_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, WARN_LOG_LEVEL) +#define LOG4CPLUS_WARN_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, WARN_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_WARN(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_WARN_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_WARN_FMT(logger, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +/** + * @def LOG4CPLUS_ERROR(logger, logEvent) This macro is used to log a + * ERROR_LOG_LEVEL message to logger. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_ERROR) +#define LOG4CPLUS_ERROR(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, ERROR_LOG_LEVEL) +#define LOG4CPLUS_ERROR_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, ERROR_LOG_LEVEL) +#define LOG4CPLUS_ERROR_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, ERROR_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_ERROR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_ERROR_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_ERROR_FMT(logger, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +/** + * @def LOG4CPLUS_FATAL(logger, logEvent) This macro is used to log a + * FATAL_LOG_LEVEL message to logger. + * logEvent will be streamed into an ostream. + */ +#if !defined(LOG4CPLUS_DISABLE_FATAL) +#define LOG4CPLUS_FATAL(logger, logEvent) \ + LOG4CPLUS_MACRO_BODY (logger, logEvent, FATAL_LOG_LEVEL) +#define LOG4CPLUS_FATAL_STR(logger, logEvent) \ + LOG4CPLUS_MACRO_STR_BODY (logger, logEvent, FATAL_LOG_LEVEL) +#define LOG4CPLUS_FATAL_FMT(logger, ...) \ + LOG4CPLUS_MACRO_FMT_BODY (logger, FATAL_LOG_LEVEL, __VA_ARGS__) + +#else +#define LOG4CPLUS_FATAL(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_FATAL_STR(logger, logEvent) LOG4CPLUS_DOWHILE_NOTHING() +#define LOG4CPLUS_FATAL_FMT(logger, ...) LOG4CPLUS_DOWHILE_NOTHING() + +#endif + +//! Helper macro for LOG4CPLUS_ASSERT() macro. +#define LOG4CPLUS_ASSERT_STRINGIFY(X) #X + +//! If the `condition` evaluates false, this macro logs it using FATAL +//! log level, including the `condition`'s source text. +#define LOG4CPLUS_ASSERT(logger, condition) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + if (LOG4CPLUS_UNLIKELY(! (condition))) \ + LOG4CPLUS_FATAL_STR ((logger), \ + LOG4CPLUS_TEXT ("failed condition: ") \ + LOG4CPLUS_TEXT (LOG4CPLUS_ASSERT_STRINGIFY (condition))); \ + } while (0) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +//! If the `condition` evaluates false, this macro logs a message +//! formatted from `printf` format string passed in 3rd and remaining +//! arguments. +#define LOG4CPLUS_ASSERT_FMT(logger, condition, ...) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + if (! (condition)) [[unlikely]] { \ + LOG4CPLUS_FATAL_FMT ((logger), __VA_ARGS__); \ + } \ + } while (false) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +//! If the `condition` evaluates false, this macro logs a message +//! formatted from `std::format` format string passed in 3rd and remaining +//! arguments. +#define LOG4CPLUS_ASSERT_FORMAT(logger, condition, ...) \ + LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \ + do { \ + if (! (condition)) [[unlikely]] { \ + LOG4CPLUS_FATAL_FORMAT ((logger), __VA_ARGS__); \ + } \ + } while (false) \ + LOG4CPLUS_RESTORE_DOWHILE_WARNING() + +#endif /* LOG4CPLUS_LOGGING_MACROS_HEADER_ */ diff --git a/log4cplus/loglevel.h b/log4cplus/loglevel.h new file mode 100644 index 0000000..5f4a814 --- /dev/null +++ b/log4cplus/loglevel.h @@ -0,0 +1,200 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loglevel.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file + * This header defines the LogLevel type. + */ + +#ifndef LOG4CPLUS_LOGLEVEL_HEADER_ +#define LOG4CPLUS_LOGLEVEL_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus { + + /** + * \typedef int LogLevel + * Defines the minimum set of priorities recognized by the system, + * that is {@link #FATAL_LOG_LEVEL}, {@link #ERROR_LOG_LEVEL}, {@link + * #WARN_LOG_LEVEL}, {@link #INFO_LOG_LEVEL}, {@link #DEBUG_LOG_LEVEL}, + * and {@link #TRACE_LOG_LEVEL}. + */ + typedef int LogLevel; + + /** \var const LogLevel OFF_LOG_LEVEL + * The OFF_LOG_LEVEL LogLevel is used during configuration to + * turn off logging. */ + const LogLevel OFF_LOG_LEVEL = 60000; + + /** \var const LogLevel FATAL_LOG_LEVEL + * The FATAL_LOG_LEVEL LogLevel designates very severe error + * events that will presumably lead the application to abort. */ + const LogLevel FATAL_LOG_LEVEL = 50000; + + /** \var const LogLevel ERROR_LOG_LEVEL + * The ERROR_LOG_LEVEL LogLevel designates error events that + * might still allow the application to continue running. */ + const LogLevel ERROR_LOG_LEVEL = 40000; + + /** \var const LogLevel WARN_LOG_LEVEL + * The WARN_LOG_LEVEL LogLevel designates potentially harmful + * situations. */ + const LogLevel WARN_LOG_LEVEL = 30000; + + /** \var const LogLevel INFO_LOG_LEVEL + * The INFO_LOG_LEVEL LogLevel designates informational + * messages that highlight the progress of the application at + * coarse-grained level. */ + const LogLevel INFO_LOG_LEVEL = 20000; + + /** \var const LogLevel DEBUG_LOG_LEVEL + * The DEBUG_LOG_LEVEL LogLevel designates fine-grained + * informational events that are most useful to debug an application. */ + const LogLevel DEBUG_LOG_LEVEL = 10000; + + /** \var const LogLevel TRACE_LOG_LEVEL + * The TRACE_LOG_LEVEL LogLevel is used to "trace" entry + * and exiting of methods. */ + const LogLevel TRACE_LOG_LEVEL = 0; + + /** \var const LogLevel ALL_LOG_LEVEL + * The ALL_LOG_LEVEL LogLevel is used during configuration to + * turn on all logging. */ + const LogLevel ALL_LOG_LEVEL = TRACE_LOG_LEVEL; + + /** \var const LogLevel NOT_SET_LOG_LEVEL + * The NOT_SET_LOG_LEVEL LogLevel is used to indicated that + * no particular LogLevel is desired and that the default should be used. + */ + const LogLevel NOT_SET_LOG_LEVEL = -1; + + + /** + * This method type defined the signature of methods that convert LogLevels + * into strings. + * + * Note: Must return an empty tstring for unrecognized values. + */ + typedef log4cplus::tstring const & (*LogLevelToStringMethod)(LogLevel); + + + /** + * This method type defined the signature of methods that convert strings + * into LogLevels. + * + * Note: Must return NOT_SET_LOG_LEVEL for unrecognized values. + */ + typedef LogLevel (*StringToLogLevelMethod)(const log4cplus::tstring&); + + + + /** + * This class is used to "manage" LogLevel definitions. This class is also + * how "derived" LogLevels are created. Here are the steps to creating a + * "derived" LogLevel: + *
    + *
  1. Create a LogLevel constant (greater than 0)
  2. + *
  3. Define a string to represent that constant
  4. + *
  5. Implement a LogLevelToStringMethod method.
  6. + *
  7. Implement a StringToLogLevelMethod method.
  8. + *
  9. create a "static initializer" that registers those 2 methods + * with the LogLevelManager singleton.
  10. + *
+ */ + class LOG4CPLUS_EXPORT LogLevelManager { + public: + LogLevelManager(); + ~LogLevelManager(); + + /** + * This method is called by all Layout classes to convert a LogLevel + * into a string. + * + * Note: It traverses the list of LogLevelToStringMethod + * to do this, so all "derived" LogLevels are recognized as well. + */ + log4cplus::tstring const & toString(LogLevel ll) const; + + /** + * This method is called by all classes internally to log4cplus to + * convert a string into a LogLevel. + * + * Note: It traverses the list of StringToLogLevelMethod + * to do this, so all "derived" LogLevels are recognized as well. + */ + LogLevel fromString(const log4cplus::tstring& arg) const; + + /** + * When creating a "derived" LogLevel, a LogLevelToStringMethod + * should be defined and registered with the LogLevelManager by calling + * this method. + * + * @see pushFromStringMethod + */ + void pushToStringMethod(LogLevelToStringMethod newToString); + + /** + * When creating a "derived" LogLevel, a StringToLogLevelMethod + * should be defined and registered with the LogLevelManager by calling + * this method. + * + * @see pushToStringMethod + */ + void pushFromStringMethod(StringToLogLevelMethod newFromString); + + private: + // Data + struct LogLevelToStringMethodRec + { + LogLevelToStringMethodRec (); + LogLevelToStringMethodRec (LogLevelToStringMethod); + + LogLevelToStringMethod func; + }; + + typedef std::vector LogLevelToStringMethodList; + LogLevelToStringMethodList toStringMethods; + + typedef std::vector StringToLogLevelMethodList; + StringToLogLevelMethodList fromStringMethods; + + // Disable Copy + LogLevelManager(const LogLevelManager&); + LogLevelManager& operator=(const LogLevelManager&); + }; + + /** + * Returns the singleton LogLevelManager. + */ + LOG4CPLUS_EXPORT LogLevelManager& getLogLevelManager(); + +} + + +#endif // LOG4CPLUS_LOGLEVEL_HEADER_ diff --git a/log4cplus/mdc.h b/log4cplus/mdc.h new file mode 100644 index 0000000..4951298 --- /dev/null +++ b/log4cplus/mdc.h @@ -0,0 +1,77 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_MDC_H_HEADER +#define LOG4CPLUS_MDC_H_HEADER + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include + + +namespace log4cplus +{ + + +typedef std::map MappedDiagnosticContextMap; + + +class LOG4CPLUS_EXPORT MDC +{ +public: + /** + * Clear any nested diagnostic information if any. This method is + * useful in cases where the same thread can be potentially used + * over and over in different unrelated contexts. + */ + void clear(); + + void put (tstring const & key, tstring const & value); + bool get (tstring * value, tstring const & key) const; + void remove (tstring const & key); + + MappedDiagnosticContextMap const & getContext () const; + + // Public ctor and dtor but only to be used by internal::DefaultContext. + MDC (); + virtual ~MDC (); + +private: + LOG4CPLUS_PRIVATE static MappedDiagnosticContextMap * getPtr (); +}; + + +LOG4CPLUS_EXPORT MDC & getMDC (); + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_MDC_H_HEADER diff --git a/log4cplus/msttsappender.h b/log4cplus/msttsappender.h new file mode 100644 index 0000000..3479725 --- /dev/null +++ b/log4cplus/msttsappender.h @@ -0,0 +1,112 @@ +// -*- C++ -*- +// Module: Log4cplus +// File: msttsappender.h +// Created: 10/2012 +// Author: Vaclav Zeman +// +// +// Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// + +/** @file */ + +#ifndef LOG4CPLUS_MSTTSAPPENDER_H +#define LOG4CPLUS_MSTTSAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +#if defined (_WIN32) + #if defined (log4cplusqt4debugappender_EXPORTS) \ + || defined (log4cplusqt4debugappenderU_EXPORTS) \ + || (defined (DLL_EXPORT) && defined (INSIDE_LOG4CPLUS_MSTTSAPPENDER)) + #undef LOG4CPLUS_MSTTSAPPENDER_BUILD_DLL + #define LOG4CPLUS_MSTTSAPPENDER_BUILD_DLL + #endif + #if defined (LOG4CPLUS_MSTTSAPPENDER_BUILD_DLL) + #if defined (INSIDE_LOG4CPLUS_MSTTSAPPENDER) + #define LOG4CPLUS_MSTTSAPPENDER_EXPORT __declspec(dllexport) + #else + #define LOG4CPLUS_MSTTSAPPENDER_EXPORT __declspec(dllimport) + #endif + #else + #define LOG4CPLUS_MSTTSAPPENDER_EXPORT + #endif +#else + #if defined (INSIDE_LOG4CPLUS_MSTTSAPPENDER) + #define LOG4CPLUS_MSTTSAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_EXPORT + #else + #define LOG4CPLUS_MSTTSAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_IMPORT + #endif // defined (INSIDE_LOG4CPLUS_MSTTSAPPENDER) +#endif // !_WIN32 + + +namespace log4cplus +{ + + +class LOG4CPLUS_MSTTSAPPENDER_EXPORT MSTTSAppender + : public Appender +{ +public: + MSTTSAppender (); + explicit MSTTSAppender (helpers::Properties const &); + virtual ~MSTTSAppender (); + + virtual void close (); + + static void registerAppender (); + +protected: + virtual void append (spi::InternalLoggingEvent const &); + + struct Data; + + Data * data; + +private: + LOG4CPLUS_PRIVATE void init (long const * rate = 0, + unsigned long const * volume = 0, bool speak_punc = false, + bool async = false); + + MSTTSAppender (MSTTSAppender const &); + MSTTSAppender & operator = (MSTTSAppender const &); +}; + + +typedef helpers::SharedObjectPtr MSTTSAppenderPtr; + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_MSTTSAPPENDER_H diff --git a/log4cplus/ndc.h b/log4cplus/ndc.h new file mode 100644 index 0000000..4fbf214 --- /dev/null +++ b/log4cplus/ndc.h @@ -0,0 +1,329 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: ndc.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file + * This header defined the NDC class. + */ + +#ifndef _LO4CPLUS_NDC_HEADER_ +#define _LO4CPLUS_NDC_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include +#include + + +namespace log4cplus { + // Forward declarations + struct DiagnosticContext; + typedef std::deque DiagnosticContextStack; + + /** + * The NDC class implements nested diagnostic contexts as + * defined by Neil Harrison in the article "Patterns for Logging + * Diagnostic Messages" part of the book "Pattern Languages of + * Program Design 3" edited by Martin et al. + * + * A Nested Diagnostic Context, or NDC in short, is an instrument + * to distinguish interleaved log output from different sources. Log + * output is typically interleaved when a server handles multiple + * clients near-simultaneously. + * + * Interleaved log output can still be meaningful if each log entry + * from different contexts had a distinctive stamp. This is where NDCs + * come into play. + * + * Note that NDCs are managed on a per thread + * basis. NDC operations such as {@link #push}, {@link + * #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth} + * affect the NDC of the current thread only. NDCs of other + * threads remain unaffected. + * + * For example, a server can build a per client request NDC + * consisting the clients host name and other information contained in + * the the request. Cookies are another source of distinctive + * information. To build an NDC one uses the {@link #push} + * operation. Simply put, + * + * - Contexts can be nested. + * - When entering a context, call `push()`. As a side effect, if + * there is no nested diagnostic context for the current thread, + * this method will create it. + * - When leaving a context, call `pop()`. + * - When exiting a thread make sure to call `remove()`. + * + * There is no penalty for forgetting to match each push() + * operation with a corresponding pop(), except the obvious + * mismatch between the real application context and the context + * set in the NDC. Use of the NDCContextCreator class can + * automate this process and make your code exception-safe. + * + * If configured to do so, {@link log4cplus::PatternLayout} and + * {@link log4cplus::TTCCLayout} instances automatically retrieve + * the nested diagnostic context for the current thread without + * any user intervention. Hence, even if a server is serving + * multiple clients simultaneously, the logs emanating from the + * same code (belonging to the same logger) can still be + * distinguished because each client request will have a different + * NDC tag. + * + * Heavy duty systems should call the {@link #remove} method when + * leaving the run method of a thread. This ensures that the memory + * used by the thread can be freed. + * + * A thread may inherit the nested diagnostic context of another + * (possibly parent) thread using the {@link #inherit inherit} + * method. A thread may obtain a copy of its NDC with the {@link + * #cloneStack cloneStack} method and pass the reference to any other + * thread, in particular to a child. + */ + class LOG4CPLUS_EXPORT NDC + { + public: + /** + * Clear any nested diagnostic information if any. This method is + * useful in cases where the same thread can be potentially used + * over and over in different unrelated contexts. + * + * This method is equivalent to calling the {@link #setMaxDepth} + * method with a zero maxDepth argument. + */ + void clear(); + + /** + * Clone the diagnostic context for the current thread. + * + * Internally a diagnostic context is represented as a stack. A + * given thread can supply the stack (i.e. diagnostic context) to a + * child thread so that the child can inherit the parent thread's + * diagnostic context. + * + * The child thread uses the {@link #inherit inherit} method to + * inherit the parent's diagnostic context. + * + * @return Stack A clone of the current thread's diagnostic context. + */ + DiagnosticContextStack cloneStack() const; + + /** + * Inherit the diagnostic context of another thread. + * + * The parent thread can obtain a reference to its diagnostic + * context using the {@link #cloneStack} method. It should + * communicate this information to its child so that it may inherit + * the parent's diagnostic context. + * + * The parent's diagnostic context is cloned before being + * inherited. In other words, once inherited, the two diagnostic + * contexts can be managed independently. + * + * @param stack The diagnostic context of the parent thread. + */ + void inherit(const DiagnosticContextStack& stack); + + /** + * Used when printing the diagnostic context. + */ + log4cplus::tstring const & get() const; + + /** + * Get the current nesting depth of this diagnostic context. + * + * @see #setMaxDepth + */ + std::size_t getDepth() const; + + /** + * Clients should call this method before leaving a diagnostic + * context. + * + * The returned value is the value that was pushed last. If no + * context is available, then the empty string is returned. If + * each call to `push()` is paired with a call to `pop()` + * (even in presence of thrown exceptions), the last `pop()` + * call frees the memory used by NDC for this + * thread. Otherwise, `remove()` must be called at the end of + * the thread to free the memory used by NDC for the thread. + * + * @return String The innermost diagnostic context. + * + * @see NDCContextCreator, remove(), push() + */ + log4cplus::tstring pop(); + + /** + * Same as pop() but without the return value. + */ + void pop_void (); + + /** + * Looks at the last diagnostic context at the top of this NDC + * without removing it. + * + * The returned value is the value that was pushed last. If no + * context is available, then the empty string is returned. + * + * @return String The innermost diagnostic context. + */ + log4cplus::tstring const & peek() const; + + /** + * Push new diagnostic context information for the current thread. + * + * The contents of the message parameter is + * determined solely by the client. Each call to push() should + * be paired with a call to pop(). + * + * @param message The new diagnostic context information. + * + * @see NDCContextCreator, pop(), remove() + */ + void push(const log4cplus::tstring& message); + void push(tchar const * message); + + /** + * Remove the diagnostic context for this thread. + * + * Each thread that created a diagnostic context by calling + * push() should call this method before exiting. Otherwise, + * the memory used by the thread cannot be reclaimed. It is + * possible to omit this call if and only if each push() call + * is always paired with a pop() call (even in presence of + * thrown exceptions). Then the memory used by NDC will be + * returned by the last pop() call and a call to remove() will + * be no-op. + */ + void remove(); + + /** + * Set maximum depth of this diagnostic context. If the + * current depth is smaller or equal to `maxDepth`, then no + * action is taken. + * + * This method is a convenient alternative to multiple `pop()` + * calls. Moreover, it is often the case that at the end of + * complex call sequences, the depth of the NDC is + * unpredictable. The `setMaxDepth()` method circumvents this + * problem. + * + * For example, the combination + * + * ~~~~{.c} + * void foo() { + * NDC & ndc = getNDC(); + * std::size_t depth = ndc.getDepth(); + * //... complex sequence of calls + * ndc.setMaxDepth(depth); + * } + * ~~~~ + * + * ensures that between the entry and exit of foo the depth of the + * diagnostic stack is conserved. + * + * \note Use of the NDCContextCreator class will solve this + * particular problem. + * + * \see NDC::getDepth() + */ + void setMaxDepth(std::size_t maxDepth); + + // Public ctor but only to be used by internal::DefaultContext. + NDC(); + + // Dtor + virtual ~NDC(); + + private: + // Methods + LOG4CPLUS_PRIVATE static DiagnosticContextStack* getPtr(); + + template + LOG4CPLUS_PRIVATE + void push_worker (StringType const &); + + // Disallow construction (and copying) except by getNDC() + NDC(const NDC&); + NDC& operator=(const NDC&); + }; + + + /** + * Return a reference to the singleton object. + */ + LOG4CPLUS_EXPORT NDC& getNDC(); + + + /** + * This is the internal object that is stored on the NDC stack. + */ + struct LOG4CPLUS_EXPORT DiagnosticContext + { + // Ctors + DiagnosticContext(const log4cplus::tstring& message, + DiagnosticContext const * parent); + DiagnosticContext(tchar const * message, + DiagnosticContext const * parent); + DiagnosticContext(const log4cplus::tstring& message); + DiagnosticContext(tchar const * message); + DiagnosticContext(DiagnosticContext const &); + DiagnosticContext & operator = (DiagnosticContext const &); + DiagnosticContext(DiagnosticContext &&); + DiagnosticContext & operator = (DiagnosticContext &&); + + void swap (DiagnosticContext &); + + // Data + log4cplus::tstring message; /*!< The message at this context level. */ + log4cplus::tstring fullMessage; /*!< The entire message stack. */ + }; + + + /** + * This class ensures that a `NDC::push()` call is always matched + * with a `NDC::pop()` call even in the face of exceptions. + */ + class LOG4CPLUS_EXPORT NDCContextCreator { + public: + /** Pushes msg onto the NDC stack. */ + explicit NDCContextCreator(const log4cplus::tstring& msg); + explicit NDCContextCreator(tchar const * msg); + + NDCContextCreator() = delete; + NDCContextCreator(NDCContextCreator const &) = delete; + NDCContextCreator(NDCContextCreator &&) = delete; + NDCContextCreator & operator= (NDCContextCreator const &) = delete; + NDCContextCreator & operator= (NDCContextCreator &&) = delete; + + /** Pops the NDC stack. */ + ~NDCContextCreator(); + }; + +} // end namespace log4cplus + + +#endif // _LO4CPLUS_NDC_HEADER_ diff --git a/log4cplus/nteventlogappender.h b/log4cplus/nteventlogappender.h new file mode 100644 index 0000000..2d8829f --- /dev/null +++ b/log4cplus/nteventlogappender.h @@ -0,0 +1,84 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: nteventlogappender.h +// Created: 4/2003 +// Author: Michael CATANZARITI +// +// Copyright 2003-2017 Michael CATANZARITI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_NT_EVENT_LOG_APPENDER_HEADER_ +#define LOG4CPLUS_NT_EVENT_LOG_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (LOG4CPLUS_HAVE_NT_EVENT_LOG) + +#include +#include + + +namespace log4cplus { + + /** + * Appends log events to NT EventLog. + */ + class LOG4CPLUS_EXPORT NTEventLogAppender : public Appender { + public: + // ctors + NTEventLogAppender(const log4cplus::tstring& server, + const log4cplus::tstring& log, + const log4cplus::tstring& source); + NTEventLogAppender(const log4cplus::helpers::Properties & properties); + + // dtor + virtual ~NTEventLogAppender(); + + // public Methods + virtual void close(); + + protected: + virtual void append(const spi::InternalLoggingEvent& event); + virtual WORD getEventType(const spi::InternalLoggingEvent& event); + virtual WORD getEventCategory(const spi::InternalLoggingEvent& event); + void init(); + + /* + * Add this source with appropriate configuration keys to the registry. + */ + void addRegistryInfo(); + + // Data + log4cplus::tstring server; + log4cplus::tstring log; + log4cplus::tstring source; + HANDLE hEventLog; + SID* pCurrentUserSID; + + private: + // Disallow copying of instances of this class + NTEventLogAppender(const NTEventLogAppender&); + NTEventLogAppender& operator=(const NTEventLogAppender&); + }; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_HAVE_NT_EVENT_LOG +#endif //LOG4CPLUS_NT_EVENT_LOG_APPENDER_HEADER_ diff --git a/log4cplus/nullappender.h b/log4cplus/nullappender.h new file mode 100644 index 0000000..18e7696 --- /dev/null +++ b/log4cplus/nullappender.h @@ -0,0 +1,65 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: nullappender.h +// Created: 6/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_NULL_APPENDER_HEADER_ +#define LOG4CPLUS_NULL_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +namespace log4cplus { + + /** + * Appends log events to a file. + */ + class LOG4CPLUS_EXPORT NullAppender : public Appender { + public: + // Ctors + NullAppender(); + NullAppender(const log4cplus::helpers::Properties&); + + // Dtor + virtual ~NullAppender(); + + // Methods + virtual void close(); + + protected: + virtual void append(const log4cplus::spi::InternalLoggingEvent& event); + + private: + // Disallow copying of instances of this class + NullAppender(const NullAppender&); + NullAppender& operator=(const NullAppender&); + }; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_NULL_APPENDER_HEADER_ + diff --git a/log4cplus/qt4debugappender.h b/log4cplus/qt4debugappender.h new file mode 100644 index 0000000..177dbda --- /dev/null +++ b/log4cplus/qt4debugappender.h @@ -0,0 +1,103 @@ +// -*- C++ -*- +// Module: Log4cplus +// File: qt4debugappender.h +// Created: 5/2012 +// Author: Vaclav Zeman +// +// +// Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// + +/** @file */ + +#ifndef LOG4CPLUS_QT4DEBUGAPPENDER_H +#define LOG4CPLUS_QT4DEBUGAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#if defined (_WIN32) + #if defined (log4cplusqt4debugappender_EXPORTS) \ + || defined (log4cplusqt4debugappenderU_EXPORTS) \ + || (defined (DLL_EXPORT) && defined (INSIDE_LOG4CPLUS_QT4DEBUGAPPENDER)) + #undef LOG4CPLUS_QT4DEBUGAPPENDER_BUILD_DLL + #define LOG4CPLUS_QT4DEBUGAPPENDER_BUILD_DLL + #endif + #if defined (LOG4CPLUS_QT4DEBUGAPPENDER_BUILD_DLL) + #if defined (INSIDE_LOG4CPLUS_QT4DEBUGAPPENDER) + #define LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT __declspec(dllexport) + #else + #define LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT __declspec(dllimport) + #endif + #else + #define LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT + #endif +#else + #if defined (INSIDE_LOG4CPLUS_QT4DEBUGAPPENDER) + #define LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_EXPORT + #else + #define LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_IMPORT + #endif // defined (INSIDE_LOG4CPLUS_QT4DEBUGAPPENDER) +#endif // !_WIN32 + + +namespace log4cplus +{ + + +class LOG4CPLUS_QT4DEBUGAPPENDER_EXPORT Qt4DebugAppender + : public Appender +{ +public: + Qt4DebugAppender (); + explicit Qt4DebugAppender (helpers::Properties const &); + virtual ~Qt4DebugAppender (); + + virtual void close (); + + static void registerAppender (); + +protected: + virtual void append (spi::InternalLoggingEvent const &); + +private: + Qt4DebugAppender (Qt4DebugAppender const &); + Qt4DebugAppender & operator = (Qt4DebugAppender const &); +}; + + +typedef helpers::SharedObjectPtr Qt4DebugAppenderPtr; + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_QT4DEBUGAPPENDER_H diff --git a/log4cplus/qt5debugappender.h b/log4cplus/qt5debugappender.h new file mode 100644 index 0000000..e14bf23 --- /dev/null +++ b/log4cplus/qt5debugappender.h @@ -0,0 +1,103 @@ +// -*- C++ -*- +// Module: Log4cplus +// File: qt5debugappender.h +// Created: 4/2013 +// Author: Vaclav Zeman +// +// +// Copyright (C) 2013-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// + +/** @file */ + +#ifndef LOG4CPLUS_QT5DEBUGAPPENDER_H +#define LOG4CPLUS_QT5DEBUGAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#if defined (_WIN32) + #if defined (log4cplusqt5debugappender_EXPORTS) \ + || defined (log4cplusqt5debugappenderU_EXPORTS) \ + || (defined (DLL_EXPORT) && defined (INSIDE_LOG4CPLUS_QT5DEBUGAPPENDER)) + #undef LOG4CPLUS_QT5DEBUGAPPENDER_BUILD_DLL + #define LOG4CPLUS_QT5DEBUGAPPENDER_BUILD_DLL + #endif + #if defined (LOG4CPLUS_QT5DEBUGAPPENDER_BUILD_DLL) + #if defined (INSIDE_LOG4CPLUS_QT5DEBUGAPPENDER) + #define LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT __declspec(dllexport) + #else + #define LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT __declspec(dllimport) + #endif + #else + #define LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT + #endif +#else + #if defined (INSIDE_LOG4CPLUS_QT5DEBUGAPPENDER) + #define LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_EXPORT + #else + #define LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT LOG4CPLUS_DECLSPEC_IMPORT + #endif // defined (INSIDE_LOG4CPLUS_QT5DEBUGAPPENDER) +#endif // !_WIN32 + + +namespace log4cplus +{ + + +class LOG4CPLUS_QT5DEBUGAPPENDER_EXPORT Qt5DebugAppender + : public Appender +{ +public: + Qt5DebugAppender (); + explicit Qt5DebugAppender (helpers::Properties const &); + virtual ~Qt5DebugAppender (); + + virtual void close (); + + static void registerAppender (); + +protected: + virtual void append (spi::InternalLoggingEvent const &); + +private: + Qt5DebugAppender (Qt5DebugAppender const &); + Qt5DebugAppender & operator = (Qt5DebugAppender const &); +}; + + +typedef helpers::SharedObjectPtr Qt5DebugAppenderPtr; + + +} // namespace log4cplus + + +#endif // LOG4CPLUS_QT5DEBUGAPPENDER_H diff --git a/log4cplus/socketappender.h b/log4cplus/socketappender.h new file mode 100644 index 0000000..f0dd564 --- /dev/null +++ b/log4cplus/socketappender.h @@ -0,0 +1,164 @@ +// -*- C++ -*- +// Module: LOG4CPLUS +// File: socketappender.h +// Created: 5/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SOCKET_APPENDER_HEADER_ +#define LOG4CPLUS_SOCKET_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include + + +namespace log4cplus +{ + +#ifndef UNICODE + std::size_t const LOG4CPLUS_MAX_MESSAGE_SIZE = 8*1024; +#else + std::size_t const LOG4CPLUS_MAX_MESSAGE_SIZE = 2*8*1024; +#endif + + + /** + * Sends {@link spi::InternalLoggingEvent} objects to a remote a log server. + * + * The SocketAppender has the following properties: + * + *
    + * + *
  • Remote logging is non-intrusive as far as the log event + * is concerned. In other words, the event will be logged with + * the same time stamp, NDC, location info as if it were logged + * locally by the client. + * + *
  • SocketAppenders do not use a layout. + * + *
  • Remote logging uses the TCP protocol. Consequently, if + * the server is reachable, then log events will eventually arrive + * at the server. + * + *
  • If the remote server is down, the logging requests are + * simply dropped. However, if and when the server comes back up, + * then event transmission is resumed transparently. This + * transparent reconneciton is performed by a connector + * thread which periodically attempts to connect to the server. + * + *
  • Logging events are automatically buffered by the + * native TCP implementation. This means that if the link to server + * is slow but still faster than the rate of (log) event production + * by the client, the client will not be affected by the slow + * network connection. However, if the network connection is slower + * then the rate of event production, then the client can only + * progress at the network rate. In particular, if the network link + * to the the server is down, the client will be blocked. + * + *
  • On the other hand, if the network link is up, but the server + * is down, the client will not be blocked when making log requests + * but the log events will be lost due to server unavailability. + *
+ * + *

Properties

+ *
+ *
host
+ *
Remote host name to connect and send events to.
+ * + *
port
+ *
Port on remote host to send events to.
+ * + *
ServerName
+ *
Host name of event's origin prepended to each event.
+ * + *
IPv6
+ *
Boolean value specifying whether to use IPv6 (true) or IPv4 + * (false). Default value is false.
+ * + *
+ */ + class LOG4CPLUS_EXPORT SocketAppender + : public Appender +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + , protected virtual helpers::IConnectorThreadClient +#endif + { + public: + // Ctors + SocketAppender(const log4cplus::tstring& host, unsigned short port, + const log4cplus::tstring& serverName = tstring(), + bool ipv6 = false); + SocketAppender(const log4cplus::helpers::Properties & properties); + + // Dtor + ~SocketAppender(); + + // Methods + virtual void close(); + + protected: + void openSocket(); + void initConnector (); + virtual void append(const spi::InternalLoggingEvent& event); + + // Data + log4cplus::helpers::Socket socket; + log4cplus::tstring host; + unsigned int port; + log4cplus::tstring serverName; + bool ipv6 = false; + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + virtual thread::Mutex const & ctcGetAccessMutex () const; + virtual helpers::Socket & ctcGetSocket (); + virtual helpers::Socket ctcConnect (); + virtual void ctcSetConnected (); + + volatile bool connected; + helpers::SharedObjectPtr connector; +#endif + + private: + // Disallow copying of instances of this class + SocketAppender(const SocketAppender&); + SocketAppender& operator=(const SocketAppender&); + }; + + namespace helpers { + LOG4CPLUS_EXPORT + void convertToBuffer (SocketBuffer & buffer, + const log4cplus::spi::InternalLoggingEvent& event, + const log4cplus::tstring& serverName); + + LOG4CPLUS_EXPORT + log4cplus::spi::InternalLoggingEvent readFromBuffer(SocketBuffer& buffer); + } // end namespace helpers + +} // end namespace log4cplus + +#endif // LOG4CPLUS_SOCKET_APPENDER_HEADER_ diff --git a/log4cplus/spi/appenderattachable.h b/log4cplus/spi/appenderattachable.h new file mode 100644 index 0000000..d0ff6fb --- /dev/null +++ b/log4cplus/spi/appenderattachable.h @@ -0,0 +1,88 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: appenderattachable.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_APPENDER_ATTACHABLE_HEADER_ +#define LOG4CPLUS_SPI_APPENDER_ATTACHABLE_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +namespace log4cplus { + // Forward Declarations + typedef std::vector SharedAppenderPtrList; + + namespace spi { + + /** + * This Interface is for attaching Appenders to objects. + */ + class LOG4CPLUS_EXPORT AppenderAttachable { + public: + // Methods + /** + * Add an appender. + */ + virtual void addAppender(SharedAppenderPtr newAppender) = 0; + + /** + * Get all previously added appenders as an Enumeration. + */ + virtual SharedAppenderPtrList getAllAppenders() = 0; + + /** + * Get an appender by name. + */ + virtual SharedAppenderPtr getAppender(const log4cplus::tstring& name) = 0; + + /** + * Remove all previously added appenders. + */ + virtual void removeAllAppenders() = 0; + + /** + * Remove the appender passed as parameter from the list of appenders. + */ + virtual void removeAppender(SharedAppenderPtr appender) = 0; + + /** + * Remove the appender with the name passed as parameter from the + * list of appenders. + */ + virtual void removeAppender(const log4cplus::tstring& name) = 0; + + // Dtor + virtual ~AppenderAttachable() = 0; + }; + + } // end namespace spi +} // end namespace log4cplus + +#endif // LOG4CPLUS_SPI_APPENDER_ATTACHABLE_HEADER_ diff --git a/log4cplus/spi/factory.h b/log4cplus/spi/factory.h new file mode 100644 index 0000000..8c5234b --- /dev/null +++ b/log4cplus/spi/factory.h @@ -0,0 +1,275 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: factory.h +// Created: 2/2002 +// Author: Tad E. Smith +// +// +// Copyright 2002-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_FACTORY_HEADER_ +#define LOG4CPLUS_SPI_FACTORY_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace log4cplus { + namespace spi { + + /** + * This is the base class for all factories. + */ + class LOG4CPLUS_EXPORT BaseFactory { + public: + virtual ~BaseFactory() = 0; + + /** + * Returns the typename of the objects this factory creates. + */ + virtual log4cplus::tstring const & getTypeName() const = 0; + }; + + + /** + * This abstract class defines the "Factory" interface to create "Appender" + * objects. + */ + class LOG4CPLUS_EXPORT AppenderFactory : public BaseFactory { + public: + typedef Appender ProductType; + typedef SharedAppenderPtr ProductPtr; + + AppenderFactory(); + virtual ~AppenderFactory() = 0; + + /** + * Create an "Appender" object. + */ + virtual SharedAppenderPtr createObject(const log4cplus::helpers::Properties& props) = 0; + }; + + + + /** + * This abstract class defines the "Factory" interface to create "Layout" + * objects. + */ + class LOG4CPLUS_EXPORT LayoutFactory : public BaseFactory { + public: + typedef Layout ProductType; + typedef std::unique_ptr ProductPtr; + + LayoutFactory(); + virtual ~LayoutFactory() = 0; + + /** + * Create a "Layout" object. + */ + virtual std::unique_ptr createObject(const log4cplus::helpers::Properties& props) = 0; + }; + + + + /** + * This abstract class defines the "Factory" interface to create "Appender" + * objects. + */ + class LOG4CPLUS_EXPORT FilterFactory : public BaseFactory { + public: + typedef Filter ProductType; + typedef FilterPtr ProductPtr; + + FilterFactory(); + virtual ~FilterFactory() = 0; + + /** + * Create a "Filter" object. + */ + virtual FilterPtr createObject(const log4cplus::helpers::Properties& props) = 0; + }; + + + /** + * This abstract class defines the "Factory" interface to + * create std::locale instances. + */ + class LOG4CPLUS_EXPORT LocaleFactory + : public BaseFactory + { + public: + typedef std::locale ProductType; + typedef std::locale ProductPtr; + + LocaleFactory(); + virtual ~LocaleFactory() = 0; + + //! \returns std::locale instance + virtual ProductPtr createObject ( + const log4cplus::helpers::Properties & props) = 0; + }; + + + /** + * This template class is used as a "Factory Registry". Objects are + * "entered" into the registry with a "name" using the + * put() method. (The registry then owns the object.) + * These object can then be retrieved using the get() + * method. + * + * Note: This class is Thread-safe. + */ + template + class LOG4CPLUS_EXPORT FactoryRegistry + : public ObjectRegistryBase + { + public: + typedef T product_type; + + virtual ~FactoryRegistry() { + clear(); + } + + // public methods + /** + * Used to enter an object into the registry. (The registry now + * owns object.) + */ + bool put(std::unique_ptr object) { + bool putValResult = putVal(object->getTypeName(), object.get()); + object.release(); + return putValResult; + } + + /** + * Used to retrieve an object from the registry. (The registry + * owns the returned pointer.) + */ + T* get(const log4cplus::tstring& name) const { + return static_cast(getVal(name)); + } + + protected: + virtual void deleteObject(void *object) const { + delete static_cast(object); + } + }; + + + typedef FactoryRegistry AppenderFactoryRegistry; + typedef FactoryRegistry LayoutFactoryRegistry; + typedef FactoryRegistry FilterFactoryRegistry; + typedef FactoryRegistry LocaleFactoryRegistry; + + + /** + * Returns the "singleton" AppenderFactoryRegistry. + */ + LOG4CPLUS_EXPORT AppenderFactoryRegistry& getAppenderFactoryRegistry(); + + /** + * Returns the "singleton" LayoutFactoryRegistry. + */ + LOG4CPLUS_EXPORT LayoutFactoryRegistry& getLayoutFactoryRegistry(); + + /** + * Returns the "singleton" FilterFactoryRegistry. + */ + LOG4CPLUS_EXPORT FilterFactoryRegistry& getFilterFactoryRegistry(); + + /** + * Returns the "singleton" LocaleFactoryRegistry. + */ + LOG4CPLUS_EXPORT LocaleFactoryRegistry& getLocaleFactoryRegistry(); + + + template + class LocalFactoryBase + : public ProductFactoryBase + { + public: + LocalFactoryBase (tchar const * n) + : name (n) + { } + + virtual log4cplus::tstring const & getTypeName() const + { + return name; + } + + private: + log4cplus::tstring name; + }; + + + template + class FactoryTempl + : public LocalFactoryBase + { + public: + typedef typename ProductFactoryBase::ProductPtr ProductPtr; + + FactoryTempl (tchar const * n) + : LocalFactoryBase (n) + { } + + virtual ProductPtr createObject (helpers::Properties const & props) + { + return ProductPtr (new LocalProduct (props)); + } + }; + + + #define LOG4CPLUS_REG_PRODUCT(reg, productprefix, productname, productns, productfact) \ + reg.put ( \ + std::unique_ptr ( \ + new log4cplus::spi::FactoryTempl ( \ + LOG4CPLUS_TEXT(productprefix) \ + LOG4CPLUS_TEXT(#productname)))) + + #define LOG4CPLUS_REG_APPENDER(reg, appendername) \ + LOG4CPLUS_REG_PRODUCT (reg, "log4cplus::", appendername, log4cplus::, \ + log4cplus::spi::AppenderFactory) + + #define LOG4CPLUS_REG_LAYOUT(reg, layoutname) \ + LOG4CPLUS_REG_PRODUCT (reg, "log4cplus::", layoutname, log4cplus::, \ + log4cplus::spi::LayoutFactory) + + #define LOG4CPLUS_REG_FILTER(reg, filtername) \ + LOG4CPLUS_REG_PRODUCT (reg, "log4cplus::spi::", filtername, log4cplus::spi::, \ + log4cplus::spi::FilterFactory) + + #define LOG4CPLUS_REG_LOCALE(reg, name, factory) \ + reg.put (std::unique_ptr ( \ + new factory (name))) + } // namespace spi +} + + +#endif // LOG4CPLUS_SPI_FACTORY_HEADER_ diff --git a/log4cplus/spi/filter.h b/log4cplus/spi/filter.h new file mode 100644 index 0000000..e778c75 --- /dev/null +++ b/log4cplus/spi/filter.h @@ -0,0 +1,404 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: filter.h +// Created: 5/2003 +// Author: Tad E. Smith +// +// +// Copyright 1999-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file + * This header defines Filter and all of it's subclasses. */ + +#ifndef LOG4CPLUS_SPI_FILTER_HEADER_ +#define LOG4CPLUS_SPI_FILTER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include +#include + + +namespace log4cplus { + + namespace helpers + { + + class Properties; + + } + + namespace spi { + + + enum FilterResult { DENY, /**< The log event must be dropped immediately + * without consulting with the remaining + * filters, if any, in the chain. */ + NEUTRAL, /**< This filter is neutral with respect to + * the log event; the remaining filters, if + * if any, should be consulted for a final + * decision. */ + ACCEPT /**< The log event must be logged immediately + * without consulting with the remaining + * filters, if any, in the chain. */ + }; + + // Forward Declarations + class Filter; + class InternalLoggingEvent; + + + /** + * This method is used to filter an InternalLoggingEvent. + * + * Note: filter can be NULL. + */ + LOG4CPLUS_EXPORT FilterResult checkFilter(const Filter* filter, + const InternalLoggingEvent& event); + + typedef helpers::SharedObjectPtr FilterPtr; + + + /** + * Users should extend this class to implement customized logging + * event filtering. Note that the {@link Logger} and {@link + * Appender} classes have built-in filtering rules. It is suggested + * that you first use and understand the built-in rules before rushing + * to write your own custom filters. + * + * This abstract class assumes and also imposes that filters be + * organized in a linear chain. The {@link #decide + * decide(LoggingEvent)} method of each filter is called sequentially, + * in the order of their addition to the chain. + * + * If the value {@link #DENY} is returned, then the log event is + * dropped immediately without consulting with the remaining + * filters. + * + * If the value {@link #NEUTRAL} is returned, then the next filter + * in the chain is consulted. If there are no more filters in the + * chain, then the log event is logged. Thus, in the presence of no + * filters, the default behaviour is to log all logging events. + * + * If the value {@link #ACCEPT} is returned, then the log + * event is logged without consulting the remaining filters. + * + * The philosophy of log4cplus filters is largely inspired from the + * Linux ipchains. + */ + class LOG4CPLUS_EXPORT Filter + : public virtual log4cplus::helpers::SharedObject + { + public: + // ctor and dtor + Filter(); + virtual ~Filter(); + + // Methods + /** + * Appends filter to the end of this filter chain. + */ + void appendFilter(FilterPtr filter); + + /** + * If the decision is DENY, then the event will be + * dropped. If the decision is NEUTRAL, then the next + * filter, if any, will be invoked. If the decision is ACCEPT then + * the event will be logged without consulting with other filters in + * the chain. + * + * @param event The LoggingEvent to decide upon. + * @return The decision of the filter. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const = 0; + + // Data + /** + * Points to the next filter in the filter chain. + */ + FilterPtr next; + }; + + + + /** + * This filter drops all logging events. + * + * You can add this filter to the end of a filter chain to + * switch from the default "accept all unless instructed otherwise" + * filtering behaviour to a "deny all unless instructed otherwise" + * behaviour. + */ + class LOG4CPLUS_EXPORT DenyAllFilter : public Filter { + public: + DenyAllFilter (); + DenyAllFilter (const log4cplus::helpers::Properties&); + + /** + * Always returns the {@link #DENY} regardless of the + * {@link InternalLoggingEvent} parameter. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + }; + + + /** + * This is a very simple filter based on LogLevel matching. + * + * The filter admits two options LogLevelToMatch and + * AcceptOnMatch. If there is an exact match between the value + * of the LogLevelToMatch option and the LogLevel of the {@link + * spi::InternalLoggingEvent}, then the {@link #decide} method returns + * {@link #ACCEPT} in case the AcceptOnMatch option value is set + * to true, if it is false then {@link #DENY} + * is returned. If there is no match, {@link #NEUTRAL} is returned. + */ + class LOG4CPLUS_EXPORT LogLevelMatchFilter : public Filter { + public: + LogLevelMatchFilter(); + LogLevelMatchFilter(const log4cplus::helpers::Properties& p); + + /** + * Return the decision of this filter. + * + * Returns {@link #NEUTRAL} if the LogLevelToMatch + * option is not set or if there is no match. Otherwise, if + * there is a match, then the returned decision is {@link #ACCEPT} + * if the AcceptOnMatch property is set to true. + * The returned decision is {@link #DENY} if the AcceptOnMatch + * property is set to false. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + + private: + // Methods + LOG4CPLUS_PRIVATE void init(); + + // Data + /** Do we return ACCEPT when a match occurs. Default is true. */ + bool acceptOnMatch; + LogLevel logLevelToMatch; + }; + + + + /** + * This is a very simple filter based on LogLevel matching, which can be + * used to reject messages with LogLevels outside a certain range. + * + * The filter admits three options LogLevelMin, LogLevelMax + * and AcceptOnMatch. + * + * If the LogLevel of the Logging event is not between Min and Max + * (inclusive), then {@link #DENY} is returned. + * + * If the Logging event LogLevel is within the specified range, then if + * AcceptOnMatch is true, {@link #ACCEPT} is returned, and if + * AcceptOnMatch is false, {@link #NEUTRAL} is returned. + * + * If LogLevelMin is not defined, then there is no + * minimum acceptable LogLevel (ie a LogLevel is never rejected for + * being too "low"/unimportant). If LogLevelMax is not + * defined, then there is no maximum acceptable LogLevel (ie a + * LogLevel is never rejected for beeing too "high"/important). + * + * Refer to the {@link + * Appender#setThreshold setThreshold} method + * available to all appenders for a more convenient way to + * filter out events by LogLevel. + */ + class LOG4CPLUS_EXPORT LogLevelRangeFilter : public Filter { + public: + // ctors + LogLevelRangeFilter(); + LogLevelRangeFilter(const log4cplus::helpers::Properties& p); + + /** + * Return the decision of this filter. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + + private: + // Methods + LOG4CPLUS_PRIVATE void init(); + + // Data + /** Do we return ACCEPT when a match occurs. Default is true. */ + bool acceptOnMatch; + LogLevel logLevelMin; + LogLevel logLevelMax; + }; + + + + /** + * This is a very simple filter based on string matching. + * + * The filter admits two options StringToMatch and + * AcceptOnMatch. If there is a match between the value of the + * StringToMatch option and the message of the Logging event, + * then the {@link #decide} method returns {@link #ACCEPT} if + * the AcceptOnMatch option value is true, if it is false then + * {@link #DENY} is returned. If there is no match, {@link #NEUTRAL} + * is returned. + */ + class LOG4CPLUS_EXPORT StringMatchFilter : public Filter { + public: + // ctors + StringMatchFilter(); + StringMatchFilter(const log4cplus::helpers::Properties& p); + + /** + * Returns {@link #NEUTRAL} is there is no string match. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + + private: + // Methods + LOG4CPLUS_PRIVATE void init(); + + // Data + /** Do we return ACCEPT when a match occurs. Default is true. */ + bool acceptOnMatch; + log4cplus::tstring stringToMatch; + }; + + /** + * This filter allows using `std::function`. + */ + class LOG4CPLUS_EXPORT FunctionFilter + : public Filter + { + public: + typedef std::function + Function; + + FunctionFilter (Function); + + /** + * Returns result returned by `function`. + */ + virtual FilterResult decide(const InternalLoggingEvent&) const; + + private: + Function function; + }; + + /** + * This is a simple filter based on the string returned by event.getNDC(). + * + * The filter admits three options NeutralOnEmpty, NDCToMatch + * and AcceptOnMatch. + * + * If NeutralOnEmpty is true and NDCToMatch is empty + * then {@link #NEUTRAL} is returned. + * + * If NeutralOnEmpty is true and the value returned by event.getNDC() is empty + * then {@link #NEUTRAL} is returned. + * + * If the string returned by event.getNDC() matches NDCToMatch, then if + * AcceptOnMatch is true, {@link #ACCEPT} is returned, and if + * AcceptOnMatch is false, {@link #DENY} is returned. + * + * If the string returned by event.getNDC() does not match NDCToMatch, then if + * AcceptOnMatch is true, {@link #DENY} is returned, and if + * AcceptOnMatch is false, {@link #ACCEPT} is returned. + * + */ + + class LOG4CPLUS_EXPORT NDCMatchFilter : public Filter + { + public: + // ctors + NDCMatchFilter(); + NDCMatchFilter(const log4cplus::helpers::Properties& p); + + /** + * Returns {@link #NEUTRAL} is there is no string match. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + + private: + // Methods + LOG4CPLUS_PRIVATE void init(); + + // Data + /** Do we return ACCEPT when a match occurs. Default is true. */ + bool acceptOnMatch; + /** return NEUTRAL if event.getNDC() is empty or ndcToMatch is empty. Default is true. */ + bool neutralOnEmpty; + log4cplus::tstring ndcToMatch; + }; + + /** + * This is a simple filter based on the key/value pair stored in MDC. + * + * The filter admits four options NeutralOnEmpty, MDCKeyToMatch + * MDCValueToMatch and AcceptOnMatch. + * + * If NeutralOnEmpty is true and MDCKeyToMatch or MDCValueToMatch + * is empty then {@link #NEUTRAL} is returned. + * + * If NeutralOnEmpty is true and the string returned by event.getMDC(MDCKeyToMatch) is empty + * then {@link #NEUTRAL} is returned. + * + * If the string returned by event.getMDC(MDCKeyToMatch) matches MDCValueToMatch, then if + * AcceptOnMatch is true, {@link #ACCEPT} is returned, and if + * AcceptOnMatch is false, {@link #DENY} is returned. + * + * If the string returned by event.getMDC(MDCKeyToMatch) does not match MDCValueToMatch, then if + * AcceptOnMatch is true, {@link #DENY} is returned, and if + * AcceptOnMatch is false, {@link #ACCEPT} is returned. + * + */ + + class LOG4CPLUS_EXPORT MDCMatchFilter : public Filter + { + public: + // ctors + MDCMatchFilter(); + MDCMatchFilter(const log4cplus::helpers::Properties& p); + + /** + * Returns {@link #NEUTRAL} is there is no string match. + */ + virtual FilterResult decide(const InternalLoggingEvent& event) const; + + private: + // Methods + LOG4CPLUS_PRIVATE void init(); + + // Data + /** Do we return ACCEPT when a match occurs. Default is true. */ + bool acceptOnMatch; + /** return NEUTRAL if mdcKeyToMatch is empty or event::getMDC(mdcKeyValue) is empty or mdcValueToMatch is empty. Default is true. */ + bool neutralOnEmpty; + /** The MDC key to retrieve **/ + log4cplus::tstring mdcKeyToMatch; + /** the MDC value to match **/ + log4cplus::tstring mdcValueToMatch; + }; + + } // end namespace spi +} // end namespace log4cplus + +#endif /* LOG4CPLUS_SPI_FILTER_HEADER_ */ diff --git a/log4cplus/spi/loggerfactory.h b/log4cplus/spi/loggerfactory.h new file mode 100644 index 0000000..55df218 --- /dev/null +++ b/log4cplus/spi/loggerfactory.h @@ -0,0 +1,65 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loggerfactory.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_LOGGER_FACTORY_HEADER +#define LOG4CPLUS_SPI_LOGGER_FACTORY_HEADER + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +namespace log4cplus { + // Forward Declarations + class Logger; + class Hierarchy; + + namespace spi { + class LoggerImpl; + + /** + * Implement this interface to create new instances of Logger or + * a sub-class of Logger. + */ + class LOG4CPLUS_EXPORT LoggerFactory { + public: + /** + * Creates a new Logger object. + */ + virtual Logger makeNewLoggerInstance(const log4cplus::tstring& name, + Hierarchy& h) = 0; + virtual ~LoggerFactory() = 0; + + protected: + virtual LoggerImpl * makeNewLoggerImplInstance( + const log4cplus::tstring& name, Hierarchy& h) = 0; + }; + + } // end namespace spi +} // end namespace log4cplus + +#endif // LOG4CPLUS_SPI_LOGGER_FACTORY_HEADER diff --git a/log4cplus/spi/loggerimpl.h b/log4cplus/spi/loggerimpl.h new file mode 100644 index 0000000..4112f0f --- /dev/null +++ b/log4cplus/spi/loggerimpl.h @@ -0,0 +1,216 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loggerimpl.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_LOGGER_HEADER_ +#define LOG4CPLUS_SPI_LOGGER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + + +namespace log4cplus { + class DefaultLoggerFactory; + + namespace spi { + + /** + * This is the central class in the log4cplus package. One of the + * distintive features of log4cplus are hierarchical loggers and their + * evaluation. + */ + class LOG4CPLUS_EXPORT LoggerImpl + : public virtual log4cplus::helpers::SharedObject, + public log4cplus::helpers::AppenderAttachableImpl + { + public: + typedef helpers::SharedObjectPtr SharedLoggerImplPtr; + + // Methods + + /** + * Call the appenders in the hierrachy starting at + * this. If no appenders could be found, emit a + * warning. + * + * This method calls all the appenders inherited from the + * hierarchy circumventing any evaluation of whether to log or not + * to log the particular log request. + * + * @param event The event to log. + */ + virtual void callAppenders(const InternalLoggingEvent& event); + + /** + * Close all attached appenders implementing the AppenderAttachable + * interface. + */ + virtual void closeNestedAppenders(); + + /** + * Check whether this logger is enabled for a given LogLevel passed + * as parameter. + * + * @return boolean True if this logger is enabled for ll. + */ + virtual bool isEnabledFor(LogLevel ll) const; + + /** + * This generic form is intended to be used by wrappers. + */ + virtual void log(LogLevel ll, const log4cplus::tstring& message, + const char* file=nullptr, int line=-1, + const char* function=nullptr); + + virtual void log(spi::InternalLoggingEvent const &); + + /** + * Starting from this logger, search the logger hierarchy for a + * "set" LogLevel and return it. Otherwise, return the LogLevel of the + * root logger. + * + * The Logger class is designed so that this method executes as + * quickly as possible. + */ + virtual LogLevel getChainedLogLevel() const; + + /** + * Returns the assigned LogLevel, if any, for this Logger. + * + * @return LogLevel - the assigned LogLevel. + */ + LogLevel getLogLevel() const { return this->ll; } + + /** + * Set the LogLevel of this Logger. + */ + void setLogLevel(LogLevel _ll) { this->ll = _ll; } + + /** + * Return the the {@link Hierarchy} where this Logger + * instance is attached. + */ + virtual Hierarchy& getHierarchy() const; + + /** + * Return the logger name. + */ + log4cplus::tstring const & getName() const { return name; } + + /** + * Get the additivity flag for this Logger instance. + */ + bool getAdditivity() const; + + /** + * Set the additivity flag for this Logger instance. + */ + void setAdditivity(bool additive); + + virtual ~LoggerImpl(); + + protected: + // Ctors + /** + * This constructor created a new Logger instance and + * sets its name. + * + * It is intended to be used by sub-classes only. You should not + * create loggers directly. + * + * @param name The name of the logger. + * @param h Hierarchy + */ + LoggerImpl(const log4cplus::tstring& name, Hierarchy& h); + + + // Methods + /** + * This method creates a new logging event and logs the event + * without further checks. + */ + virtual void forcedLog(LogLevel ll, + const log4cplus::tstring& message, + const char* file, + int line, + const char* function); + + virtual void forcedLog(spi::InternalLoggingEvent const & ev); + + + // Data + /** The name of this logger */ + log4cplus::tstring name; + + /** + * The assigned LogLevel of this logger. + */ + LogLevel ll; + + /** + * The parent of this logger. All loggers have at least one + * ancestor which is the root logger. + */ + SharedLoggerImplPtr parent; + + /** + * Additivity is set to true by default, that is children inherit + * the appenders of their ancestors by default. If this variable is + * set to false then the appenders found in the + * ancestors of this logger are not used. However, the children + * of this logger will inherit its appenders, unless the children + * have their additivity flag set to false too. See + * the user manual for more details. + */ + bool additive; + + private: + // Data + /** Loggers need to know what Hierarchy they are in. */ + Hierarchy& hierarchy; + + // Disallow copying of instances of this class + LoggerImpl(const LoggerImpl&) = delete; + LoggerImpl& operator=(const LoggerImpl&) = delete; + + // Friends + friend class log4cplus::Logger; + friend class log4cplus::DefaultLoggerFactory; + friend class log4cplus::Hierarchy; + }; + + typedef LoggerImpl::SharedLoggerImplPtr SharedLoggerImplPtr; + + } // end namespace spi +} // end namespace log4cplus + +#endif // LOG4CPLUS_SPI_LOGGER_HEADER_ diff --git a/log4cplus/spi/loggingevent.h b/log4cplus/spi/loggingevent.h new file mode 100644 index 0000000..de3417e --- /dev/null +++ b/log4cplus/spi/loggingevent.h @@ -0,0 +1,239 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: loggingevent.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_INTERNAL_LOGGING_EVENT_HEADER_ +#define LOG4CPLUS_SPI_INTERNAL_LOGGING_EVENT_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace log4cplus { + namespace spi { + /** + * The internal representation of logging events. When an affirmative + * decision is made to log then a InternalLoggingEvent + * instance is created. This instance is passed around to the + * different log4cplus components. + * + * This class is of concern to those wishing to extend log4cplus. + */ + class LOG4CPLUS_EXPORT InternalLoggingEvent { + public: + // Ctors + /** + * Instantiate a LoggingEvent from the supplied parameters. + * + * @param logger The logger of this event. + * @param loglevel The LogLevel of this event. + * @param message The message of this event. + * @param filename Name of file where this event has occurred, + * can be NULL. + * @param line Line number in file specified by + * the filename parameter. + * @param function Name of function that is logging this event. + */ + InternalLoggingEvent(const log4cplus::tstring& logger, + LogLevel loglevel, const log4cplus::tstring& message, + const char* filename, int line, const char * function = nullptr); + + InternalLoggingEvent(const log4cplus::tstring& logger, + LogLevel loglevel, const log4cplus::tstring& ndc, + MappedDiagnosticContextMap const & mdc, + const log4cplus::tstring& message, + const log4cplus::tstring& thread, + log4cplus::helpers::Time time, const log4cplus::tstring& file, + int line, const log4cplus::tstring & function + = log4cplus::tstring ()) LOG4CPLUS_ATTRIBUTE_DEPRECATED; + + InternalLoggingEvent(const log4cplus::tstring& logger, + LogLevel loglevel, const log4cplus::tstring& ndc, + MappedDiagnosticContextMap const & mdc, + const log4cplus::tstring& message, + const log4cplus::tstring& thread, + const log4cplus::tstring& thread2, + log4cplus::helpers::Time time, const log4cplus::tstring& file, + int line, const log4cplus::tstring & function + = log4cplus::tstring ()); + + InternalLoggingEvent (); + + InternalLoggingEvent( + const log4cplus::spi::InternalLoggingEvent& rhs); + + virtual ~InternalLoggingEvent(); + + void setLoggingEvent (const log4cplus::tstring & logger, + LogLevel ll, const log4cplus::tstring & message, + const char * filename, int line, + const char * function = nullptr); + + void setFunction (char const * func); + void setFunction (log4cplus::tstring const &); + + + // public virtual methods + /** The application supplied message of logging event. */ + virtual const log4cplus::tstring& getMessage() const; + + /** Returns the 'type' of InternalLoggingEvent. Derived classes + * should override this method. (NOTE: Values <= 1000 are + * reserved for log4cplus and should not be used.) + */ + virtual unsigned int getType() const; + + /** Returns a copy of this object. Derived classes + * should override this method. + */ + virtual std::unique_ptr clone() const; + + + // public methods + /** The logger of the logging event. It is set by + * the LoggingEvent constructor. + */ + const log4cplus::tstring& getLoggerName() const + { + return loggerName; + } + + /** LogLevel of logging event. */ + LogLevel getLogLevel() const + { + return ll; + } + + /** The nested diagnostic context (NDC) of logging event. */ + const log4cplus::tstring& getNDC() const + { + if (!ndcCached) + { + ndc = log4cplus::getNDC().get(); + ndcCached = true; + } + return ndc; + } + + MappedDiagnosticContextMap const & getMDCCopy () const + { + if (!mdcCached) + { + mdc = log4cplus::getMDC().getContext (); + mdcCached = true; + } + return mdc; + } + + tstring const & getMDC (tstring const & key) const; + + /** The name of thread in which this logging event was generated. */ + const log4cplus::tstring& getThread() const + { + if (! threadCached) + { + thread = thread::getCurrentThreadName (); + threadCached = true; + } + return thread; + } + + //! The alternative name of thread in which this logging event + //! was generated. + const log4cplus::tstring& getThread2() const + { + if (! thread2Cached) + { + thread2 = thread::getCurrentThreadName2 (); + thread2Cached = true; + } + return thread2; + } + + + /** Time stamp when the event was created. */ + const log4cplus::helpers::Time& getTimestamp() const + { + return timestamp; + } + + /** The is the file where this log statement was written */ + const log4cplus::tstring& getFile() const + { + return file; + } + + /** The is the line where this log statement was written */ + int getLine() const { return line; } + + log4cplus::tstring const & getFunction () const + { + return function; + } + + void gatherThreadSpecificData () const; + + void swap (InternalLoggingEvent &); + + // public operators + log4cplus::spi::InternalLoggingEvent& + operator=(const log4cplus::spi::InternalLoggingEvent& rhs); + + // static methods + static unsigned int getDefaultType(); + + protected: + // Data + log4cplus::tstring message; + log4cplus::tstring loggerName; + LogLevel ll; + mutable log4cplus::tstring ndc; + mutable MappedDiagnosticContextMap mdc; + mutable log4cplus::tstring thread; + mutable log4cplus::tstring thread2; + log4cplus::helpers::Time timestamp; + log4cplus::tstring file; + log4cplus::tstring function; + int line; + /** Indicates whether or not the Threadname has been retrieved. */ + mutable bool threadCached; + mutable bool thread2Cached; + /** Indicates whether or not the NDC has been retrieved. */ + mutable bool ndcCached; + /** Indicates whether or not the MDC has been retrieved. */ + mutable bool mdcCached; + }; + + } // end namespace spi +} // end namespace log4cplus + +#endif // LOG4CPLUS_SPI_INTERNAL_LOGGING_EVENT_HEADER_ diff --git a/log4cplus/spi/objectregistry.h b/log4cplus/spi/objectregistry.h new file mode 100644 index 0000000..a63cecd --- /dev/null +++ b/log4cplus/spi/objectregistry.h @@ -0,0 +1,113 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: objectregistry.h +// Created: 3/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_OBJECT_REGISTRY_HEADER_ +#define LOG4CPLUS_SPI_OBJECT_REGISTRY_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include + + +namespace log4cplus { + namespace spi { + + /** + * This is the base class used to implement the functionality required + * by the ObjectRegistry template class. + */ + class LOG4CPLUS_EXPORT ObjectRegistryBase { + public: + // public methods + /** + * Tests to see whether or not an object is bound in the + * registry as name. + */ + bool exists(const log4cplus::tstring& name) const; + + /** + * Returns the names of all registered objects. + */ + std::vector getAllNames() const; + + //! This function is internal implementation detail. + //! It is related to work-around needed for initialization when + //! using C++11 threads and mutexes. + void _enableLocking (bool); + + protected: + // Ctor and Dtor + ObjectRegistryBase(); + virtual ~ObjectRegistryBase(); + + // protected methods + /** + * Used to enter an object into the registry. (The registry now + * owns object.) + */ + bool putVal(const log4cplus::tstring& name, void* object); + + /** + * Used to retrieve an object from the registry. (The registry + * owns the returned pointer.) + */ + void* getVal(const log4cplus::tstring& name) const; + + /** + * Deletes object. + */ + virtual void deleteObject(void *object) const = 0; + + /** + * Deletes all objects from this registry. + */ + virtual void clear(); + + // Types + typedef std::map ObjectMap; + + // Data + thread::Mutex mutex; + ObjectMap data; + + private: + ObjectRegistryBase (ObjectRegistryBase const &); + ObjectRegistryBase & operator = (ObjectRegistryBase const &); + + bool volatile locking; + }; + + } +} + + +#endif // LOG4CPLUS_SPI_OBJECT_REGISTRY_HEADER_ + diff --git a/log4cplus/spi/rootlogger.h b/log4cplus/spi/rootlogger.h new file mode 100644 index 0000000..91d3a31 --- /dev/null +++ b/log4cplus/spi/rootlogger.h @@ -0,0 +1,75 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: rootlogger.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SPI_ROOT_LOGGER_HEADER_ +#define LOG4CPLUS_SPI_ROOT_LOGGER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +namespace log4cplus { + namespace spi { + + /** + * RootLogger sits at the top of the logger hierachy. It is a + * regular logger except that it provides several guarantees. + * + * First, it cannot be assigned a NOT_SET_LOG_LEVEL + * LogLevel. Second, since root logger cannot have a parent, the + * getChainedLogLevel method always returns the value of the + * ll field without walking the hierarchy. + */ + class LOG4CPLUS_EXPORT RootLogger : public LoggerImpl { + public: + // Ctors + /** + * The root logger names itself as "root". However, the root + * logger cannot be retrieved by name. + */ + RootLogger(Hierarchy& h, LogLevel ll); + + // Methods + /** + * Return the assigned LogLevel value without walking the logger + * hierarchy. + */ + virtual LogLevel getChainedLogLevel() const; + + /** + * Setting a NOT_SET_LOG_LEVEL value to the LogLevel of the root logger + * may have catastrophic results. We prevent this here. + */ + void setLogLevel(LogLevel); + + }; + + } // end namespace spi +} // end namespace log4cplus + +#endif // LOG4CPLUS_SPI_ROOT_LOGGER_HEADER_ + diff --git a/log4cplus/streams.h b/log4cplus/streams.h new file mode 100644 index 0000000..5d61010 --- /dev/null +++ b/log4cplus/streams.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: streams.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_STREAMS_HEADER_ +#define LOG4CPLUS_STREAMS_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include + + +namespace log4cplus +{ + typedef std::basic_ostream tostream; + typedef std::basic_istream tistream; + typedef std::basic_ostringstream tostringstream; + typedef std::basic_istringstream tistringstream; + extern LOG4CPLUS_EXPORT tostream & tcout; + extern LOG4CPLUS_EXPORT tostream & tcerr; +} + +#if defined (UNICODE) && defined (LOG4CPLUS_ENABLE_GLOBAL_C_STRING_STREAM_INSERTER) + +LOG4CPLUS_EXPORT log4cplus::tostream& operator <<(log4cplus::tostream&, const char* psz ); + +#endif + +#endif // LOG4CPLUS_STREAMS_HEADER_ + diff --git a/log4cplus/syslogappender.h b/log4cplus/syslogappender.h new file mode 100644 index 0000000..1171a36 --- /dev/null +++ b/log4cplus/syslogappender.h @@ -0,0 +1,167 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: syslogappender.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_SYSLOG_APPENDER_HEADER_ +#define LOG4CPLUS_SYSLOG_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + + +namespace log4cplus +{ + + /** + * Appends log events to a file. + * + *

Properties

+ *
+ *
ident
+ *
First argument to openlog(), a string that + * will be prepended to every message.
+ * + *
facility
+ *
Facility is used in combination with syslog level in first + * argument to syslog(). It can be one of the supported facility + * names (case insensitive), e.g. auth, cron, kern, mail, news + * etc.
+ * + *
host
+ *
Destination syslog host. When this property is specified, + * messages are sent using UDP to destination host, otherwise + * messages are logged to local syslog.
+ * + *
port
+ *
Destination port of syslog service on host specified by the + * host property. The default value is port 514.
+ * + *
udp
When the syslog is remote, this + * property picks the IP protocol. When the value is true, UDP is + * used. When the value is false, TCP is used. The default value + * is true.
+ * + *
IPv6
+ *
Boolean value specifying whether to use IPv6 (true) or IPv4 + * (false). Default value is false.
+ * + *
fqdn
+ *
Boolean value specifying whether to use FQDN for hostname field. + * Default value is true.
+ * + *
+ * + * \note Messages sent to remote syslog using UDP are conforming + * to RFC5424. Messages sent to remote syslog using TCP are + * using octet counting as described in RFC6587. + */ + class LOG4CPLUS_EXPORT SysLogAppender + : public Appender +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + , protected virtual helpers::IConnectorThreadClient +#endif + { + public: + //! Remote syslog IP protocol type. + enum RemoteSyslogType + { + RSTUdp, + RSTTcp + }; + + // Ctors +#if defined (LOG4CPLUS_HAVE_SYSLOG_H) + SysLogAppender(const tstring& ident); +#endif + SysLogAppender(const tstring& ident, const tstring & host, + int port = 514, const tstring & facility = tstring (), + RemoteSyslogType remoteSyslogType = RSTUdp, bool ipv6 = false); + SysLogAppender(const tstring& ident, const tstring & host, + int port, const tstring & facility, + RemoteSyslogType remoteSyslogType, bool ipv6, bool fqdn); + SysLogAppender(const log4cplus::helpers::Properties & properties); + + // Dtor + virtual ~SysLogAppender(); + + // Methods + virtual void close(); + + protected: + virtual int getSysLogLevel(const LogLevel& ll) const; + virtual void append(const spi::InternalLoggingEvent& event); +#if defined (LOG4CPLUS_HAVE_SYSLOG_H) + //! Local syslog (served by `syslog()`) worker function. + void appendLocal(const spi::InternalLoggingEvent& event); +#endif + //! Remote syslog worker function. + void appendRemote(const spi::InternalLoggingEvent& event); + + // Data + tstring ident; + int facility; + + typedef void (SysLogAppender:: * AppendFuncType) ( + const spi::InternalLoggingEvent&); + AppendFuncType appendFunc; + + tstring host; + int port; + RemoteSyslogType remoteSyslogType; + helpers::Socket syslogSocket; + bool connected; + bool ipv6 = false; + + static tstring const remoteTimeFormat; + + void initConnector (); + void openSocket (); + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + virtual thread::Mutex const & ctcGetAccessMutex () const; + virtual helpers::Socket & ctcGetSocket (); + virtual helpers::Socket ctcConnect (); + virtual void ctcSetConnected (); + + helpers::SharedObjectPtr connector; +#endif + + private: + // Disallow copying of instances of this class + SysLogAppender(const SysLogAppender&); + SysLogAppender& operator=(const SysLogAppender&); + + std::string identStr; + tstring hostname; + }; + +} // end namespace log4cplus + + +#endif // LOG4CPLUS_SYSLOG_APPENDER_HEADER_ diff --git a/log4cplus/tchar.h b/log4cplus/tchar.h new file mode 100644 index 0000000..1c99ba6 --- /dev/null +++ b/log4cplus/tchar.h @@ -0,0 +1,63 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/** @file */ + +#ifndef LOG4CPLUS_TCHAR_HEADER_ +#define LOG4CPLUS_TCHAR_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (_WIN32) +#include +#endif + + +#ifdef UNICODE +# define LOG4CPLUS_TEXT2(STRING) L##STRING +#else +# define LOG4CPLUS_TEXT2(STRING) STRING +#endif // UNICODE +#define LOG4CPLUS_TEXT(STRING) LOG4CPLUS_TEXT2(STRING) + + +namespace log4cplus +{ + +#if defined (UNICODE) +typedef wchar_t tchar; + +#else +typedef char tchar; + +#endif + +} // namespace log4cplus + + +#endif // LOG4CPLUS_TCHAR_HEADER_ diff --git a/log4cplus/thread/impl/syncprims-cxx11.h b/log4cplus/thread/impl/syncprims-cxx11.h new file mode 100644 index 0000000..be3cc0d --- /dev/null +++ b/log4cplus/thread/impl/syncprims-cxx11.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +// Copyright (C) 2013-2017, Vaclav Zeman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//! @file +//! This file contains implementations of synchronization +//! primitives using the C++11 API. It does not contain any include +//! guards because it is only a fragment to be included by +//! syncprims.h. + +namespace log4cplus { namespace thread { namespace impl { + +#include "log4cplus/thread/impl/syncprims-pmsm.h" + +} } } // namespace log4cplus { namespace thread { namespace impl { diff --git a/log4cplus/thread/impl/syncprims-impl.h b/log4cplus/thread/impl/syncprims-impl.h new file mode 100644 index 0000000..2222a01 --- /dev/null +++ b/log4cplus/thread/impl/syncprims-impl.h @@ -0,0 +1,90 @@ +// -*- C++ -*- +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_THREAD_SYNCPRIMS_IMPL_H +#define LOG4CPLUS_THREAD_SYNCPRIMS_IMPL_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + +#include +#include +#include +#include +#include + + +namespace log4cplus { namespace thread { namespace impl { + + +LOG4CPLUS_EXPORT void LOG4CPLUS_ATTRIBUTE_NORETURN + syncprims_throw_exception (char const * const msg, + char const * const file, int line); + + +class SharedMutex + : public SharedMutexImplBase +{ +public: + SharedMutex (); + ~SharedMutex (); + + void rdlock () const; + void wrlock () const; + void rdunlock () const; + void wrunlock () const; + +private: + Mutex m1; + Mutex m2; + Mutex m3; + Semaphore w; + mutable unsigned writer_count; + Semaphore r; + mutable unsigned reader_count; + + SharedMutex (SharedMutex const &); + SharedMutex & operator = (SharedMutex const &); +}; + + +} } } // namespace log4cplus { namespace thread { namespace impl { + + +// Include the appropriate implementations of the classes declared +// above. + +#include + +#undef LOG4CPLUS_THROW_RTE + + +#endif // LOG4CPLUS_THREAD_SYNCPRIMS_IMPL_H diff --git a/log4cplus/thread/impl/syncprims-pmsm.h b/log4cplus/thread/impl/syncprims-pmsm.h new file mode 100644 index 0000000..bba97ea --- /dev/null +++ b/log4cplus/thread/impl/syncprims-pmsm.h @@ -0,0 +1,119 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//! @file +//! This file contains implementations of reader-writer locking +//! primitive using other primitives, IOW poor man's rwlock. +//! It does not contain any include guards because it is only a fragment +//! to be included by syncprims-{pthreads,win32}.h. + + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + + +// This implements algorithm described in "Concurrent Control with "Readers" +// and "Writers"; P.J. Courtois, F. Heymans, and D.L. Parnas; +// MBLE Research Laboratory; Brussels, Belgium" + + +inline +SharedMutex::SharedMutex () + : m1 () + , m2 () + , m3 () + , w (1, 1) + , writer_count (0) + , r (1, 1) + , reader_count (0) +{ } + + +inline +SharedMutex::~SharedMutex () +{ } + + +inline +void +SharedMutex::rdlock () const +{ + MutexGuard m3_guard (m3); + SemaphoreGuard r_guard (r); + MutexGuard m1_guard (m1); + if (reader_count + 1 == 1) + w.lock (); + + reader_count += 1; +} + + +inline +void +SharedMutex::rdunlock () const +{ + MutexGuard m1_guard (m1); + if (reader_count - 1 == 0) + w.unlock (); + + reader_count -= 1; +} + + +inline +void +SharedMutex::wrlock () const +{ + { + MutexGuard m2_guard (m2); + if (writer_count + 1 == 1) + r.lock (); + + writer_count += 1; + } + try + { + w.lock (); + } + catch (...) + { + MutexGuard m2_guard (m2); + writer_count -= 1; + throw; + } +} + + +inline +void +SharedMutex::wrunlock () const +{ + w.unlock (); + MutexGuard m2_guard (m2); + if (writer_count - 1 == 0) + r.unlock (); + + writer_count -= 1; +} diff --git a/log4cplus/thread/impl/threads-impl.h b/log4cplus/thread/impl/threads-impl.h new file mode 100644 index 0000000..2c6ae4f --- /dev/null +++ b/log4cplus/thread/impl/threads-impl.h @@ -0,0 +1,96 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: threads.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_IMPL_THREADS_IMPL_HEADER_ +#define LOG4CPLUS_IMPL_THREADS_IMPL_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (_WIN32) +#include +#endif +#include +#include +#include + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + + +namespace log4cplus { namespace thread { namespace impl { + + +#if defined (LOG4CPLUS_USE_PTHREADS) + +typedef pthread_t os_handle_type; +typedef pthread_t os_id_type; + + +inline +pthread_t +getCurrentThreadId () +{ + return pthread_self (); +} + + +#elif defined (LOG4CPLUS_USE_WIN32_THREADS) + +typedef HANDLE os_handle_type; +typedef DWORD os_id_type; + + +inline +DWORD +getCurrentThreadId () +{ + return GetCurrentThreadId (); +} + + +#elif defined (LOG4CPLUS_SINGLE_THREADED) + +typedef void * os_handle_type; +typedef int os_id_type; + + +inline +int +getCurrentThreadId () +{ + return 1; +} + + +#endif + + +} } } // namespace log4cplus { namespace thread { namespace impl { + + +#endif // LOG4CPLUS_IMPL_THREADS_IMPL_HEADER_ diff --git a/log4cplus/thread/impl/tls.h b/log4cplus/thread/impl/tls.h new file mode 100644 index 0000000..2c1270e --- /dev/null +++ b/log4cplus/thread/impl/tls.h @@ -0,0 +1,193 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_THREAD_IMPL_TLS_H +#define LOG4CPLUS_THREAD_IMPL_TLS_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + +#if ! defined (INSIDE_LOG4CPLUS) +# error "This header must not be be used outside log4cplus' implementation files." +#endif + +#ifdef LOG4CPLUS_USE_PTHREADS +# include + +#elif defined (LOG4CPLUS_USE_WIN32_THREADS) +# include + +#elif defined (LOG4CPLUS_SINGLE_THREADED) +# include + +#endif + + +namespace log4cplus { namespace thread { namespace impl { + + +typedef void * tls_value_type; + +#ifdef LOG4CPLUS_USE_PTHREADS +typedef pthread_key_t * tls_key_type; +typedef void (* tls_init_cleanup_func_type)(void *); + +#elif defined (LOG4CPLUS_USE_WIN32_THREADS) +typedef DWORD tls_key_type; +typedef PFLS_CALLBACK_FUNCTION tls_init_cleanup_func_type; + +#elif defined (LOG4CPLUS_SINGLE_THREADED) +typedef std::size_t tls_key_type; +typedef void (* tls_init_cleanup_func_type)(void *); + +#endif + + +inline tls_key_type tls_init (tls_init_cleanup_func_type); +inline tls_value_type tls_get_value (tls_key_type); +inline void tls_set_value (tls_key_type, tls_value_type); +inline void tls_cleanup (tls_key_type); + + +#if defined (LOG4CPLUS_USE_PTHREADS) +tls_key_type +tls_init (tls_init_cleanup_func_type cleanupfunc) +{ + pthread_key_t * key = new pthread_key_t; + int ret = pthread_key_create (key, cleanupfunc); + if (LOG4CPLUS_UNLIKELY (ret != 0)) + throw std::system_error(ret, std::system_category (), + "pthread_key_create() failed"); + return key; +} + + +tls_value_type +tls_get_value (tls_key_type key) +{ + return pthread_getspecific (*key); +} + + +void +tls_set_value (tls_key_type key, tls_value_type value) +{ + pthread_setspecific(*key, value); +} + + +void +tls_cleanup (tls_key_type key) +{ + pthread_key_delete (*key); + delete key; +} + + +#elif defined (LOG4CPLUS_USE_WIN32_THREADS) +tls_key_type +tls_init (tls_init_cleanup_func_type cleanupfunc) +{ + DWORD const slot = FlsAlloc (cleanupfunc); + if (LOG4CPLUS_UNLIKELY (slot == FLS_OUT_OF_INDEXES)) + { + DWORD const eno = GetLastError (); + throw std::system_error (static_cast(eno), + std::system_category (), "FlsAlloc() failed"); + } + return slot; +} + + +tls_value_type tls_get_value (tls_key_type k) +{ + return FlsGetValue (k); +} + + +void +tls_set_value (tls_key_type k, tls_value_type value) +{ + FlsSetValue (k, value); +} + + +void +tls_cleanup (tls_key_type k) +{ + FlsFree (k); +} + + +#elif defined (LOG4CPLUS_SINGLE_THREADED) +extern std::vector * tls_single_threaded_values; + + +tls_key_type +tls_init (tls_init_cleanup_func_type) +{ + if (! tls_single_threaded_values) + tls_single_threaded_values = new std::vector; + tls_key_type key = tls_single_threaded_values->size (); + tls_single_threaded_values->resize (key + 1); + return key; +} + + +tls_value_type +tls_get_value (tls_key_type k) +{ + assert (k < tls_single_threaded_values->size ()); + return (*tls_single_threaded_values)[k]; +} + + +void +tls_set_value (tls_key_type k, tls_value_type val) +{ + assert (k < tls_single_threaded_values->size ()); + (*tls_single_threaded_values)[k] = val; +} + + +void +tls_cleanup (tls_key_type k) +{ + assert (k < tls_single_threaded_values->size ()); + (*tls_single_threaded_values)[k] = 0; +} + +#endif + + +} } } // namespace log4cplus { namespace thread { namespace impl { + +#endif // LOG4CPLUS_THREAD_IMPL_TLS_H diff --git a/log4cplus/thread/syncprims-pub-impl.h b/log4cplus/thread/syncprims-pub-impl.h new file mode 100644 index 0000000..d759d1f --- /dev/null +++ b/log4cplus/thread/syncprims-pub-impl.h @@ -0,0 +1,359 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_THREAD_SYNCPRIMS_PUB_IMPL_H +#define LOG4CPLUS_THREAD_SYNCPRIMS_PUB_IMPL_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#if (defined (LOG4CPLUS_INLINES_ARE_EXPORTED) \ + && defined (LOG4CPLUS_BUILD_DLL)) \ + || defined (LOG4CPLUS_ENABLE_SYNCPRIMS_PUB_IMPL) +#include + +#if ! defined (LOG4CPLUS_SINGLE_THREADED) +# include +#endif + +#define LOG4CPLUS_THROW_RTE(msg) \ + do { log4cplus::thread::impl::syncprims_throw_exception (msg, __FILE__, \ + __LINE__); } while (0) + +namespace log4cplus { namespace thread { + +namespace impl +{ + +LOG4CPLUS_EXPORT void LOG4CPLUS_ATTRIBUTE_NORETURN + syncprims_throw_exception(char const * const msg, + char const * const file, int line); + +} + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +SimpleMutex::SimpleMutex () + LOG4CPLUS_THREADED (: mtx ()) +{ } + + +LOG4CPLUS_INLINE_EXPORT +SimpleMutex::~SimpleMutex () +{ } + + +LOG4CPLUS_INLINE_EXPORT +void +SimpleMutex::lock () const +{ + LOG4CPLUS_THREADED (mtx.lock ()); +} + +LOG4CPLUS_INLINE_EXPORT +bool +SimpleMutex::try_lock () const +{ +#if defined (LOG4CPLUS_SINGLE_THREADED) + return true; +#else + return mtx.try_lock (); +#endif +} + + +LOG4CPLUS_INLINE_EXPORT +void +SimpleMutex::unlock () const +{ + LOG4CPLUS_THREADED (mtx.unlock ()); +} + + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +Mutex::Mutex () + LOG4CPLUS_THREADED (: mtx ()) +{ } + + +LOG4CPLUS_INLINE_EXPORT +Mutex::~Mutex () +{ } + + +LOG4CPLUS_INLINE_EXPORT +void +Mutex::lock () const +{ + LOG4CPLUS_THREADED (mtx.lock ()); +} + + +LOG4CPLUS_INLINE_EXPORT +void +Mutex::unlock () const +{ + LOG4CPLUS_THREADED (mtx.unlock ()); +} + + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +Semaphore::Semaphore (unsigned LOG4CPLUS_THREADED (max_), + unsigned LOG4CPLUS_THREADED (initial)) +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + : maximum(max_) + , val ((std::min) (maximum, initial)) +#endif +{ } + + +LOG4CPLUS_INLINE_EXPORT +Semaphore::~Semaphore () +{ } + + +LOG4CPLUS_INLINE_EXPORT +void +Semaphore::unlock () const +{ +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::lock_guard guard (mtx); + + if (val >= maximum) + LOG4CPLUS_THROW_RTE ("Semaphore::unlock(): val >= max"); + + ++val; + cv.notify_all (); +#endif +} + + +LOG4CPLUS_INLINE_EXPORT +void +Semaphore::lock () const +{ +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::unique_lock guard (mtx); + + if (LOG4CPLUS_UNLIKELY(val > maximum)) + LOG4CPLUS_THROW_RTE ("Semaphore::unlock(): val > max"); + + while (val == 0) + cv.wait (guard); + + --val; + + if (LOG4CPLUS_UNLIKELY(val >= maximum)) + LOG4CPLUS_THROW_RTE ("Semaphore::unlock(): val >= max"); +#endif +} + + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +ManualResetEvent::ManualResetEvent (bool LOG4CPLUS_THREADED (sig)) +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + : signaled (sig) + , sigcount (0) +#endif +{ } + + +LOG4CPLUS_INLINE_EXPORT +ManualResetEvent::~ManualResetEvent () +{ } + + +LOG4CPLUS_INLINE_EXPORT +void +ManualResetEvent::signal () const +{ +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::unique_lock guard (mtx); + + signaled = true; + sigcount += 1; + cv.notify_all (); +#endif +} + + +LOG4CPLUS_INLINE_EXPORT +void +ManualResetEvent::wait () const +{ +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::unique_lock guard (mtx); + + if (! signaled) + { + unsigned prev_count = sigcount; + do + { + cv.wait (guard); + } + while (prev_count == sigcount); + } +#endif +} + + +LOG4CPLUS_INLINE_EXPORT +bool +ManualResetEvent::timed_wait (unsigned long LOG4CPLUS_THREADED (msec)) const +{ +#if defined (LOG4CPLUS_SINGLE_THREADED) + return true; + +#else + std::unique_lock guard (mtx); + + if (! signaled) + { + unsigned prev_count = sigcount; + + std::chrono::steady_clock::time_point const wait_until_time + = std::chrono::steady_clock::now () + + std::chrono::milliseconds (msec); + + do + { + int ret = static_cast( + cv.wait_until (guard, wait_until_time)); + switch (ret) + { + case static_cast(std::cv_status::no_timeout): + break; + + case static_cast(std::cv_status::timeout): + return false; + + default: + guard.unlock (); + guard.release (); + LOG4CPLUS_THROW_RTE ("ManualResetEvent::timed_wait"); + } + } + while (prev_count == sigcount); + } + + return true; +#endif +} + + +LOG4CPLUS_INLINE_EXPORT +void +ManualResetEvent::reset () const +{ +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + std::lock_guard guard (mtx); + + signaled = false; +#endif +} + + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +SharedMutexImplBase::~SharedMutexImplBase () +{ } + + +// +// +// + +LOG4CPLUS_INLINE_EXPORT +SharedMutex::SharedMutex () + : sm (LOG4CPLUS_THREADED (new impl::SharedMutex)) +{ } + + +LOG4CPLUS_INLINE_EXPORT +SharedMutex::~SharedMutex () +{ + LOG4CPLUS_THREADED (delete static_cast(sm)); +} + + +LOG4CPLUS_INLINE_EXPORT +void +SharedMutex::rdlock () const +{ + LOG4CPLUS_THREADED (static_cast(sm)->rdlock ()); +} + + +LOG4CPLUS_INLINE_EXPORT +void +SharedMutex::wrlock () const +{ + LOG4CPLUS_THREADED (static_cast(sm)->wrlock ()); +} + + +LOG4CPLUS_INLINE_EXPORT +void +SharedMutex::rdunlock () const +{ + LOG4CPLUS_THREADED (static_cast(sm)->rdunlock ()); +} + + +LOG4CPLUS_INLINE_EXPORT +void +SharedMutex::wrunlock () const +{ + LOG4CPLUS_THREADED (static_cast(sm)->wrunlock ()); +} + + +} } // namespace log4cplus { namespace thread { + +#endif // LOG4CPLUS_ENABLE_SYNCPRIMS_PUB_IMPL + +#endif // LOG4CPLUS_THREAD_SYNCPRIMS_PUB_IMPL_H diff --git a/log4cplus/thread/syncprims.h b/log4cplus/thread/syncprims.h new file mode 100644 index 0000000..4c288d6 --- /dev/null +++ b/log4cplus/thread/syncprims.h @@ -0,0 +1,354 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_THREAD_SYNCPRIMS_H +#define LOG4CPLUS_THREAD_SYNCPRIMS_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + + +namespace log4cplus { namespace thread { + + +template +class SyncGuard +{ +public: + SyncGuard (); + SyncGuard (SyncPrim const &); + ~SyncGuard (); + SyncGuard (SyncGuard const &) = delete; + SyncGuard & operator = (SyncGuard const &) = delete; + + void lock (); + void unlock (); + void attach (SyncPrim const &); + void attach_and_lock (SyncPrim const &); + void detach (); + +private: + SyncPrim const * sp; +}; + + +class LOG4CPLUS_EXPORT SimpleMutex +{ +public: + SimpleMutex (); + ~SimpleMutex (); + SimpleMutex (SimpleMutex const &) = delete; + SimpleMutex & operator = (SimpleMutex const &) = delete; + + void lock () const; + bool try_lock () const; + void unlock () const; + +private: + LOG4CPLUS_THREADED (mutable std::mutex mtx;) +}; + + +typedef SyncGuard SimpleMutexGuard; + + +class LOG4CPLUS_EXPORT Mutex +{ +public: + Mutex (); + ~Mutex (); + Mutex (Mutex const &) = delete; + Mutex & operator = (Mutex const &) = delete; + + void lock () const; + void unlock () const; + +private: + LOG4CPLUS_THREADED (mutable std::recursive_mutex mtx;) +}; + + +typedef SyncGuard MutexGuard; + + +class LOG4CPLUS_EXPORT Semaphore +{ +public: + Semaphore (unsigned max, unsigned initial); + ~Semaphore (); + Semaphore (Semaphore const &) = delete; + Semaphore & operator = (Semaphore const &) = delete; + + void lock () const; + void unlock () const; + +private: +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + mutable std::mutex mtx; + mutable std::condition_variable cv; + mutable unsigned maximum; + mutable unsigned val; +#endif +}; + + +typedef SyncGuard SemaphoreGuard; + + +class LOG4CPLUS_EXPORT ManualResetEvent +{ +public: + explicit ManualResetEvent (bool = false); + ~ManualResetEvent (); + ManualResetEvent (ManualResetEvent const &) = delete; + ManualResetEvent & operator = (ManualResetEvent const &) = delete; + + void signal () const; + void wait () const; + bool timed_wait (unsigned long msec) const; + void reset () const; + +private: +#if ! defined (LOG4CPLUS_SINGLE_THREADED) + mutable std::mutex mtx; + mutable std::condition_variable cv; + mutable bool signaled; + mutable unsigned sigcount; +#endif +}; + + +class SharedMutexImplBase +{ +protected: + ~SharedMutexImplBase (); +}; + + +template +class SyncGuardFunc +{ +public: + SyncGuardFunc (SyncPrim const &); + ~SyncGuardFunc (); + + void lock (); + void unlock (); + void attach (SyncPrim const &); + void detach (); + +private: + SyncPrim const * sp; + + SyncGuardFunc (SyncGuardFunc const &); + SyncGuardFunc & operator = (SyncGuardFunc const &); +}; + + +class LOG4CPLUS_EXPORT SharedMutex +{ +public: + SharedMutex (); + ~SharedMutex (); + + void rdlock () const; + void rdunlock () const; + + void wrlock () const; + void wrunlock () const; + +private: + SharedMutexImplBase * sm; + + SharedMutex (SharedMutex const &); + SharedMutex & operator = (SharedMutex const &); +}; + + +typedef SyncGuardFunc SharedMutexReaderGuard; + + +typedef SyncGuardFunc SharedMutexWriterGuard; + + +// +// +// + +template +inline +SyncGuard::SyncGuard () + : sp (0) +{ } + + +template +inline +SyncGuard::SyncGuard (SyncPrim const & m) + : sp (&m) +{ + sp->lock (); +} + + +template +inline +SyncGuard::~SyncGuard () +{ + if (sp) + sp->unlock (); +} + + +template +inline +void +SyncGuard::lock () +{ + sp->lock (); +} + + +template +inline +void +SyncGuard::unlock () +{ + sp->unlock (); +} + + +template +inline +void +SyncGuard::attach (SyncPrim const & m) +{ + sp = &m; +} + + +template +inline +void +SyncGuard::attach_and_lock (SyncPrim const & m) +{ + attach (m); + try + { + lock(); + } + catch (...) + { + detach (); + throw; + } +} + + +template +inline +void +SyncGuard::detach () +{ + sp = 0; +} + + +// +// +// + +template +inline +SyncGuardFunc::SyncGuardFunc (SyncPrim const & m) + : sp (&m) +{ + (sp->*lock_func) (); +} + + +template +inline +SyncGuardFunc::~SyncGuardFunc () +{ + if (sp) + (sp->*unlock_func) (); +} + + +template +inline +void +SyncGuardFunc::lock () +{ + (sp->*lock_func) (); +} + + +template +inline +void +SyncGuardFunc::unlock () +{ + (sp->*unlock_func) (); +} + + +template +inline +void +SyncGuardFunc::attach (SyncPrim const & m) +{ + sp = &m; +} + + +template +inline +void +SyncGuardFunc::detach () +{ + sp = 0; +} + + +} } // namespace log4cplus { namespace thread { + + +#endif // LOG4CPLUS_THREAD_SYNCPRIMS_H diff --git a/log4cplus/thread/threads.h b/log4cplus/thread/threads.h new file mode 100644 index 0000000..c9ce7d4 --- /dev/null +++ b/log4cplus/thread/threads.h @@ -0,0 +1,113 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: threads.h +// Created: 6/2001 +// Author: Tad E. Smith +// +// +// Copyright 2001-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_THREADS_HEADER_ +#define LOG4CPLUS_THREADS_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include + + +namespace log4cplus { namespace thread { + + +LOG4CPLUS_EXPORT log4cplus::tstring const & getCurrentThreadName(); +LOG4CPLUS_EXPORT log4cplus::tstring const & getCurrentThreadName2(); +LOG4CPLUS_EXPORT void setCurrentThreadName(const log4cplus::tstring & name); +LOG4CPLUS_EXPORT void setCurrentThreadName2(const log4cplus::tstring & name); +LOG4CPLUS_EXPORT void yield(); +LOG4CPLUS_EXPORT void blockAllSignals(); + +/** + * This class blocks all POSIX signals when created and unblocks them when + * destroyed. + */ +class LOG4CPLUS_EXPORT SignalsBlocker +{ +public: + SignalsBlocker(); + ~SignalsBlocker(); + +private: + struct SignalsBlockerImpl; + std::unique_ptr impl; +}; + + +#ifndef LOG4CPLUS_SINGLE_THREADED + + +/** + * There are many cross-platform C++ Threading libraries. The goal of + * this class is not to replace (or match in functionality) those + * libraries. The goal of this class is to provide a simple Threading + * class with basic functionality. + */ +class LOG4CPLUS_EXPORT AbstractThread + : public virtual log4cplus::helpers::SharedObject +{ +public: + AbstractThread(); + // Disallow copying of instances of this class. + AbstractThread(const AbstractThread&) = delete; + AbstractThread& operator=(const AbstractThread&) = delete; + + bool isRunning() const; + virtual void start(); + void join () const; + virtual void run() = 0; + +protected: + // Force objects to be constructed on the heap + virtual ~AbstractThread(); + +private: + enum Flags + { + fRUNNING = 1, + fJOINED = 2 + }; + + std::unique_ptr thread; + mutable std::atomic flags; +}; + +typedef helpers::SharedObjectPtr AbstractThreadPtr; + + +#endif // LOG4CPLUS_SINGLE_THREADED + + +} } // namespace log4cplus { namespace thread { + + +#endif // LOG4CPLUS_THREADS_HEADER_ diff --git a/log4cplus/tracelogger.h b/log4cplus/tracelogger.h new file mode 100644 index 0000000..4fdbcce --- /dev/null +++ b/log4cplus/tracelogger.h @@ -0,0 +1,87 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: tracelogger.h +// Created: 1/2009 +// Author: Vaclav Haisman +// +// +// Copyright 2009-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_TRACELOGGER_H +#define LOG4CPLUS_TRACELOGGER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include + + +namespace log4cplus +{ + + +/** + * This class is used to produce "Trace" logging. When an instance of + * this class is created, it will log a "ENTER: " + msg + * log message if TRACE_LOG_LEVEL is enabled for logger. + * When an instance of this class is destroyed, it will log a + * "ENTER: " + msg log message if TRACE_LOG_LEVEL is enabled + * for logger. + *

+ * @see LOG4CPLUS_TRACE + */ +class TraceLogger +{ +public: + TraceLogger(Logger l, log4cplus::tstring _msg, + const char* _file = LOG4CPLUS_CALLER_FILE (), + int _line = LOG4CPLUS_CALLER_LINE (), + char const * _function = LOG4CPLUS_CALLER_FUNCTION ()) + : logger(std::move (l)), msg(std::move (_msg)), file(_file), + function(_function), line(_line) + { + if(logger.isEnabledFor(TRACE_LOG_LEVEL)) + logger.forcedLog(TRACE_LOG_LEVEL, LOG4CPLUS_TEXT("ENTER: ") + msg, + file, line, function); + } + + ~TraceLogger() + { + if(logger.isEnabledFor(TRACE_LOG_LEVEL)) + logger.forcedLog(TRACE_LOG_LEVEL, LOG4CPLUS_TEXT("EXIT: ") + msg, + file, line, function); + } + +private: + TraceLogger (TraceLogger const &); + TraceLogger & operator = (TraceLogger const &); + + Logger logger; + log4cplus::tstring msg; + const char* file; + const char* function; + int line; +}; + + +} // log4cplus + + +#endif // LOG4CPLUS_TRACELOGGER_H diff --git a/log4cplus/tstring.h b/log4cplus/tstring.h new file mode 100644 index 0000000..7526568 --- /dev/null +++ b/log4cplus/tstring.h @@ -0,0 +1,128 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: tstring.h +// Created: 4/2003 +// Author: Tad E. Smith +// +// +// Copyright 2003-2017 Tad E. Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_TSTRING_HEADER_ +#define LOG4CPLUS_TSTRING_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +namespace log4cplus +{ + +typedef std::basic_string tstring; + + +namespace helpers +{ + +inline +std::string +tostring (char const * str) +{ + return std::string (str); +} + +inline +std::string +tostring (std::string const & str) +{ + return str; +} + +inline +std::string const & +tostring (std::string & str) +{ + return str; +} + +inline +std::string +tostring (std::string && str) +{ + return std::move (str); +} + + +inline +std::wstring +towstring (wchar_t const * str) +{ + return std::wstring (str); +} + +inline +std::wstring +towstring (std::wstring const & str) +{ + return str; +} + +inline +std::wstring const & +towstring (std::wstring & str) +{ + return str; +} + +inline +std::wstring +towstring (std::wstring && str) +{ + return std::move (str); +} + + +LOG4CPLUS_EXPORT std::string tostring(const std::wstring&); +LOG4CPLUS_EXPORT std::string tostring(wchar_t const *); + +LOG4CPLUS_EXPORT std::wstring towstring(const std::string&); +LOG4CPLUS_EXPORT std::wstring towstring(char const *); + +} // namespace helpers + +#ifdef UNICODE + +#define LOG4CPLUS_C_STR_TO_TSTRING(STRING) log4cplus::helpers::towstring(STRING) +#define LOG4CPLUS_STRING_TO_TSTRING(STRING) log4cplus::helpers::towstring(STRING) +#define LOG4CPLUS_TSTRING_TO_STRING(STRING) log4cplus::helpers::tostring(STRING) + +#else // UNICODE + +#define LOG4CPLUS_C_STR_TO_TSTRING(STRING) (std::string(STRING)) +#define LOG4CPLUS_STRING_TO_TSTRING(STRING) STRING +#define LOG4CPLUS_TSTRING_TO_STRING(STRING) STRING + +#endif // UNICODE + +} // namespace log4cplus + + +#endif // LOG4CPLUS_TSTRING_HEADER_ diff --git a/log4cplus/version.h b/log4cplus/version.h new file mode 100644 index 0000000..0daf2f1 --- /dev/null +++ b/log4cplus/version.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +// Copyright (C) 2010-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#if ! defined (LOG4CPLUS_VERSION_H) +#define LOG4CPLUS_VERSION_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#define LOG4CPLUS_MAKE_VERSION(major, minor, point) \ + (major * 1000 * 1000u + minor * 1000u + point) + +#define LOG4CPLUS_MAKE_VERSION_STR(major, minor, point) \ + #major "." #minor "." #point + +//! This is log4cplus version number as unsigned integer. This must +//! be kept on a single line. It is used by Autotool and CMake build +//! systems to parse version number. +#define LOG4CPLUS_VERSION LOG4CPLUS_MAKE_VERSION(2, 1, 2) + +//! This is log4cplus version number as a string. +#define LOG4CPLUS_VERSION_STR LOG4CPLUS_MAKE_VERSION_STR(2, 1, 2) + + +namespace log4cplus +{ + +extern LOG4CPLUS_EXPORT unsigned const version; +extern LOG4CPLUS_EXPORT char const versionStr[]; + +} + +#endif diff --git a/log4cplus/win32consoleappender.h b/log4cplus/win32consoleappender.h new file mode 100644 index 0000000..0339c7f --- /dev/null +++ b/log4cplus/win32consoleappender.h @@ -0,0 +1,93 @@ +// -*- C++ -*- +// Copyright (C) 2009-2017, Vaclav Haisman. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modifica- +// tion, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- +// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef LOG4CPLUS_WIN32CONSOLEAPPENDER_H +#define LOG4CPLUS_WIN32CONSOLEAPPENDER_H + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined(_WIN32) && defined (LOG4CPLUS_HAVE_WIN32_CONSOLE) + +#include + + +namespace log4cplus +{ + + /** + * Prints events to Win32 console. + * + *

Properties

+ *
+ *
AllocConsole
+ *
This boolean property specifies whether or not this appender + * will try to allocate new console using the + * AllocConsole() Win32 function.
+ * + *
logToStdErr
+ *
When it is set true, the output will be into + * STD_ERROR_HANDLE instead of STD_OUTPUT_HANDLE. + *
+ * + *
TextColor
+ *
See MSDN documentation for + * + * Character Attributes. + *
+ */ + class LOG4CPLUS_EXPORT Win32ConsoleAppender + : public Appender + { + public: + explicit Win32ConsoleAppender (bool allocConsole = true, + bool logToStdErr = false, unsigned int textColor = 0); + Win32ConsoleAppender (helpers::Properties const & properties); + virtual ~Win32ConsoleAppender (); + + virtual void close (); + + protected: + virtual void append (spi::InternalLoggingEvent const &); + + void write_handle (void *, tchar const *, std::size_t); + void write_console (void *, tchar const *, std::size_t); + + bool alloc_console; + bool log_to_std_err; + unsigned int text_color; + + private: + Win32ConsoleAppender (Win32ConsoleAppender const &); + Win32ConsoleAppender & operator = (Win32ConsoleAppender const &); + }; + +} // namespace log4cplus + +#endif + +#endif // LOG4CPLUS_WIN32CONSOLEAPPENDER_H diff --git a/log4cplus/win32debugappender.h b/log4cplus/win32debugappender.h new file mode 100644 index 0000000..31cbc3d --- /dev/null +++ b/log4cplus/win32debugappender.h @@ -0,0 +1,69 @@ +// -*- C++ -*- +// Module: Log4CPLUS +// File: win32debugappender.h +// Created: 12/2003 +// Author: Eduardo Francos, Odalio SARL +// +// +// Copyright 2003-2017 Odalio SARL +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @file */ + +#ifndef LOG4CPLUS_WIN32DEBUG_APPENDER_HEADER_ +#define LOG4CPLUS_WIN32DEBUG_APPENDER_HEADER_ + +#include + +#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) +#pragma once +#endif + +#if defined (LOG4CPLUS_HAVE_OUTPUTDEBUGSTRING) + +#include + + +namespace log4cplus { + + /** + * Prints log events using OutputDebugString(). + */ + class LOG4CPLUS_EXPORT Win32DebugAppender + : public Appender + { + public: + // Ctors + Win32DebugAppender(); + Win32DebugAppender(const log4cplus::helpers::Properties& properties); + + // Dtor + virtual ~Win32DebugAppender(); + + // Methods + virtual void close(); + + protected: + virtual void append(const log4cplus::spi::InternalLoggingEvent& event); + + private: + // Disallow copying of instances of this class + Win32DebugAppender(const Win32DebugAppender&); + Win32DebugAppender& operator=(const Win32DebugAppender&); + }; + +} // end namespace log4cplus + +#endif // LOG4CPLUS_HAVE_OUTPUTDEBUGSTRING +#endif // LOG4CPLUS_WIN32DEBUG_APPENDER_HEADER_ diff --git a/mms/db_interface.h b/mms/db_interface.h index e7184de..853e8d2 100644 --- a/mms/db_interface.h +++ b/mms/db_interface.h @@ -60,27 +60,27 @@ void try_start_kafka_thread(); void try_start_mqconsumer_thread();//lnk20241216 -//0. jsonɿʼ +//0. json生成开始函数 int json_block_create_start( char voltage_level[],char monid_char[],int flicker_flag, char temcode[],int line_id); -//1. jsonʱ꺯 +//1. json生成设置时标函数 int json_block_create_time(char monid_char[], long long Time, int flicker_flag); -//1.5 jsonflag +//1.5 json生成设置flag函数 int json_block_create_flag(char monid_char[], int flag, int flicker_flag); -//2. jsonݻص +//2. json生成数据回调函数 int json_block_create_data(char monid_char[], char* mms_str , double v, int flicker_flag); -//3. jsonɽ -//lnk2024-8-16Ӳ -int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag); //CZY 2023-08-17 +//3. json生成结束函数 +//lnk2024-8-16添加参数 +int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag); //CZY 2023-08-17 测试 -//zw 2024-01-31 ģʽŻ +//zw 2024-01-31 补招模式优化 void add_mvl_type_ctrl(char doname[], int ctrl); int sel_mvl_type_ctrl_flag(char doname[]); void del_mvl_type_ctrl(); -//ģʽŻ end +//补招模式优化 end #ifndef DB_INTERFACE_H #define DB_INTERFACE_H -// ǰ LD_info_t +// 前向声明 LD_info_t typedef struct LD_info_t LD_info_t; int urcbRealDataHasReceived(int dev_index, LD_info_t* LD_info, long long Time); //lnk20241223 #endif @@ -98,21 +98,21 @@ void add_comm_log(char* log_str); void clear_old_comtrade_files(); int process_login_verify(); -//////////////////////////////WW 20230819ݿ +//////////////////////////////WW 20230819增加数据库操作函数 void TestToken(); -void TestBodyPost();//WW qt post -void TestSMSPost();//WW qt post +void TestBodyPost();//WW 测试qt post +void TestSMSPost();//WW 测试qt post void TestJson(char* szJson); -void TestOSS();//WW -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 TestOSS();//WW 测试 +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 DelOSS(char* File_Name); void delete_object_new(char* File_Name); 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_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_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); @@ -120,21 +120,21 @@ void Read_Nacos_Param_Kafka(char** broker_list, char** topic_stat, char** topic_ void Read_Nacos_Param_Web(char** client_id, char** client_secret, char** token_url, char** device_url, char** grant_type); void Read_Nacos_Param_Flag(int* file_flag, int* send_flag, int* front_inst, char** front_ip); void Read_Nacos_Param_Recall(int* recall_len, int* recall_sta, int* recall_daily); -void Read_Nacos_Param_Uds(char** uds_upload_url, char** uds_download_url, char** uds_delete_url);//nacosȡuds +void Read_Nacos_Param_Uds(char** uds_upload_url, char** uds_download_url, char** uds_delete_url);//nacos获取uds参数 int WebAPI_Uds_Upload(char* strUrl, char* loacl_path, char* uuid,char* filename); void WebAPI_Uds_Download(char* strUrl, char* uuid, char* local_path,char* filename); int base64_decode(const char* indata, int inlen, char* outdata, long* outlen); int testbase64(); /////////////////////////////WW end -//////////////////////////////WW 20230822ݿWebSocket߳ -void try_start_socket_thread(); //Web Socket߳ -void try_start_ontimer_thread();//ʱ߳s +//////////////////////////////WW 20230822增加数据库和WebSocket线程 +void try_start_socket_thread(); //启动Web Socket线程 +void try_start_ontimer_thread();//启动定时线程s /////////////////////////////WW end -//lnk20241029http߳//////////////////////////////////////// -void try_start_web_http_thread(); //Webhttp߳ -void try_start_http_thread(); //http߳ +//lnk20241029增加http线程//////////////////////////////////////// +void try_start_web_http_thread(); //启动Webhttp线程 +void try_start_http_thread(); //启动http线程 int try_start_mqtest_thread(int argc, char *argv[]); //20241202 void CreateRecallXml(); void DeletcRecallXml(); @@ -148,6 +148,7 @@ void comflag_test(); int parse_device_cfg_web(); int parse_model_cfg_web(); void SOEFileWeb(char* localpath,char* cloudpath,char* wavepath); +const char* get_front_msg_from_subdir(); ////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus diff --git a/mms/main.c b/mms/main.c index 2b53c72..99105c6 100644 --- a/mms/main.c +++ b/mms/main.c @@ -16,7 +16,9 @@ #include "node.h" /*lnk10-10 */ -#include "../include/rocketmq/SimpleProducer.h" +#include "../rocketmq/SimpleProducer.h" + +#include "../log4cplus/log4.h"//lnk添加log4 #include "../cfg_parse/custom_printf.h"//lnk20250225 @@ -27,7 +29,7 @@ extern pt61850app_t *g_pt61850app; extern node_t *g_node; char g_my_conf_fname[256]; -char g_onlyIP[255]; //ֱijIPΪ +char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 apr_pool_t *g_root_pool; apr_pool_t *g_rdb_pool; @@ -58,34 +60,34 @@ int three_secs_enabled = 0; int auto_register_report_enabled = 0; int g_front_seg_index = 0; int g_front_seg_num = 0; -int FRONT_MP_NUM = 0;//ն -int g_front_num_count = 0;//նʹ +int FRONT_MP_NUM = 0;//终端连接数量 +int g_front_num_count = 0;//终端连接数量过低次数 /////////////////////////////////////////////////////////////////////////////// -//Ŀ¼бȫֹܵͶˣ趨ĸֹܾĹл趨 +//根据配置子目录判别全局功能的投退,设定四个分功能性能均衡程序的功能运行划分设定 void init_global_function_enable() { - if (strcmp(subdir,"cfg_stat_data")==0) { //ʷ̬ + if (strcmp(subdir,"cfg_stat_data")==0) { //历史稳态 g_node_id = STAT_DATA_BASE_NODE_ID; auto_register_report_enabled = 1; - }else if (strcmp(subdir,"cfg_3s_data")==0) { //ʵʱ + }else if (strcmp(subdir,"cfg_3s_data")==0) { //实时 g_node_id = THREE_SECS_DATA_BASE_NODE_ID; three_secs_enabled = 1; - }else if (strcmp(subdir,"cfg_soe_comtrade")==0) { //澯¼̬ + }else if (strcmp(subdir,"cfg_soe_comtrade")==0) { //告警和录波和暂态 g_node_id = SOE_COMTRADE_BASE_NODE_ID; - }else if (strcmp(subdir,"cfg_his_data")==0) { //ʹ + }else if (strcmp(subdir,"cfg_his_data")==0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; g_node_id = HIS_DATA_BASE_NODE_ID; } - else if (strcmp(subdir, "cfg_newhis_data") == 0) { //ʹ + else if (strcmp(subdir, "cfg_newhis_data") == 0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; g_node_id = NEW_HIS_DATA_BASE_NODE_ID; } - else if (strcmp(subdir, "cfg_recallhis_data") == 0) { // + else if (strcmp(subdir, "cfg_recallhis_data") == 0) { //补招 g_node_id = RECALL_HIS_DATA_BASE_NODE_ID; } - else if (strcmp(subdir, "cfg_recallall_data") == 0) { //ʹ + else if (strcmp(subdir, "cfg_recallall_data") == 0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; } } @@ -98,21 +100,21 @@ void init_daemon(void) int i; if( pid = fork() ) - exit(0); /** Ṇ̀ */ + exit(0); /** 是父进程,结束父进程 */ else if( pid < 0 ) - exit(1); /** forkʧܣ˳ */ + exit(1); /** fork失败,退出 */ - /** ǵһӽִ̨̣ */ + /** 是第一子进程,后台继续执行 */ - setsid(); /** һӽ̳ΪµĻỰ鳤ͽ鳤ն˷ */ + setsid(); /** 第一子进程成为新的会话组长和进程组长并与控制终端分离 */ if( pid = fork() ) - exit(0); /** ǵһӽ̣һӽ */ + exit(0); /** 是第一子进程,结束第一子进程 */ else if( pid < 0) - exit(1); /** forkʧܣ˳ */ + exit(1); /** fork失败,退出 */ chdir("/FeProject/bin/"); //multi process running at same time - umask(0); /** ļ */ + umask(0); /** 重设文件创建掩码 */ return; } @@ -132,12 +134,12 @@ int prepare_entironment_2() apr_status_t rv; /* apr library need call this first. */ - apr_initialize(); //APACHEʼ + apr_initialize(); //APACHE初始化 atexit(apr_terminate); /* Create node root pool */ - rv = apr_pool_create(&g_root_pool, NULL); //ڴ + rv = apr_pool_create(&g_root_pool, NULL); //分配根内存 if(rv != APR_SUCCESS) { fprintf(stderr,"%s","Create node root pool failed!\n"); return (-1); @@ -165,13 +167,13 @@ int prepare_entironment_2() } echo_msg("==============================================================\n"); - rv = apr_pool_create(&g_rdb_pool, g_root_pool); //RDBڴ + rv = apr_pool_create(&g_rdb_pool, g_root_pool); //分配RDB内存 if(rv != APR_SUCCESS) { echo_errg("Create system runtime pool failed!\n"); return (-1); } - rv = apr_pool_create(&g_cfg_pool, g_root_pool); //ڴ + rv = apr_pool_create(&g_cfg_pool, g_root_pool); //分配配置内存 if(rv != APR_SUCCESS) { echo_errg("Create system config pool failed!\n"); return (-1); @@ -211,6 +213,8 @@ int main(int argc, const char **argv) return rv; } + + getVersion(argc,argv); rv=parse_param(argc, argv); @@ -218,6 +222,13 @@ int main(int argc, const char **argv) return rv; } + + //lnk启动进程日志 + init_logger_process(); + char buf[256]; + sprintf(buf, "前置的%s%d号进程 进程级日志初始化完毕", get_front_msg_from_subdir(), g_front_seg_index); + log_debug("process", buf); + #ifdef _OS_UNIX_ #ifdef QT_NO_DEBUG if (!g_need_password) @@ -250,23 +261,26 @@ int main(int argc, const char **argv) rv = init_rdb(); if (rv!=APR_SUCCESS){ return rv; - } + } + + //初始化终端和监测点日志 + init_loggers(); rv = run_protocol(); if (rv!=APR_SUCCESS){ return rv; } - //ʼɱ־,ֹδ׼ȫͽϢ± + //初始化完成标志,防止还未准备完全就接收消息处理导致崩溃 INITFLAG = 1; - // + //调试用 printf("INITFLAG=%d\n",INITFLAG); if (1 == G_TEST_FLAG) { - //lnkmqģ,ֻܷ߳ + //lnk添加mq模拟测试,这个只能放在主线程 printf("try_start_mqtest_thread \n"); int ret = try_start_mqtest_thread(0,NULL); - // ȴ߳˳ + // 等待线程退出 echo_warn1("%-60s","System shutdown now......"); apr_pool_destroy(g_root_pool); echo_msg("OK\n"); @@ -276,16 +290,16 @@ int main(int argc, const char **argv) while(1) { /* sleep 1s, just like 1s timer */ apr_sleep(apr_time_from_sec(1)); - /* ÿ30Ӽһ״̬ */ + /* 每30秒钟检查一次状态 */ - if( !(stimer++ % 60) ) {// - if (g_dead_lock_counter++ >=3) {// + if( !(stimer++ % 60) ) {//分钟 + if (g_dead_lock_counter++ >=3) {//三分钟 g_thread_blocked_times++; g_dead_lock_counter = 0; } MVL_LOG_ACSE1 ("MYLOG: current g_thread_blocked_times = %u ", g_thread_blocked_times); - if (FRONT_MP_NUM <= 1) {// + if (FRONT_MP_NUM <= 1) {//监测点数 g_front_num_count++; } else { @@ -293,16 +307,16 @@ int main(int argc, const char **argv) } } - //work߳3*13ӣ˳ + //work线程死了3*13分钟,退出进程 if (g_thread_blocked_times>=13) { MVL_LOG_ACSE0 ("MYLOG: g_thread_blocked_times>=3, so exit to restart "); apr_sleep(apr_time_from_sec(10)); exit(-1039); } - //lnk20241211 ӲԿ + //lnk20241211 添加测试开关 pthread_mutex_lock(&mtx); - if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30Ҳǵ̨˴ʮն + if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30分钟连接数量过低且不是单连且台账大于十个终端 MVL_LOG_ACSE0("MYLOG: g_front_num_count>=20, so exit to restart "); apr_sleep(apr_time_from_sec(10)); @@ -403,19 +417,19 @@ int parse_param(int argc, const char **argv) return 0; } -///////////////////////////////////////////////////////////////ӲԽ̵ļغlnk20250304 +///////////////////////////////////////////////////////////////添加测试进程的监控函数lnk20250304 void doMonitorTaskmain(void) { static int stimer = 0; stimer++; - if( !(stimer++ % 60) ) {// - if (g_dead_lock_counter++ >=3) {// + if( !(stimer++ % 60) ) {//分钟 + if (g_dead_lock_counter++ >=3) {//三分钟 g_thread_blocked_times++; g_dead_lock_counter = 0; } MVL_LOG_ACSE1 ("MYLOG: current g_thread_blocked_times = %u ", g_thread_blocked_times); - if (FRONT_MP_NUM <= 1) {// + if (FRONT_MP_NUM <= 1) {//监测点数 g_front_num_count++; } else { @@ -423,16 +437,16 @@ void doMonitorTaskmain(void) { } } - //work߳3*13ӣ˳ + //work线程死了3*13分钟,退出进程 if (g_thread_blocked_times>=13) { MVL_LOG_ACSE0 ("MYLOG: g_thread_blocked_times>=3, so exit to restart "); apr_sleep(apr_time_from_sec(10)); exit(-1039); } - //lnk20241211 ӲԿ + //lnk20241211 添加测试开关 pthread_mutex_lock(&mtx); - if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30Ҳǵ̨˴ʮն + if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30分钟连接数量过低且不是单连且台账大于十个终端 MVL_LOG_ACSE0("MYLOG: g_front_num_count>=20, so exit to restart "); apr_sleep(apr_time_from_sec(10)); diff --git a/mms/mms_process.c b/mms/mms_process.c index 8b9044d..cb02f85 100644 --- a/mms/mms_process.c +++ b/mms/mms_process.c @@ -1,6 +1,6 @@ /** * @file: $RCSfile: mms_process.c,v $ -* @brief: $PROFIBUS SSRTDB +* @brief: $PROFIBUS 与SSRTDB交互 * * @version: $Revision: 1.28 $ * @date: $Date: 2022/11/28 07:13:13 $ @@ -18,18 +18,20 @@ #include "../json/mms_json_inter.h" #include "../cfg_parse/custom_printf.h"//lnk20250225 +#include "../log4cplus/log4.h"//lnk添加log4 + void clear_rpt_counter_by_trigger(trigger_t *trigger); //lnk20241031 extern void SOEFileWeb(char* localpath,char* cloudpath,char* wavepath); -//lnk 2024-11-4 ʱת +//lnk 2024-11-4 添加时间转换函数 char* convertMsToDateTimeString(int64_t msTime); //lnk20250115 extern pthread_mutex_t mtx; extern apr_pool_t* g_cfg_pool; extern apr_pool_t* g_init_pool; -extern int g_DevFlag; //־жȡIJضʹlnk20250121 +extern int g_DevFlag; //日志配置中读取的参数,暂无特定使用lnk20250121 extern int IED_COUNT; @@ -55,7 +57,7 @@ extern apr_pool_t *g_init_pool; extern apr_pool_t *g_run_pool; extern pt61850app_t *g_pt61850app; //extern char *g_sysfile_filedir; -extern char g_onlyIP[255]; //ֱijIPΪ +extern char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 //extern int g_sysfile_appid; //add by rzx //extern apr_time_t g_file_valid_time; extern uint32_t g_min_free_size; @@ -85,12 +87,12 @@ apr_status_t init_rem_dib_table() chnl_usr_t *chnl_usr; if(IED_COUNT < g_pt61850app->chnl_counts){ - set_rem_dib_table_size( g_pt61850app->chnl_counts );//ն + set_rem_dib_table_size( g_pt61850app->chnl_counts );//按照最大的终端数来申请 g_pt61850app->chnl_usr = apr_pcalloc( g_init_pool,g_pt61850app->chnl_counts*sizeof(chnl_usr_t*) ); printf( "set_rem_dib_table_size %d \n",g_pt61850app->chnl_counts ); } else{ - set_rem_dib_table_size( IED_COUNT );//ն + set_rem_dib_table_size( IED_COUNT );//按照最大的终端数来申请 g_pt61850app->chnl_usr = apr_pcalloc( g_init_pool,IED_COUNT*sizeof(chnl_usr_t*) ); printf( "set_rem_dib_table_size %d \n",IED_COUNT ); } @@ -138,7 +140,7 @@ void CloseIECReports(chnl_usr_t *chnl_usr) continue; rptinfo->rpt_registered = FALSE; - //עȡ10 עһεƣע + //注销报告后,取消10分钟 再注册一次的限制,可立即注册 rptinfo->m_LastRegisterFailedTime = sGetMsTime() -10*60*1000; rptinfo->m_rcb_info = NULL; } @@ -232,7 +234,7 @@ ST_VOID Callback_channel_disconnect_ind(MVL_NET_INFO * NetInfo, ST_INT discType) } printf(" Callback_channel_disconnect_ind ,NetInfo = %x",NetInfo); - //zw޸ 2023 - 8 - 17 ͨѶжϻص PG¼жϴ + //zw修改 2023 - 8 - 17 通讯中断回调函数 PG库记录当日中断次数 ied_usr_t* ied_usr = (ied_usr_t*)(chnl_usr->chnl[0].ied->usr_ext); } @@ -251,16 +253,16 @@ void IECReport_tryGI(chnl_usr_t *chnl_usr,rptinfo_t *rptinfo) g_rpt_typeids.mmsbool, (ST_CHAR *) &GI, g_pt61850app->mmsOpTimeout); } -//Ӵ̬̬ܵȣ ǷҪעᡢȡע κδ +//增加处理根据稳态,或暂态功能等,决定 报告是否需要注册、取消注册或 不做任何处理 int judge_rpt_next_should_do(rptinfo_t *rptinfo) { - int should_register_state = 1; //Ĭע - int is_real_report = (rptinfo->report_PQ_type & REPORT_TYPE_REAL);//а + int should_register_state = 1; //各功能默认注册 + int is_real_report = (rptinfo->report_PQ_type & REPORT_TYPE_REAL);//报告控制中包含的类型 int is_soe_report = (rptinfo->report_PQ_type & REPORT_TYPE_SOE); if (three_secs_enabled) { - should_register_state = 0; //3빦ģ飬Ĭϲע - if (is_real_report) {//ӳаƿҴ + should_register_state = 0; //3秒功能模块,默认不注册 + if (is_real_report) {//映射中包含控制块且触发 should_register_state = rptinfo->LD_info->real_data; } if (is_soe_report) { @@ -268,12 +270,12 @@ int judge_rpt_next_should_do(rptinfo_t *rptinfo) } } - if (should_register_state==rptinfo->rpt_registered)//Ѿ/ûдûб䶯 + if (should_register_state==rptinfo->rpt_registered)//已经触发/没有触发,没有变动 return SHOULD_DO_NOTHING; - else if (should_register_state)//б䶯Ҫ + else if (should_register_state)//有变动且要触发 return SHOULD_REGISTER; else - return SHOULD_UNREGISTER;//б䶯 + return SHOULD_UNREGISTER;//有变动,不触发 } void ChannelCheckIECReports(chnl_usr_t *chnl_usr) @@ -294,32 +296,32 @@ void ChannelCheckIECReports(chnl_usr_t *chnl_usr) for(cpuno=0 ; cpunocpucount; cpuno++) { - LD_info = &(ied_usr->LD_info[cpuno]); // + LD_info = &(ied_usr->LD_info[cpuno]); //遍历监测点 if (LD_info->cpuno==0) continue; - for(rpt_no=0 ; rpt_norptcount; rpt_no++) { //棨ӳļжȡıƣ + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { //遍历报告(映射文件中读取的报告控制) rptinfo = LD_info->rptinfo[rpt_no] ; - if (judge_rpt_next_should_do(rptinfo)==SHOULD_DO_NOTHING)//Ƿ񴥷 + if (judge_rpt_next_should_do(rptinfo)==SHOULD_DO_NOTHING)//检查是否触发 continue; if(rptinfo->m_curRptSuffix==-1) rptinfo->m_curRptSuffix = g_pt61850app->rptSuffix[g_client_id][0] ; - get_rpt_inst_name(rptinfo,rpt_inst_name);//ȡ + get_rpt_inst_name(rptinfo,rpt_inst_name);//获取报告名 if ( ! rptinfo->rpt_registered ) { if ( (sGetMsTime() -rptinfo->m_LastRegisterFailedTime) > 20*1000 ) { - //עʧܺ 20 עһ + //注册失败后间隔 20秒 再注册一次 RCB_INFO *rcb_info; printf("start mms_register_iec_rpt................................\n"); if ( strstr(rptinfo->rptID,"LLN0$BR$brcbFlickerData") ) - rptinfo->IntgPd = 600; //10 + rptinfo->IntgPd = 600; //10分钟 - /////////////////////////WW 2023-08-30 豸뱨 + /////////////////////////WW 2023-08-30 增加设备类型与报告绑定 rcb_info = mms_register_iec_rpt (chnl_usr->net_info, &g_rpt_typeids, LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout, rptinfo->IntgPd,rptinfo->TrgOpt, (ST_UINT8*)rptinfo->m_EntryID ,(ST_UINT8*)rptinfo->OptFlds); @@ -332,7 +334,7 @@ void ChannelCheckIECReports(chnl_usr_t *chnl_usr) rptinfo->m_LastRegisterFailedTime = sGetMsTime() ; - echo_err9("\nעᱨʧܣRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x \n", + echo_err9("\n注册报告失败!Rregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x \n", APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port, chnl_usr->chnl_id, rptinfo->IntgPd,rptinfo->TrgOpt ); @@ -360,7 +362,7 @@ void ChannelCheckIECReports(chnl_usr_t *chnl_usr) } else { //rpt_registered ==TRUE if ( (sGetMsTime() -rptinfo->m_LastUnRegisterFailedTime) > 20*1000 ) { - //ȡעʧܺ 20 ȡעһ + //取消注册失败后间隔 20秒 再取消注册一次 printf("start mms_unregister_iec_rpt................................\n"); ret = mms_unregister_iec_rpt (chnl_usr->net_info, &g_rpt_typeids, @@ -368,7 +370,7 @@ void ChannelCheckIECReports(chnl_usr_t *chnl_usr) if( ret == SD_FAILURE ) { rptinfo->m_LastUnRegisterFailedTime = sGetMsTime() ; - echo_err6("\nȡעᱨʧܣUnRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n", + echo_err6("\n取消注册报告失败!UnRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n", APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl_id); } else { @@ -425,7 +427,7 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr) apr_sleep(apr_time_from_sec(1) / 10); - Check_Recall_Config(LD_info->mp_id);//Իȡxmlṹ + Check_Recall_Config(LD_info->mp_id);//尝试获取xml结构 if (LD_info->autorecallcount != 0 && LD_info->autorecallflag != 1) { int i; @@ -434,7 +436,7 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr) LD_info->autorecallflag = 1; - //ǰ̬̬lnk20241030޸ģCheck_Recall_Configxmlļȡݺ󣬸ֵLD_info + //当前不区分稳态和暂态lnk20241030,如果做区分修改:Check_Recall_Config从xml文件获取数据后,赋值给了LD_info loginfo->need_steady = LD_info->autorecall[i]->need_steady; loginfo->need_voltage = LD_info->autorecall[i]->need_voltage; loginfo->start_time = apr_time_from_sec(LD_info->autorecall[i]->start - 5); @@ -465,7 +467,7 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr) loginfo->start_time = loginfo->end_time; g_dead_lock_counter = 0; - g_thread_blocked_times = 0; //ֹʱ½˳ + g_thread_blocked_times = 0; //防止补招时间过长导致进程退出 now = sGetMsTime(); last_check_recall_config_time = now; @@ -473,7 +475,7 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr) printf("end mms_jread................................\n"); } - if (failed_count==0) {//ɹ + if (failed_count==0) {//成功 Delete_recall_Xml(LD_info->mp_id); } } @@ -497,7 +499,7 @@ void process_3s_config(trigger_3s_xml_t *trigger_3s_xml) printf("start process_3s_config\n"); need_write_file = FALSE; - trigger = trigger_3s_xml->new_triggers; //3sļеnewtrigger飬ûnewtrigger0 + trigger = trigger_3s_xml->new_triggers; //3s配置文件中的newtrigger数组,如果没有newtrigger这里就是0 trigger_num = trigger_3s_xml->new_trigger_num; for (i=0; idev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { if (trigger[i].real_data>=0) - trigger_work->real_data = trigger[i].real_data;//rtdata־ + trigger_work->real_data = trigger[i].real_data;//更新rtdata标志 if (trigger[i].soe_data>=0) - trigger_work->soe_data = trigger[i].soe_data; //soe־ + trigger_work->soe_data = trigger[i].soe_data; //更新soe标志 trigger_work->limit = trigger[i].limit; - clear_rpt_counter_by_trigger(trigger_work);// + clear_rpt_counter_by_trigger(trigger_work);//清理报告 new_in_work_found = TRUE; } } - if (!new_in_work_found) { //newtriggerΪ0ȫµĴڹĴ + if (!new_in_work_found) { //newtrigger为0,这是全新的触发,不是正在工作的触发 clear_rpt_counter_by_trigger(&trigger[i]); if (trigger[i].real_data<0) trigger[i].real_data = 0; @@ -523,10 +525,10 @@ void process_3s_config(trigger_3s_xml_t *trigger_3s_xml) trigger[i].soe_data = 0; trigger_3s_xml->work_triggers[trigger_3s_xml->work_trigger_num++] = trigger[i]; } - need_write_file = TRUE;//Ҫĵдļ + need_write_file = TRUE;//需要将新增的点写到文件中 } - trigger = trigger_3s_xml->delete_triggers; //ûdeletetrigger0 + trigger = trigger_3s_xml->delete_triggers; //如果没有deletetrigger这里就是0 trigger_num = trigger_3s_xml->delete_trigger_num; for (i=0; iwork_trigger_num; j++){ @@ -539,7 +541,7 @@ void process_3s_config(trigger_3s_xml_t *trigger_3s_xml) need_write_file = TRUE; } - trigger = trigger_3s_xml->modify_triggers; //ûmodifytrigger0 + trigger = trigger_3s_xml->modify_triggers; //如果没有modifytrigger这里就是0 trigger_num = trigger_3s_xml->modify_trigger_num; for (i=0; iwork_trigger_num; j++){ @@ -552,55 +554,55 @@ void process_3s_config(trigger_3s_xml_t *trigger_3s_xml) need_write_file = TRUE; } - clear_all_LD_real_soe_report_shoud_register(); //Ҫעı棬ʵʱļʹLD_info->real_data = 0;LD_info->soe_data = 0;Ͳᴥ + clear_all_LD_real_soe_report_shoud_register(); //清空所有需要注册的报告,根据实时配置文件来。这里使LD_info->real_data = 0;LD_info->soe_data = 0;就不会触发报告 - trigger = trigger_3s_xml->work_triggers; //ļwork + trigger = trigger_3s_xml->work_triggers; //文件的work块 trigger_num = trigger_3s_xml->work_trigger_num; - for (i=0; irptinfo[rpt_no]->count + real_report_count = get_real_report_count(LD_info); //获取监测点的实时报告数量LD_info->rptinfo[rpt_no]->count - // + //调试用 printf("terminal:%s - mp:%s real_report_count %d\n", ((ied_usr_t*)(ied->usr_ext))->terminal_id, LD_info->mp_id, real_report_count); - trigger[i].count = real_report_count; //¼ʱʵʱ - if (trigger[i].real_data && trigger[i].limit && (real_report_count>trigger[i].limit) ) {//ʵʱڵǰļеƣ㲻ٴ + trigger[i].count = real_report_count; //记录此时这个监测点的实时报告数量 + if (trigger[i].real_data && trigger[i].limit && (real_report_count>trigger[i].limit) ) {//监测点的实时报告数量大于当前文件中的限制,这个监测点的数据清零不再触发 trigger[i].real_data = 0; trigger[i].limit = 0; trigger[i].count = 0; need_write_file = TRUE; } - LD_info->real_data = trigger[i].real_data; //ļеãȻڱ津дʵʱ + LD_info->real_data = trigger[i].real_data; //根据文件中的配置来设置,然后在报告触发中触发实时报告 LD_info->soe_data = trigger[i].soe_data; LD_info->limit = trigger[i].limit; LD_info->count = trigger[i].count; - if (LD_info->limit > 0) //¼¼ + if (LD_info->limit > 0) //限制数更新记录 need_write_file = TRUE; - if ( trigger[i].real_data==0 && trigger[i].soe_data==0 )//¼ + if ( trigger[i].real_data==0 && trigger[i].soe_data==0 )//不触发条件记录 need_write_file = TRUE; } if (need_write_file) - create_3s_xml(trigger_3s_xml); //дļwork + create_3s_xml(trigger_3s_xml); //写入文件的work块 } void del_process_recall_config(recall_xml_t* recall_xml) @@ -645,42 +647,42 @@ void del_process_recall_config(recall_xml_t* recall_xml) void check_3s_config() { double now; - static double last_check_3s_config_time = 0.0;//ʼʱ - trigger_3s_xml_t trigger_3s_xml; //3sļ + static double last_check_3s_config_time = 0.0;//初始化时间 + trigger_3s_xml_t trigger_3s_xml; //3s触发文件 - if (!three_secs_enabled) //cfg_3s_data̲ŻῪ + if (!three_secs_enabled) //cfg_3s_data进程才会开启 return; - now = sGetMsTime(); //ǰʱ - if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //ǰִʱ鿴ǰʱϴִʱС3벻ִУڵ3ִ + now = sGetMsTime(); //当前时间 + if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //当前进程任务执行时查看当前时间和上次执行时间间隔,小于3秒不执行,大于等于3秒往下执行 return; printf("begin 3s config...\n"); - last_check_3s_config_time = now; //¼ʱ - while (APR_SUCCESS==parse_3s_xml(&trigger_3s_xml)){ //3ļ - //ʵʱ̨lnk20250114 + last_check_3s_config_time = now; //记录本次运行时间 + while (APR_SUCCESS==parse_3s_xml(&trigger_3s_xml)){ //处理3秒文件 + //处理实时触发加台账锁lnk20250114 //pthread_mutex_lock(&mtx); printf("3s hold lock !!!!!!!!!!!"); - process_3s_config(&trigger_3s_xml); //ļ + process_3s_config(&trigger_3s_xml); //根据文件处理数据 //pthread_mutex_unlock(&mtx); printf("3s free lock !!!!!!!!!!!"); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//lnk20250114ʵʱݷ̨Ϣ +//lnk20250114参照实时数据方法处理台账信息 int isValidModelId(const char* model_id) { size_t i; - if (model_id == NULL) return 0; // NULL Ч + if (model_id == NULL) return 0; // NULL 无效 size_t len = strlen(model_id); - if (len < 4) return 0; // < 4 Ч + if (len < 4) return 0; // 长度 < 4 无效 - // Ƿȫǿո + // 检查是否全是空格 for (i = 0; i < len; i++) { if (!isspace((unsigned char)model_id[i])) { - return 1; // ֻҪǿոַǺϷ + return 1; // 只要包含非空格字符,就是合法的 } } - return 0; // ոЧ + return 0; // 仅包含空格,无效 } void process_ledger_update(trigger_update_xml_t *ledger_update_xml) @@ -699,30 +701,30 @@ void process_ledger_update(trigger_update_xml_t *ledger_update_xml) printf("!!!start update ledger!!!\n"); - update = ledger_update_xml->new_updates; //̨˲ + update = ledger_update_xml->new_updates; //处理新增台账部分 update_num = ledger_update_xml->new_update_num; printf("add ledger num:%d\n",update_num); - for (i=0; imodify_update_num < MAX_UPDATEA_NUM) { - // ӵ modify_updates + // 添加到 modify_updates 数组 ledger_update_xml->modify_updates[ledger_update_xml->modify_update_num] = update[i]; - ledger_update_xml->modify_update_num++; // modify ļ + ledger_update_xml->modify_update_num++; // 更新 modify 数组的计数器 - // ɾնˣ new_updates Ƴ + // 删除该终端(从 new_updates 数组中移除) for (j = i; j < ledger_update_xml->new_update_num - 1; j++) { - ledger_update_xml->new_updates[j] = ledger_update_xml->new_updates[j + 1]; // ǰƶԪ + ledger_update_xml->new_updates[j] = ledger_update_xml->new_updates[j + 1]; // 向前移动元素 } - ledger_update_xml->new_update_num--; // new_update_numһԪ + ledger_update_xml->new_update_num--; // 更新 new_update_num,减少一个元素 continue; } else { fprintf(stderr, "Exceeded MAX_UPDATEA_NUM limit for modify_updates!\n"); @@ -730,300 +732,332 @@ void process_ledger_update(trigger_update_xml_t *ledger_update_xml) } } - if (!new_in_work_found) { //ȫµ̨ˣ̨ûа豸 + if (!new_in_work_found) { //这是全新的台账,在台账数组中没有包含这个设备 int terminal_index; - int ied_take = 0; //ǰ̨вʹõiedռ䣿0ûУ1 - //̨Ӻͳʼ - //1-µڴռ////////////////////////////// - //µ̨ (n_clients) ԭе̨ (ԭΪ g_node->n_clients) - int new_client_count = g_node->n_clients + 1; // һµ̨ + int ied_take = 0; //当前台账数组里有不使用的ied空间?0没有,1有 + //进行台账添加和初始化操作 + //1-申请新的内存空间////////////////////////////// + //新的台账数量 (n_clients) 和原有的台账数量 (原数量为 g_node->n_clients) + int new_client_count = g_node->n_clients + 1; // 增加一个新的台账 - //ж̺Ƿ񳬹ԭе̨飬˾ʹӲʹܵiedռҿÿռ䣬ûǾʾܺظն - if(new_client_count > IED_COUNT){ //̨ + //判断新增进程后是否超过原有的台账数组,如果超过了就从不使能的ied空间中找可用空间,如果还是没有那就提示不能荷载更多终端 + if(new_client_count > IED_COUNT){ //不更新台账数量 ied_t *ied_unused = NULL; ied_usr_t* ied_usr_unused = NULL; - ied_unused = find_ied_unused();//g_nodeҵһʹõiedied֮ǰʼʱռ䣬ֱռ + ied_unused = find_ied_unused();//遍历g_node找到第一个不使用的ied,这个ied之前初始化时分配过空间,直接占用 if(ied_unused != NULL){ ied_usr_unused = (ied_usr_t*)ied_unused->usr_ext; - ied = ied_unused; //iedָеδʹõiedռ - terminal_index = ied_usr_unused->dev_idx; //¼iedıţg_node± + ied = ied_unused; //新增的ied指向已有的未使用的ied空间 + terminal_index = ied_usr_unused->dev_idx; //记录这个ied的编号,即g_node的下标 - //ӡʾ + //打印提示 printf("!!!!!!!!ied index:%d ,origin terminal_id:%s has been taken!!!!!!!!!!\n",ied_usr_unused->dev_idx,ied_usr_unused->terminal_id); - //ն˳ʼҪռ + //终端初始化,不需要再申请空间 ied_usr = (ied_usr_t*)ied->usr_ext; ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; - ied_usr->dev_flag = ENABLE;//նЧ + ied_usr->dev_flag = ENABLE;//终端有效 - ied->chncount = 1; //ͨŶ˿ - //ٷͨռ - ied->channel[0].ied = ied; //ͨ豸 - ied->channel[0].status = STATUS_BREAKOFF;//ʼΪͨж - ied->cpucount = 0; //ʼΪ0ȡ̨ʱд + ied->chncount = 1; //通信端口数 + //不再分配通道空间 + ied->channel[0].ied = ied; //通道的所属设备 + ied->channel[0].status = STATUS_BREAKOFF;//初始化为通信中断 + ied->cpucount = 0; //监测点数初始为0,读取监测点台账时写入 - ied_take = 1;//ied֮ǰ + ied_take = 1;//ied之前存在 } - else{ //еǫ̈̄жûҵʹõied˵̿ɹҵ̨ˣٴ + else{ //在已有的全部台账中都没找到不使用的ied,说明这个进程可挂的台账满了,不再处理 printf("!!!!!!!!!!ledger array is full!!!!!!\n"); + + //添加mq响应台账添加失败:台账挂满 + //update[i].guid + return; } - }//̨Сڵ趨̨ + }//新台账数量小于等于设定的台账数量 else{ - // + //调试用 printf("!!!!!!!!!!gnodeindex:%d!!!!!!\n",new_client_count - 1); - // ̨е̨м¼ + // 新增的台账在已有的台账数组中记录 g_node->clients[new_client_count - 1] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); - // ̨ - g_node->n_clients = new_client_count; // ̨ - //1-µڴռ////////////////////////////// + // 更新台账数量 + g_node->n_clients = new_client_count; // 更新台账数量 + //1-申请新的内存空间////////////////////////////// - //2-ն̨/////////////////////////////////// - ied = g_node->clients[new_client_count - 1];//նָ̨붨ied鵱ǰλõĺһλ + //2-处理终端台账/////////////////////////////////// + ied = g_node->clients[new_client_count - 1];//终端台账指针定向到ied数组当前位置的后一位 - terminal_index = new_client_count;//µ̨ն + terminal_index = new_client_count;//新的台账终端 ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); - ied->usr_ext = ied_usr;//ڴҵied + ied->usr_ext = ied_usr;//内存挂到ied上 if (ied_usr == NULL) return APR_ENOMEM; - ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//FeProject/ӹĿ¼/etc/pt61850netd_pqfe.xmlжȡܲѯʱ + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//从FeProject/子功能目录/etc/pt61850netd_pqfe.xml中读取的总查询时间 - ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//ڴҵied + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//内存挂到ied上 if (ied_usr->LD_info == NULL) return APR_ENOMEM; - ied_usr->dev_flag = ENABLE;//նЧ + ied_usr->dev_flag = ENABLE;//终端有效 - ied->chncount = 1; //ͨŶ˿,һնһֻһ - ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//ڴҵied - ied->channel[0].ied = ied; //ͨ豸 - ied->channel[0].status = STATUS_BREAKOFF;//ʼΪͨж - ied->cpucount = 0; //ʼΪ0ȡ̨ʱд - //2-ն̨/////////////////////////////////// + ied->chncount = 1; //通信端口数,一个终端一般只有一个 + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//内存挂到ied上 + ied->channel[0].ied = ied; //通道的所属设备 + ied->channel[0].status = STATUS_BREAKOFF;//初始化为通信中断 + ied->cpucount = 0; //监测点数初始为0,读取监测点台账时写入 + //2-处理终端台账/////////////////////////////////// } - //3-д̨////////////////////////////// + //3-写入台账内容////////////////////////////// int ret = update_one_terminal_ledger(update,i,ied,terminal_index,ied_take); if(ret){ printf("ledger can not be update!!!!!quit process!!!!!\n"); return 0; } - //3-д̨/////////////////////////////////// + //3-写入台账内容/////////////////////////////////// - //4-ӳļ////////////////////////////// + //4-配置映射文件////////////////////////////// char model[64]; - // ȡģIDǷ񷵻 NULL - char* model_id = parse_model_cfg_web_one(ied);//洢/FeProject/dat/ + // 获取模型ID,检查是否返回 NULL + char* model_id = parse_model_cfg_web_one(ied);//存储在/FeProject/dat/ - if (isValidModelId(model_id)) { //lnk20250313ֹòӳļ - // ȫַ model + if (isValidModelId(model_id)) { //lnk20250313防止拿不到映射文件 + // 安全拷贝字符串到 model 数组 strncpy(model, model_id, sizeof(model) - 1); - model[sizeof(model) - 1] = '\0'; // ȷ null β + model[sizeof(model) - 1] = '\0'; // 确保以 null 结尾 printf("ledger Model ID: %s\n", model); } else { printf("ledger No model ID found.quit\n"); return ; } char full_path[128]; - snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // ƴ· + snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // 拼接路径 - // ӡģ· + // 打印模型路径 printf("ledger icd config file full path: %s\n", full_path); - //ӳļ + //映射文件解析 Set_xml_nodeinfo_one(ied_usr->dev_type); - //4-ӳļ/////////////////////////////////// + //4-配置映射文件/////////////////////////////////// - //5-ʼ////////////////////////////// + //5-报告块初始化////////////////////////////// parse_rpt_log_ini_one(ied); - //5-ʼ/////////////////////////////////// + //5-报告块初始化/////////////////////////////////// - // + //调试 printf("ledger id: %s\n", ((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id); //6-init_rem_dib_table////////////////////////////// init_rem_dib_table_one(ied); //6-init_rem_dib_table/////////////////////////////////// + + //7启动终端日志 + init_loggers_bydevid(((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id); + + //8响应添加成功 + //update[i].guid } } //////////////////////////////////////////////////////////////////////////////modify - update = ledger_update_xml->modify_updates; //޸̨˲ + update = ledger_update_xml->modify_updates; //处理修改台账部分 update_num = ledger_update_xml->modify_update_num; printf("modify ledger num:%d\n",update_num); - for (i=0; ichncount; chnl_no++) { chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect; - if (chnl_usr->m_state!=CHANNEL_CONNECTED){//δӵͨ + if (chnl_usr->m_state!=CHANNEL_CONNECTED){//跳过未连接的通道 continue; } - closeChannel(chnl_usr);//رո̨˺Զ + closeChannel(chnl_usr);//关闭更新台账后,任务会自动连接 } - /////////////////////////////////////////////////////////////////////////////////// - //3-д̨////////////////////////////// + //更新数据///////////////////////////////////////////////////////////////////////////////// + //3-写入台账内容////////////////////////////// ied_usr = ied->usr_ext; - //дǰ - clearIedUsr(ied_usr);//dev_idx + //清空logger + remove_loggers_by_terminal_id(update[i].terminal_id); - //ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//FeProject/ӹĿ¼/etc/pt61850netd_pqfe.xmlжȡܲѯʱ + //写入前先清空已有数据 + clearIedUsr(ied_usr);//不会清空dev_idx - ied_usr->dev_flag = ENABLE;//նЧ + //ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//从FeProject/子功能目录/etc/pt61850netd_pqfe.xml中读取的总查询时间 - int ret = update_one_terminal_ledger(update,i,ied,ied_usr->dev_idx,1);//1еied + ied_usr->dev_flag = ENABLE;//终端有效 + + int ret = update_one_terminal_ledger(update,i,ied,ied_usr->dev_idx,1);//1:更新已有的ied if(ret){ printf("ledger can not be update!!!!!quit process!!!!!\n"); return 0; } - //3-д̨//////////////////////////////////////////// + //3-写入台账内容//////////////////////////////////////////// - //4-ӳļ/////////////////////////////////////////// + //4-配置映射文件/////////////////////////////////////////// char model[64] = {0}; - // ȡģIDǷ񷵻 NULL - char* model_id = parse_model_cfg_web_one(ied);//洢/FeProject/dat/ + // 获取模型ID,检查是否返回 NULL + char* model_id = parse_model_cfg_web_one(ied);//存储在/FeProject/dat/ if (model_id != NULL) { - // ȫַ model + // 安全拷贝字符串到 model 数组 strncpy(model, model_id, sizeof(model) - 1); - model[sizeof(model) - 1] = '\0'; // ȷ null β + model[sizeof(model) - 1] = '\0'; // 确保以 null 结尾 printf("ledger Model ID: %s\n", model); } else { printf("ledger No model ID found.\n"); } char full_path[128]; - snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // ƴ· + snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // 拼接路径 - // ӡģ· + // 打印模型路径 printf("ledger icd config file full path: %s\n", full_path); - //ӳļ + //映射文件解析 Set_xml_nodeinfo_one(ied_usr->dev_type); - //4-ӳļ/////////////////////////////////// + //4-配置映射文件/////////////////////////////////// - //5-ʼ////////////////////////////// + //5-报告块初始化////////////////////////////// parse_rpt_log_ini_one(ied); - //5-ʼ/////////////////////////////////// + //5-报告块初始化/////////////////////////////////// //6-init_rem_dib_table////////////////////////////// init_rem_dib_table_one(ied); //6-init_rem_dib_table/////////////////////////////////// - //////////////////////////////////////////////////////////////////////// + //更新数据////////////////////////////////////////////////////////////////////// + + //7启动终端日志 + init_loggers_bydevid(((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id); + + //8响应添加成功 + //update[i].guid } } if (!new_in_work_found){ printf("modify_updates can not find ied!!!!!!\n"); + + //添加mq响应台账添加失败:台账找不到 + //update[i].guid } } ///////////////////////////////////////////////////////////////////////////////delete - update = ledger_update_xml->delete_updates; //ɾ̨˲ - update_num = ledger_update_xml->delete_update_num; //ɾ + update = ledger_update_xml->delete_updates; //处理删除台账部分 + update_num = ledger_update_xml->delete_update_num; //删除的数量 printf("delete ledger num:%d\n",update_num); - for (i=0; ichncount; chnl_no++) { chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect; - if (chnl_usr->m_state!=CHANNEL_CONNECTED){ //ûӵͨһһնֻһ + if (chnl_usr->m_state!=CHANNEL_CONNECTED){ //跳过没连接的通道,一般一个终端只有一个 continue; } - closeChannel(chnl_usr);//رո̨˺ɾ򲻻ӣرʱiedıᱻƻᱻע + closeChannel(chnl_usr);//关闭更新台账后,如果是删除则不会再连接,关闭连接时这个ied的报告会被清除,报告控制会被注销 } - //////////////////////////////////////////////////////////////////////// - //3-ɾ̨////////////////////////////// + //更新数据////////////////////////////////////////////////////////////////////// + //3-删除台账内容////////////////////////////// -// - // Ҫɾ g_node->clients еij iedindex Ϊɾ +//调试用 + // 假设要删除 g_node->clients 中的某个 ied,index 为删除的索引 int index_to_remove = 0; ied_t* ied_find = NULL; int iedno; - ied_usr_t* ied_usr_find = NULL; //ied - ied_usr = (ied_usr_t*)ied->usr_ext;//Ҫɾied + ied_usr_t* ied_usr_find = NULL; //遍历的ied + ied_usr = (ied_usr_t*)ied->usr_ext;//要删除的ied for (iedno = 0; iedno < g_node->n_clients; iedno++) { ied_find = g_node->clients[iedno]; ied_usr_find = (ied_usr_t*)ied_find->usr_ext; if (ied_usr_find && strcmp(ied_usr_find->terminal_id, ied_usr->terminal_id) == 0) { - index_to_remove = iedno;//ҵҪɾiedg_nodeеλ - break; //ҵ˳ + index_to_remove = iedno;//找到要删除的ied在g_node中的位置 + break; //找到退出 } } - // Ҫɾ ied - ied_t* ied_to_remove = g_node->clients[index_to_remove];//ָg_nodeӦڴ + // 先清理要删除的 ied 的内容 + ied_t* ied_to_remove = g_node->clients[index_to_remove];//指向g_node对应的内存区 - if(ied_to_remove == ied){//ͨնidҵiedӦҲָg_nodeӦڴ + if(ied_to_remove == ied){//通过终端id找到的ied应该也指向g_node对应的内存区 printf("this ied is ied_to_remove\n"); } -// +//调试用 - //ied + //清空logger + remove_loggers_by_terminal_id(update[i].terminal_id); + + //清空ied的内容 clearIed(ied_to_remove); - //3-ɾ̨/////////////////////////////////// + //3-删除台账内容/////////////////////////////////// - //4-ӳļ////////////////////////////// - //ӳļٴiedͬӳļֱӼ - //4-ӳļ/////////////////////////////////// + //4-配置映射文件////////////////////////////// + //映射文件保留,如果再次添加这个ied,如果是相同的映射文件则可以直接加载 + //4-配置映射文件/////////////////////////////////// - //5-////////////////////////////// - //رʱiedıաƿ鱣ΪƿǸ豸õģɾӰͬ͵iediedӦĿƿʱ - //5-/////////////////////////////////// + //5-报告块////////////////////////////// + //关闭连接时这个ied的报告已清空。报告控制块保留,因为报告控制块是根据设备类型设置的,如果删除会影响其他同类型的ied。这个ied对应的控制块在清空内容时已清空 + //5-报告块/////////////////////////////////// //6-init_rem_dib_table////////////////////////////// - //rem_dib_tableݽᱻµ̨ʹλãֱӸ + //rem_dib_table的内容将会被保留,如果有新的台账使用这个位置,将会直接覆盖 //6-init_rem_dib_table/////////////////////////////////// - //////////////////////////////////////////////////////////////////////// + //更新数据////////////////////////////////////////////////////////////////////// + + //7响应添加成功 + //update[i].guid } } if (!new_in_work_found) { printf("modify_updates can not find ied!!!!!!\n"); + + //添加mq响应台账添加失败:台账找不到 + //update[i].guid + } } ////////////////////////////////////////////////////////////////////////////// if (ledger_update_xml->modify_update_num || ledger_update_xml->new_update_num || ledger_update_xml->delete_update_num){ - create_ledger_log(ledger_update_xml); //дļ + create_ledger_log(ledger_update_xml); //写入文件 } } -//̨˸µԴӡ -// ַǷΪ -// ַǷΪ +//台账更新调试打印函数 +// 检查字符串是否为空 +// 检查字符串是否为空 int is_empty(const char* str) { return (str == NULL || str[0] == '\0'); } -// ӡ monitor ṹϢ +// 打印 monitor 结构体信息 void print_monitor(const monitor* mon) { printf("Monitor ID: %s\n", is_empty(mon->monitor_id) ? "N/A" : mon->monitor_id); printf("Terminal Code: %s\n", is_empty(mon->terminal_code) ? "N/A" : mon->terminal_code); @@ -1035,8 +1069,9 @@ void print_monitor(const monitor* mon) { printf("Status: %s\n", is_empty(mon->status) ? "N/A" : mon->status); } -// ӡ terminal ṹϢ +// 打印 terminal 结构体信息 void print_terminal(const terminal* tmnl) { + printf("GUID: %s\n", is_empty(tmnl->guid) ? "N/A" : tmnl->guid);//lnk20250506 printf("Terminal ID: %s\n", is_empty(tmnl->terminal_id) ? "N/A" : tmnl->terminal_id); printf("Terminal Code: %s\n", is_empty(tmnl->terminal_code) ? "N/A" : tmnl->terminal_code); printf("Organization Name: %s\n", is_empty(tmnl->org_name) ? "N/A" : tmnl->org_name); @@ -1051,7 +1086,7 @@ void print_terminal(const terminal* tmnl) { printf("Port: %s\n", is_empty(tmnl->port) ? "N/A" : tmnl->port); printf("Timestamp: %s\n", is_empty(tmnl->timestamp) ? "N/A" : tmnl->timestamp); - // ӡϢֶΪգӡ N/A + // 打印监测点信息,如果监测点字段为空,则打印 N/A int i; for (i = 0; i < 10 && !is_empty(tmnl->line[i].monitor_id); ++i) { printf(" Monitor %d:\n", i + 1); @@ -1059,7 +1094,7 @@ void print_terminal(const terminal* tmnl) { } } -// ӡ trigger_update_xml_t ṹϢ +// 打印 trigger_update_xml_t 结构体信息 void print_trigger_update_xml(const trigger_update_xml_t* trigger_update) { printf("Work Updates Count: %d\n", trigger_update->work_update_num); printf("New Updates Count: %d\n", trigger_update->new_update_num); @@ -1095,41 +1130,41 @@ void print_trigger_update_xml(const trigger_update_xml_t* trigger_update) { void check_ledger_update()//lnk20250113 { double now; - static double last_check_3s_config_time = 0.0;//ʼʱ + static double last_check_3s_config_time = 0.0;//初始化时间 - now = sGetMsTime(); //ǰʱ - if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //ǰִʱ鿴ǰʱϴִʱС3벻ִУڵ3ִ + now = sGetMsTime(); //当前时间 + if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //当前进程任务执行时查看当前时间和上次执行时间间隔,小于3秒不执行,大于等于3秒往下执行 return; - // ̬ڴ trigger_ledger_update_xml ṹ + // 动态分配内存给 trigger_ledger_update_xml 结构体 trigger_update_xml_t* trigger_ledger_update_xml = (trigger_update_xml_t*)malloc(sizeof(trigger_update_xml_t)); if (trigger_ledger_update_xml == NULL) { printf("Memory allocation failed!\n"); - return; // ڴʧܣ + return; // 如果内存分配失败,返回 } - //ÿζʼֹظ + //每次都初始化防止重复 memset(trigger_ledger_update_xml, 0, sizeof(trigger_update_xml_t)); - //printf("check ledger update...trigger_ledger_update_xml:%d\n",trigger_ledger_update_xml->modify_update_num);//ٲҪĴӡ + //printf("check ledger update...trigger_ledger_update_xml:%d\n",trigger_ledger_update_xml->modify_update_num);//减少不必要的打印 - last_check_3s_config_time = now; //¼ʱ + last_check_3s_config_time = now; //记录本次运行时间 - //жǷִһļһնˣȡļɾļ - if (APR_SUCCESS==parse_ledger_update_xml(trigger_ledger_update_xml)){ //̨˸ļ,пԸ»̨˵ - // + //判断是否满足执行条件,一个文件就是一个终端,读取文件后删除文件 + if (APR_SUCCESS==parse_ledger_update_xml(trigger_ledger_update_xml)){ //处理台账更新文件,如果有可以更新或者添加台账的 + //调试用 print_trigger_update_xml(trigger_ledger_update_xml); - //̨˸¼̨lnk20250114 + //处理台账更新加台账锁lnk20250114 //pthread_mutex_lock(&mtx); printf("ledgerupdate hold lock !!!!!!!!!!!"); - process_ledger_update(trigger_ledger_update_xml); //̨˸ + process_ledger_update(trigger_ledger_update_xml); //台账更新 //pthread_mutex_unlock(&mtx); printf("ledgerupdate free lock !!!!!!!!!!!"); } - // ʹͷŶ̬ڴ + // 使用完后释放动态分配的内存 free(trigger_ledger_update_xml); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1188,7 +1223,7 @@ void check_disk_quota() void create_recall_xml() { - //ɴxmlļ + //生成待补招xml文件 if (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)) { DeletcRecallXml(); CreateRecallXml(); @@ -1202,14 +1237,14 @@ void Delete_recall_Xml(char* id) { } } -void Check_Recall_Config(char *id) //鲹ļRecall.xml +void Check_Recall_Config(char *id) //检查补招配置文件Recall.xml { if (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)) { recall_xml_t recall_xml; memset((char*)&recall_xml, 0, sizeof(recall_xml_t)); - parse_recall_xml(&recall_xml,id); //ļ - process_recall_config(&recall_xml); //IJݸֵȫֱ + parse_recall_xml(&recall_xml,id); //解析补招文件 + process_recall_config(&recall_xml); //解析的补招数据赋值到全局变量 } } @@ -1217,7 +1252,7 @@ void CheckAllConnectedChannel() { chnl_usr_t *chnl_usr; static uint32_t chnl_sequence_no = 0; - //һηһն + //一次访问一个终端 do { chnl_usr = g_pt61850app->chnl_usr[chnl_sequence_no]; chnl_sequence_no = (chnl_sequence_no+1) % g_pt61850app->chnl_counts; @@ -1226,12 +1261,12 @@ void CheckAllConnectedChannel() if(chnl_usr->m_state == CHANNEL_CONNECTED) { - 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)) - ChannelCheckWaveFiles(chnl_usr);//¼ļ + ChannelCheckWaveFiles(chnl_usr);//录波文件 if(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)) - ChannelCheckIECLogs(chnl_usr);//ļ - if ( (sGetMsTime() - chnl_usr->m_LastPosRespTime) > 15*1000 ) //wait 15 secs15ȡһӦûӦر + ChannelCheckIECLogs(chnl_usr);//补招文件 + if ( (sGetMsTime() - chnl_usr->m_LastPosRespTime) > 15*1000 ) //wait 15 secs,隔15秒获取一次响应,两次没响应后关闭 { char** varnames ; int varnum; @@ -1251,7 +1286,7 @@ void CheckAllConnectedChannel() } if ( chnl_usr->m_NegRespTimes >=2 ) { - closeChannel(chnl_usr);//???ǷҪ mms_release_connection + closeChannel(chnl_usr);//???特殊情况是否需要 mms_release_connection chnl_usr->m_NegRespTimes = 0; chnl_usr->m_LastPosRespTime = sGetMsTime(); } @@ -1274,7 +1309,7 @@ void CheckNextNotConnectedChannel() g_pt61850app->initNum++; } - if(chnl_usr->m_state == CHANNEL_CONNECTING)// + if(chnl_usr->m_state == CHANNEL_CONNECTING)//正在连接 { MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; @@ -1314,15 +1349,15 @@ void CheckNextNotConnectedChannel() FRONT_MP_NUM++; } - //lnk202411-1ӳɹļ¼ + //lnk202411-1添加连接成功的记录 ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; apr_time_t t_now = apr_time_now(); printf("msTime:%ld",t_now); - connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),1);//1ɹ + connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),1);//1成功 } else - {// solaris 9 224 + {// solaris 9 上 224秒 int secsSince = (int)(sGetMsTime() - chnl_usr->m_StartConnectingTime)/1000 ; @@ -1343,9 +1378,9 @@ void CheckNextNotConnectedChannel() { ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; - echo_warn2( "reqCtrl->doneδ,but time over 300 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); + echo_warn2( "reqCtrl->done未完成,but time over 300 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); if (chnl_usr->net_info->req_pend_list) { - echo_warn("reqCtrl->doneδ,but time over 300 secs!!!!!!!!\n"); + echo_warn("reqCtrl->done未完成,but time over 300 secs!!!!!!!!\n"); mvl_free_req_ctrl(chnl_usr->m_reqCtrl); chnl_usr->m_reqCtrl = NULL; } @@ -1369,7 +1404,7 @@ void CheckNextNotConnectedChannel() ST_CHAR serverARName[32]; ied_usr_t *ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; apr_snprintf(serverARName,sizeof(serverARName),"%s:%d",chnl_usr->ip_str,chnl_usr->chnl->port); - if (chnl_usr->chnl->ied->cpucount != NULL && chnl_usr->chnl->ied->cpucount > 0 && ied_usr->dev_flag == ENABLE) {//2023-09-26 czy line count<0 Ҫ//lnk20250121նЧ + if (chnl_usr->chnl->ied->cpucount != NULL && chnl_usr->chnl->ied->cpucount > 0 && ied_usr->dev_flag == ENABLE) {//2023-09-26 czy 如果line count<0 不需要连接//lnk20250121如果终端无效则不连接 ret = mms_connectToServer(ied_usr->dev_key, ied_usr->dev_series, serverARName, &(chnl_usr->net_info), &(chnl_usr->m_reqCtrl)); if (ret == SD_SUCCESS) @@ -1392,7 +1427,7 @@ void CheckNextNotConnectedChannel() } } - else if(chnl_usr->m_state == CHANNEL_DISCONNECTING) //need check timeout?᲻Զͣ + else if(chnl_usr->m_state == CHANNEL_DISCONNECTING) //need check timeout?会不会永远停留在这里 { MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; @@ -1408,7 +1443,7 @@ void CheckNextNotConnectedChannel() chnl_usr->net_info = NULL; chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = sGetMsTime(); - //ɹ + //断联成功 ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; apr_time_t t_now = apr_time_now(); connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),0); @@ -1422,7 +1457,7 @@ void CheckNextNotConnectedChannel() if ( (sGetMsTime() - chnl_usr->m_StartDisconnectingTime) > 30*1000 ) // //wait 30 secs ????? { - echo_warn2( "CHANNEL_DISCONNECTING reqCtrl->doneδ,but time over 180 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); + echo_warn2( "CHANNEL_DISCONNECTING reqCtrl->done未完成,but time over 180 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); mvl_free_req_ctrl(chnl_usr->m_reqCtrl); chnl_usr->net_info->user_ext = NULL; @@ -1432,7 +1467,7 @@ void CheckNextNotConnectedChannel() chnl_usr->net_info = NULL; chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = sGetMsTime(); - //ʱɹ + //超时断联成功 ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; apr_time_t t_now = apr_time_now(); connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),0); @@ -1441,7 +1476,7 @@ void CheckNextNotConnectedChannel() } } -//////////////////////*********ؿƲ**********//////////////////////////////////////////////// +//////////////////////*********相关控制操作**********//////////////////////////////////////////////// static ST_RET Read_Named_Var(LD_info_t *LD_info,chnl_usr_t *chnl_usr,char* VarName,ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut) { ST_RET ret= SD_FAILURE; @@ -1566,7 +1601,7 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) for (i=0;i<256;i++) { if (LD_info->FltNum[i]<=0) continue; - //LDƹ淶ֽڣPQMn, PQLDn ,5ֽڣ Ҳֻȡ4ַƥ + //LD名称规范四字节:PQMn, 或者PQLDn ,有5个字节, 但也只取4个字符进行匹配 ldstr = LD_info->LD_name+strlen(LD_info->LD_name)-4; apr_snprintf(file_match_str,sizeof(file_match_str),"%s_%06d",ldstr,LD_info->FltNum[i]); @@ -1590,63 +1625,63 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) char dat_only_filename_ret[256]; int ret2,ret3; - //WW 2023-11-01¼κַƥ޸Ϊintfltnumƥ + //WW 2023-11-01将录波段号由字符串匹配修改为int的fltnum匹配 ret2 = parse_file_names_by_fltnum(LD_info->FltNum[i], ldstr, filenames, filenum, &cfg_idx, &dat_idx, file_base_name, file_yyyymm); //WW 2023-11-01 end if (ret2 !=APR_SUCCESS) return ret2; - //¼ļ¼ļdat/cfg_only_filename_retУ׺һ¼ļҪϴ + //完成录波文件,记录在文件名dat/cfg_only_filename_ret中,两个后缀不一样的录波文件,要上传两次 ret2 = pt61850_write_cn_file(chnl_usr,ied,filenames[cfg_idx],cfg_only_filename_ret); ret3 = pt61850_write_cn_file(chnl_usr,ied,filenames[dat_idx],dat_only_filename_ret); have_new_files = TRUE; -/////////////////////////////////////////////////////////////////////////////////////////////ϴļ - if (ret2==SD_SUCCESS && ret3==SD_SUCCESS ) { //ļд - QVVR_t *qvvr; //̬¼ +/////////////////////////////////////////////////////////////////////////////////////////////上传文件 + if (ret2==SD_SUCCESS && ret3==SD_SUCCESS ) { //两个文件都写好了 + QVVR_t *qvvr; //暂态事件 long long start_tm,trig_tm,end_tm; - ret2 = extract_timestamp_from_cfg_file(filenames[cfg_idx],&start_tm,&trig_tm);//ȡļĿʼʱʹʱ + ret2 = extract_timestamp_from_cfg_file(filenames[cfg_idx],&start_tm,&trig_tm);//提取文件的开始时间和触发时间 printf(">>>>>>>> extract_timestamp_from_cfg_file end \n"); if (ret2 ==APR_SUCCESS) { //to find the paired qvvr by the time of trig_tm printf(">>>>>>>> extract_timestamp_from_cfg_file success \n"); - qvvr = find_qvvr_by_trig_tm(LD_info,trig_tm); //ļĴʱҼ¼ƥϵ̬¼ + qvvr = find_qvvr_by_trig_tm(LD_info,trig_tm); //根据文件的触发时间查找检测点记录的匹配上的暂态事件 if (qvvr) { - char* uuid_cfg = (char*)malloc(65 * sizeof(char));//ϴļȡ· + char* uuid_cfg = (char*)malloc(65 * sizeof(char));//上传文件后获取到的路径 char* uuid_dat = (char*)malloc(65 * sizeof(char)); - char* filename_cfg = (char*)malloc(100 * sizeof(char));//ϴļȡļ + char* filename_cfg = (char*)malloc(100 * sizeof(char));//上传文件后获取到的文件名 char* filename_dat = (char*)malloc(100 * sizeof(char)); - //lnk202411-5 ¼webص·+ļ + //lnk202411-5 记录web返回的路径+文件名 char* wavepath_cfg = (char*)malloc(256 * sizeof(char)); char* wavepath_dat = (char*)malloc(256 * sizeof(char)); -/*ϴ.cfg.datļ*/ +/*上传.cfg和.dat两个文件*/ char linux_cmd[256] = {0}; printf(">>>>>>>> qvvr ok end \n"); - apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",cfg_only_filename_ret,file_yyyymm,LD_info->line_id);//ûʹ + apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",cfg_only_filename_ret,file_yyyymm,LD_info->line_id);//没有使用 - char loc_file_fullname_cfg[256];//ļ + char loc_file_fullname_cfg[256];//本地文件名 memset(loc_file_fullname_cfg, 0, sizeof(loc_file_fullname_cfg)); apr_snprintf(loc_file_fullname_cfg, sizeof(loc_file_fullname_cfg), "/home/pq/FeProject/comtrade/%s", cfg_only_filename_ret); - char oss_file_fullname_cfg[256];//Զļ + char oss_file_fullname_cfg[256];//远端文件名 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); 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) { - 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){ - 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) { - char mq_file_fullname_cfg[256]; // Զļ + char mq_file_fullname_cfg[256]; // 远端文件名 memset(mq_file_fullname_cfg, 0, sizeof(mq_file_fullname_cfg)); - // ʹ޸ĺļ apr_snprintf + // 使用修改后的文件名传入 apr_snprintf apr_snprintf(mq_file_fullname_cfg, sizeof(mq_file_fullname_cfg), "comtrade/%s/", LD_info->ied->channel[0].addr_str); @@ -1662,7 +1697,7 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_cfg, loc_file_fullname_cfg); } - apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",dat_only_filename_ret,file_yyyymm,LD_info->line_id);//ͨsftpϴŷjsonȥ + apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",dat_only_filename_ret,file_yyyymm,LD_info->line_id);//先通过sftp上传才发json过去 char loc_file_fullname_dat[256]; memset(loc_file_fullname_dat, 0, sizeof(loc_file_fullname_dat)); @@ -1671,20 +1706,20 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) 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); 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) { - 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){ - 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) { - char mq_file_fullname_dat[256]; // Զļ + char mq_file_fullname_dat[256]; // 远端文件名 memset(mq_file_fullname_dat, 0, sizeof(mq_file_fullname_dat)); - // ʹ޸ĺļ apr_snprintf + // 使用修改后的文件名传入 apr_snprintf apr_snprintf(mq_file_fullname_dat, sizeof(mq_file_fullname_dat), "comtrade/%s/", LD_info->ied->channel[0].addr_str); @@ -1700,61 +1735,61 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_dat, loc_file_fullname_dat); } -/*ϴ.cfg.datļ*/ -/*ϴϢ*/ +/*上传.cfg和.dat两个文件*/ +/*上传消息*/ //to send json of this qvvr and rdre - end_tm = (long long)(qvvr->QVVR_PerTime*1000) + trig_tm; //ʱdzʱӴʱ + end_tm = (long long)(qvvr->QVVR_PerTime*1000) + trig_tm; //结束时间是持续时间加触发时间 if (FILE_FLAG == 3) { - size_t cfg_len = strlen(uuid_cfg) + strlen(filename_cfg) + 3; // 3ַ"-"ͽ'\0' - char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ - size_t dat_len = strlen(uuid_dat) + strlen(filename_dat) + 3; // 3ַ"-"ͽ'\0' - char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + size_t cfg_len = strlen(uuid_cfg) + strlen(filename_cfg) + 3; // 额外的3个字符用于"-"和结束符'\0' + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间 + size_t dat_len = strlen(uuid_dat) + strlen(filename_dat) + 3; // 额外的3个字符用于"-"和结束符'\0' + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间 if (cfg_result != NULL && dat_result != NULL) { - snprintf(cfg_result, cfg_len, "%s-%s", uuid_cfg, filename_cfg); // ƴַȷĿ껺 - snprintf(dat_result, dat_len, "%s-%s", uuid_dat, filename_dat); // ƴַȷĿ껺 + snprintf(cfg_result, cfg_len, "%s-%s", uuid_cfg, filename_cfg); // 拼接字符串并确保不会溢出目标缓冲区 + snprintf(dat_result, dat_len, "%s-%s", uuid_dat, filename_dat); // 拼接字符串并确保不会溢出目标缓冲区 ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, (double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type); } - free(cfg_result); // ʹϺͷŶ̬ڴռ - free(dat_result); // ʹϺͷŶ̬ڴռ + free(cfg_result); // 使用完毕后释放动态分配的内存空间 + free(dat_result); // 使用完毕后释放动态分配的内存空间 } - else if(FILE_FLAG==4)//lnk20241031̬webϢ + else if(FILE_FLAG==4)//lnk20241031发送暂态web消息 { - //ڴ䲿ֲ޸ + //内存分配部分不修改 size_t cfg_len = strlen(wavepath_cfg) + 1; - char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间 size_t dat_len = strlen(wavepath_dat) + 1; - char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间 if (cfg_result != NULL && dat_result != NULL) { - snprintf(cfg_result, cfg_len, wavepath_cfg); // ƴַȷĿ껺 - snprintf(dat_result, dat_len, wavepath_dat); // ƴַȷĿ껺 - ret3 = transfer_json_qvvr_data(g_node_id, //ûʹ - LD_info->line_id, // + snprintf(cfg_result, cfg_len, wavepath_cfg); // 拼接字符串并确保不会溢出目标缓冲区 + snprintf(dat_result, dat_len, wavepath_dat); // 拼接字符串并确保不会溢出目标缓冲区 + ret3 = transfer_json_qvvr_data(g_node_id, //这个参数没有使用 + LD_info->line_id, //监测点序号 (double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime, - qvvr->QVVR_time, //ﲻʹļеĿʼʱstart_tmΪӰд⣬ʹQVVRʱQVVR_time//lnk20250311 - end_tm, qvvr->QVVR_type, //ֵʱ䡢ʼʱ䡢ʱ䡢̬ - cfg_result, dat_result, //ļ· - LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);//ţļͼ̬¼ƥϵ̬ն + qvvr->QVVR_time, //这里不使用文件中的开始时间start_tm,因为会影响写库,使用QVVR的时间QVVR_time//lnk20250311 + end_tm, qvvr->QVVR_type, //伏值、持续时间、开始时间、结束时间、暂态类型 + cfg_result, dat_result, //两个文件路径 + LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);//监测点号,文件和监测点暂态事件匹配上的暂态报告名,终端类型 } - free(cfg_result); // ʹϺͷŶ̬ڴռ - free(dat_result); // ʹϺͷŶ̬ڴռ + free(cfg_result); // 使用完毕后释放动态分配的内存空间 + free(dat_result); // 使用完毕后释放动态分配的内存空间 } else if (FILE_FLAG == 1 || FILE_FLAG == 2) { - size_t cfg_len = strlen(oss_file_fullname_cfg) + strlen(cfg_only_filename_ret) + 3; // 3ַ"-"ͽ'\0' - char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ - size_t dat_len = strlen(oss_file_fullname_dat) + strlen(dat_only_filename_ret) + 3; // 3ַ"-"ͽ'\0' - char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + size_t cfg_len = strlen(oss_file_fullname_cfg) + strlen(cfg_only_filename_ret) + 3; // 额外的3个字符用于"-"和结束符'\0' + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间 + size_t dat_len = strlen(oss_file_fullname_dat) + strlen(dat_only_filename_ret) + 3; // 额外的3个字符用于"-"和结束符'\0' + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间 if (cfg_result != NULL && dat_result != NULL) { - snprintf(cfg_result, cfg_len, "%s-%s", oss_file_fullname_cfg, cfg_only_filename_ret); // ƴַȷĿ껺 - snprintf(dat_result, dat_len, "%s-%s", oss_file_fullname_dat, dat_only_filename_ret); // ƴַȷĿ껺 + snprintf(cfg_result, cfg_len, "%s-%s", oss_file_fullname_cfg, cfg_only_filename_ret); // 拼接字符串并确保不会溢出目标缓冲区 + snprintf(dat_result, dat_len, "%s-%s", oss_file_fullname_dat, dat_only_filename_ret); // 拼接字符串并确保不会溢出目标缓冲区 ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, (double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type); } - free(cfg_result); // ʹϺͷŶ̬ڴռ - free(dat_result); // ʹϺͷŶ̬ڴռ + free(cfg_result); // 使用完毕后释放动态分配的内存空间 + free(dat_result); // 使用完毕后释放动态分配的内存空间 } -/*ϴϢ*/ - qvvr->used_status = QVVR_DATA_NOT_USED;//ϴϢqvvr״̬Ϊδʹ +/*上传消息*/ + qvvr->used_status = QVVR_DATA_NOT_USED;//上传信息后这个qvvr的状态置为未使用 free(uuid_cfg); free(uuid_dat); free(filename_cfg); @@ -1783,22 +1818,22 @@ apr_status_t call_cn_wavelist(LD_info_t *LD_info ) return APR_SUCCESS; } -//lnk 2024-11-4 ʱת +//lnk 2024-11-4 添加时间转换函数 char* convertMsToDateTimeString(int64_t usTime) { - // ȷʱЧ + // 确保时间戳是有效的 if (usTime < 0) { return "Invalid timestamp"; } - // `apr_time_t` ΢루usתΪ `time_t` 루s + // 将 `apr_time_t` 微秒(us)转换为 `time_t` 秒(s) time_t seconds = usTime / 1000000; - // `struct tm` 洢ʱ + // 用 `struct tm` 变量存储时间 struct tm timeInfo; - // **ʹ `localtime_r()` ϵͳʱ** + // **使用 `localtime_r()` 考虑系统时区** localtime_r(&seconds, &timeInfo); - // ַ̬洢תַ + // 静态分配的字符数组存储转换后的字符串 static char buffer[30]; strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeInfo); diff --git a/mms/mmscli_log.c b/mms/mmscli_log.c index 6acf5cd..1d530ff 100644 --- a/mms/mmscli_log.c +++ b/mms/mmscli_log.c @@ -121,8 +121,8 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, not_set_log_q_this = TRUE; not_set_log_t_this = TRUE; - ST_INT timeflag = TRUE;//ִǰȡʱ - int log_data_steady_type = 0;//̬ ־ + ST_INT timeflag = TRUE;//执行前先取时标 + int log_data_steady_type = 0;//稳态 长闪 短闪标志 double start, end; static double last_check_recall_config_time = 0.0; @@ -186,7 +186,7 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, v = mms_dec_data.data_item[ii].u.data_double; apr_snprintf(mms_ref, sizeof(mms_ref), "%s$%s", do_name, mms_dec_data.data_item[ii].comp_name); - // + //调试用 printf("u.data_str: %s (as hex: 0x%X)\n", mms_dec_data.data_item[ii].u.data_str, *((ST_UINT16*)mms_dec_data.data_item[ii].u.data_str)); if (strstr(mms_ref, "QVVR")) { @@ -202,18 +202,18 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, length_FCDA = strlen(mms_ref); if (('$' == mms_ref[length_FCDA - 2]) && ('t' == mms_ref[length_FCDA - 1])) { - //lnk20250307 + //调试用lnk20250307 printf("readtime = 1"); readtime = 1; t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); - // - // һṹ屣תʱϢ + //调试用 + // 定义一个结构体保存转换后的时间信息 apr_time_exp_t xt; - // ʹñʱתҲ apr_time_exp_gmt(&xt, t) õ GMT ʱ䣩 + // 使用本地时区转换(也可以用 apr_time_exp_gmt(&xt, t) 得到 GMT 时间) if (apr_time_exp_lt(&xt, t) == APR_SUCCESS) { - // tm_year ʾ 1900 Ҫ 1900tm_mon ΧΪ 0~11Ҫ 1 + // tm_year 表示自 1900 年起的年数,需要加上 1900;tm_mon 范围为 0~11,需要加 1 printf("Converted time: %04d-%02d-%02d %02d:%02d:%02d.%06d\n", xt.tm_year + 1900, xt.tm_mon + 1, @@ -225,36 +225,36 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, } else { printf("Failed to convert apr_time_t\n"); } - // + //调试用 } if (('$' == mms_ref[length_FCDA - 2]) && ('q' == mms_ref[length_FCDA - 1])) { if (log_data_type == STEADY_DATA) { readquailty = 1; char* q = mms_dec_data.data_item[ii].u.data_str; - //lnk20250307 + //调试用lnk20250307 if (q != NULL) { int i; for (i = 0; q[i] != '\0'; i++) { - /* ǰַ '\0' ѭѾų '\0' */ + /* 如果当前字符是 '\0' 则跳过,但循环条件已经排除了 '\0' */ if (q[i] == '\0') continue; printf("q[%d] = %c\n", i, q[i]); } printf("!!!!!\n"); } - //lnk20250307 + //调试用lnk20250307 if (q[0] == '0' && q[1] == '0'){ quality = 0; - //lnk20250307 + //调试用lnk20250307 printf("quality = 0"); }else{ - //lnk20250307 + //调试用lnk20250307 printf("quality = 1"); quality = 1; } @@ -262,21 +262,21 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, } } if (readtime == 1 && readquailty == 1) { - //lnk20250307 + //调试用lnk20250307 printf("readtime == 1 && readquailty = 1"); break; } } if (readtime == 1 && readquailty == 1) { - if (0) {//ԣҪĻquality == 0 + if (0) {//调试,要改回quality == 0 timeflag = TRUE; - //lnk20250307 + //调试用lnk20250307 printf("readtime == 1 && readquailty = 1 && quality == 1 continue"); continue; } else { - //lnk20250307 + //调试用lnk20250307 printf("readtime == 1 && readquailty = 1 && quality == 0 log"); timeflag = FALSE; @@ -289,21 +289,21 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, apr_time_exp_t preTime; apr_time_exp_gmt(&preTime, process_jou_entry_t); - if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || newTime.tm_hour != preTime.tm_hour || newTime.tm_min != preTime.tm_min) //ʱ䷢ ִ̬json + if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || newTime.tm_hour != preTime.tm_hour || newTime.tm_min != preTime.tm_min) //时间发生跳变 长闪 短闪 和稳态数据执行json推送 { printf("\n newTime: %d %d %d %d %d %d", newTime.tm_year, newTime.tm_mon, newTime.tm_mday, newTime.tm_hour, newTime.tm_min, newTime.tm_sec); printf("\n preTime: %d %d %d %d %d %d", preTime.tm_year, preTime.tm_mon, preTime.tm_mday, preTime.tm_hour, preTime.tm_min, preTime.tm_sec); - json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 0);//̬ - json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 1);// - json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 2);// - process_jou_entry_t = t;//ʱ + json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 0);//稳态 + json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 1);//长闪 + json_block_create_end(loginfo->LD_info->v_wiring_type,loginfo->LD_info->mp_id, 2);//短闪 波动 + process_jou_entry_t = t;//调整至最新时标 ied_t* ied; ied = find_ied_from_dev_code(loginfo->LD_info->terminal_code); ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//ͽ ³ʼ¶ ̬ - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);// - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);// + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//推送结束 重新初始化新队列 稳态 + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);//长闪 + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);//短闪 } } } @@ -363,7 +363,7 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, int quality = 0; char* q = mms_dec_data.data_item[ii].u.data_str; - //lnk20250307 + //调试用lnk20250307 printf("q[0] = %c ,q[1] = %c !!!!!",q[0],q[1]); if (q[0]=='0'&& q[1]=='0'){ @@ -373,7 +373,7 @@ static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, printf("quality = 1"); quality = 1; } - if (0) {//ãҪĻquality == 0 + if (0) {//调试用,要改回quality == 0 printf("quality = 1 continue"); continue; } @@ -503,12 +503,12 @@ ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_n double start,end; static double last_check_recall_config_time = 0.0; - static double heart_time_cout = 0.0;//ʱ - static double heart_time_cout_start = 0.0;//ʱ ʼ - static double heart_time_cout_now = 0.0;//ʱ ǰ + static double heart_time_cout = 0.0;//心跳计时 + static double heart_time_cout_start = 0.0;//心跳计时 开始 + static double heart_time_cout_now = 0.0;//心跳计时 当前 do { heart_time_cout_now = sGetMsTime(); - if (heart_time_cout_now - heart_time_cout_start > 30000)//30 ʱ + if (heart_time_cout_now - heart_time_cout_start > 30000)//30秒 定时心跳 { printf("\n heart_time_cout OK"); heart_time_cout_start = sGetMsTime(); @@ -600,17 +600,17 @@ ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_n if ( jread_resp->more_follows == 0 && ((i + 1) == jread_resp->num_of_jou_entry)) { printf("\njread_resp->more_follows == 0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - //lnk2024-8-16ӽ߲ - json_block_create_end(loginfo->LD_info->v_wiring_type, loginfo->LD_info->mp_id, 0);//more followsΪ0 ݽһ ǿд̬ݵjsonֹ + //lnk2024-8-16添加接线参数 + json_block_create_end(loginfo->LD_info->v_wiring_type, loginfo->LD_info->mp_id, 0);//more follows为0 数据接受最后一条 强行处理稳态数据的json防止遗留 json_block_create_end(loginfo->LD_info->v_wiring_type, loginfo->LD_info->mp_id, 1); json_block_create_end(loginfo->LD_info->v_wiring_type, loginfo->LD_info->mp_id, 2); ied_t* ied; ied = find_ied_from_dev_code(loginfo->LD_info->terminal_code); ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//ͽ ³ʼ¶ ̬ - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);// - json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);// + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//推送结束 重新初始化新队列 稳态 + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);//长闪 + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);//短闪 } end = sGetMsTime(); } @@ -627,7 +627,7 @@ ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_n apr_time_exp_t preTime; apr_time_exp_gmt(&preTime, end_time); printf("\nstart timecheck_2"); - if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || (newTime.tm_hour != preTime.tm_hour && newTime.tm_hour != preTime.tm_hour + 1 && newTime.tm_hour != preTime.tm_hour - 1)) //ʱж ʱ䳬ʱʱ + if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || (newTime.tm_hour != preTime.tm_hour && newTime.tm_hour != preTime.tm_hour + 1 && newTime.tm_hour != preTime.tm_hour - 1)) //结束时标判断 当上送时间超过结束时标时 跳出 { printf("\nstart timecheck_3"); printf("\n more_follows newTime: %d %d %d %d %d %d", newTime.tm_year, newTime.tm_mon, newTime.tm_mday, newTime.tm_hour, newTime.tm_min, newTime.tm_sec); diff --git a/mms/mmscli_rpt.c b/mms/mmscli_rpt.c index a1e374c..dc0217e 100644 --- a/mms/mmscli_rpt.c +++ b/mms/mmscli_rpt.c @@ -95,7 +95,7 @@ ST_VOID object_name_clone_destroy(OBJECT_NAME* obj); static ST_ULONG a_get_rem_ip_addr_inline(ST_LONG acse_conn_id, int* nPort); static char* _convert_ip_2_char(unsigned long dwIP); -#if 1 // ȡIP WW 2023-08-29 +#if 1 //测试 获取服务器IP WW 2023-08-29 static char* _convert_ip_2_char(unsigned long dwIP) { static char buf[64] = { 0 }; @@ -293,10 +293,10 @@ RCB_INFO* rcb_info_create(MVL_NET_INFO* net_info, ST_CHAR* domName, + BSTR_NUMBITS_TO_NUMBYTES(numDsVar); /* rcb_info->rcb_data.Inclusion */ rcb_info = (RCB_INFO*)chk_calloc(1, extended_size); - strcpy(rcb_info->dom_Name, domName); //WW 2023-08-29 ߼豸 - strcpy(rcb_info->rcb_name, rcbName); //WW 2023-08-29 ƿ + strcpy(rcb_info->dom_Name, domName); //WW 2023-08-29 逻辑设备名称 + strcpy(rcb_info->rcb_name, rcbName); //WW 2023-08-29 报告控制块名称 ////////////////////////////////////////////////////////////////////////// - strcpy(rcb_info->ds_Nam, datSetName); //WW 2023-08-29 ݼ + strcpy(rcb_info->ds_Nam, datSetName); //WW 2023-08-29 数据集名称 ////////////////////////////////////////////////////////////////////////// echo_msg4("Client RCB info 0x%X created for '%s' in domain '%s'.datasetnam '%s' \n", rcb_info, rcbName, domName, datSetName); @@ -732,11 +732,11 @@ ST_RET rcb_enable(MVL_NET_INFO* netInfo, ST_CHAR* domName, ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->bstr6, TrgOps, timeOut); if (ret != SD_SUCCESS) { printf("%s Write Error!!!", varName); - echo_warn1("Reportע %s Write Error!!!", varName); + echo_warn1("Report注册 %s Write Error!!!", varName); } } -#if 0 /* Add something like this if other options needed. ???????? BufTm ??*/ +#if 0 /* Add something like this if other options needed. ???????? BufTm 等??*/ if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$Trgs", rcbName); @@ -841,7 +841,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); rptinfo = find_rptinfo_from_net_rpt_info_name(net_info, rcb_info); - //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 ȥ + //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 去除 LD_info = rptinfo->LD_info; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; @@ -850,7 +850,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, not_set_rpt_q_this = TRUE; //g_db_inf_clear_data(RPT_IDX); rptinfo->count++; - printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTime = apr_time_now();// @@ -980,9 +980,9 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, //assert(0); if (LD_info->line_id > 0) { - if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_start(LD_info); - else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_start(LD_info); else { ied_t* ied; @@ -990,7 +990,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; - if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 ֻ͵һνŻʼ json_block_create_start(LD_info->line_id); + if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 只有闪变和第一次进入才会初始化 json_block_create_start(LD_info->line_id); json_block_create_start( LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); else if(rptinfo->flickerflag == 0) { if (LD_info->rptRecvCheckFlag == 0) @@ -1038,16 +1038,16 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR //need do nothing! not_set_rpt_q_this = FALSE; } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_q_this = FALSE; } @@ -1059,14 +1059,14 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, } else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { if (not_set_rpt_TimeID_this) { - apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6));//΢ - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6));//微秒 + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR if (strstr(FULL_FCDA_Name, "VarStr$t")) { - processQVVR_time(LD_info, t / 1000);// + processQVVR_time(LD_info, t / 1000);//毫秒 not_set_rpt_TimeID_this = FALSE; } } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } @@ -1075,7 +1075,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); not_set_rpt_TimeID_this = FALSE; if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { - //20241223lnkն˺Ų + //20241223lnk添加终端号参数 ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000)) return; @@ -1098,10 +1098,10 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_data(LD_info, FULL_FCDA_Name, v); } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_data(LD_info, FULL_FCDA_Name, v); } else @@ -1114,34 +1114,34 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, //set_rpt_LineID(LD_info->line_id); //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); //write_updatetime_to_db(chnl_usr->chnl->addr); - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_end(LD_info); } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_end(LD_info); } else { printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); //append_db_records(RPT_IDX); - if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 ־ + if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 增加闪变标志 { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16ӽͲ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16增加接线类型参数 } - else if(rptinfo->flickerflag == 0){//CZY 2023-08-17 WW 2022-11-14 Ӷж + else if(rptinfo->flickerflag == 0){//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16ӽͲ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16增加接线类型参数 LD_info->rptRecvCheckFlag = 0; } } - else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16ӽͲ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag); //lnk2024-8-16增加接线类型参数 LD_info->rptPstRecvCheckFlag = 0; } } @@ -1151,7 +1151,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); } - printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTimeend = apr_time_now();// @@ -1171,7 +1171,7 @@ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, } } - //Ӧʱ䣬Ƶٻװƣ¶ add on Aug 3 for testing of guangdong CRITICAL + //设置响应时间,避免频繁召唤装置名称,导致丢包 add on Aug 3 for testing of guangdong CRITICAL chnl_usr->m_LastPosRespTime = sGetMsTime(); //assert (va_num==va_total); /* Did we count right? */ @@ -1204,7 +1204,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); rptinfo = find_rptinfo_from_net_rcb_info(net_info, rcb_info); - //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 ȥ + //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 去除 LD_info = rptinfo->LD_info; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; @@ -1213,7 +1213,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, not_set_rpt_q_this = TRUE; //g_db_inf_clear_data(RPT_IDX); rptinfo->count++; - printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,count = %i mp_id=%s\n", + printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,【count = %i】 mp_id=%s\n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count, LD_info->mp_id); //apr_time_t previousTime = apr_time_now();// @@ -1342,9 +1342,9 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, // cout<<"pEquipment->m_OMSObject_FULL_FCDA_Map.entries() = "<m_OMSObject_FULL_FCDA_Map.entries()<line_id > 0) { - if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR - processQVVR_start(LD_info);//͵ıļ - else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR + processQVVR_start(LD_info);//上送的报告里面的监测点号 + else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_start(LD_info); else { ied_t* ied; @@ -1352,7 +1352,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, ied = find_ied_from_dev_code(LD_info->terminal_code); ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; - if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 ֻ͵һνŻʼ json_block_create_start(LD_info->line_id); + if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 只有闪变和第一次进入才会初始化 json_block_create_start(LD_info->line_id); json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); else if (rptinfo->flickerflag == 0) { if (LD_info->rptRecvCheckFlag == 0) @@ -1404,7 +1404,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, break; } } - for (ii = 0; ii < mms_dec_data.item_num; ++ii)//FCDA + for (ii = 0; ii < mms_dec_data.item_num; ++ii)//遍历FCDA { char* FULL_FCDA_Name; int length_FCDA; @@ -1417,16 +1417,16 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR //need do nothing! not_set_rpt_q_this = FALSE; } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_q_this = FALSE; } @@ -1443,17 +1443,17 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { if (not_set_rpt_TimeID_this) { apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR if (strstr(FULL_FCDA_Name, "VarStr$t")) { processQVVR_time(LD_info, t / 1000); not_set_rpt_TimeID_this = FALSE; } } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } - else if (strstr(FULL_FCDA_Name, "GGIO")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + else if (strstr(FULL_FCDA_Name, "GGIO")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } @@ -1462,9 +1462,9 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); not_set_rpt_TimeID_this = FALSE; if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { - //20241223lnkն˺Ų + //20241223lnk添加终端号参数 ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); - if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000))//жʱظ + if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000))//判断时间重复 return; } } @@ -1485,17 +1485,17 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_data(LD_info, FULL_FCDA_Name, v); } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_data(LD_info, FULL_FCDA_Name, v); } else if (strstr(FULL_FCDA_Name, "GGIO")) { ied_t* ied = LD_info->ied; ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); - processGGIO_start_data_end(LD_info->mp_id, FULL_FCDA_Name, v, time, ied_usr->dev_type, LD_info->line_id);//GGIOȫ״ + processGGIO_start_data_end(LD_info->mp_id, FULL_FCDA_Name, v, time, ied_usr->dev_type, LD_info->line_id);//GGIO数据全套处理流程 } else json_block_create_data(LD_info->mp_id, FULL_FCDA_Name, v, rptinfo->flickerflag); @@ -1508,34 +1508,34 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, //set_rpt_LineID(LD_info->line_id); //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); //write_updatetime_to_db(chnl_usr->chnl->addr); - if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_end(LD_info); } - else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_end(LD_info); } else { printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); //append_db_records(RPT_IDX); - if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 ־ + if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 增加闪变标志 { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnkδ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnk角形处理 } - else if (rptinfo->flickerflag == 0) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + else if (rptinfo->flickerflag == 0) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnkδ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnk角形处理 LD_info->rptRecvCheckFlag = 0; } } - else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { - //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; - json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnkδ + json_block_create_end(LD_info->v_wiring_type, LD_info->mp_id, rptinfo->flickerflag);//lnk角形处理 LD_info->rptPstRecvCheckFlag = 0; } } @@ -1545,7 +1545,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); } - printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTimeend = apr_time_now();// @@ -1565,7 +1565,7 @@ ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, } } } - //Ӧʱ䣬Ƶٻװƣ¶ add on Aug 3 for testing of guangdong CRITICAL + //设置响应时间,避免频繁召唤装置名称,导致丢包 add on Aug 3 for testing of guangdong CRITICAL chnl_usr->m_LastPosRespTime = sGetMsTime(); //assert (va_num==va_total); /* Did we count right? */ if (va_num != va_total) @@ -1670,58 +1670,58 @@ ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) return (SD_FAILURE); } ////////////////// - //WW 2023-08-29 ն뱨rcb_info󶨴 - int port; //˿ + //WW 2023-08-29 增加终端类型与报告rcb_info绑定代码 + int port; //端口 RCB_INFO *rcb_info1; - ST_CHAR rptID[MVL61850_MAX_RPTID_LEN + 1] = { 0 }; //ID 66 - ST_ULONG a_ip = get_rem_ip_addr_inline(event->net_info->acse_conn_id, &port); //WW 2023-08-29 ȡװIP˿ں - ST_CHAR *p_ip = _convert_ip_2_char(htonl(a_ip)); //WW 2023-08-29 IPתΪַָ 192.168.1.238 - if (gDev_rcb_list.dev_rcb_info_Head == NULL) //ȫֱƿָ || gDev_rcb_list->rcb_info_list == NULL + ST_CHAR rptID[MVL61850_MAX_RPTID_LEN + 1] = { 0 }; //报告ID 66 + ST_ULONG a_ip = get_rem_ip_addr_inline(event->net_info->acse_conn_id, &port); //WW 2023-08-29 获取装置IP、端口号 + ST_CHAR *p_ip = _convert_ip_2_char(htonl(a_ip)); //WW 2023-08-29 将IP转为字符串指针 例:192.168.1.238 + if (gDev_rcb_list.dev_rcb_info_Head == NULL) //全局报告控制块指针 || gDev_rcb_list->rcb_info_list == NULL { //SLOGALWAYS0 ("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); - //LOG_INFO("յ棬δIEC-61850UCA RCBʹܡԣ"); //ʹã zl 2019-1-23 09:10:39 + //LOG_INFO("收到报告,未启用IEC-61850或UCA RCB使能。忽略!"); //仅调试使用! zl 2019-1-23 09:10:39 return (SD_FAILURE); } - //߼װIP˿ںţҵװͣƥ䱨Ϣٽ棡2019-12-24 17:27:29 -//װͲж------------------------------------------------------------------------------------------------------------------------------ - Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ - Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ - ST_BOOLEAN bFindIpPort = 0; //Ƿƥ䵽װIP˿ں - for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + //逻辑:根据装置IP、端口号,先找到装置类型,再匹配报告信息,再解析报告!2019-12-24 17:27:29 +//装置类型查找判断------------------------------------------------------------------------------------------------------------------------------ + Dev_RCB_INFO *dev_rcb = NULL;//装置报告结构指针 + Dev_IP_Port_INFO *dev_info = NULL; //装置IP、端口号结构指针 + ST_BOOLEAN bFindIpPort = 0; //是否在链表中匹配到装置IP、端口号 + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //①遍历 全局装置报告控制块链表 { - //LOG_INFO("()gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 - //װIP˿ںŲж------------------------------------------------------------------------------------------------------------------------------------------------------------------- - for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + //LOG_INFO("(报告解析)遍历gDev_rcb_list链表, dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:16:31 + //装置IP、端口号查找判断------------------------------------------------------------------------------------------------------------------------------------------------------------------- + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //②遍历 全局装置IP、端口链表 { - //LOG_INFO("()dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 - if ((strcmp(dev_info->IP, p_ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + //LOG_INFO("(报告解析)遍历dev_ip_port_list链表, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, p_ip) == 0) && (dev_info->Port == port)) //匹配 装置IP && 端口号 { - bFindIpPort = 1; //ҵװIP && ˿ں - //LOG_INFO("()ƥ䵽װdev_type_name= %s, IP= %sPort= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 - //strcpy(dev_rcb->dev_type_name, dev_rcb->dev_type_name); //ƥ װ + bFindIpPort = 1; //查找到装置IP && 端口号 + //LOG_INFO("(报告解析)匹配到装置dev_type_name= %s, IP= %s,Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:23:55 + //strcpy(dev_rcb->dev_type_name, dev_rcb->dev_type_name); //匹配 装置类型 break; } - } // װIP˿ - if (bFindIpPort) //ƥ䵽װIP˿ں + } //遍历 装置IP、端口链表 结束 + if (bFindIpPort) //在链表中匹配到装置IP、端口号 break; - } // ȫװñƿ + } //遍历 全局装置报告控制块链表 结束 - if (!bFindIpPort) //δҵװIP˿ + if (!bFindIpPort) //未查找到装置IP、端口 { - //LOG_INFO("()dev_type_name= %sδƥ䵽IP= %sPort= %dװͣgoto CLEANUP", dev_rcb->dev_type_name, p_ip, port); //ʹã zl 2019-12-24 00:23:55 + //LOG_INFO("(报告解析)dev_type_name= %s未匹配到IP= %s,Port= %d的装置类型,goto CLEANUP跳出!", dev_rcb->dev_type_name, p_ip, port); //仅调试使用! zl 2019-12-24 00:23:55 retcode = SD_FAILURE; - goto END; //ת CLEANUPretcode + goto END; //跳转至 CLEANUP,即:返回retcode结束 } - rcb_info = dev_rcb->rcb_info_list; //װͣƥ䱨ƿϢ + rcb_info = dev_rcb->rcb_info_list; //根据装置类型,匹配报告控制块信息 //WW 2023-08-29 end ////////////////////////////// /* Get "all_rcb_info" from "user_info". User must set "user_info" when conn established.*/ ////////////////////// - //WW 2023-08-29ע + //WW 2023-08-29注释 //all_rcb_info = (ALL_RCB_INFO*)event->net_info->user_info; ///* Check "all_rcb_info" to see if any RCB has been enabled. */ @@ -1742,11 +1742,11 @@ ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) sizeof(MVL_VAR_ASSOC*)); ////////////////// -//WW 2023-08-29 ն뱨rcb_info󶨴 - rcb_info = dev_rcb->rcb_info_list; //װͣƥ䱨ƿϢ +//WW 2023-08-29 增加终端类型与报告rcb_info绑定代码 + rcb_info = dev_rcb->rcb_info_list; //根据装置类型,匹配报告控制块信息 va_num = 0; info_va[va_num++] = rcb_info->rcb_var.RptID; - //LOG_INFO("va_num = %d", va_num); //ʹã zl 2019-1-23 09:10:39 + //LOG_INFO("va_num = %d", va_num); //仅调试使用! zl 2019-1-23 09:10:39 all_rcb_info = (ALL_RCB_INFO*)chk_calloc(1, sizeof(ALL_RCB_INFO)); all_rcb_info->rpt_typeids = &g_rpt_typeids; @@ -1754,32 +1754,32 @@ ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) event->net_info->user_info = all_rcb_info; rcb_info = all_rcb_info->rcb_info_list; rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ - mvl_info_data_to_local(event, va_num, info_va); //תΪظʽ + mvl_info_data_to_local(event, va_num, info_va); //将报告数据转换为本地格式 /* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ - strcpy(saveRptID, rcb_info->rcb_data.RptID); //װͱID PQM2/LLN0$BR$brcbStatisticData01 - //LOG_INFO("װͱsaveRptID%s", saveRptID); //ʹã zl 2019-1-23 09:10:39 + strcpy(saveRptID, rcb_info->rcb_data.RptID); //装置上送报告ID 例:PQM2/LLN0$BR$brcbStatisticData01 + //LOG_INFO("装置上送报告saveRptID:%s", saveRptID); //仅调试使用! zl 2019-1-23 09:10:39 chk_free(all_rcb_info); event->net_info->user_info = NULL; /* Search list of "rcb_info" to find one with matching RptID. If not found, rcb_info will be == NULL. */ - //װñƿж----------------------------------------------------------------------------------------------------------------------------------------------------- - for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) // ȫֱƿ + //装置报告控制块查找判断----------------------------------------------------------------------------------------------------------------------------------------------------- + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //遍历 全局报告控制块链表 { - //LOG_INFO("ƿRptID%ssaveRptID%s", rcb_info->RptID, saveRptID); //ʹã zl 2019-1-23 09:10:39 + //LOG_INFO("遍历报告控制块链表RptID:%s,saveRptID:%s", rcb_info->RptID, saveRptID); //仅调试使用! zl 2019-1-23 09:10:39 if (strcmp(rcb_info->RptID, saveRptID) == 0) break; /* rcb_info now points to right structure */ } - if (!rcb_info) //ƿָΪգ + if (!rcb_info) //报告控制块指针为空! { //SLOGALWAYS1 ("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); - //LOG_INFO("()ƿҲRptID= '%s'goto CLEANUP", saveRptID); //ʹã zl 2019-12-23 15:09:36 + //LOG_INFO("(报告解析)报告控制块链表查找不到RptID= '%s',goto CLEANUP跳出!", saveRptID); //仅调试使用! zl 2019-12-23 15:09:36 retcode = SD_FAILURE; - goto CLEANUP; //ת CLEANUPretcode + goto CLEANUP; //跳转至 CLEANUP,即:返回retcode结束 } //WW 2023-08-29 end ////////////////////////////// ////////////////////// - //WW 2023-08-29ע + //WW 2023-08-29注释 ///* Must decode the RptID first to find the correct RCB_INFO. Could decode into //* any "vstring65" variable. We just use the RptID variable from the first //* rcb_info on the list. @@ -1842,15 +1842,15 @@ ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) log_var_to_data(rcb_info->rcb_var.DatSetNa, rptID); //for (rcb_info1 = all_rcb_info->rcb_info_list; // rcb_info1 != NULL; - // rcb_info1 = (RCB_INFO *) list_get_next (all_rcb_info->rcb_info_list, rcb_info1)) // װñƿ + // rcb_info1 = (RCB_INFO *) list_get_next (all_rcb_info->rcb_info_list, rcb_info1)) //遍历 装置报告控制块链表 for (rcb_info1 = dev_rcb->rcb_info_list; rcb_info1 != NULL; - rcb_info1 = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info1)) // ƿ + rcb_info1 = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info1)) //遍历 报告控制块链表 { - if (strcmp(rcb_info1->ds_Nam, rptID) == 0) //IDΪͬΨһʶ + if (strcmp(rcb_info1->ds_Nam, rptID) == 0) //报告ID,作为不同报告间的唯一标识符 { //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); - //LOG_INFO("()ձRptID= '%s'ݼrptID= %sС(%d)ԤڴС(%d)ƥ䣬brak", saveRptID, rptID, va_total, va_num); //ʹã zl 2019-12-23 15:09:30 + //LOG_INFO("(报告解析)接收报告RptID= '%s'数据集rptID= %s,大小(%d)与预期大小(%d)不匹配,brak跳出!", saveRptID, rptID, va_total, va_num); //仅调试使用! zl 2019-12-23 15:09:30 rcb_info = rcb_info1; break; } @@ -2044,7 +2044,7 @@ ST_RET u_iec_rpt_ind(MVL_COMM_EVENT* event) info_va[va_num++] = rcb_info->rcb_var.TimeOfEntry; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; - //WW 2024-09-02 ݼȷ + //WW 2024-09-02 数据集名称确认 if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) info_va[va_num++] = rcb_info->rcb_var.DatSetNa; @@ -2053,19 +2053,19 @@ ST_RET u_iec_rpt_ind(MVL_COMM_EVENT* event) if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) { - //info_va[va_num++] = rcb_info->rcb_var.DatSetNa; //WW 2024-09-02 ע + //info_va[va_num++] = rcb_info->rcb_var.DatSetNa; //WW 2024-09-02 注释 /////////////////// //WW 2023-08-29 log_var_to_data(rcb_info->rcb_var.DatSetNa, saveRptID); for (rcb_info1 = all_rcb_info->rcb_info_list; rcb_info1 != NULL; - rcb_info1 = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info1)) // ƿ + rcb_info1 = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info1)) //遍历 报告控制块链表 { - if (strcmp(rcb_info1->ds_Nam, saveRptID) == 0) //IDΪͬΨһʶ + if (strcmp(rcb_info1->ds_Nam, saveRptID) == 0) //报告ID,作为不同报告间的唯一标识符 { printf("ds_name '%s' ! Recive name %s WWTest \n", rcb_info1->ds_Nam, saveRptID); //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); - //LOG_INFO("()ձRptID= '%s'ݼrptID= %sС(%d)ԤڴС(%d)ƥ䣬brak", saveRptID, rptID, va_total, va_num); //ʹã zl 2019-12-23 15:09:30 + //LOG_INFO("(报告解析)接收报告RptID= '%s'数据集rptID= %s,大小(%d)与预期大小(%d)不匹配,brak跳出!", saveRptID, rptID, va_total, va_num); //仅调试使用! zl 2019-12-23 15:09:30 rcb_info = rcb_info1; break; } @@ -2152,7 +2152,7 @@ ST_RET u_iec_rpt_ind(MVL_COMM_EVENT* event) /* Perform 3rd decode (everything). */ mvl_info_data_to_local(event, va_num, info_va); - //洦lnk20250114 + //报告处理加锁lnk20250114 //pthread_mutex_lock(&mtx); printf("rpt hold lock !!!!!!!!!!!"); u_iec_rpt_ind_data(info_va, OptFldsData, InclusionData, rcb_info, va_total, event->net_info); //pthread_mutex_unlock(&mtx); printf("rpt free lock !!!!!!!!!!!"); @@ -2164,7 +2164,7 @@ CLEANUP: return (retcode); } /************************************************************************/ -//61850Ϊ +//61850报告解析为本地数据 /************************************************************************/ void log_var_to_data(MVL_VAR_ASSOC *var, char *pdata) { @@ -2200,7 +2200,7 @@ static ST_RET myLocToTextBs(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) ST_CHAR* destBuf; ST_UCHAR mask; - // + //调试用 //printf("pSrc[0]: 0x%X, pSrc[1]: 0x%X, text: %s\n", pSrc[0], pSrc[1], text); //printf("%s text_len %d %d pSrc %d %d \n", text, strlen(text), rt->u.p.el_len, pSrc[0], pSrc[1]); @@ -2245,7 +2245,7 @@ static ST_RET myLocToTextBs(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) } destBuf[i] = 0; - // + //调试用 //printf("pSrc[0]: 0x%X, pSrc[1]: 0x%X, text: %s\n", pSrc[0], pSrc[1], text); return (SD_SUCCESS); @@ -2313,7 +2313,7 @@ ST_RET my_asn1_convert_utc_to_btod(MMS_UTC_TIME* utc, MMS_BTOD* btod) btod->day = (long)(utc->secs - tJan84) / SECONDS_PER_DAY; /* num of days since 1/1/1984 */ btod->ms = (long)((utc->secs - tJan84) % SECONDS_PER_DAY) * 1000; /* num milliseconds since midnight */ /* NOTE: use 0x01000000 (2**24) in fraction computations. */ - // Ҫ뵽 28.9999Ӧ29ms + // 要四舍五入到毫秒数,比如 28.9999应该是29ms btod->ms += (ST_INT32)(0.5 + (ST_DOUBLE)utc->fraction * 1000.0 / (ST_DOUBLE)0x01000000); /* add the milliseconds left in a sec */ btod->form = MMS_BTOD6; @@ -2458,7 +2458,7 @@ void my_local_to_data(ST_CHAR* datptr, SD_CONST RUNTIME_TYPE* rt_head, break; case RT_BIT_STRING: - myLocToTextBs((ST_UCHAR*)datptr, rt_ptr, tmpBuf);//洢ڴеıشתΪӦıַַ '1' '0' ɣ + myLocToTextBs((ST_UCHAR*)datptr, rt_ptr, tmpBuf);//将存储在内存中的比特串转换为对应的文本字符串(由字符 '1' 和 '0' 组成) strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_STR_TYPE; @@ -2503,7 +2503,7 @@ void my_local_to_data(ST_CHAR* datptr, SD_CONST RUNTIME_TYPE* rt_head, break; #endif default: - echo_warn1("δRT_INTEGERRT_BCD size = %i \n", rt_ptr->u.p.el_len); + echo_warn1("未处理的RT_INTEGER或RT_BCD 整数 size = %i \n", rt_ptr->u.p.el_len); break; } break; @@ -2542,7 +2542,7 @@ void my_local_to_data(ST_CHAR* datptr, SD_CONST RUNTIME_TYPE* rt_head, break; #endif /* INT64_SUPPORT */ default: - echo_warn1("δ ޷ size = %i \n", rt_ptr->u.p.el_len); + echo_warn1("未处理的 无符号整数 size = %i \n", rt_ptr->u.p.el_len); break; } break; diff --git a/mms/mmsclient.c b/mms/mmsclient.c index f116603..39999b4 100644 --- a/mms/mmsclient.c +++ b/mms/mmsclient.c @@ -83,7 +83,7 @@ extern uint32_t g_node_id; extern char subdir[128]; unsigned int g_no_auth = 0; -DEV_TYPE_LIST gDev_rcb_list; //ȫֱƿ +DEV_TYPE_LIST gDev_rcb_list; //全局报告控制块链表 #if defined(MVL_GOOSE_SUPPORT) /* Need parts of "iecgoose" sample app */ #include "iec_demo.h" /* definitions from "iecgoose" sample app */ @@ -312,7 +312,7 @@ ST_INT mms_get_datatype_from_type_id (ST_INT type_id, ST_UCHAR* datatype,ST_INT ret = mvl_get_runtime (type_id, &rt_ctrl.rt_first,&rt_ctrl.rt_num); if (ret == SD_SUCCESS) - {//ֻ rt_ctrl.rt_num еһݵͺ + {//只返回 rt_ctrl.rt_num 中第一个数据的类型和 长度 RUNTIME_TYPE *rt_type = &rt_ctrl.rt_first[0]; *datatype = rt_type->el_tag; *len = rt_type->u.p.el_len; @@ -433,7 +433,7 @@ void init_MMS() loc_dib_table = localDibTable; // num_rem_dib_entries = sizeof(rem_dib_table)/sizeof(DIB_ENTRY); - memset(&gDev_rcb_list, 0, sizeof(DEV_TYPE_LIST)); //WW 2023-08-29 ȫװñָʼ + memset(&gDev_rcb_list, 0, sizeof(DEV_TYPE_LIST)); //WW 2023-08-29 全局装置报告指针初始化 // tp4_config(); /* see tp4_hc.c */ tp0_cfg.max_tpdu_len = 8192;//8192; @@ -450,7 +450,7 @@ void init_MMS() /* Fill in mvlCfg. */ mvlCfg.num_called = 0; - mvlCfg.max_msg_size = 320000; //to enlage to fit the 豸 + mvlCfg.max_msg_size = 320000; //to enlage to fit the 主设备保护 strcpy (mvlCfg.local_ar_name, "local1"); #else /* #if defined(HARD_CODED_CFG) */ @@ -595,7 +595,7 @@ ST_RET mms_mvla_fdelete (MVL_NET_INFO *net_info,ST_CHAR *file_to_delete,int iTi } #endif -//ڷļĿ¼󣬻ȡԶ豸ļбطļ +//用于发送文件目录请求,获取远程设备的文件列表,并返回符合条件的文件名。 #if (MMS_FDIR_EN & REQ_EN) ST_RET mms_mvla_fdir (MVL_NET_INFO *net_info,ST_CHAR *filespec,int iTimeout, char*** filenames ,int* filenum,apr_pool_t *pool) @@ -712,7 +712,7 @@ ST_RET mms_mvla_getnam (MVL_NET_INFO *net_info,ST_INT scope, //else { // printf ("\n More Follows : FALSE"); //} - printf("");// + printf("★");// //printf ("mms_mvla_getname %d Names returned . \n",getnam_resp->num_names); varnames2 = apr_pcalloc( pool,(*varnum+getnam_resp->num_names)*sizeof(char*) ); @@ -769,7 +769,7 @@ ST_UCHAR TrgOps [1]; /* 8 bit bitstring */ rcb_info = rcb_info_create (clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); if (rcb_info) { - //ע + //先注销报告先 ST_BOOLEAN RptDisEna = 0; /* 0 = disable the report */ ST_CHAR varName [MAX_IDENT_LEN + 1]; apr_snprintf (varName,sizeof(varName), "%s$RptEna", rcb_name); @@ -825,7 +825,7 @@ ST_UCHAR TrgOps [1]; /* 8 bit bitstring */ } /////////////////////////////////////////// -//WW 2023-08-29 豸ʹ,Ż津ٶ +//WW 2023-08-29 增加设备类型处理,优化报告触发速度 RCB_INFO* mms_register_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, ST_CHAR *dom_name, ST_CHAR *rcb_name, ST_INT timeOut, ST_CHAR *dev_type, ST_CHAR *ip, int port, ST_INT scanRate, ST_UCHAR trgops, ST_UINT8* pEntryID, ST_UINT8* OptFlds) @@ -835,80 +835,80 @@ RCB_INFO* mms_register_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEI ST_UCHAR TrgOps[1]; /* 8 bit bitstring */ - //һװͲж--------------------------------------------------------------------------------------------------------------------------- - ST_BOOLEAN bFindDevType = 0; //Ƿвҵװ - Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ - for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + //一、装置类型查找判断--------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindDevType = 0; //是否在链表中查找到装置类型 + Dev_RCB_INFO *dev_rcb = NULL;//装置报告结构指针 + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //①遍历 全局装置报告控制块链表 { - //LOG_INFO("(津)gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 - if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //ƥ װ + //LOG_INFO("(报告触发)遍历gDev_rcb_list链表, dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:16:31 + if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //匹配 装置类型 { - bFindDevType = 1; //ҵװ - //LOG_INFO("(津)ƥ䵽װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 + bFindDevType = 1; //查找到装置类型 + //LOG_INFO("(报告触发)匹配到装置类型,dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:23:55 break; } - } // װ - if (!bFindDevType) //δҵװ + } //遍历 装置类型链表 结束 + if (!bFindDevType) //未查找到装置类型 { - dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New - strcpy(dev_rcb->dev_type_name, dev_type); //װ - //LOG_INFO("(津)װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 - list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); // ȫװñƿ + dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); //调用 申请连续内存空间,并初始化为0,返回首地址指针,相当于New + strcpy(dev_rcb->dev_type_name, dev_type); //装置类型 + //LOG_INFO("(报告触发)新增装置类型,dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:23:55 + list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); //添加 全局装置报告控制块链表 } - //װIP˿ںŲж--------------------------------------------------------------------------------------------------------------------------------------------------- - ST_BOOLEAN bFindIpPort = 0; //ǷвҵװIP˿ں - Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ - for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + //二、装置IP、端口号查找判断--------------------------------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindIpPort = 0; //是否在链表中查找到装置IP、端口号 + Dev_IP_Port_INFO *dev_info = NULL; //装置IP、端口号结构指针 + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //②遍历 全局装置IP、端口链表 { - //LOG_INFO("(津)dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 - if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + //LOG_INFO("(报告触发)遍历dev_ip_port_list链表, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //匹配 装置IP && 端口号 { - bFindIpPort = 1; //ҵװIP && ˿ں - //LOG_INFO("(津)ƥ䵽װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + bFindIpPort = 1; //查找到装置IP && 端口号 + //LOG_INFO("(报告触发)匹配到装置dev_type_name= %s, IP= %s, Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:23:55 break; } - }// װIP˿ - if (!bFindIpPort) //δҵװIP˿ + }//遍历 装置IP、端口链表 结束 + if (!bFindIpPort) //未查找到装置IP、端口 { - dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New + dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); //调用 申请连续内存空间,并初始化为0,返回首地址指针,相当于New - strcpy(dev_info->IP, ip); //װIP - dev_info->Port = port; //˿ں - //LOG_INFO("(津)װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 - list_add_last(&dev_rcb->dev_ip_port_list, dev_info); // ȫװñƿ->װIP˿ + strcpy(dev_info->IP, ip); //装置IP + dev_info->Port = port; //端口号 + //LOG_INFO("(报告触发)新增装置dev_type_name= %s, IP= %s, Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:23:55 + list_add_last(&dev_rcb->dev_ip_port_list, dev_info); //添加 全局装置报告控制块链表->装置IP、端口链表 } - //װñƿж---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - RCB_INFO *rcb_info = NULL; //ƿָ - ST_BOOLEAN bFindRCB = 0; //Ƿװñƿвҵ - for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //۱ ȫװñƿ->ƿϢ + //三、装置报告控制块查找判断---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + RCB_INFO *rcb_info = NULL; //报告控制块指针 + ST_BOOLEAN bFindRCB = 0; //是否在装置报告控制块链表中查找到 + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //③遍历 全局装置报告控制块链表->报告控制块信息链表 { - //LOG_INFO("(津)rcb_info_list, RptID= %sdom_Name= %sdom= %srcb_name= %srpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //ʹã zl 2018-10-17 21:19:36 - if ((strcmp(rcb_info->rcb_name, rcb_name) == 0) && (strcmp(rcb_info->dom_Name, dom_name) == 0)) //ƥ װñƿ + //LOG_INFO("(报告触发)遍历rcb_info_list链表, RptID= %s,dom_Name= %s,dom= %s,rcb_name= %s,rpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //仅调试使用! zl 2018-10-17 21:19:36 + if ((strcmp(rcb_info->rcb_name, rcb_name) == 0) && (strcmp(rcb_info->dom_Name, dom_name) == 0)) //匹配 装置报告控制块 { - bFindRCB = 1; //ҵװñƿ - //LOG_INFO("(津)ƥ䵽ƿdev_type_name= %s, dom= %srcb= %sѴ", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 + bFindRCB = 1; //查找到装置报告控制块 + //LOG_INFO("(报告触发)匹配到报告控制块dev_type_name= %s, dom= %s,rcb= %s,已触发过!", dev_rcb->dev_type_name, dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 break; /* rcb_info now points to right structure */ } } - if (!bFindRCB) //δҵװñƿ + if (!bFindRCB) //未查找到装置报告控制块 { - rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); // װñƿ >> עúΪʱװ͵ıƿѴٽд + rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); //调用 创建装置报告控制块 —>> 注:该函数较为耗时,若本装置类型的报告控制块已创建过,则不需再进行创建! if (rcb_info == NULL) { - //LOG_INFO("(津)ƿʧܣdev_type_name= %s, dom= %srcb= %s", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 + //LOG_INFO("(报告触发)创建报告控制块失败!dev_type_name= %s, dom= %s,rcb= %s", dev_rcb->dev_type_name, dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 return SD_FAILURE; } else { - //LOG_INFO("(津)ƿɹȫֱƿdev_type_name= %s, dom= %srcb= %s", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 - list_add_last(&dev_rcb->rcb_info_list, rcb_info); // ȫֱƿ->ƿϢ + //LOG_INFO("(报告触发)创建报告控制块成功,新增全局报告控制块链表!dev_type_name= %s, dom= %s,rcb= %s", dev_rcb->dev_type_name, dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 + list_add_last(&dev_rcb->rcb_info_list, rcb_info); //添加 全局报告控制块链表->报告控制块信息链表 } - //TRACE("(津)ƿ飡dom= %s rcb= %sʱ:%0.6fС:%d", dom, rpt, dwEnd - dwStart, sizeof(RCB_INFO)); + //TRACE("(报告触发)创建报告控制块!dom= %s rcb= %s,耗时:%0.6f,报告大小:%d", dom, rpt, dwEnd - dwStart, sizeof(RCB_INFO)); } if (rcb_info) { - //ע WW 2023-08-29עעĴ + //先注销报告先 WW 2023-08-29注释先注销报告的代码 //ST_BOOLEAN RptDisEna = 0; /* 0 = disable the report */ //ST_CHAR varName[MAX_IDENT_LEN + 1]; //apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcb_name); @@ -971,81 +971,81 @@ ST_RET mms_unregister_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEID ST_BOOLEAN RptEna = 0; ST_CHAR varName[MAX_IDENT_LEN + 1]; - ST_RET ret; //ִзֵ + ST_RET ret; //函数执行返回值 - //һװͲж--------------------------------------------------------------------------------------------------------------------------- - ST_BOOLEAN bFindDevType = 0; //Ƿвҵװ - Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ - for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + //一、装置类型查找判断--------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindDevType = 0; //是否在链表中查找到装置类型 + Dev_RCB_INFO *dev_rcb = NULL;//装置报告结构指针 + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //①遍历 全局装置报告控制块链表 { - //LOG_INFO("(ֹͣ)gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 - if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //ƥ װ + //LOG_INFO("(报告停止)遍历gDev_rcb_list链表, dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:16:31 + if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //匹配 装置类型 { - bFindDevType = 1; //ҵװ - //LOG_INFO("(ֹͣ)ƥ䵽װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 + bFindDevType = 1; //查找到装置类型 + //LOG_INFO("(报告停止)匹配到装置类型,dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:23:55 break; } - } // װ + } //遍历 装置类型链表 结束 - if (!bFindDevType) //δҵװ + if (!bFindDevType) //未查找到装置类型 { - dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New - //memset(dev_rcb, 0, sizeof(Dev_RCB_INFO)); //ָ 0 - strcpy(dev_rcb->dev_type_name, dev_type); //װ - list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); // ȫװñƿ + dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); //调用 申请连续内存空间,并初始化为0,返回首地址指针,相当于New + //memset(dev_rcb, 0, sizeof(Dev_RCB_INFO)); //指针 清0 + strcpy(dev_rcb->dev_type_name, dev_type); //装置类型 + list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); //添加 全局装置报告控制块链表 } - //װIP˿ںŲж--------------------------------------------------------------------------------------------------------------------------------------------------- - ST_BOOLEAN bFindIpPort = 0; //ǷвҵװIP˿ں - Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ - for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + //二、装置IP、端口号查找判断--------------------------------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindIpPort = 0; //是否在链表中查找到装置IP、端口号 + Dev_IP_Port_INFO *dev_info = NULL; //装置IP、端口号结构指针 + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //②遍历 全局装置IP、端口链表 { - //LOG_INFO("(ֹͣ)dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 - if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + //LOG_INFO("(报告停止)遍历dev_ip_port_list链表, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //匹配 装置IP && 端口号 { - bFindIpPort = 1; //ҵװIP && ˿ں - //LOG_INFO("(ֹͣ)ƥ䵽װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + bFindIpPort = 1; //查找到装置IP && 端口号 + //LOG_INFO("(报告停止)匹配到装置dev_type_name= %s, IP= %s, Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:23:55 break; } - } // װIP˿ - if (!bFindIpPort) //δҵװIP˿ + } //遍历 装置IP、端口链表 结束 + if (!bFindIpPort) //未查找到装置IP、端口 { - dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New - //memset(dev_info, 0, sizeof(Dev_IP_Port_INFO)); //ָ 0 - strcpy(dev_info->IP, ip); //װIP - dev_info->Port = port; //˿ں - list_add_last(&dev_rcb->dev_ip_port_list, dev_info); // ȫװñƿ->װIP˿ + dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); //调用 申请连续内存空间,并初始化为0,返回首地址指针,相当于New + //memset(dev_info, 0, sizeof(Dev_IP_Port_INFO)); //指针 清0 + strcpy(dev_info->IP, ip); //装置IP + dev_info->Port = port; //端口号 + list_add_last(&dev_rcb->dev_ip_port_list, dev_info); //添加 全局装置报告控制块链表->装置IP、端口链表 } - //װñƿж---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - RCB_INFO *rcb_info = NULL; //ƿָ - ST_BOOLEAN bFindRCB = 0; //Ƿװñƿвҵ - for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //۱ ȫװñƿ->ƿϢ + //三、装置报告控制块查找判断---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + RCB_INFO *rcb_info = NULL; //报告控制块指针 + ST_BOOLEAN bFindRCB = 0; //是否在装置报告控制块链表中查找到 + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //③遍历 全局装置报告控制块链表->报告控制块信息链表 { - //LOG_INFO("(ֹͣ)rcb_info_list, RptID= %sdom_Name= %sdom= %srcb_name= %srpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //ʹã zl 2018-10-17 21:19:36 - //if ((strcmp (rcb_info->rcb_name, rpt) == 0) && (strcmp(rcb_info->dom_Name, dom) == 0)) //ƥ װñƿ zl 2019-12-26 17:27:29 - if ((strcmp(rcb_info->rcb_name, rcb_name) == 0)) //ƥ װñƿ + //LOG_INFO("(报告停止)遍历rcb_info_list链表, RptID= %s,dom_Name= %s,dom= %s,rcb_name= %s,rpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //仅调试使用! zl 2018-10-17 21:19:36 + //if ((strcmp (rcb_info->rcb_name, rpt) == 0) && (strcmp(rcb_info->dom_Name, dom) == 0)) //匹配 装置报告控制块 —— 废弃! zl 2019-12-26 17:27:29 + if ((strcmp(rcb_info->rcb_name, rcb_name) == 0)) //匹配 装置报告控制块 { - bFindRCB = 1; //ҵװñƿ - //LOG_INFO("(ֹͣ)ƥ䵽ƿdom= %srcb= %sѴ", dom, rpt); //ʹã zl 2019-3-13 14:24:43 + bFindRCB = 1; //查找到装置报告控制块 + //LOG_INFO("(报告停止)匹配到报告控制块dom= %s,rcb= %s,已触发过!", dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 break; /* rcb_info now points to right structure */ } } - if (!bFindRCB) //δҵװñƿ + if (!bFindRCB) //未查找到装置报告控制块 { - rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); // װñƿ >> עúΪʱװ͵ıƿѴٽд + rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); //调用 创建装置报告控制块 —>> 注:该函数较为耗时,若本装置类型的报告控制块已创建过,则不需再进行创建! if (rcb_info == NULL) { - //LOG_INFO("(ֹͣ)ƿʧܣdom= %srcb= %s", dom, rpt); //ʹã zl 2019-3-13 14:24:43 + //LOG_INFO("(报告停止)创建报告控制块失败!dom= %s,rcb= %s", dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 return SD_FAILURE; } else { - //LOG_INFO("(ֹͣ)ƿɹȫֱƿdom= %srcb= %s", dom, rpt); //ʹã zl 2019-3-13 14:24:43 - list_add_last(&dev_rcb->rcb_info_list, rcb_info); // ȫֱƿ->ƿϢ + //LOG_INFO("(报告停止)创建报告控制块成功,新增全局报告控制块链表!dom= %s,rcb= %s", dom, rpt); //仅调试使用! zl 2019-3-13 14:24:43 + list_add_last(&dev_rcb->rcb_info_list, rcb_info); //添加 全局报告控制块链表->报告控制块信息链表 } } - sprintf(varName, "%s$RptEna", rcb_name); //ֹͣ LLN0$BR$brcbStatisticData03$RptEna - ret = mms_named_var_write(clientNetInfo, varName, DOM_SPEC, dom_name, rpt_typeids->mmsbool, (ST_CHAR *)&RptEna, timeOut); // дװñƿ(ֹͣ) + sprintf(varName, "%s$RptEna", rcb_name); //报告停止 例:LLN0$BR$brcbStatisticData03$RptEna + ret = mms_named_var_write(clientNetInfo, varName, DOM_SPEC, dom_name, rpt_typeids->mmsbool, (ST_CHAR *)&RptEna, timeOut); //调用 写入装置报告控制块(报告停止) return ret; @@ -1107,18 +1107,18 @@ ST_VOID doCommService () /* connectToServer */ /************************************************************************/ -// ַǷΪաո򲻿ɼַlnk20241119 +// 检查字符串是否为空、仅空格或不可见字符lnk20241119 int is_empty_or_whitespace(const char* str) { if (str == NULL) { - return 1; // NULL Ϊ"" + return 1; // NULL 情况,视为"空" } while (*str) { if (!isspace((unsigned char)*str)) { - return 0; // зǿոַ"" + return 0; // 有非空格字符,非"空" } str++; } - return 1; // ȫǿո򲻿ɼַΪ"" + return 1; // 全是空格或不可见字符,视为"空" } ST_RET mms_connectToServer (ST_CHAR * dev_key,ST_CHAR *dev_series, ST_CHAR *serverARName, @@ -1174,7 +1174,7 @@ S_SEC_ENCRYPT_CTRL *encryptCtrl = NULL; /* conn enctryption info */ //authInfo->mech_type = ACSE_AUTH_MECH_PASSWORD; //memset(ied_password,0,sizeof(ied_password)); - //lnk20241119жϺʹӡȷʶԿΪʱü + //lnk20241119添加判断和打印,确保识别码秘钥为空时不调用加密 if (!is_empty_or_whitespace(dev_series) || !is_empty_or_whitespace(dev_key)) { printf("dev_series= %s,dev_key= %s\n", dev_series,dev_key); /* Fill out an authentication structure */ diff --git a/mms/parse_xml.c b/mms/parse_xml.c index 60d9cd6..3ac2d7f 100644 --- a/mms/parse_xml.c +++ b/mms/parse_xml.c @@ -1,6 +1,6 @@ /** * @file: $RCSfile: parse_xml.c,v $ - * @brief: $xml + * @brief: $解析xml * * @version: $Revision: 1.5 $ * @date: $Date: 2018/12/29 03:18:14 $ @@ -85,11 +85,11 @@ apr_status_t app_get_private_config(const char *myfilename) -//************ ReportControl.xml ***************// +//************解析 ReportControl.xml ***************// #define REPORTCONTROL_FILE_PATH CONFIG_FILEPATH /* - + 104,1,2 */ //lnk20250122start @@ -101,12 +101,12 @@ int init_rptctrl_by_count(LD_info_t* LD_info,int rptcount) int j,i; LD_info->rptcount = rptcount; - if(LD_info->rptinfo == NULL){ //ǿյ˵ǵһγʼҪռ䣬ֱӸÿ20λ̨ɾֱݣҪֱ¸ֵ + if(LD_info->rptinfo == NULL){ //如果是空的说明是第一次初始化,需要申请空间,直接给每个监测点申请20个报告位,如果台账删除直接清空内容,如果需要重用直接重新赋值 LD_info->rptinfo = apr_pcalloc( g_init_pool,MAX_RPT_COUNT*sizeof(rptinfo_t*) ); } for(j=0; jrptinfo[j] == NULL){//ǿյ˵ǵһγʼҪռ䣬ԭĿռ䣬ֱӽֵijʼ + if(LD_info->rptinfo[j] == NULL){//如果是空的说明是第一次初始化,需要申请空间,否则沿用原来的空间,直接进行值的初始化 LD_info->rptinfo[j] = apr_pcalloc( g_init_pool,sizeof(rptinfo_t) ); } LD_info->rptinfo[j]->LD_info = LD_info; @@ -124,7 +124,7 @@ int init_rptctrl_by_count(LD_info_t* LD_info,int rptcount) } //lnk20250122end -//ReportControl: װID,CPUID,ID,RCBName, intgPd, dchg, qchg, dupd, period ,gi, ʵǷӺ׺, +//ReportControl: 装置ID,CPUID,ID,RCBName, intgPd, dchg, qchg, dupd, period ,gi, 实例名是否增加后缀,  // seqNum, timeStamp, reasonCode, dataSet, dataRef, bufOvfl, entryID, configRef, segmentation //104,1,1,brcbDin,60,1,0,0,1,0,yes,1,1,0,1,1,1,1,1,0 int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf) @@ -138,7 +138,7 @@ int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf) if(!(str = strtok(buf,","))) return 1; - rptinfo->rptNo = rptno;//CZY 2023-08-16 WW 2022-11-14 ӱţжϱǷ꣬Խݴ + rptinfo->rptNo = rptno;//CZY 2023-08-16 WW 2022-11-14 增加报告编号,用于判断报告是否收完,可以进行数据处理 tmp_str = apr_pstrdup(g_init_pool,str); rptinfo->rptID = str_trim_both(tmp_str," \t\'" ); @@ -199,7 +199,7 @@ int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf) rptinfo->report_PQ_type = atoi(str); }else return 1; - if ((str = strtok(NULL, ","))) { //CZY 2023-08-16 WW 2022-11-14䱨־ + if ((str = strtok(NULL, ","))) { //CZY 2023-08-16 WW 2022-11-14增加闪变报告标志 rptinfo->flickerflag = atoi(str); if (rptinfo->flickerflag == 0) { LD_info->rptRecvFlag += 0x01 << rptno; @@ -218,10 +218,10 @@ int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf) ////////////////////////////////////////////////////////// -//************ LogControl.xml ***************// +//************解析 LogControl.xml ***************// /* - + 104,1,2 */ @@ -274,7 +274,7 @@ int fill_logctrl_by_cfg(LD_info_t* LD_info,int logno,char *buf,char* devtype) if(!(str = strtok(NULL,","))) return 1; - apr_snprintf(loginfo->logName,sizeof(loginfo->logName), devtype,LD_info->cpuno);//PQM1 + apr_snprintf(loginfo->logName,sizeof(loginfo->logName), devtype,LD_info->cpuno);//例如PQM1 if((str = strtok(NULL,","))) loginfo->reasonCode = atoi(str); else return 1; if((str = strtok(NULL,","))) loginfo->IntgPd = atoi(str); else return 1; diff --git a/mms/rdb_client.c b/mms/rdb_client.c index 638b2f5..27e9c86 100644 --- a/mms/rdb_client.c +++ b/mms/rdb_client.c @@ -1,6 +1,6 @@ /** * @file: $RCSfile: rdb_client.c,v $ - * @brief: $PROFIBUS SSRTDB + * @brief: $PROFIBUS 与SSRTDB交互 * * @version: $Revision: 1.11 $ * @date: $Date: 2020/10/28 05:21:18 $ @@ -14,7 +14,7 @@ #include "rdb_client.h" #include "db_interface.h" #include "node.h" -#include //lnk20250114̨ӻ +#include //lnk20250114给台账添加互斥锁 /*lnk10-10 *///////////////////////////////// extern int HTTP_PORT; @@ -23,7 +23,7 @@ extern int G_TEST_FLAG; extern int g_front_seg_index; extern int g_front_seg_num; -#include "../include/rocketmq/SimpleProducer.h" +#include "../rocketmq/SimpleProducer.h" #include "../cfg_parse/custom_printf.h"//lnk20250225 //////////////////////////////////////////// @@ -42,11 +42,11 @@ apr_pool_t* g_init_pool; apr_pool_t* g_run_pool; apr_pool_t* g_temp_dev_pool; -//lnk20250114̨ӻ +//lnk20250114给台账添加互斥锁 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; -extern char g_onlyIP[255]; //ֱijIPΪ -//Ϊ +extern char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 +//为无锡西径变调档添加 uint8_t set_mx_q; pt61850app_t* g_pt61850app; @@ -186,21 +186,23 @@ apr_status_t init_rdb() GetServerIndexFromDB(); rv = parse_device_cfg_web(); - if (rv != APR_SUCCESS) { echo_errg("Parsed device config xml file with error,try to run! \n"); return rv; } + //台账读取过后初始化各级的日志 + + rv = parse_model_cfg_web(); if (rv != APR_SUCCESS) { echo_errg("Parsed model with error,try to run! \n"); return rv; } - Set_xml_nodeinfo();//xmlģ + Set_xml_nodeinfo();//解析xml模型 - rv = parse_rpt_log_ini();//ʼ + rv = parse_rpt_log_ini();//报告块初始化 if (rv != APR_SUCCESS) { echo_errg("Failed to parse report log define ini file! \n"); return rv; @@ -216,7 +218,7 @@ apr_status_t init_rdb() extern int SOCKETENABLE; extern int HTTPENABLE; -/*--------------------------- Լʼ -----------------------------------*/ +/*--------------------------- 规约初始化 -----------------------------------*/ apr_status_t run_protocol() { apr_status_t rv; @@ -224,9 +226,9 @@ apr_status_t run_protocol() static apr_threadattr_t* worker_attr = NULL; - //lnk20250214//ģʽ̺ͨ0ȡ̨ˣȻٸԼĽ̺ - if (g_onlyIP[0] != 0 && g_front_seg_index == 0 && g_front_seg_num >= 10){ //web˿ƴ򿪵ĵ - g_front_seg_index = g_front_seg_num; //½̺ΪΪõĽ̺ţʵʱ־ + //lnk20250214//单连模式,进程先通过进程号0获取所有台账,然后再更新自己的进程号 + if (g_onlyIP[0] != 0 && g_front_seg_index == 0 && g_front_seg_num >= 10){ //这是web端控制打开的单连进程 + g_front_seg_index = g_front_seg_num; //更新进程号为:为这个单连进程设置的进程号,用来控制实时日志 } init_MMS(); @@ -248,20 +250,20 @@ apr_status_t run_protocol() if ((rv = apr_thread_create(&rtdb_thread, worker_attr, rtdb_worker, NULL, g_run_pool)) != APR_SUCCESS) return rv; - try_start_kafka_thread();//mq߳ + try_start_kafka_thread();//mq线程 - //lnk20241213mq߳ + //lnk20241213添加mq消费者线程 try_start_mqconsumer_thread(); - ///////////////////WW 2023-08-22 ݿWebSocket߳ + ///////////////////WW 2023-08-22 增加数据库和WebSocket线程 if (g_onlyIP[0] != 0 || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_ALL_DATA_BASE_NODE_ID) { printf("g_onlyIP[0] != 0!\n\a"); - //̲sockethttp߳ + //单连进程不打开socket、http线程 } - else //sockethttp̵߳Ŀ + else //socket、http、测试线程的开启 { printf("g_onlyIP[0] == 0!\n\a"); if (1 == SOCKETENABLE) @@ -272,16 +274,16 @@ apr_status_t run_protocol() exit(1); } - int ServerPort = 13000;//WW Ҫݿıжȡ - if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ + int ServerPort = 13000;//WW 这里后面需要从数据库的表中读取 + if (g_node_id == STAT_DATA_BASE_NODE_ID)//统计采集 ServerPort = SOCKET_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; - else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//补召 ServerPort = SOCKET_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3秒采集 ServerPort = SOCKET_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//暂态录波 ServerPort = SOCKET_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; } @@ -312,23 +314,23 @@ apr_status_t run_protocol() if (1 == HTTPENABLE) { - //lnk20241029http߳/////////////////////////////////////////////////////////////////////////////////////////////// - if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ + //lnk20241029增加http线程/////////////////////////////////////////////////////////////////////////////////////////////// + if (g_node_id == STAT_DATA_BASE_NODE_ID)//统计采集 HTTP_PORT = HTTP_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; - else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//补召 HTTP_PORT = HTTP_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3秒采集 HTTP_PORT = HTTP_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; } - else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//暂态录波 HTTP_PORT = HTTP_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; } printf("try_start_web_http_thread \n"); try_start_web_http_thread(); printf("try_start_http_thread \n"); try_start_http_thread(); - //lnk20241029http߳/////////////////////////////////////////////////////////////////////////////////////////////////// + //lnk20241029增加http线程/////////////////////////////////////////////////////////////////////////////////////////////////// } @@ -342,32 +344,32 @@ apr_status_t run_protocol() extern uint32_t g_dead_lock_counter; extern uint32_t g_thread_blocked_times; -/*--------------------------- ʵʱ߳ -----------------------------------*/ +/*--------------------------- 连接实时库线程 -----------------------------------*/ static void* APR_THREAD_FUNC rtdb_worker(apr_thread_t* thd, void* data) { while (1) { - doCommService();//61850Ϣ + doCommService();//处理61850消息 - check_3s_config();//3ݽ̶ȡ3봥 + check_3s_config();//3秒数据进程读取3秒触发 - CheckNextNotConnectedChannel();//гӽж״̬ + CheckNextNotConnectedChannel();//所有长连接进程判断连接状态 - CheckAllConnectedChannel();//桢־١ + CheckAllConnectedChannel();//触发报告、日志补召、发送心跳 - create_recall_xml();//ɴxmlļ + create_recall_xml();//生成待补招xml文件 pthread_mutex_lock(&mtx); - check_ledger_update();//lnk20250113ȡ̨˸£̨˸ + check_ledger_update();//lnk20250113读取台账更新,触发台账更新 pthread_mutex_unlock(&mtx); - check_disk_quota();//жϴ̿ռ + check_disk_quota();//判断磁盘空间 - apr_pool_clear(g_pt61850app->tmp_pool);//ʱ + apr_pool_clear(g_pt61850app->tmp_pool);//清除临时缓存 g_dead_lock_counter = 0; - g_thread_blocked_times = 0;//߳ + g_thread_blocked_times = 0;//监控线程 } echo_msg("rtdb worker thread terminated..."); @@ -406,7 +408,7 @@ apr_time_t convert_btime6_to_apr_time(MMS_BTIME6* bTime6) { apr_time_t ticks; if ((TIME_T_1984_JAN_1 + (bTime6->day * SECONDS_PER_DAY)) > TIME_T_2036) { - echo_warn("ʱ󣬳2036꣡"); + echo_warn("时标错误,超过2036年!"); } ticks = TIME_T_1984_JAN_1; ticks += (bTime6->day * SECONDS_PER_DAY); @@ -418,7 +420,7 @@ apr_time_t convert_btime6_to_apr_time(MMS_BTIME6* bTime6) /* 61850 -λ ֵ +位 属性名称 值 0-1 Good 00 Invalid 01 Reserved 10 @@ -437,15 +439,15 @@ apr_time_t convert_btime6_to_apr_time(MMS_BTIME6* bTime6) */ /* 60870 -λ ֵ -0 -1 -2 -3 -4 -5 ȡ -6 ǵǰֵ -7 Ч +位 属性名称 值 +0 溢出 +1 保留 +2 保留 +3 保留 +4 被封锁 +5 被取代 +6 非当前值 +7 无效 */ byte_t get_mx_q_from_61850(char* q_61850) { @@ -480,15 +482,15 @@ byte_t get_mx_q_from_61850(char* q_61850) /* 60870 -λ ֵ -0 -1 -2 -3 -4 -5 ȡ -6 ǵǰֵ -7 Ч +位 属性名称 值 +0 保留 +1 保留 +2 保留 +3 保留 +4 被封锁 +5 被取代 +6 非当前值 +7 无效 */ byte_t get_st_q_from_61850(char* q_61850) { diff --git a/mms/rdb_client.h b/mms/rdb_client.h index 41f0cde..655e226 100644 --- a/mms/rdb_client.h +++ b/mms/rdb_client.h @@ -1,6 +1,6 @@ /** * @file iec103ttylink.h - * @brief IEC61850 rdb ͷļ + * @brief IEC61850 与rdb 交互处理 的头文件 * * @version $Revision: 1.18 $ * @date $Date: 2018/12/29 12:30:29 $ @@ -16,23 +16,23 @@ #include "ied.h" #include "node.h" -//lnk20250113Ӱ̨˶ͷļ +//lnk20250113添加包含台账定义的头文件 #include "../json/save2json.h" #include -//ļЧʱȡֵ +//文件有效时间的取值 #define FROM_FILE_NAME (0) #define FROM_SYSTEM (1) -//ͨļŵĿ¼ +//通用文件存放的目录 #define GENERAL_PREFIX "0_0" #define GENERAL_PATH "0_0\\19700101\\00" -//iec report ݵ״̬ -#define VALUE_REACHED (0x01) // ״̬ңֵյ -#define Q_REACHED (0x02) // յ -#define T_REACHED (0x04) // ʱյ -#define REASON_REACHED (0x08) // ԭյ +//iec report 数据到达状态 +#define VALUE_REACHED (0x01) // 状态或遥测值已收到 +#define Q_REACHED (0x02) // 数据质量已收到 +#define T_REACHED (0x04) // 时标已收到 +#define REASON_REACHED (0x08) // 发送原因已收到 //CHANNELSTATE macro defines #define CHANNEL_CONNECTING (0x01) // @@ -45,19 +45,19 @@ #define RELAY_RUN (0x02) // #define RELAY_CANCEL (0x03) // -#define MIN_INIT_NUM (10) //·ȫʼٴΪԽٻ¼ļ -#define NEXT_CONNECT_TIME (10000) //һʧܺ´ʱ10*1000=10s +#define MIN_INIT_NUM (10) //链路层完全初始化最少次数,作为可以进行召唤录波文件的条件。 +#define NEXT_CONNECT_TIME (10000) //一次链接失败后,下次链接时间间隔10*1000=10s -#define MAX_SAME_FCDNAME_OBJECTS (500) // for PQװãij64 2016-5-10 //һFCDֳɶĸ һ ACT󣬷ֳgeneralphsabc +#define MAX_SAME_FCDNAME_OBJECTS (500) // for 灿能PQ装置,改成64 2016-5-10 //最多一个FCD分成多个对象的个数 ,如一个 ACT对象,分成general,phsa,b,c等数个对象 -/** ======================㽭涼˳չͬڹ============================ */ +/** ======================浙江渔都变顺控扩展同期功能============================ */ /* -16:ֵʽբ -17:ͬںբ -18:ͬںբ -19:ѹբ -CHECK_BY_SETTING CHECK_U Ӧ˳Ʊͬңصĵһңص -CHECK_NOTHING CHECK_SYN Ӧ˳Ʊͬңصĵڶңص +16:按定值方式合闸 +17:不检同期合闸 +18:检同期合闸 +19:检无压合闸 +CHECK_BY_SETTING CHECK_U 对应顺控票同期遥控点的第一个遥控点 +CHECK_NOTHING CHECK_SYN 对应顺控票同期遥控点的第二个遥控点 */ #define CHECK_START_QU 16 #define CHECK_BY_SETTING 0 @@ -65,10 +65,10 @@ CHECK_NOTHING CHECK_SYN #define CHECK_SYN 2 #define CHECK_U 3 -#define DEFAULT_EDIT_FXDAREANO (0x80FE) /**< Ĭϱ༭ֵ */ -#define FIXED_AREA_GRP_DOT2_EDIT_AREA (2) /**< ֵ->༭ֵ */ +#define DEFAULT_EDIT_FXDAREANO (0x80FE) /**< 默认编辑区定值区号 */ +#define FIXED_AREA_GRP_DOT2_EDIT_AREA (2) /**< 定值区组->编辑定值区点 */ -//lnkʹܱ־20250121 +//lnk添加使能标志20250121 #define ENABLE 1 #define UNUSED 0 @@ -87,7 +87,7 @@ typedef struct ied_info_t ied_info_t; struct autorecall_t { long long start; long long end; - int need_steady; //lnk20241030Ӳ̬̬־ + int need_steady; //lnk20241030添加补招稳态暂态标志 int need_voltage; }; ////////////////////////////////////////////////////////// @@ -96,7 +96,7 @@ struct ied_info_t{ unsigned char name[50][128]; char value[50][20]; }; -//lnk20250113̨˸½ṹ/////////////////////////////// +//lnk20250113添加台账更新结构/////////////////////////////// #define MAX_UPDATEA_NUM 10 typedef struct trigger_update_xml_t trigger_update_xml_t; struct trigger_update_xml_t{ @@ -138,8 +138,8 @@ struct trigger_3s_xml_t{ typedef struct recall_t recall_t; struct recall_t{ char* line_id; - long long start_time; //ٻ־ʼʱ - long long end_time; //ٻ־ʱ + long long start_time; //待召唤日志起始时间 + long long end_time; //待召唤日志结束时间 int need_steady; int need_voltage; }; @@ -175,30 +175,30 @@ struct element_usr_t{ struct rptinfo_t{ char* rptID; - byte_t instanceNeedSuffix; //ʵǷӺ׺ + byte_t instanceNeedSuffix; //实例名是否增加后缀 byte_t TrgOpt; byte_t OptFlds [2]; /* 10 bit bitstring but only allow write of 9 bits*/ - uint32_t IntgPd; //ʱ䣨룩 - int report_PQ_type; //ǰͣͳơʵʱsoe¼͵ + uint32_t IntgPd; //完整性上送时间(秒) + int report_PQ_type; //报告前置类型,统计、实时、soe、事件类型等 LD_info_t* LD_info; - int rpt_registered; //Ƿעɹ - byte_t chnl_id; //δעᣬ´ͼעᱨͨ - //עᣬDZעᱨͨ + int rpt_registered; //是否注册成功 + byte_t chnl_id; //如果未注册,下次试图注册报告的通道号 + //如果已注册,则是本次注册报告的通道号 RCB_INFO * m_rcb_info; - double m_LastDataTime; //ϴյݵʱ - double m_LastGITime; //ϴGIʱ - double m_LastRegisterFailedTime; //ϴעʧܵʱ - double m_LastUnRegisterFailedTime; //ϴȡעʧܵʱ + double m_LastDataTime; //上次收到数据的时间 + double m_LastGITime; //上次GI的时间 + double m_LastRegisterFailedTime; //上次注册失败的时间 + double m_LastUnRegisterFailedTime; //上次取消注册失败的时间 byte_t m_EntryID[8]; int m_curRptSuffix; - int count; //յݵĴ - int rptNo;//CZY 2023-08-17 WW 2022-11-14ӱƥռ - int flickerflag;//CZY 2023-08-17 WW 2022-11-14־ + int count; //收到报告数据的次数 + int rptNo;//CZY 2023-08-17 WW 2022-11-14增加编号用于匹配数据收集 + int flickerflag;//CZY 2023-08-17 WW 2022-11-14增加闪变标志 - int pstflag;//CZY 2023-08-17 WW 2022-11-14Ӷ־ + int pstflag;//CZY 2023-08-17 WW 2022-11-14增加短闪闪变标志 }; @@ -206,14 +206,14 @@ struct loginfo_t{ char* lcbName; char* datasetName; char logName[32]; - uint32_t IntgPd; //ʱ䣨룩 + uint32_t IntgPd; //完整性上送时间(秒) byte_t reasonCode; byte_t TrgOpt; LD_info_t* LD_info; //LCB_INFO * m_lcb_info; - apr_time_t start_time; //ٻ־ʼʱ - apr_time_t end_time; //ٻ־ʱ + apr_time_t start_time; //待召唤日志起始时间 + apr_time_t end_time; //待召唤日志结束时间 //double last_checktime; int need_steady; @@ -243,107 +243,107 @@ struct LD_info_t{ ied_t *ied; byte_t cpuno; char *LD_name; - apr_hash_t *ht_fcd; /**< FCD object hash element */ - apr_hash_t *ht_full_fcda; /**< FCDA object hash element */ - int rptcount; /**< report */ - rptinfo_t **rptinfo; /**< rptinfo_t* */ - int read_flag ; //CZY 2023-02-28 жǷ񽫼ǷЧ + apr_hash_t *ht_fcd; /**< FCD object hash索引 到 element */ + apr_hash_t *ht_full_fcda; /**< 完整FCDA object hash索引 到 element */ + int rptcount; /**< report 个数 */ + rptinfo_t **rptinfo; /**< rptinfo_t* 数组 */ + int read_flag ; //CZY 2023-02-28 判断是否将监测点是否有效 - char mp_id[256];//CZY 2023-08-20 룬8afaa - char terminal_code[256];//CZY 2023-08-20 ն˱ - //int ld_ins;//CZY 2023-08-20 ߼豸ʵţ1 - char voltage_level[256];//CZY 2023-08-20 ѹȼ30 - char v_wiring_type[256];//CZY 2023-08-20 ѹ߷ʽ01-ͣ02- - long long time; //CZY 2023-08-20 ʱ() ̨˸ʱ䣬1691656669 - int update_flag;//CZY 2023-08-20 ̨˸±־ 0:keep 2:delete 4:update 8:add - char monitor_status[64]; //lnk20241031״̬ -// - int rptRecvFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,rptRecvFlag=Ч - int rptRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,ÿյrptRecvFlagһжǷ - int rptPstRecvFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,rptRecvFlag=Ч - int rptPstRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,ÿյrptRecvFlagһжǷ -// -//ʹ - int iUnitOfTime;//CZY 2023-08-17 WW 202212715:43:34 װ¼ʱ䵥λл(0-ms; 1-s) - int iStatOfTime;//CZY 2023-08-17 WW 202212715:48:33 ͳʱ 0-ʱ 1-UTCʱ - int iJournalTime;//CZY 2023-08-17 WW 202212715:52:32 ־ʱ(0-UTCʱ(־¼ļΪUTCʱ); 1-ʱ(־ʱ䡢¼ļUTCʱ עĴ+8Сʱȡ־)) -//ʹ -//־ - int logcount; /**< log */ - loginfo_t **loginfo; /**< loginfo_t* */ -//־ -// + char mp_id[256];//CZY 2023-08-20 监测点编码,例:8afaa + char terminal_code[256];//CZY 2023-08-20 终端编码 + //int ld_ins;//CZY 2023-08-20 逻辑设备实例号,例:1 + char voltage_level[256];//CZY 2023-08-20 电压等级,例:30 + char v_wiring_type[256];//CZY 2023-08-20 监测点电压接线方式,例:01-三相星型,02-三相角型 + long long time; //CZY 2023-08-20 时间戳(秒) 台账更新时间,例:1691656669 + int update_flag;//CZY 2023-08-20 台账更新标志 0:keep 2:delete 4:update 8:add + char monitor_status[64]; //lnk20241031监测点状态 +//报告 + int rptRecvFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,rptRecvFlag=有效报告序号相加 + int rptRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,每次收到报告相加与rptRecvFlag一起判断是否收完 + int rptPstRecvFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,rptRecvFlag=有效报告序号相加 + int rptPstRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,每次收到报告相加与rptRecvFlag一起判断是否收完 +//报告 +//不使用 + 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 iJournalTime;//CZY 2023-08-17 WW 2022年12月7日15:52:32 补招日志时间(0-UTC时间(日志、录波文件均为UTC时间); 1-北京时间(日志北京时间、录波文件UTC时间 注:仅四川地区+8小时读取补招日志)) +//不使用 +//日志 + int logcount; /**< log 个数 */ + loginfo_t **loginfo; /**< loginfo_t* 数组 */ +//日志 +//补招 int autorecallflag; int autorecallcount; autorecall_t **autorecall; -// -//ʹ +//补招 +//不使用 uint32_t group; //add by rzx -//ʹ -//ʵʱ +//不使用 +//实时数据 int line_id; -//ʵʱ -//¼ +//实时数据 +//录波 int FltNum[256]; -//¼ -//ʵʱ +//录波 +//实时数据 int real_data; int soe_data; int limit; int count; -//ʵʱ -//ʹ +//实时数据 +//不使用 int SubV_Index; int Dev_Index; int Sub_Index; int GD_Index; -//ʹ +//不使用 //process QVVR QVVR_t qvvr[QVVR_NUM]; int qvvr_idx; - //̬ + //暂态 //process RDRE int RDRE_FltNum; - //¼ + //录波 }; struct ied_usr_t{ - LD_info_t *LD_info; /**< LD */ - int dev_idx; /**< 豸 */ - char dev_type[256]; /**< 豸 */ - char dev_key[256]; /**< 豸Կ */ - char dev_series[256]; /**< 豸ʶ */ - int dev_flag; /**< 豸־ */ + LD_info_t *LD_info; /**< LD数组 */ + int dev_idx; /**< 设备序号 */ + char dev_type[256]; /**< 设备类型 */ + char dev_key[256]; /**< 设备秘钥 */ + char dev_series[256]; /**< 设备识别码 */ + int dev_flag; /**< 设备标志 */ void *cookie; - double last_call_wavelist_time ; //ϴ¼бʱ + double last_call_wavelist_time ; //上次召录波列表时间 - char terminal_id[256];//CZY 2023-08-20 նid8afaa9a15707483a0157262f8e78077d - char org_name[256];//CZY 2023-08-20 λϾ˾ - char maint_name[256];//CZY 2023-08-20 άλϾ˾ - char station_name[256];//CZY 2023-08-20 վ220kV̨ɽ - char tmnl_factory[256];//CZY 2023-08-20 ն˳ңϾԶɷ޹˾ - long long time; //CZY 2023-08-20 ʱ() ̨˸ʱ䣬1691656669 - char tmnl_status[256];//CZY 2023-08-30 ״̬ - char terminal_code[256];//CZY 2023-08-30 ն˱ - int update_flag;//CZY 2023-08-20 ̨˸±־ 0:keep 2:delete 4:update 8:add + char terminal_id[256];//CZY 2023-08-20 终端id,例:8afaa9a15707483a0157262f8e78077d + char org_name[256];//CZY 2023-08-20 所属单位,例:南京供公司 + char maint_name[256];//CZY 2023-08-20 运维单位,例:南京供公司 + char station_name[256];//CZY 2023-08-20 所属变电站,例:220kV五台山变 + char tmnl_factory[256];//CZY 2023-08-20 终端厂家,例:南京自动化股份有限公司 + long long time; //CZY 2023-08-20 时间戳(秒) 台账更新时间,例:1691656669 + char tmnl_status[256];//CZY 2023-08-30 运行状态 + char terminal_code[256];//CZY 2023-08-30 终端编码 + int update_flag;//CZY 2023-08-20 台账更新标志 0:keep 2:delete 4:update 8:add - char processNo[64];//̨˽̺ + char processNo[64];//台账进程号 }; struct chnl_usr_t{ byte_t chnl_id; char ip_str[20]; - channel_t *chnl; /**< Ӧchannel ָ */ + channel_t *chnl; /**< 对应的channel 指针 */ MVL_NET_INFO *net_info; MVL_REQ_PEND *m_reqCtrl; //MVL_REQ_PEND int m_state; - double m_StartConnectingTime; //οʼ connect ʱ - double m_StartDisconnectingTime; //οʼ disconnect ʱ - double m_ClosedMsTime; //ϴͨرʱ - double m_LastPosRespTime; //ϴο϶Ӧʱ - int m_NegRespTimes; // ۼƷӦ + double m_StartConnectingTime; //这次开始 connect 的时间 + double m_StartDisconnectingTime; //这次开始 disconnect 的时间 + double m_ClosedMsTime; //上次通道关闭时间 + double m_LastPosRespTime; //上次肯定响应的时间 + int m_NegRespTimes; // 累计否定响应次数 }; @@ -354,32 +354,32 @@ struct pt61850app_t // rdb_t *rdb; node_t *node; // driver_t *driver; - //byte_t IsMaster; //ǰ״̬ + //byte_t IsMaster; //当前的主备状态 //////////////////////////// - uint32_t mmsOpTimeout; //mmsдȵĽʱʱ - //uint32_t relayTimeout; //ңصȴңŷصijʱʱ - uint32_t giTime; //ܲѯʱ - int rptSuffix[2][2]; //ƿ׺ + uint32_t mmsOpTimeout; //mms操作,读写变量等的交互超时时间 + //uint32_t relayTimeout; //遥控等待遥信返回的超时时间 + uint32_t giTime; //总查询时间 + int rptSuffix[2][2]; //报告控制块后缀 //char ftp_srv_ip[16]; //char ftpsrv_path[64]; //char ftp_user[32]; //char ftp_password[32]; - char accPath[65]; //װ¼ļ· - //char RcdMadeAddStr[65]; //¼ңŵַ - //uint8_t change_file_name; //ʱǷ޸ļ + char accPath[65]; //装置录波文件路径 + //char RcdMadeAddStr[65]; //录波动作遥信地址 + //uint8_t change_file_name; //保存时,是否修改文件名 uint32_t chnl_counts; chnl_usr_t **chnl_usr; - apr_pool_t *tmp_pool; // ʱpool - //·ȫʼΪԽٻ¼ļȷװóʼһκʼٻļ + apr_pool_t *tmp_pool; // 临时pool + //链路层完全初始化次数,作为可以进行召唤录波文件的条件。即确保所有装置初始化最少一次后才允许开始召唤文件 uint8_t initNum; - //ٻļͣΪ0ֻٻӦĿ¼µ¼ļΪ1ٻӦĿ¼µļչ + //召唤文件类型,为0则只召唤对应目录下的录波文件,为1则召唤对应目录下的所有文件,其余留待扩展 //uint8_t call_file_type; - //ǰǷֵЧ - uint8_t check_dgtVal;//0У0 + //数字量入库前是否检查值有效 + uint8_t check_dgtVal;//0不判,非0判 }; -//Ϊ +//为无锡西径变调档添加 extern uint8_t set_mx_q; #ifdef _OS_WIN32_ @@ -420,14 +420,14 @@ rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO void get_rpt_inst_name(rptinfo_t *rptinfo, char * rpt_inst_name ); /** -* @brief ʼrdb -* @return ɹ APR_SUCCESS +* @brief 初始化rdb库相关内容 +* @return 如果创建成功,返回 APR_SUCCESS */ apr_status_t init_rdb(); /** -* @brief Լ߳ -* @return ɹ APR_SUCCESS +* @brief 启动规约处理相关线程 +* @return 如果成功,返回 APR_SUCCESS */ apr_status_t run_protocol(); @@ -440,7 +440,7 @@ void CheckNextNotConnectedChannel(); //WW 2023-08-22 int HandleReceiveMessage(int socketClient, char buffer[256]); int ExecuteWebCommand(LD_info_t *LD_info, int iType); -int SendMessageToWeb(int socketClient, int iErrorCode); //Web Socketͻ˷Ϣ +int SendMessageToWeb(int socketClient, int iErrorCode); //向Web Socket客户端发送消息 //WW 2023-08-22 end void CheckAllConnectedChannel() ; diff --git a/mms/rdb_ext_utils.c b/mms/rdb_ext_utils.c index b36e720..c895414 100644 --- a/mms/rdb_ext_utils.c +++ b/mms/rdb_ext_utils.c @@ -1,6 +1,6 @@ /** * @file: $RCSfile: rdb_ext_utils.c,v $ - * @brief: $ rdb usr_extĽṹһЩߺ + * @brief: $ rdb 利用usr_ext扩充的结构的一些工具函数 * * @version: $Revision: 1.11 $ * @date: $Date: 2018/12/23 12:39:52 $ @@ -26,7 +26,7 @@ extern pt61850app_t* g_pt61850app; //extern ied_info_t *my_info; //extern byte_t g_file_name_len; //extern byte_t g_file_time_from; -////////////////////////str ////////////////////////// +////////////////////////str 辅助函数////////////////////////// char* str_trim_both(char* temp,const char* pattern) { // pattern such as " \t" or " \t\'" @@ -47,7 +47,7 @@ char* str_trim_both(char* temp,const char* pattern) } -////////////////////////rdb 61850ṹ ////////////////////////// +////////////////////////rdb 61850扩充结构 辅助函数////////////////////////// ied_usr_t* GET_IEDEXT_ADDR(ied_t *ied) { @@ -163,7 +163,7 @@ RCB_INFO* FindRcbInfo(MVL_NET_INFO *net_info,ST_CHAR *dom_name, ST_CHAR *rcb_nam return NULL; } //////////////////////////////////////// -//WW 2023-08-29 rcb_infodev_type󶨲Ǻͼ󶨣޸Ĺ򣬱ƥ +//WW 2023-08-29 由于rcb_info和dev_type绑定不是和监测点绑定,这里修改规则,保留报告名称匹配 rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO *rcb_info) { ied_t *ied; @@ -183,17 +183,17 @@ rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; printf("%d rptinfo %s,rcbinfo %s ", rpt_no, rptinfo->rptID, rcb_info->RptID); - if (strcmp(rcb_info->RptID,rptinfo->rptID)==0)//WW ޸Ϊƥַ + if (strcmp(rcb_info->RptID,rptinfo->rptID)==0)//WW 修改为匹配字符串 return rptinfo; } } return NULL; } -//WW 2023-08-29 ע +//WW 2023-08-29 注释 //////////////////////////////////////// //////////////////////////////////////// -//WW 2023-08-29 ע +//WW 2023-08-29 注释 rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_info) { ied_t *ied; @@ -219,7 +219,7 @@ rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_i return NULL; } //////////////////////////////////////// -//WW 2023-08-29 ע end +//WW 2023-08-29 注释 end void get_rpt_inst_name(rptinfo_t *rptinfo, char * rpt_inst_name ) { strcpy(rpt_inst_name,rptinfo->rptID); @@ -293,7 +293,7 @@ ied_t* find_ied_from_dev_code(char dev_idx[]) return NULL; } -//lnk20250114ͨնidն +//lnk20250114新增通过终端id查找终端 ied_t* find_ied_from_terminal_id(char terminal_id[]) { ied_t* ied = NULL; @@ -309,7 +309,7 @@ ied_t* find_ied_from_terminal_id(char terminal_id[]) } return NULL; } -//lnk20250121Ҳʹõiedռ +//lnk20250121找不使用的ied空间 ied_t* find_ied_unused() { ied_t* ied_find_unused = NULL; @@ -319,7 +319,7 @@ ied_t* find_ied_unused() ied_find_unused = g_node->clients[iedno]; ied_usr_find_unused = (ied_usr_t*)ied_find_unused->usr_ext; if (ied_usr_find_unused && ied_usr_find_unused->dev_flag == UNUSED) { - return ied_find_unused;//ҵһͷ + return ied_find_unused;//找到第一个就返回 } } return NULL; @@ -436,8 +436,8 @@ int get_real_report_count(LD_info_t *LD_info) for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; - //if (rptinfo->report_PQ_type & REPORT_TYPE_REAL)//бжϱ - if (rptinfo->report_PQ_type)//ϲжʵʱݣҪж + //if (rptinfo->report_PQ_type & REPORT_TYPE_REAL)//遍历所有报告判断报告类型 + if (rptinfo->report_PQ_type)//上层已判断实时数据,不需要再判断 return rptinfo->count; } return 0; @@ -445,32 +445,32 @@ int get_real_report_count(LD_info_t *LD_info) //////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////ѹ///////////////////////////// +////////////////////电压波动处理///////////////////////////// void processQVVR_start(LD_info_t* LD_info) { int i; for (i=0;iqvvr[i].used_status==QVVR_DATA_NOT_USED) { - LD_info->qvvr_idx = i; //ûʹãʹ + LD_info->qvvr_idx = i; //这个点没使用,使用这个点 break; } } - if (i>=QVVR_NUM) { //Ѿʹõһ - uint32_t timestamp = LD_info->qvvr[0].timestamp;//һʱ - LD_info->qvvr_idx = 0;//ӵһ㿪ʼ¼ + if (i>=QVVR_NUM) { //已经使用到了最后一个点 + uint32_t timestamp = LD_info->qvvr[0].timestamp;//第一个点的时间 + LD_info->qvvr_idx = 0;//从第一个点开始记录 echo_warn1("QVVR data memory is full,to replace the oldest,line_id=%d \n",LD_info->line_id); for (i=1;iqvvr[i].timestampqvvr[i].timestampqvvr_idx = i; timestamp = LD_info->qvvr[i].timestamp; } } } - LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_RECEIVED;//Ϊյ̬ - LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 0; //δ - LD_info->qvvr[LD_info->qvvr_idx].timestamp = apr_time_sec(apr_time_now());//¼ǰʱΪ̬ʱ + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_RECEIVED;//这个点标记为收到暂态数据 + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 0; //类型未定 + LD_info->qvvr[LD_info->qvvr_idx].timestamp = apr_time_sec(apr_time_now());//记录当前时间为暂态时间 printf("\n~~~~~~~~~~~~~~~~~ processQVVR_start: line_id=%d \n",LD_info->line_id); } @@ -492,11 +492,11 @@ void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) else if ( strstr(FULL_FCDA_Name,"VVa$mag$f") ) LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg = (float)v; else { - if ( strstr(FULL_FCDA_Name,"DipStr$stVal") && (v>0.99) ) //ѹݽ - LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210002;//սӿ޸ - else if ( strstr(FULL_FCDA_Name,"SwlStr$stVal") && (v>0.99) ) //ѹ + if ( strstr(FULL_FCDA_Name,"DipStr$stVal") && (v>0.99) ) //电压暂降 + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210002;//按照接口修改 + else if ( strstr(FULL_FCDA_Name,"SwlStr$stVal") && (v>0.99) ) //电压暂升 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210001; - else if ( strstr(FULL_FCDA_Name,"IntrStr$stVal") && (v>0.99) ) //ѹж + else if ( strstr(FULL_FCDA_Name,"IntrStr$stVal") && (v>0.99) ) //电压中断 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210004; } @@ -512,7 +512,7 @@ void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) void processQVVR_end(LD_info_t* LD_info) { - //lnk20241227lnk̬¼ֱϱ¼¼DZ߻ϱһθļ·ﲻļ· + //lnk20241227lnk添加暂态事件直接上报,等录波事件上来后,那边会再上报一次更新文件路径,这里不更新文件路径 ied_t *ied = LD_info->ied; ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); int ret; @@ -522,20 +522,20 @@ void processQVVR_end(LD_info_t* LD_info) int find_paired = FALSE; int i; - if (LD_info->qvvr[LD_info->qvvr_idx].QVVR_start)//ݴʱFCDAVarStr$stValQVVR_startΪ1˳ + if (LD_info->qvvr[LD_info->qvvr_idx].QVVR_start)//波动数据处理时FCDA包含VarStr$stVal,QVVR_start为1,退出处理 return; - for (i=0;iqvvr_idx) //㵱ǰλ,һμ¼κ󣬵һεĵ¼0ŵΪQVVR_DATA_RECEIVED - //ڶμ¼Σڶεĵһ¼qvvr_idx=11ΪQVVR_DATA_RECEIVEDQVVR_start=1¼ - //ڶεĵڶ¼qvvr_idx=1QVVR_start=0¼0У0ΪQVVR_DATA_PAIRED - //ڶεĵ¼qvvr_idx=22ΪQVVR_DATA_RECEIVEDQVVR_start=1¼ - //ڶ¼ƥļʱӦƥ䵽1ŵqvvrtime1ûQVVR_DATA_PAIREDԶԲϣҪ޸߼ + for (i=0;iqvvr_idx) //跳过监测点当前波动位置,第一次记录波形后,第一次的第三个事件会让0号点为QVVR_DATA_RECEIVED, + //第二次记录波形,第二次的第一个事件qvvr_idx=1,1号中为QVVR_DATA_RECEIVED,QVVR_start=1,跳过记录, + //第二次的第二个事件qvvr_idx=1,QVVR_start=0,记录到0中,0为QVVR_DATA_PAIRED + //第二次的第三个事件qvvr_idx=2,2号中为QVVR_DATA_RECEIVED,QVVR_start=1,跳过记录 + //第二次录波匹配文件时应该匹配到1号的qvvrtime,但是1没有QVVR_DATA_PAIRED所以对不上,需要修改逻辑 continue; - if (LD_info->qvvr[i].used_status != QVVR_DATA_RECEIVED)//ûյλ + if (LD_info->qvvr[i].used_status != QVVR_DATA_RECEIVED)//跳过没有收到波动的位置 continue; - //ʱжlnk20250311 + //添加时间判断lnk20250311 if (fabs((LD_info->qvvr[LD_info->qvvr_idx].QVVR_time - LD_info->qvvr[i].QVVR_time)/1.0 - LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime) > 1.0){ printf("~~~~~~~fail in pair qvvr node %f~~~~~~~~~~ \n",fabs((LD_info->qvvr[LD_info->qvvr_idx].QVVR_time - LD_info->qvvr[i].QVVR_time)/1.0 @@ -545,10 +545,10 @@ void processQVVR_end(LD_info_t* LD_info) - //ijλõIJҲûж/λõIJͺ͵ǰλõIJһ£ݽ¼һλᷢ,ֵͽ + //其他某位置的波动也没有定义类型/这个位置的波动类型和当前位置的波动类型一致,暂降事件一次会发三个报告,启动和上值和结束 if ( (LD_info->qvvr[i].QVVR_type==0)||(LD_info->qvvr[i].QVVR_type==LD_info->qvvr[LD_info->qvvr_idx].QVVR_type) ) { - long long end_tm = (long long)(LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime*1000) + LD_info->qvvr[i].QVVR_time;//ʱdzʱĴʱ䣬 + long long end_tm = (long long)(LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime*1000) + LD_info->qvvr[i].QVVR_time;//结束时间是持续时间加最初的触发时间,毫秒 printf("\n~~~~~~~now qvvr node type before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); printf("~~~~~~~now qvvr node QVVR_PerTime before record is %f~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime); @@ -558,12 +558,12 @@ void processQVVR_end(LD_info_t* LD_info) printf("~~~~~~~now qvvr node QVVR_start before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_start); printf("~~~~~~~now qvvr node timestamp before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].timestamp); - LD_info->qvvr[i].used_status = QVVR_DATA_PAIRED; //ƥ + LD_info->qvvr[i].used_status = QVVR_DATA_PAIRED; //匹配上了 LD_info->qvvr[i].QVVR_type = LD_info->qvvr[LD_info->qvvr_idx].QVVR_type; LD_info->qvvr[i].QVVR_PerTime = LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime; - LD_info->qvvr[i].QVVR_Amg = LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg; //¼ǰIJݵҵĵλϣȷ¼µͬ͵¼ + LD_info->qvvr[i].QVVR_Amg = LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg; //记录当前这个点的波动数据到找到的点位置上,确保记录的是最新的相同类型的事件 - LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //ǰλͷ + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //当前这个点位置释放 find_paired = TRUE; printf("~~~~~~~this qvvr node QVVR_PerTime after record is %f~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_PerTime); @@ -574,17 +574,17 @@ void processQVVR_end(LD_info_t* LD_info) printf("~~~~~~~this qvvr node timestamp before record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].timestamp); printf("~~~~~~~this qvvr node QVVR_start before record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_start); - //ƥٷqvvrʼʱҪ̬ʱ䣬ǵһ¼ʱֻʱûֵǸʱ - ret = transfer_json_qvvr_data(g_node_id, //ûʹ - LD_info->line_id, // + //匹配后再发qvvr,起始时间要填暂态触发的时间,就是第一次事件上送时只有时间没有值的那个时间 + ret = transfer_json_qvvr_data(g_node_id, //这个参数没有使用 + LD_info->line_id, //监测点序号 (double)LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg, (double)LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime, LD_info->qvvr[i].QVVR_time, end_tm, - LD_info->qvvr[LD_info->qvvr_idx].QVVR_type, //ֵʱ䡢ʼʱ䡢ʱ䡢̬ - "", "", //ļ·Ϊ - LD_info->mp_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, ied_usr->dev_type);//ţļͼ̬¼ƥϵ̬ն - if(!ret)//ʧ + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type, //伏值、持续时间、开始时间、结束时间、暂态类型 + "", "", //两个文件路径为空 + LD_info->mp_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, ied_usr->dev_type);//监测点号,文件和监测点暂态事件匹配上的暂态报告名,终端类型 + if(!ret)//失败 { printf("\n~~~~~~~~~~~~~~~~~ QVVR_json_data send error: line_id=%d \n",LD_info->line_id); } @@ -594,7 +594,7 @@ void processQVVR_end(LD_info_t* LD_info) } if (find_paired == FALSE) { - LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //ȫûƥֱͷ㣬´¼ֱʹ + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //全都没有匹配上直接释放这个点,下次事件可以直接在这个点上使用 printf("\nERROR:~~~~~~~~~~~~~ processQVVR qvvr returned to 0,but found no data to pair!, line_id=%d,QVVR_type=%d \n", LD_info->line_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); } @@ -602,38 +602,38 @@ void processQVVR_end(LD_info_t* LD_info) printf("\n~~~~~~~~~~~~~~~~~ processQVVR_end: line_id=%d \n",LD_info->line_id); } -// ܣݴʱtrig_tmƥ QVVR ݡ -// -// - LD_infoָ LD_info_t ͽṹָ룬 QVVR ݡ -// - trig_tmʱ QVVR еʱƥ䡣 -// -// - ƥ QVVR ݵָ롣ûҵƥ QVVR ݣ򷵻 NULL -// ֵ -// - ҵ QVVR ݣָݵָ롣 -// - ûҵ QVVR ݣ NULL +// 函数功能:根据触发时间戳(trig_tm)查找匹配的 QVVR 数据。 +// 输入参数: +// - LD_info:指向 LD_info_t 类型结构体的指针,包含多个 QVVR 数据。 +// - trig_tm:触发时间戳,用于与 QVVR 数据中的时间进行匹配。 +// 输出参数: +// - 返回匹配的 QVVR 数据的指针。如果没有找到匹配的 QVVR 数据,则返回 NULL。 +// 返回值: +// - 如果找到符合条件的 QVVR 数据,返回指向该数据的指针。 +// - 如果没有找到符合条件的 QVVR 数据,返回 NULL。 QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info, long long trig_tm) { - long long diff; // ڼʱ - int i; // ѭ + long long diff; // 用于计算时间戳差异 + int i; // 循环计数器 - // LD_info е QVVR + // 遍历 LD_info 中的 QVVR 数据数组 for (i = 0; i < QVVR_NUM; i++) { - // 㵱ǰ QVVR ݵʱ봥ʱ֮IJ + // 计算当前 QVVR 数据的时间戳与触发时间戳之间的差异 diff = abs(LD_info->qvvr[i].QVVR_time - trig_tm); - // + //调试用 printf("QVVRTIME:%lld >>>>> COMTRADE trig_tm:%lld >>>>> diff:%lld\n",LD_info->qvvr[i].QVVR_time,trig_tm,diff); - // QVVR ݵ״̬ ""QVVR_DATA_PAIREDʱСڵ 1λ룩 + // 如果该 QVVR 数据的状态是 "已配对"(QVVR_DATA_PAIRED)并且时间差小于等于 1(单位:毫秒) if ((LD_info->qvvr[i].used_status == QVVR_DATA_PAIRED) && (diff <= 1)) { - // ƥ䣬ظ QVVR ݵָ + // 如果匹配,返回该 QVVR 数据的指针 printf(">>>>> pair QVVR success>>>>>> \n"); return &(LD_info->qvvr[i]); } } printf(">>>>> pair QVVR fail>>>>>> \n"); - // ûҵƥ QVVR ݣ NULL + // 如果没有找到匹配的 QVVR 数据,返回 NULL return NULL; } #if 0 @@ -651,7 +651,7 @@ QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm) return NULL; } #endif -////////////////////¼ļ///////////////////////////// +////////////////////录波文件处理///////////////////////////// void processRDRE_start(LD_info_t* LD_info) { diff --git a/pt61850netd_pqfe.pro b/pt61850netd_pqfe.pro index 261b7df..9b6a893 100644 --- a/pt61850netd_pqfe.pro +++ b/pt61850netd_pqfe.pro @@ -92,10 +92,12 @@ unix { /FeProject/lib/liboss_c_sdk.so.3.0.0 \ /FeProject/lib/libmxml.so \ /FeProject/lib/librocketmq.so \ - /FeProject/lib/libhttprun.so + /FeProject/lib/libhttprun.so \ + /FeProject/lib/liblog4cplus.so LIBS += -lapr-1 -laprutil-1 -ljclite LIBS += -lrdkafka++ LIBS += -lhttprun + LIBS += -llog4cplus } #install @@ -123,8 +125,10 @@ HEADERS += source/mms/db_interface.h \ source/json/rdkafkacpp.h \ source/json/kafka_producer.h \ source/json/cjson.h \ - source/include/rocketmq/SimpleProducer.h \ - source/cfg_parse/custom_printf.h + source/rocketmq/SimpleProducer.h \ + source/cfg_parse/custom_printf.h \ + source/log4cplus/log4.h + SOURCES += source/mms/main.c \ source/mms/clntobj.c \ source/mms/logcfgx.c \ @@ -158,4 +162,5 @@ SOURCES += source/mms/main.c \ source/cfg_parse/nacos.cpp \ source/cfg_parse/base64.cpp \ source/cfg_parse/uds_huaweiyun.cpp \ - source/cfg_parse/SimpleProducer.cpp + source/cfg_parse/SimpleProducer.cpp \ + source/cfg_parse/log4.cpp diff --git a/rocketmq/CPushConsumer.h b/rocketmq/CPushConsumer.h index 5ed83f3..69cd09c 100644 --- a/rocketmq/CPushConsumer.h +++ b/rocketmq/CPushConsumer.h @@ -33,34 +33,141 @@ typedef enum E_CConsumeStatus { E_CONSUME_SUCCESS = 0, E_RECONSUME_LATER = 1 } C typedef int (*MessageCallBack)(CPushConsumer*, CMessageExt*); ROCKETMQCLIENT_API CPushConsumer* CreatePushConsumer(const char* groupId); +// 创建一个消费者实例并返回指向该实例的指针。 +// 参数:groupId - 消费者所属的消费者组ID。 +// 必要性:是必须的,创建消费者实例时必须提供消费者组ID。 + ROCKETMQCLIENT_API int DestroyPushConsumer(CPushConsumer* consumer); +// 销毁指定的消费者实例。 +// 参数:consumer - 需要销毁的消费者实例。 +// 必要性:在消费者不再需要时调用,以释放资源。 + ROCKETMQCLIENT_API int StartPushConsumer(CPushConsumer* consumer); +// 启动消费者,开始消费消息。 +// 参数:consumer - 要启动的消费者实例。 +// 必要性:启动消费者并开始接收消息是必须的。 + ROCKETMQCLIENT_API int ShutdownPushConsumer(CPushConsumer* consumer); +// 关闭消费者,停止消费消息。 +// 参数:consumer - 要关闭的消费者实例。 +// 必要性:在应用程序结束时,必须调用该函数来安全地关闭消费者。 + ROCKETMQCLIENT_API const char* ShowPushConsumerVersion(CPushConsumer* consumer); +// 获取当前消费者实例的版本信息。 +// 参数:consumer - 需要获取版本信息的消费者实例。 +// 必要性:不是必须的,但可以用于调试和确认消费者版本。 + ROCKETMQCLIENT_API int SetPushConsumerGroupID(CPushConsumer* consumer, const char* groupId); +// 设置消费者的消费者组ID。 +// 参数:consumer - 消费者实例;groupId - 消费者组ID。 +// 必要性:用于设置消费者的消费者组ID,必须设置。 + ROCKETMQCLIENT_API const char* GetPushConsumerGroupID(CPushConsumer* consumer); +// 获取消费者实例的消费者组ID。 +// 参数:consumer - 消费者实例。 +// 必要性:不是必须的,但可以用于检查当前的消费者组ID。 + ROCKETMQCLIENT_API int SetPushConsumerNameServerAddress(CPushConsumer* consumer, const char* namesrv); +// 设置消费者的 NameServer 地址。 +// 参数:consumer - 消费者实例;namesrv - NameServer 地址。 +// 必要性:必须配置,以便消费者能够连接到 RocketMQ NameServer。 + ROCKETMQCLIENT_API int SetPushConsumerNameServerDomain(CPushConsumer* consumer, const char* domain); +// 设置消费者的 NameServer 域名。 +// 参数:consumer - 消费者实例;domain - NameServer 域名。 +// 必要性:不是必须的,通常会使用 SetPushConsumerNameServerAddress 设置 IP 地址。 + ROCKETMQCLIENT_API int Subscribe(CPushConsumer* consumer, const char* topic, const char* expression); +// 订阅一个指定的 topic 和 tag。 +// 参数:consumer - 消费者实例;topic - 消息主题;expression - 消息标签(可以为空,表示订阅所有标签)。 +// 必要性:必须配置消费者要订阅的 topic。 + ROCKETMQCLIENT_API int RegisterMessageCallbackOrderly(CPushConsumer* consumer, MessageCallBack pCallback); +// 注册顺序消息的回调函数。 +// 参数:consumer - 消费者实例;pCallback - 消息回调函数。 +// 必要性:如果需要顺序消费消息,则需要使用此函数注册顺序消息回调。 + ROCKETMQCLIENT_API int RegisterMessageCallback(CPushConsumer* consumer, MessageCallBack pCallback); +// 注册异步消息的回调函数。 +// 参数:consumer - 消费者实例;pCallback - 消息回调函数。 +// 必要性:必须配置回调函数,以便消费者能够处理收到的消息。 + ROCKETMQCLIENT_API int UnregisterMessageCallbackOrderly(CPushConsumer* consumer); +// 注销顺序消息的回调函数。 +// 参数:consumer - 消费者实例。 +// 必要性:不是必须的,只有在不再需要顺序消息时调用。 + ROCKETMQCLIENT_API int UnregisterMessageCallback(CPushConsumer* consumer); +// 注销异步消息的回调函数。 +// 参数:consumer - 消费者实例。 +// 必要性:不是必须的,只有在不再需要处理消息时调用。 + ROCKETMQCLIENT_API int SetPushConsumerThreadCount(CPushConsumer* consumer, int threadCount); +// 设置消费者的线程数量。 +// 参数:consumer - 消费者实例;threadCount - 消费者线程数量。 +// 必要性:用于控制消费者处理消息的并发度。如果不设置,默认值通常为1。 + ROCKETMQCLIENT_API int SetPushConsumerMessageBatchMaxSize(CPushConsumer* consumer, int batchSize); +// 设置消费者最大批量消息大小。 +// 参数:consumer - 消费者实例;batchSize - 最大批量消息大小。 +// 必要性:不是必须的,只有在需要调整消息消费的批量大小时才使用。 + ROCKETMQCLIENT_API int SetPushConsumerInstanceName(CPushConsumer* consumer, const char* instanceName); +// 设置消费者实例名称。 +// 参数:consumer - 消费者实例;instanceName - 消费者实例名称。 +// 必要性:不是必须的,可以为空,默认使用系统生成的实例名。 + ROCKETMQCLIENT_API int SetPushConsumerSessionCredentials(CPushConsumer* consumer, const char* accessKey, const char* secretKey, const char* channel); +// 设置消费者的身份验证信息。 +// 参数:consumer - 消费者实例;accessKey - 访问密钥;secretKey - 密钥;channel - 渠道。 +// 必要性:在需要身份验证的环境下(如阿里云RocketMQ),此项配置是必须的。 + + +// 设置消费者日志文件路径 +// 功能:设置日志文件的存储路径。消费者在运行时会将日志信息写入该路径指定的文件。 +// 必要性:日志路径配置有助于在生产环境中追踪和调试消费者的行为,记录日志是运维管理中的重要环节。 ROCKETMQCLIENT_API int SetPushConsumerLogPath(CPushConsumer* consumer, const char* logPath); + + +// 设置日志文件的数量和每个文件的最大大小 +// 功能:设置日志文件的数量和每个日志文件的最大大小。超过最大大小时会创建新日志文件。 +// 必要性:控制日志文件的数量和大小有助于防止日志文件过大,占用过多磁盘空间。对于高频消息消费的场景,合理配置日志文件大小和数量至关重要。 ROCKETMQCLIENT_API int SetPushConsumerLogFileNumAndSize(CPushConsumer* consumer, int fileNum, long fileSize); + + +// 设置消费者的日志级别 +// 功能:设置消费者的日志级别(如 DEBUG, INFO, WARN, ERROR 等),控制输出的日志详细程度。 +// 必要性:日志级别配置可以帮助调节日志的详细程度,根据环境不同选择适当的日志级别(例如,生产环境使用 ERROR 级别,开发环境使用 DEBUG 级别)。 ROCKETMQCLIENT_API int SetPushConsumerLogLevel(CPushConsumer* consumer, CLogLevel level); + + +// 设置消息模型(广播模式或集群模式) +// 功能:设置消费者的消息消费模型。广播模式(`CMessageModel::BROADCASTING`)会将消息推送到所有消费者,而集群模式(`CMessageModel::CLUSTERING`)则只会将消息推送到一个消费者。 +// 必要性:选择消息模型对消息消费的行为有直接影响,集群模式适用于负载均衡,而广播模式适用于所有消费者都需要接收消息的场景。 ROCKETMQCLIENT_API int SetPushConsumerMessageModel(CPushConsumer* consumer, CMessageModel messageModel); + + +// 设置消费者最大缓存消息大小(以字节为单位) +// 功能:设置消费者最大缓存消息的大小。当缓存达到此大小时,消费者会停止消费,直到缓存被处理并清空。 +// 必要性:此配置对于高吞吐量场景非常重要,它可以防止消费者在消息积压时出现内存溢出,保证消费者稳定运行。 ROCKETMQCLIENT_API int SetPushConsumerMaxCacheMessageSize(CPushConsumer* consumer, int maxCacheSize); + + +// 设置消费者最大缓存消息大小(以 MB 为单位) +// 功能:与 `SetPushConsumerMaxCacheMessageSize` 类似,不过该参数以 MB 为单位,设置最大缓存消息的大小。 +// 必要性:提供 MB 级别的配置对于一些需要调整内存和消息缓存的应用场景,能够更加精细地控制内存使用情况。 ROCKETMQCLIENT_API int SetPushConsumerMaxCacheMessageSizeInMb(CPushConsumer* consumer, int maxCacheSizeInMb); + + +// 设置消息追踪模型 +// 功能:设置消息的追踪模式。开启追踪会记录消费者的消费信息,帮助开发者分析消息的流转和消费情况。 +// 必要性:对于消息的追踪和监控至关重要,尤其在故障排查和性能优化中,可以通过追踪记录分析消费者的消息处理状态。 ROCKETMQCLIENT_API int SetPushConsumerMessageTrace(CPushConsumer* consumer, CTraceModel openTrace); + #ifdef __cplusplus } #endif diff --git a/rocketmq/SimpleProducer.h b/rocketmq/SimpleProducer.h index 0765a6f..22a066f 100644 --- a/rocketmq/SimpleProducer.h +++ b/rocketmq/SimpleProducer.h @@ -1,15 +1,58 @@ + +#ifdef __cplusplus #include "../json/mms_json_inter.h" -#include "../include/rocketmq/CProducer.h" -#include "../include/rocketmq/CMessage.h" -#include "../include/rocketmq/CSendResult.h" +#include "../rocketmq/CProducer.h" +#include "../rocketmq/CMessage.h" +#include "../rocketmq/CSendResult.h" + +#include "../rocketmq/CPushConsumer.h" + +#include + + /*添加测试函数lnk10-10*/ void producer_send0(); -void StartSendMessage(CProducer* producer); void StartSendMessage(CProducer* producer,const char* strbody); void producer_send(const char* strbody); void rocketmq_producer_send(const char* strbody,const char* topic); -void rocketmq_StartSendMessage(CProducer* producer,const char* strbody,std::string topic); -void rocketmq_test(); -void my_rocketmq_send(Ckafka_data_t& data); +void rocketmq_StartSendMessage(CProducer* producer,const char* strbody,const char* topic); +extern "C" { +void rocketmq_test_rt(); +void rocketmq_test_ud(); +void rocketmq_test_rc(); +void rocketmq_test_log(); +void rocketmq_test_set(); +void rocketmq_test_only(); +void rocketmq_test_300(int mpnum,int front_index); +} +//void rocketmq_test_300(int mpnum,int front_index);//20241202lnk +extern void my_rocketmq_send(Ckafka_data_t& data); -////////////////////////////////////////////////////// \ No newline at end of file + +///////////////////////////////////////////////////////生产者 +void InitializeProducer(); +void ShutdownAndDestroyProducer(); +//////////////////////////////////////////////////////消费者 +void InitializeConsumer(const std::string& consumerName, const std::string& nameServer, const char* topic, const char* tag, const std::string& key); +void ShutdownAndDestroyConsumer(); + +struct Subscription { + std::string topic; + std::string tag; + MessageCallBack callback; + + Subscription(const std::string& t, const std::string& tg, MessageCallBack cb) + : topic(t), tag(tg), callback(cb) {} +}; + +void rocketmq_consumer_receive( + const std::string& consumerName, + const std::string& nameServer, + //const std::string& topic, + //const std::string& tag, + //MessageCallBack callback); + const std::vector& subscriptions); + +////////////////////////////////////////////////////// +#endif +//////////////////////////////////////////////////////