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);