Compare commits

...

4 Commits

Author SHA1 Message Date
lnk
7725fd2d87 fix comtrade file pair 2026-01-05 16:29:42 +08:00
lnk
dd01a31a77 fix coredump error 2025-12-23 15:09:28 +08:00
lnk
1014aeafbc add comment 2025-12-22 11:42:02 +08:00
lnk
c5ded4c032 fix recall file 2025-12-18 11:42:57 +08:00
6 changed files with 155 additions and 91 deletions

View File

@@ -49,11 +49,11 @@ fi
# 判断是否为 debug 版本
if [[ "$1" == "debug" ]]; then
CXXFLAGS="-std=c++11 -g -O0"
CXXFLAGS="-std=c++11 -g -O0 -Wformat -Wformat-security -Werror=format"
TARGET="${TARGET}d"
echo "🟢 编译调试版本 (-g -O0)"
else
CXXFLAGS="-std=c++11 -O2 -static-libstdc++ -static-libgcc"
CXXFLAGS="-std=c++11 -O2 -static-libstdc++ -static-libgcc -Wformat -Wformat-security -Werror=format"
echo "🔵 编译正式版本 (-O2 -static)"
fi

View File

@@ -2922,11 +2922,19 @@ bool compare_qvvr_and_file(const std::string& cfg_path, std::vector<qvvr_data>&
// 遍历所有暂态事件,查找与 trig_tm 匹配的
for (auto& data : data_list) {
long long diff = static_cast<long long>(data.QVVR_time) - trig_tm;
std::cout << "[调试] QVVR_time=" << data.QVVR_time
<< ", trig_tm=" << trig_tm
<< ", diff=" << diff << "\n";
if (std::abs(diff) <= 1) {
data.is_pair = true; // 标记为已匹配
matched_data = data; // 返回匹配到的事件
std::cout << "[调试] 匹配成功diff=" << diff << "\n";
return true;
}
}
@@ -3312,93 +3320,102 @@ bool update_qvvr_file_download(const std::string& filename_with_mac_in, const st
// 找到其中的 .cfg 文件进行匹配
for (const auto& fpath : qfile.file_download) {
std::string fname = extract_filename1(fpath);
if (fname.size() >= 4 && fname.substr(fname.size() - 4) == ".cfg") {
// 提取文件时标和监测点事件的时标匹配
qvvr_data matched;
if (compare_qvvr_and_file(fpath, monitor.qvvrevent.qvvrdata,matched)) {
qfile.is_pair = true; // 文件与事件匹配成功
if (fname.size() >= 4) {
std::string ext = fname.substr(fname.size() - 4);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if (ext == ".cfg") {
//if (fname.size() >= 4 && fname.substr(fname.size() - 4) == ".cfg") {
// 提取文件时标和监测点事件的时标匹配
qvvr_data matched;
if (compare_qvvr_and_file(fpath, monitor.qvvrevent.qvvrdata,matched)) {
qfile.is_pair = true; // 文件与事件匹配成功
// ★新增:上传前拷贝“将要上传的文件列表”,避免锁外用容器引用
std::vector<std::string> files_to_send(qfile.file_download.begin(),
qfile.file_download.end());
// ★新增:上传前拷贝“将要上传的文件列表”,避免锁外用容器引用
std::vector<std::string> files_to_send(qfile.file_download.begin(),
qfile.file_download.end());
// ★新增:构造一个临时 qvvr_file仅用于上传不改动原结构
qvvr_file tmp_send;
tmp_send.file_download.assign(files_to_send.begin(), files_to_send.end());
// ★新增:构造一个临时 qvvr_file仅用于上传不改动原结构
qvvr_file tmp_send;
tmp_send.file_download.assign(files_to_send.begin(), files_to_send.end());
// 发送所有文件(已下载完成)
std::string wavepath;
// 发送所有文件(已下载完成)
std::string wavepath;
// ★在解锁前,备份“签名”,用于回锁后定位同一个 qfile
std::set<std::string> sig_names(qfile.file_name.begin(), qfile.file_name.end());
std::set<std::string> sig_downs(qfile.file_download.begin(), qfile.file_download.end());
// ★在解锁前,备份“签名”,用于回锁后定位同一个 qfile
std::set<std::string> sig_names(qfile.file_name.begin(), qfile.file_name.end());
std::set<std::string> sig_downs(qfile.file_download.begin(), qfile.file_download.end());
// ★修改:把上传与上送 JSON 放到“解锁区间”
lock.unlock(); // ★新增:提前解锁
// ★修改:把上传与上送 JSON 放到“解锁区间”
lock.unlock(); // ★新增:提前解锁
if (SendAllQvvrFiles(qfile, wavepath)) {
//文件发送成功后更新事件
transfer_json_qvvr_data(terminal_id,
logical_seq,
matched.QVVR_Amg,
matched.QVVR_PerTime,
matched.QVVR_time,
matched.QVVR_type,
matched.phase,
wavepath);
if (SendAllQvvrFiles(qfile, wavepath)) {
//文件发送成功后更新事件
// ★新增:上传成功后再加锁,准备修改台账
lock.lock();
transfer_json_qvvr_data(terminal_id,
logical_seq,
matched.QVVR_Amg,
matched.QVVR_PerTime,
matched.QVVR_time,
matched.QVVR_type,
matched.phase,
wavepath);
// 删除上传成功的文件
for (const auto& uploaded_file : qfile.file_download) {
if (std::remove(uploaded_file.c_str()) != 0) {
std::cerr << "[Cleanup] Failed to delete file: " << uploaded_file << "\n";
} else {
std::cout << "[Cleanup] Deleted uploaded file: " << uploaded_file << "\n";
// ★新增:上传成功后再加锁,准备修改台账
lock.lock();
// 删除上传成功的文件
for (const auto& uploaded_file : qfile.file_download) {
if (std::remove(uploaded_file.c_str()) != 0) {
std::cerr << "[Cleanup] Failed to delete file: " << uploaded_file << "\n";
} else {
std::cout << "[Cleanup] Deleted uploaded file: " << uploaded_file << "\n";
}
}
}
// ★替换原来的 i<size 判断为:按签名查找当前容器里的那一条
auto it_qf = std::find_if(monitor.qvvrevent.qvvrfile.begin(),
monitor.qvvrevent.qvvrfile.end(),
[&](const qvvr_file& x){
std::set<std::string> n(x.file_name.begin(), x.file_name.end());
std::set<std::string> d(x.file_download.begin(), x.file_download.end());
return n==sig_names && d==sig_downs;
});
if (it_qf != monitor.qvvrevent.qvvrfile.end()) {
monitor.qvvrevent.qvvrfile.erase(it_qf); // ✔ 删到同一条
} else {
std::cerr << "[Cleanup] qvvrfile changed; target group not found, skip erase\n";
}
// ★替换原来的 i<size 判断为:按签名查找当前容器里的那一条
auto it_qf = std::find_if(monitor.qvvrevent.qvvrfile.begin(),
monitor.qvvrevent.qvvrfile.end(),
[&](const qvvr_file& x){
std::set<std::string> n(x.file_name.begin(), x.file_name.end());
std::set<std::string> d(x.file_download.begin(), x.file_download.end());
return n==sig_names && d==sig_downs;
});
if (it_qf != monitor.qvvrevent.qvvrfile.end()) {
monitor.qvvrevent.qvvrfile.erase(it_qf); // ✔ 删到同一条
} else {
std::cerr << "[Cleanup] qvvrfile changed; target group not found, skip erase\n";
}
//清除暂态事件
auto it = std::find_if(
monitor.qvvrevent.qvvrdata.begin(),
monitor.qvvrevent.qvvrdata.end(),
[&](const qvvr_data& d) {
return d.QVVR_time == matched.QVVR_time;
});
if (it != monitor.qvvrevent.qvvrdata.end()) {
monitor.qvvrevent.qvvrdata.erase(it);
}
}
//清除暂态事件
auto it = std::find_if(
monitor.qvvrevent.qvvrdata.begin(),
monitor.qvvrevent.qvvrdata.end(),
[&](const qvvr_data& d) {
return d.QVVR_time == matched.QVVR_time;
});
if (it != monitor.qvvrevent.qvvrdata.end()) {
monitor.qvvrevent.qvvrdata.erase(it);
}
}
else {
lock.lock(); // ★新增:失败时补回锁
std::cerr << "[update_qvvr_file_download] Failed to send qvvr files for logical_seq=" << logical_seq << std::endl;
}
}
else {
lock.lock(); // ★新增:失败时补回锁
std::cerr << "[update_qvvr_file_download] Failed to send qvvr files for logical_seq=" << logical_seq << std::endl;
}
}
else {
std::cout << "[update_qvvr_file_download] No matching qvvr_data found for cfg file: " << fpath << std::endl;
}
break; // 只处理第一个 cfg 文件
std::cout << "[update_qvvr_file_download] No matching qvvr_data found for cfg file: " << fpath << std::endl;
}
break; // 只处理第一个 cfg 文件
}//end if ext==.cfg
}
}
else {
std::cout << "[update_qvvr_file_download] Filename too short to check extension: " << fname << std::endl;
}
}//end for file_download
}
else{
std::cout << "qvvr file still imcomplete!!!" << std::endl;
@@ -3406,12 +3423,12 @@ bool update_qvvr_file_download(const std::string& filename_with_mac_in, const st
lock.unlock();
return true; // 当前文件处理成功
}
}
}//end for qvvrfile
std::cout << "file name doesnt match any file in this monitor!!!" << std::endl;
}
}
}//end for monitor
}//end for dev
lock.unlock();
return false; // 未匹配到终端ID或逻辑序号对应的监测点
}
@@ -4869,6 +4886,20 @@ void check_recall_file() {
std::cout << "[check_recall_stat] FAILED dev=" << dev.terminal_id
<< " monitor=" << lm.monitor_id
<< " " << front.StartTime << " ~ " << front.EndTime << std::endl;
//20251218添加记录
std::string msg_fail;
if (front.direct_mode) {
msg_fail = std::string("监测点:") + lm.monitor_name
+ " 补招波形文件失败,目标时标:"
+ front.target_filetimes;
} else {
msg_fail = std::string("监测点:") + lm.monitor_name
+ " 补招波形文件失败,时间范围:"
+ front.StartTime + " ~ " + front.EndTime;
}
append_recall_record_line(dev.guid, lm.monitor_id, msg_fail);
//20251218添加记录
lm.recall_list_static.pop_front();
@@ -5374,6 +5405,21 @@ void check_recall_file() {
<< std::endl;
} else {
front.recall_status = static_cast<int>(RecallStatus::FAILED);
//20251218添加记录
std::string msg_fail;
if (front.direct_mode) {
msg_fail = std::string("监测点:") + lm.monitor_name
+ " 补招波形文件下载失败,目标时标:"
+ front.target_filetimes;
} else {
msg_fail = std::string("监测点:") + lm.monitor_name
+ " 补招波形文件下载失败,时间范围:"
+ front.StartTime + " ~ " + front.EndTime;
}
append_recall_record_line(dev.guid, lm.monitor_id, msg_fail);
//20251218添加记录
std::cout << "[check_recall_stat] some files failed, FAIL dev=" << dev.terminal_id
<< " monitor=" << lm.monitor_id
<< " ok=" << front.file_success.size()
@@ -5769,7 +5815,7 @@ void on_device_response_minimal(int response_code,
<< " rc=" << response_code << " recall_status=" << front.recall_status << std::endl; //错误响应码
//记录日志
DIY_ERRORLOG_CODE(matched_monitor->monitor_id.c_str(),2,static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%lld 至 %lld",matched_monitor->monitor_id.c_str(),front.StartTime,front.EndTime);
DIY_ERRORLOG_CODE(matched_monitor->monitor_id.c_str(),2,static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%s 至 %s",matched_monitor->monitor_id.c_str(),front.StartTime.c_str(),front.EndTime.c_str());
}
else { //补招失败
front.recall_status = static_cast<int>(RecallStatus::FAILED);
@@ -5779,7 +5825,7 @@ void on_device_response_minimal(int response_code,
<< " rc=" << response_code << " recall_status=" << front.recall_status<< std::endl; //错误响应码
//记录日志
DIY_ERRORLOG_CODE(matched_monitor->monitor_id.c_str(),2,static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%lld 至 %lld",matched_monitor->monitor_id.c_str(),front.StartTime,front.EndTime);
DIY_ERRORLOG_CODE(matched_monitor->monitor_id.c_str(),2,static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%s 至 %s",matched_monitor->monitor_id.c_str(),front.StartTime.c_str(),front.EndTime.c_str());
}
updated = true;
} else { //首条不是 RUNNING 状态,不应该收到这条响应

View File

@@ -271,7 +271,7 @@ void SendFileWeb(const std::string& strUrl, const std::string& localpath, const
if (res != CURLE_OK) {
const char* em = errbuf[0] ? errbuf : curl_easy_strerror(res);
std::cerr << "http web failed: " << em << std::endl;
DIY_ERRORLOG("process","【ERROR】前置上传暂态录波文件 %s 失败,请检查文件上传接口配置",localpath);
DIY_ERRORLOG("process","【ERROR】前置上传暂态录波文件 %s 失败,请检查文件上传接口配置",localpath.c_str());
} else {
std::cout << "http web success, response: " << resPost0 << std::endl;
handleUploadResponse(resPost0, wavepath); // 处理响应
@@ -389,7 +389,7 @@ void download_xml_for_icd(const std::string& MODEL_ID,
std::cout << "remote file name:" << remote_file_name << "local save name:" << save_name << std::endl;
// mq日志
DIY_WARNLOG("process","【WARN】前置获取到终端类型%s,该终端类型对应的映射文件为%s,映射文件将下载并保存在本地为%s",TMNL_TYPE,FILE_PATH,save_name);
DIY_WARNLOG("process","【WARN】前置获取到终端类型%s,该终端类型对应的映射文件为%s,映射文件将下载并保存在本地为%s",TMNL_TYPE.c_str(),FILE_PATH.c_str(),save_name.c_str());
std::string fileContent;
std::string fullPath = std::string("filePath=") + filepath; //填写远端路径作为入参
@@ -409,14 +409,14 @@ void download_xml_for_icd(const std::string& MODEL_ID,
outFile.close();
std::cout << "File saved successfully!" << std::endl;
DIY_WARNLOG("process","【WARN】前置下载映射文件%s成功",save_name);
DIY_WARNLOG("process","【WARN】前置下载映射文件%s成功",save_name.c_str());
} else {
std::cerr << "Error: Unable to open file for writing." << std::endl;
DIY_ERRORLOG("process","【ERROR】前置写入本地映射文件%s失败",save_name);
DIY_ERRORLOG("process","【ERROR】前置写入本地映射文件%s失败",save_name.c_str());
}
} else {
std::cerr << "Error: Unable to download file." << std::endl;
DIY_ERRORLOG("process","【ERROR】前置调用文件下载接口下载远端文件文件%s失败",FILE_PATH);
DIY_ERRORLOG("process","【ERROR】前置调用文件下载接口下载远端文件文件%s失败",FILE_PATH.c_str());
}
}
@@ -1244,10 +1244,18 @@ int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
root["eventType"] = dis_kind;
// 时间处理
time_t start_sec = start_tm / 1000; //毫秒级取秒
/*time_t start_sec = start_tm / 1000; //毫秒级取秒
struct tm* time_info = localtime(&start_sec);
char time_buf[32];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", time_info);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", time_info);*/
time_t start_sec = start_tm / 1000;
struct tm tm_info;
localtime_r(&start_sec, &tm_info);
char time_buf[32];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &tm_info);
std::ostringstream start_time_stream;
start_time_stream << time_buf << "." << std::setfill('0') << std::setw(3) << (start_tm % 1000);//构造成年月日时分秒.毫秒
std::string start_time_str = start_time_stream.str();
@@ -1271,7 +1279,7 @@ int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
// 有效响应,略过
} catch (...) {
// 响应异常,保存 json
DIY_ERRORLOG(mpid.c_str(), "【ERROR】暂态接口响应异常,无法上送装置%s监测点%s的暂态事件",dev_id, monitor_id);
DIY_ERRORLOG(mpid.c_str(), "【ERROR】暂态接口响应异常,无法上送装置%s监测点%u的暂态事件",dev_id.c_str(), (unsigned)monitor_id);
std::cout << "qvvr send fail ,store in local" << std::endl;
std::string qvvrDir = FRONT_PATH + "/dat/qvvr/";
@@ -1281,7 +1289,7 @@ int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
}
} else {
// 无响应,保存 json
DIY_ERRORLOG(mpid.c_str(), "【ERROR】暂态接口无响应,无法上送装置%s监测点%s的暂态事件",dev_id, monitor_id);
DIY_ERRORLOG(mpid.c_str(), "【ERROR】暂态接口无响应,无法上送装置%s监测点%u的暂态事件",dev_id.c_str(), (unsigned)monitor_id);
std::cout << "qvvr send fail ,store in local" << std::endl;
std::string qvvrDir = FRONT_PATH + "/dat/qvvr/";

View File

@@ -484,6 +484,7 @@ extern "C" {
//标准化日志接口
// #define LOGMSG_WITH_TS // 需要时间时再打开
//已在头文件添加编译校验
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...) {
if (!buf || buf_size == 0) return;
buf[0] = '\0';

View File

@@ -34,7 +34,13 @@ extern LOG_TLS_SPEC int g_log_code_tls;
#define LOGTYPE_COM 1
#define LOGTYPE_DATA 2
/////////////////////////////////////////////入参验证
#if defined(__GNUC__) || defined(__clang__)
# define PRINTF_LIKE(fmt_index, first_arg) __attribute__((format(printf, fmt_index, first_arg)))
#else
# define PRINTF_LIKE(fmt_index, first_arg)
#endif
/////////////////////////////////////////
struct TypedLogger {
log4cplus::Logger logger;
int logtype;
@@ -94,7 +100,9 @@ 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);
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...);
//void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...);
//带验证
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...) PRINTF_LIKE(3,4);
// ====================== ★新增:线程局部变量透传 code ======================
// 说明:使用编译器的 TLS__thread保存当前日志的 code 值。

View File

@@ -300,6 +300,7 @@ extern bool normalOutputEnabled;
"G_TEST_NUM=<num> - Set the G_TEST_NUM\r\n"
"G_TEST_TYPE=<num> - Set the G_TEST_TYPE 0:use ledger,1:use number\r\n"
"LOG=<bool> - Set the LOG\r\n"
"MAX=<int> - Set the MAX_ITEMS\r\n"
"dir - Execute rocketmq_test_getdir\r\n"
"rc - Execute rocketmq_test_rc\r\n"
"rt - Execute rocketmq_test_rt\r\n"