Add alarm event trace ids

This commit is contained in:
tian 2026-04-18 20:58:31 +08:00
parent 64af954fe4
commit 90ec18dc9a
9 changed files with 74 additions and 41 deletions

View File

@ -36,6 +36,7 @@ struct FaceAlarmMatch {
};
struct AlarmEvent {
std::string event_id;
std::string rule_name;
std::string node_id;
uint64_t timestamp_ms;

View File

@ -220,18 +220,18 @@ bool ClipAction::Init(const SimpleJson& config) {
return true;
}
void ClipAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
if (!packet_buffer_) {
LogError("[ClipAction] packet buffer not set");
return;
}
void ClipAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> 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<int64_t>(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<int64_t>(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<int64_t>(std::max(0, pre_sec_)) * 1000LL;
const int64_t post_ms = static_cast<int64_t>(std::max(0, post_sec_)) * 1000LL;
@ -253,17 +253,18 @@ void ClipAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> 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<std::shared_ptr<EncodedVideoFrameMeta>>& metas,
const AlarmEvent& event) {
@ -435,8 +436,9 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
std::filesystem::remove(tmp_path, ec);
if (result.success) return result.url;
LogWarn("[ClipAction] upload failed: " + result.error);
return "";
LogWarn("[ClipAction] upload failed event_id=" + (event.event_id.empty() ? "-" : event.event_id) +
" error=" + result.error);
return "";
#else
(void)metas;
(void)event;

View File

@ -117,6 +117,7 @@ const SimpleJson* FindByDottedPath(const SimpleJson& root, const std::string& pa
} // namespace
std::string BuildExternalApiResultLogLine(const std::string& prefix,
const std::string& event_id,
const std::string& alarm_content,
const std::string& pic_url,
const std::string& video_url,
@ -125,6 +126,7 @@ std::string BuildExternalApiResultLogLine(const std::string& prefix,
std::ostringstream oss;
oss << "[ExternalApiAction] " << prefix
<< " http=" << http_code
<< " event_id=" << (event_id.empty() ? "-" : event_id)
<< " alarm_content=" << alarm_content;
if (!pic_url.empty()) {
oss << " pic_url=" << pic_url;
@ -200,6 +202,7 @@ void ExternalApiAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> /*fram
Job job;
job.tenant_code = tenant_code_;
job.channel_no = channel_no_;
job.event_id = event.event_id;
job.timestamp_ms = event.timestamp_ms;
if (!alarm_content_.empty()) {
@ -279,7 +282,7 @@ void ExternalApiAction::WorkerLoop() {
std::string send_err;
if (SendMessageWithToken(job, token, http_code, send_err)) {
LogInfo(BuildExternalApiResultLogLine(
"send ok", job.alarm_content, job.pic_url, job.video_url, http_code, ""));
"send ok", job.event_id, job.alarm_content, job.pic_url, job.video_url, http_code, ""));
break;
}
@ -300,7 +303,7 @@ void ExternalApiAction::WorkerLoop() {
}
LogWarn(BuildExternalApiResultLogLine(
"send failed", job.alarm_content, job.pic_url, job.video_url, http_code, send_err));
"send failed", job.event_id, job.alarm_content, job.pic_url, job.video_url, http_code, send_err));
}
}

View File

@ -13,6 +13,7 @@
namespace rk3588 {
std::string BuildExternalApiResultLogLine(const std::string& prefix,
const std::string& event_id,
const std::string& alarm_content,
const std::string& pic_url,
const std::string& video_url,
@ -33,6 +34,7 @@ private:
struct Job {
std::string tenant_code;
std::string channel_no;
std::string event_id;
std::string alarm_content;
uint64_t timestamp_ms = 0;
std::string pic_url;

View File

@ -51,6 +51,7 @@ void LogAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> /*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;

View File

@ -221,30 +221,32 @@ bool SnapshotAction::Init(const SimpleJson& config) {
return true;
}
void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
if (!frame || !frame->data) {
LogWarn("[SnapshotAction] no frame data");
return;
}
void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> 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();

View File

@ -199,6 +199,15 @@ uint64_t NowEpochMs() {
return static_cast<uint64_t>(duration_cast<milliseconds>(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<char>(ch) : '_');
}
return out.empty() ? "event" : out;
}
class RateLimitedAction final : public IAlarmAction {
public:
RateLimitedAction(std::unique_ptr<IAlarmAction> inner, uint64_t min_interval_ms)
@ -1094,10 +1103,17 @@ private:
event.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
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<SpscQueue<FramePtr>> input_queue_;
uint64_t processed_frames_ = 0;
uint64_t alarm_count_ = 0;
std::atomic<uint64_t> next_event_seq_{0};
int64_t eval_interval_ms_ = 0;
int64_t last_eval_pts_ms_ = 0;

View File

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

View File

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