Add alarm event trace ids
This commit is contained in:
parent
64af954fe4
commit
90ec18dc9a
@ -36,6 +36,7 @@ struct FaceAlarmMatch {
|
||||
};
|
||||
|
||||
struct AlarmEvent {
|
||||
std::string event_id;
|
||||
std::string rule_name;
|
||||
std::string node_id;
|
||||
uint64_t timestamp_ms;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user