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/// 对齐 python 约定的级别常量(0..100)。
18pub const LOG_LEVEL_INFO: u8 = 20;
19pub const LOG_LEVEL_WARN: u8 = 30;
20pub const LOG_LEVEL_ERROR: u8 = 40;
21
22/// 日志事件载荷。
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct LogData {
25    pub level: u8,
26    pub source: String,
27    pub msg: String,
28}
29
30impl fmt::Display for LogData {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        write!(f, "[{}] {}: {}", self.level, self.source, self.msg)
33    }
34}
35
36/// 日志落点(可换 sink,测试捕获得用)。
37pub type LogSink = Arc<dyn Fn(&LogData) + Send + Sync>;
38
39fn default_console_sink() -> LogSink {
40    Arc::new(|d: &LogData| println!("{d}"))
41}
42
43/// 内置日志插件:注册名 "log",只订阅 EVENT_LOG,deps 为空。
44pub struct LogPlugin {
45    sink: Mutex<LogSink>,
46}
47
48impl LogPlugin {
49    pub fn console() -> Self {
50        Self { sink: Mutex::new(default_console_sink()) }
51    }
52    pub fn with_sink(sink: impl Fn(&LogData) + Send + Sync + 'static) -> Self {
53        Self { sink: Mutex::new(Arc::new(sink)) }
54    }
55    pub fn set_sink(&self, sink: LogSink) {
56        *self.sink.lock().unwrap() = sink;
57    }
58}
59
60impl Plugin for LogPlugin {
61    fn name(&self) -> &str {
62        "log"
63    }
64
65    fn routes(&self) -> Vec<Cow<'static, str>> {
66        vec![Cow::Borrowed(EVENT_LOG)]
67    }
68
69    fn on_mail(&self, event: &Event) {
70        if let Some(d) = event.data.downcast_ref::<LogData>() {
71            let sink = self.sink.lock().unwrap().clone();
72            sink(d);
73        }
74    }
75}