1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
mod macros;
mod mongo_backend;
mod stdout_backend;

use chrono::{DateTime, Utc};
use potatonet::*;
use rmpv::Value;
use std::collections::HashMap;

#[doc(hidden)]
pub use chrono;

pub use mongo_backend::{MongoBackend, MongoBackendConfig};
pub use stdout_backend::StdoutBackend;

#[message]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Level {
    Trace,
    Debug,
    Info,
    Warn,
    Error,
}

impl Level {
    pub fn as_str(&self) -> &'static str {
        match self {
            Level::Trace => "TRACE",
            Level::Debug => "DEBUG",
            Level::Info => "INFO",
            Level::Warn => "WARN",
            Level::Error => "ERROR",
        }
    }
}

pub type KvsHashMap = HashMap<String, Value>;

#[message]
pub struct Item {
    pub time: DateTime<Utc>,
    pub service: String,
    pub level: Level,
    pub message: String,
    pub kvs: Option<KvsHashMap>,
}

/// 日志后台
pub trait Backend: Sync + Send + 'static {
    /// 添加日志
    fn append(&self, item: Item) -> Result<()>;

    /// 查询最新日志
    fn query_latest(&self, limit: usize) -> Result<Vec<Item>>;
}

/// 日志服务
pub struct Logger {
    backend: Box<dyn Backend>,
}

impl Logger {
    /// 新建日志服务
    pub fn new<B: Backend>(backend: B) -> Self {
        Self {
            backend: Box::new(backend),
        }
    }
}

#[service]
impl Logger {
    #[notify]
    async fn log(&self, item: Item) {
        self.backend.append(item).ok();
    }

    #[call]
    async fn query_latest(&self, limit: usize) -> Result<Vec<Item>> {
        self.backend.query_latest(limit)
    }
}