captains_log/
lib.rs

1//! # captains-log
2//!
3//! A light-weight logger for rust, implementation base on the crate `log`.
4//!
5//! ## Features
6//!
7//! * Allow customize log format and time format. Refer to [LogFormat].
8//!
9//! * Supports multiple types of sink stacking, each with its own log level.
10//!
11//!     + [Builder]::console([LogConsole]):   Console output to stdout/stderr.
12//!
13//!     + [Builder]::raw_file([LogRawFile]):  Support atomic appending from multi-process on linux
14//!
15//! * Log panic message by default.
16//!
17//! * Supports signal listening for log-rotate. Refer to [Builder]::signal()
18//!
19//! * Fine-grain module-level control.
20//!
21//!   Provides [LogFilter] to filter specified logs on-the-fly.
22//!
23//! * API-level log handling.
24//!
25//!   Provides [LogFilterKV] for API logging with additional key.
26//!
27//!   For example, you can set `req_id` in `LogFilterKV`, and track the
28//! complete request handling procedure from log.
29//!
30//! * For test suits usage:
31//!
32//!   Allow dynamic reconfigure logger setting in different test function.
33//!
34//!   (NOTE: currently signal_listener does not support reconfigure).
35//!
36//!   Provides an attribute macro [#\[logfn\]] to wrap test function.
37//!  Logging test-start and test-end.
38//!
39//! * Provides a [parser] to work on your log files.
40//!
41//! ## Usage
42//!
43//! Cargo.toml
44//!
45//! ``` toml
46//! [dependencies]
47//! log = { version = "0.4", features = ["std", "kv_unstable"] }
48//! captains_log = "0.4"
49//! ```
50//!
51//! lib.rs or main.rs:
52//! ```
53//! #[macro_use]
54//! extern crate captains_log;
55//! #[macro_use]
56//! extern crate log;
57//! ```
58//!
59//! ## Production example:
60//!
61//! <font color=Blue>Refer to recipe in `recipe` module, including console & file output. </font>
62//!
63//! ```rust
64
65//! use log::{debug, info, error};
66//! use captains_log::recipe::split_error_file_logger;
67//!
68//! // You'll get /tmp/test.log with all logs, and /tmp/test.log.wf only with error logs.
69//! let mut log_builder = split_error_file_logger("/tmp", "test", log::Level::Debug);
70//! // Builder::build() is equivalent of setup_log().
71//! log_builder.build();
72//!
73//! // non-error msg will only appear in /tmp/test.log
74//! debug!("Set a course to Sol system");
75//! info!("Engage");
76//!
77//! // will appear in both /tmp/test.log and /tmp/test.log.wf
78//! error!("Engine over heat!");
79//!
80//! ```
81//!
82//! ## Unit test example
83//!
84//! To setup different log config on different tests.
85//!
86//! call <font color=Blue> test() </font> on [Builder],
87//! which enable dynamic log config and disable signal_hook.
88//!
89//! ```rust
90//! use log::{debug, info, error, Level};
91//! use captains_log::recipe;
92//!
93//! #[test]
94//! fn test1() {
95//!     recipe::raw_file_logger(
96//!         "/tmp", "test1", Level::Debug).test().build();
97//!     info!("doing test1");
98//! }
99//!
100//! #[test]
101//! fn test2() {
102//!     recipe::raw_file_logger(
103//!         "/tmp", "test2", Level::Debug).test().build();
104//!     info!("doing test2");
105//! }
106//! ```
107//!
108//! ## Customize format example
109//!
110//! ``` rust
111//! extern crate signal_hook;
112//! extern crate chrono;
113//! use captains_log::*;
114
115//! fn format_f(r: FormatRecord) -> String {
116//!     let time = r.time();
117//!     let level = r.level();
118//!     let file = r.file();
119//!     let line = r.line();
120//!     let msg = r.msg();
121//!     format!("{time}|{level}|{file}:{line}|{msg}\n").to_string()
122//! }
123//! let debug_format = LogFormat::new(
124//!     "%Y%m%d %H:%M:%S%.6f",
125//!     format_f,
126//! );
127//! let debug_file = LogRawFile::new(
128//!     "/tmp", "test.log", log::Level::Trace, debug_format);
129//! let config = Builder::default()
130//!     .signal(signal_hook::consts::SIGINT)
131//!     .raw_file(debug_file);
132//!
133//! config.build();
134//! ```
135//!
136//! ## Fine-grain module-level control
137//!
138//! Place `LogFilter` in Arc and share among coroutines.
139//! Log level can be changed on-the-fly.
140//!
141//! ``` rust
142//! use std::sync::Arc;
143//! use captains_log::*;
144//! log::set_max_level(log::LevelFilter::Debug);
145//! let logger_io = Arc::new(LogFilter::new());
146//! let logger_req = Arc::new(LogFilter::new());
147//! logger_io.set_level(log::Level::Error);
148//! logger_req.set_level(log::Level::Debug);
149//! logger_debug!(logger_req, "Begin handle req ...");
150//! logger_debug!(logger_io, "Issue io to disk ...");
151//! logger_error!(logger_req, "Req invalid ...");
152//!
153//! ```
154//!
155//! ## API-level log handling
156//!
157//! Request log can be track by custom key `req_id`, which kept in `LogFilterKV`.
158//!
159//! ``` rust
160//! use captains_log::*;
161//! use log::*;
162//! fn debug_format_req_id_f(r: FormatRecord) -> String {
163//!     let time = r.time();
164//!     let level = r.level();
165//!     let file = r.file();
166//!     let line = r.line();
167//!     let msg = r.msg();
168//!     let req_id = r.key("req_id");
169//!     format!("[{time}][{level}][{file}:{line}] {msg}{req_id}\n").to_string()
170//! }
171//! let builder = recipe::raw_file_logger_custom("/tmp", "log_filter.log", log::Level::Debug,
172//!     recipe::DEFAULT_TIME, debug_format_req_id_f);
173//! builder.build().expect("setup_log");
174//! let logger = LogFilterKV::new("req_id", format!("{:016x}", 123).to_string());
175//! info!("API service started");
176//! logger_debug!(logger, "Req / received");
177//! logger_debug!(logger, "header xxx");
178//! logger_info!(logger, "Req / 200 complete");
179//! ```
180//!
181//! The log will be:
182//!
183//! ``` text
184//! [2025-06-11 14:33:08.089090][DEBUG][request.rs:67] API service started
185//! [2025-06-11 14:33:10.099092][DEBUG][request.rs:67] Req / received (000000000000007b)
186//! [2025-06-11 14:33:10.099232][WARN][request.rs:68] header xxx (000000000000007b)
187//! [2025-06-11 14:33:11.009092][DEBUG][request.rs:67] Req / 200 complete (000000000000007b)
188//! ```
189
190extern crate captains_log_helper;
191extern crate log;
192extern crate signal_hook;
193
194#[macro_use]
195extern crate enum_dispatch;
196
197mod config;
198mod console_impl;
199mod file_impl;
200mod formatter;
201mod log_impl;
202mod time;
203
204pub mod macros;
205pub mod parser;
206pub mod recipe;
207
208mod log_filter;
209
210pub use self::{config::*, formatter::FormatRecord, log_filter::*, log_impl::setup_log};
211pub use captains_log_helper::logfn;
212
213#[cfg(test)]
214mod tests;