actix_cloud_extra/logger.rs
1//! Default logger setup for Actix Cloud applications.
2//!
3//! The output is normalized for readability:
4//! - Target: only keeps the first path before `::` (e.g. `project::module1::module2` => `project`).
5//! - Filename: only keeps the path starting from the last `src` (e.g. `/a/b/src/c/d/main.rs` => `src/c/d/main.rs`).
6
7use std::path::PathBuf;
8
9use actix_cloud::{
10 logger::{LogItem, Logger, LoggerBuilder, LoggerGuard},
11 tracing::Level,
12};
13
14/// Transform a log item before printing, see [module docs](self) for the rules.
15fn transformer(mut item: LogItem) -> LogItem {
16 // Trim target path.
17 // Only keep the first path before `::`. Change several library targets to our own.
18 item.target = item
19 .target
20 .split("::")
21 .next()
22 .unwrap_or("unknown")
23 .to_owned();
24
25 // Remove useless file path.
26 // Only keep path starting from the last `src`.
27 if let Some(filename) = &item.filename {
28 let mut buf = Vec::new();
29 let s = PathBuf::from(filename);
30 for i in s.iter().rev() {
31 buf.push(i);
32 if i.eq_ignore_ascii_case("src") {
33 break;
34 }
35 }
36 let mut s = PathBuf::new();
37 for i in buf.into_iter().rev() {
38 s.push(i);
39 }
40 item.filename = Some(s.to_string_lossy().into());
41 }
42 item
43}
44
45/// Start the default logger.
46///
47/// - `enable`: when `false`, nothing is started and `(None, None)` is returned.
48/// - `json`: output JSON lines instead of plain text.
49/// - `verbose`: include file name and line number, and log at `DEBUG` level.
50/// - `filter`: extra predicate, items returning `false` are dropped.
51///
52/// Returns the logger and a guard which stops logging when dropped; both are
53/// `Some` on success and `None` when the logger is disabled.
54pub fn start_logger(
55 enable: bool,
56 json: bool,
57 verbose: bool,
58 filter: fn(item: &LogItem) -> bool,
59) -> (Option<Logger>, Option<LoggerGuard>) {
60 if enable {
61 let mut builder = LoggerBuilder::new();
62 if json {
63 builder = builder.json();
64 }
65 if verbose {
66 builder = builder.filename().line_number().level(Level::DEBUG);
67 }
68 builder = builder.transformer(transformer).filter(filter);
69 let (logger, guard) = builder.start();
70 (Some(logger), Some(guard))
71 } else {
72 (None, None)
73 }
74}