Skip to main content

ek_core/
log_plugin.rs

1//! 内置通用日志插件(公用层,宿主级,零业务)。
2//!
3//! 事件:`EVENT_LOG`(载荷 `LogData`);任何 ctx.write_log → 总线 → 本插件 on_mail → sink。
4//! 另有 `EVENT_PLUG_DOWN_PREFIX` 熔断广播 type 前缀(`ePlugQDown.<name>`),由 worker 自发,
5//! 宿主与监控插件均可订阅感知。
6
7use crate::plugin::Plugin;
8use std::borrow::Cow;
9use std::fmt;
10use std::sync::{Arc, Mutex};
11
12use ek_event::Event;
13
14pub const EVENT_LOG: &str = "eLog";
15pub const EVENT_PLUG_DOWN_PREFIX: &str = "ePlugQDown.";
16
17/// 生命周期事件(0.2.0):固定键(巡检全宿主)+ 后缀键(只盯单个插件,载荷=版本串)。
18pub const EVENT_PLUG_UP: &str = "ePlugUp";
19pub const EVENT_PLUG_DOWN: &str = "ePlugDown";
20pub const EVENT_SRV_CHG: &str = "eSrvChg";
21pub const EVENT_PLUG_UP_PREFIX: &str = "ePlugUp.";
22pub const EVENT_PLUG_DOWN_EVENT_PREFIX: &str = "ePlugDown.";
23pub const EVENT_SRV_CHG_PREFIX: &str = "eSrvChg.";
24
25/// 对齐 python 约定的级别常量(0..100)。
26pub const LOG_LEVEL_INFO: u8 = 20;
27pub const LOG_LEVEL_WARN: u8 = 30;
28pub const LOG_LEVEL_ERROR: u8 = 40;
29
30/// 日志事件载荷。
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct LogData {
33    pub level: u8,
34    pub source: String,
35    pub msg: String,
36}
37
38impl fmt::Display for LogData {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "[{}] {}: {}", self.level, self.source, self.msg)
41    }
42}
43
44/// 日志落点(可换 sink,测试捕获得用)。
45pub type LogSink = Arc<dyn Fn(&LogData) + Send + Sync>;
46
47fn default_console_sink() -> LogSink {
48    Arc::new(|d: &LogData| println!("{d}"))
49}
50
51/// 内置日志插件:注册名 "log",只订阅 EVENT_LOG,deps 为空。
52pub struct LogPlugin {
53    sink: Mutex<LogSink>,
54}
55
56impl LogPlugin {
57    pub fn console() -> Self {
58        Self { sink: Mutex::new(default_console_sink()) }
59    }
60    pub fn with_sink(sink: impl Fn(&LogData) + Send + Sync + 'static) -> Self {
61        Self { sink: Mutex::new(Arc::new(sink)) }
62    }
63    pub fn set_sink(&self, sink: LogSink) {
64        *self.sink.lock().unwrap() = sink;
65    }
66}
67
68impl Plugin for LogPlugin {
69    fn name(&self) -> &str {
70        "log"
71    }
72
73    fn routes(&self) -> Vec<Cow<'static, str>> {
74        vec![Cow::Borrowed(EVENT_LOG)]
75    }
76
77    fn on_mail(&self, event: &Event) {
78        if let Some(d) = event.data.downcast_ref::<LogData>() {
79            let sink = self.sink.lock().unwrap().clone();
80            sink(d);
81        }
82    }
83}