Skip to main content

yggdrasil/models/
log.rs

1//! 运行日志查看器的共享 DTO(server / wasm 双目标)。
2//!
3//! `LogEntry` 同时用于历史查询(`get_logs` 分页)与 SSE 实时事件
4//! (`/api/logs/stream` 的 `log` 事件负载;实时事件尚未落库,`id` 恒为 0)。
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9/// 默认日志保留天数(天)。
10pub const DEFAULT_LOGS_RETENTION_DAYS: i32 = 7;
11/// 默认日志最大行数:超出后按 id 从新到旧裁剪。
12pub const DEFAULT_LOGS_MAX_ROWS: i32 = 100_000;
13/// 保留天数下限(天)。
14#[cfg(feature = "server")]
15pub const MIN_LOGS_RETENTION_DAYS: i32 = 1;
16/// 保留天数上限(天)。防止误填超大值导致永不清理。
17#[cfg(feature = "server")]
18pub const MAX_LOGS_RETENTION_DAYS: i32 = 90;
19/// 最大行数下限。防止误填过小值把日志表裁空。
20#[cfg(feature = "server")]
21pub const MIN_LOGS_MAX_ROWS: i32 = 1_000;
22/// 最大行数上限。防止误填超大值导致表无限增长。
23#[cfg(feature = "server")]
24pub const MAX_LOGS_MAX_ROWS: i32 = 1_000_000;
25
26/// 单条日志记录。
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct LogEntry {
29    /// 数据库主键(按 id 游标分页)。SSE 实时事件尚未落库,恒为 0。
30    pub id: i64,
31    /// 事件捕获时刻(UTC)。
32    #[cfg_attr(
33        target_arch = "wasm32",
34        serde(deserialize_with = "crate::models::rfc3339::deserialize")
35    )]
36    pub ts: DateTime<Utc>,
37    /// 级别大写:ERROR / WARN / INFO / DEBUG / TRACE。
38    pub level: String,
39    /// tracing target(模块路径)。
40    pub target: String,
41    /// 消息文本(含追加的结构化字段,截断至 4KB)。
42    pub message: String,
43}
44
45/// `get_logs` 的一页结果(按 id DESC 游标分页)。
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub struct LogsPage {
48    /// 本页条目(id 降序,最新在前)。
49    pub entries: Vec<LogEntry>,
50    /// 下一页游标(本页最后一条的 id);None 表示没有更多。
51    pub next_cursor: Option<i64>,
52    /// 进程启动以来因管道满 / 写库失败被丢弃的日志条数。
53    pub dropped: u64,
54}
55
56/// 日志查看器配置(settings 表 `logs_retention_days` / `logs_max_rows` 键)。
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct LogSettings {
59    /// 日志保留天数,超过后被后台任务删除。
60    pub retention_days: i32,
61    /// 日志表最大行数,超出后从新到旧裁剪。
62    pub max_rows: i32,
63}
64
65impl Default for LogSettings {
66    fn default() -> Self {
67        Self {
68            retention_days: DEFAULT_LOGS_RETENTION_DAYS,
69            max_rows: DEFAULT_LOGS_MAX_ROWS,
70        }
71    }
72}
73
74impl LogSettings {
75    /// 将保留天数钳制到合法范围 [MIN, MAX]。
76    #[cfg(feature = "server")]
77    pub fn clamp_retention(days: i32) -> i32 {
78        days.clamp(MIN_LOGS_RETENTION_DAYS, MAX_LOGS_RETENTION_DAYS)
79    }
80
81    /// 将最大行数钳制到合法范围 [MIN, MAX]。
82    #[cfg(feature = "server")]
83    pub fn clamp_max_rows(rows: i32) -> i32 {
84        rows.clamp(MIN_LOGS_MAX_ROWS, MAX_LOGS_MAX_ROWS)
85    }
86}