From 90ec18dc9ab7b223b19396c951fc2d87f24f5ab2 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 18 Apr 2026 20:58:31 +0800 Subject: [PATCH] Add alarm event trace ids --- plugins/alarm/actions/action_base.h | 1 + plugins/alarm/actions/clip_action.cpp | 44 ++++++++++--------- plugins/alarm/actions/external_api_action.cpp | 7 ++- plugins/alarm/actions/external_api_action.h | 2 + plugins/alarm/actions/log_action.cpp | 1 + plugins/alarm/actions/snapshot_action.cpp | 34 +++++++------- plugins/alarm/alarm_node.cpp | 17 +++++++ tests/test_external_api_action.cpp | 7 ++- tests/test_log_action.cpp | 2 + 9 files changed, 74 insertions(+), 41 deletions(-) diff --git a/plugins/alarm/actions/action_base.h b/plugins/alarm/actions/action_base.h index 32786e5..43a0c06 100644 --- a/plugins/alarm/actions/action_base.h +++ b/plugins/alarm/actions/action_base.h @@ -36,6 +36,7 @@ struct FaceAlarmMatch { }; struct AlarmEvent { + std::string event_id; std::string rule_name; std::string node_id; uint64_t timestamp_ms; diff --git a/plugins/alarm/actions/clip_action.cpp b/plugins/alarm/actions/clip_action.cpp index b5da531..48d2af4 100644 --- a/plugins/alarm/actions/clip_action.cpp +++ b/plugins/alarm/actions/clip_action.cpp @@ -220,18 +220,18 @@ bool ClipAction::Init(const SimpleJson& config) { return true; } -void ClipAction::Execute(AlarmEvent& event, std::shared_ptr frame) { - if (!packet_buffer_) { - LogError("[ClipAction] packet buffer not set"); - return; - } +void ClipAction::Execute(AlarmEvent& event, std::shared_ptr frame) { + if (!packet_buffer_) { + LogError("[ClipAction] packet buffer not set event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + return; + } if (!frame) return; - const int64_t trigger_pts_ms = frame->pts > 0 ? static_cast(frame->pts / 1000ULL) : 0; - if (trigger_pts_ms <= 0) { - LogWarn("[ClipAction] invalid trigger pts"); - return; - } + const int64_t trigger_pts_ms = frame->pts > 0 ? static_cast(frame->pts / 1000ULL) : 0; + if (trigger_pts_ms <= 0) { + LogWarn("[ClipAction] invalid trigger pts event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + return; + } const int64_t pre_ms = static_cast(std::max(0, pre_sec_)) * 1000LL; const int64_t post_ms = static_cast(std::max(0, post_sec_)) * 1000LL; @@ -253,17 +253,18 @@ void ClipAction::Execute(AlarmEvent& event, std::shared_ptr frame) { // Fallback: at least try the latest packet. metas = packet_buffer_->GetPacketsInRange(trigger_pts_ms, end_pts); } - if (metas.empty()) { - LogWarn("[ClipAction] no packets in range"); - return; - } + if (metas.empty()) { + LogWarn("[ClipAction] no packets in range event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + return; + } std::string url = ProcessClipFromPackets(metas, event); - if (!url.empty()) { - event.clip_url = url; - LogInfo("[ClipAction] clip uploaded: " + url); - } -} + if (!url.empty()) { + event.clip_url = url; + LogInfo("[ClipAction] clip uploaded: " + url + + " event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + } +} std::string ClipAction::ProcessClipFromPackets(const std::vector>& metas, const AlarmEvent& event) { @@ -435,8 +436,9 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector /*frame*/) { std::ostringstream oss; oss << "[ALARM][" << level_ << "] " << std::put_time(&tm_now, "%Y-%m-%d %H:%M:%S") + << " event_id=" << (event.event_id.empty() ? "-" : event.event_id) << " node=" << event.node_id << " rule=" << event.rule_name << " frame=" << event.frame_id; diff --git a/plugins/alarm/actions/snapshot_action.cpp b/plugins/alarm/actions/snapshot_action.cpp index e9b17b8..961e7b8 100644 --- a/plugins/alarm/actions/snapshot_action.cpp +++ b/plugins/alarm/actions/snapshot_action.cpp @@ -221,30 +221,32 @@ bool SnapshotAction::Init(const SimpleJson& config) { return true; } -void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr frame) { - if (!frame || !frame->data) { - LogWarn("[SnapshotAction] no frame data"); - return; - } +void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr frame) { + if (!frame || !frame->data) { + LogWarn("[SnapshotAction] no frame data event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + return; + } if (frame->DmaFd() >= 0) frame->SyncStart(); auto jpeg_data = EncodeJpeg(frame); if (frame->DmaFd() >= 0) frame->SyncEnd(); - if (jpeg_data.empty()) { - LogWarn("[SnapshotAction] failed to encode JPEG"); - return; - } + if (jpeg_data.empty()) { + LogWarn("[SnapshotAction] failed to encode JPEG event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + return; + } std::string key = GenerateKey(event); auto result = uploader_->Upload(key, jpeg_data.data(), jpeg_data.size(), "image/jpeg"); - if (result.success) { - event.snapshot_url = result.url; - LogInfo("[SnapshotAction] uploaded: " + result.url); - } else { - LogWarn("[SnapshotAction] upload failed: " + result.error); - } -} + if (result.success) { + event.snapshot_url = result.url; + LogInfo("[SnapshotAction] uploaded: " + result.url + + " event_id=" + (event.event_id.empty() ? "-" : event.event_id)); + } else { + LogWarn("[SnapshotAction] upload failed event_id=" + (event.event_id.empty() ? "-" : event.event_id) + + " error=" + result.error); + } +} std::string SnapshotAction::GenerateKey(const AlarmEvent& event) { auto now = std::chrono::system_clock::now(); diff --git a/plugins/alarm/alarm_node.cpp b/plugins/alarm/alarm_node.cpp index 32b5d25..aa55853 100644 --- a/plugins/alarm/alarm_node.cpp +++ b/plugins/alarm/alarm_node.cpp @@ -199,6 +199,15 @@ uint64_t NowEpochMs() { return static_cast(duration_cast(system_clock::now().time_since_epoch()).count()); } +std::string SanitizeEventIdPart(const std::string& value) { + std::string out; + out.reserve(value.size()); + for (unsigned char ch : value) { + out.push_back(std::isalnum(ch) ? static_cast(ch) : '_'); + } + return out.empty() ? "event" : out; +} + class RateLimitedAction final : public IAlarmAction { public: RateLimitedAction(std::unique_ptr inner, uint64_t min_interval_ms) @@ -1094,10 +1103,17 @@ private: event.timestamp_ms = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); event.frame_id = frame->frame_id; + const uint64_t seq = next_event_seq_.fetch_add(1, std::memory_order_relaxed) + 1; + event.event_id = id_ + "_" + SanitizeEventIdPart(result.rule_name) + "_" + + std::to_string(event.frame_id) + "_" + std::to_string(seq); event.detections = result.matched_detections; event.face_matches = std::move(face_matches); event.behavior_events = result.matched_behavior_events; + LogInfo("[alarm] trigger event_id=" + event.event_id + + " rule=" + event.rule_name + + " frame=" + std::to_string(event.frame_id)); + AlarmJob job; job.event = std::move(event); job.frame = std::move(frame); @@ -1134,6 +1150,7 @@ private: std::shared_ptr> input_queue_; uint64_t processed_frames_ = 0; uint64_t alarm_count_ = 0; + std::atomic next_event_seq_{0}; int64_t eval_interval_ms_ = 0; int64_t last_eval_pts_ms_ = 0; diff --git a/tests/test_external_api_action.cpp b/tests/test_external_api_action.cpp index 9ac087c..8c0fcd1 100644 --- a/tests/test_external_api_action.cpp +++ b/tests/test_external_api_action.cpp @@ -9,9 +9,11 @@ namespace { TEST(ExternalApiActionTest, BuildsSuccessLogLineWithContext) { const std::string line = BuildExternalApiResultLogLine( - "send ok", "known_person:reg_001", "http://example/pic.jpg", "http://example/clip.mp4", 200, ""); + "send ok", "cam1_alarm_42_7", "known_person:reg_001", "http://example/pic.jpg", + "http://example/clip.mp4", 200, ""); EXPECT_NE(line.find("send ok"), std::string::npos); + EXPECT_NE(line.find("event_id=cam1_alarm_42_7"), std::string::npos); EXPECT_NE(line.find("http=200"), std::string::npos); EXPECT_NE(line.find("alarm_content=known_person:reg_001"), std::string::npos); EXPECT_NE(line.find("pic_url=http://example/pic.jpg"), std::string::npos); @@ -20,9 +22,10 @@ TEST(ExternalApiActionTest, BuildsSuccessLogLineWithContext) { TEST(ExternalApiActionTest, BuildsFailureLogLineWithError) { const std::string line = BuildExternalApiResultLogLine( - "send failed", "unknown_face", "", "", 500, "timeout"); + "send failed", "cam1_alarm_51_8", "unknown_face", "", "", 500, "timeout"); EXPECT_NE(line.find("send failed"), std::string::npos); + EXPECT_NE(line.find("event_id=cam1_alarm_51_8"), std::string::npos); EXPECT_NE(line.find("http=500"), std::string::npos); EXPECT_NE(line.find("error=timeout"), std::string::npos); EXPECT_NE(line.find("alarm_content=unknown_face"), std::string::npos); diff --git a/tests/test_log_action.cpp b/tests/test_log_action.cpp index 2325761..bf56cdd 100644 --- a/tests/test_log_action.cpp +++ b/tests/test_log_action.cpp @@ -21,6 +21,7 @@ TEST(LogActionTest, IncludesFaceRecognitionDetailsInAlarmLog) { ASSERT_TRUE(action.Init(cfg)); AlarmEvent event; + event.event_id = "cam1_alarm_42_1"; event.node_id = "alarm_face_cam1"; event.rule_name = "unknown_face"; event.frame_id = 42; @@ -44,6 +45,7 @@ TEST(LogActionTest, IncludesFaceRecognitionDetailsInAlarmLog) { const auto lines = Logger::Instance().RecentLines(10); ASSERT_FALSE(lines.empty()); const std::string& line = lines.back(); + EXPECT_NE(line.find("event_id=cam1_alarm_42_1"), std::string::npos); EXPECT_NE(line.find("rule=unknown_face"), std::string::npos); EXPECT_NE(line.find("candidate=alice"), std::string::npos); EXPECT_NE(line.find("status=unknown"), std::string::npos);