tracing_plus/
lib.rs

1//! 该库是对[tracing](https://docs.rs/tracing/latest/tracing/)库的增强
2//!
3//! 在项目的的根目录创建一个文件名为`tracing-log.toml`或`tracing-log.yaml`或`tracing-log.yml`的文件,
4//! 也可通过环境变量`TRACING_LOG_FILE`来指定配置文件
5//! 
6//! 该库会根据配置文件动态的注册日志,然后调用`init_tracing_log`方法即可完成日志的初始化工作
7//!
8//! > 优先级
9//! > TRACING_LOG_FILE > toml > yaml > yml
10//! # 示例
11//!
12//! ```toml
13//! # 文件名 tracing-log.toml
14//!
15//! # 最小日志级别,低于此日志级别则不打印,非必填(可选值:`error`、`warn`、`info`、`debug`、`trace`)
16//! min-level = "info"
17//! # 控制台输出配置
18//! [console]
19//! # 日志级别, 必填(可选值:`error`、`warn`、`info`、`debug`、`trace`)
20//! level = "info"
21//! # 是否打印线程名 默认为 true
22//! thread = true
23//! # 时间格式 默认为 "%Y-%m-%d %H:%M:%S"
24//! format = "%Y-%m-%d %H:%M:%S"
25//! # 是否打印行号  默认为 false
26//! line-number = true
27//!
28//! # 文件输出配置
29//! [[file]]
30//! # 日志级别, 必填(可选值:`error`、`warn`、`info`、`debug`、`trace`)
31//! level = "info"
32//! # 是否打印线程名 默认为 true
33//! thread = true
34//! # 时间格式 默认为 "%Y-%m-%d %H:%M:%S"
35//! format = "%Y-%m-%d %H:%M:%S"
36//! # 是否打印行号 默认为 false
37//! line-number = true
38//! # 保留的最大文件数量 默认为 30
39//! max-files = 60
40//! # 日志文件滚动的固定时间段,可选值: "minutely"、"hourly"、"daily"、"never", 默认值为: "daily"
41//! rotation = "daily"
42//! # 生成的文件名前缀, 必填
43//! prefix = "info"
44//! # 生成的文件名后缀, 默认值为: "log"
45//! suffix = "log"
46//! # 生成的文件所在目录前缀, 默认值为: "logs"
47//! directory = "logs"
48//! # 只记录`target`指定的值的日志 (不配置,则记录全部)
49//! target = "abc"
50//!
51//! [[file]]
52//! level = "error"
53//! thread = false
54//! format = "%Y-%m-%d %H:%M:%S"
55//! line-number = true
56//! max-files = 60
57//! rotation = "daily"
58//! prefix = "error"
59//! directory = "logs"
60//!
61//! [[file]]
62//! level = "error"
63//! thread = false
64//! format = "%Y-%m-%d %H:%M:%S"
65//! line-number = true
66//! max-files = 60
67//! rotation = "daily"
68//! prefix = "error-worker"
69//! directory = "logs"
70//! target = "worker"
71//! ```
72#[cfg(feature = "blocking")]
73mod blocking_layer;
74mod config;
75#[cfg(not(feature = "blocking"))]
76mod non_blocking_layer;
77
78use tracing::level_filters::LevelFilter;
79use tracing_appender::rolling::Rotation;
80#[cfg(feature = "blocking")]
81use crate::blocking_layer::{get_console_layer, get_file_layer};
82use crate::config::TracingLog;
83
84#[cfg(not(feature = "blocking"))]
85use crate::non_blocking_layer::{get_console_layer, get_file_layer};
86use tracing_subscriber::Registry;
87use tracing_subscriber::layer::SubscriberExt;
88use tracing_subscriber::util::SubscriberInitExt;
89
90pub fn init_tracing_log() {
91    let config = TracingLog::config();
92    let option = &config.min_level;
93
94    let console = &config.console;
95    let files = &config.file;
96
97    let console = get_console_layer(console);
98
99    let file_layers = files
100        .iter()
101        .map(|file| get_file_layer(file))
102        .collect::<Vec<_>>();
103
104    let layered = Registry::default().with(console).with(file_layers);
105
106    if let Some(level)  = option {
107        let min_level = level_from_str(level);
108        layered.with(min_level).init();
109    } else {
110        layered.init();
111    }
112
113    #[cfg(feature = "blocking")]
114    tracing::debug!("blocking log enabled");
115
116    #[cfg(not(feature = "blocking"))]
117    tracing::debug!("non blocking log enabled");
118}
119
120
121
122fn level_from_str(level: &str) -> LevelFilter {
123    match level {
124        s if s.eq_ignore_ascii_case("error") => LevelFilter::ERROR,
125        s if s.eq_ignore_ascii_case("warn") => LevelFilter::WARN,
126        s if s.eq_ignore_ascii_case("info") => LevelFilter::INFO,
127        s if s.eq_ignore_ascii_case("debug") => LevelFilter::DEBUG,
128        s if s.eq_ignore_ascii_case("trace") => LevelFilter::TRACE,
129        _ => panic!("未知的`level`属性值, 可选值:`error`、`warn`、`info`、`debug`、`trace`"),
130    }
131}
132
133fn rotation_from_str(rotation: &str) -> Rotation {
134    match rotation {
135        s if s.eq_ignore_ascii_case("minutely") => Rotation::MINUTELY,
136        s if s.eq_ignore_ascii_case("hourly") => Rotation::HOURLY,
137        s if s.eq_ignore_ascii_case("daily") => Rotation::DAILY,
138        s if s.eq_ignore_ascii_case("never") => Rotation::NEVER,
139        _ => panic!("未知的`rotation`属性值, 可选值:`minutely`、`hourly`、`daily`、`never`"),
140    }
141}