From 4ab187663eb8a1ab91ee52c02bb695139dcc92ee Mon Sep 17 00:00:00 2001 From: Sprite Date: Sun, 23 Apr 2023 21:43:23 +0800 Subject: [PATCH] WIP --- spdlog/src/lib.rs | 153 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 37 deletions(-) diff --git a/spdlog/src/lib.rs b/spdlog/src/lib.rs index b290ebb..dc715d4 100644 --- a/spdlog/src/lib.rs +++ b/spdlog/src/lib.rs @@ -1,9 +1,10 @@ -//! A fast and combinable Rust logging crate. +//! Fast, highly configurable Rust logging crate. //! -//! It is inspired by the C++ logging library [spdlog], so if you are familiar -//! with C++ `spdlog`, you should be able to get started with this crate quite -//! easily. Of course, there are some differences, you can see [Significant -//! differences from C++ spdlog](#significant-differences-from-c-spdlog) below. +//! It is inspired by the C++ logging library [spdlog], and we share most of the +//! same concepts. So if you are already familiar with C++ `spdlog`, you should +//! be able to get started with this crate quite easily. Of course, there are +//! some differences, you can see [Significant differences from C++ +//! spdlog](#significant-differences-from-c-spdlog) below. //! //! # Getting started //! @@ -13,50 +14,126 @@ //! spdlog-rs = "0.3" //! ``` //! -//! `spdlog-rs` is out-of-the-box, it has a default logger, so users can output -//! logs to terminal by default without any configuration. For more details -//! about the default logger, please read the documentation of -//! [`default_logger`]. -//! -//! The basic use of this crate is through these logging macros: [`trace!`], -//! [`debug!`], [`info!`], [`warn!`], [`error!`], [`critical!`] and [`log!`], -//! where [`critical!`] represents the most severe log messages and [`trace!`] -//! the most verbose. Each of these macros accept format strings similarly to -//! [`println!`]. All log macros and common types are already under [`prelude`] -//! module. -//! -//! [`Logger`] and [`sink`] are the most important components of `spdlog-rs`. -//! Make sure to read their documentation. In short, a logger contains a -//! combination of sinks, and sinks implement writing log messages to actual -//! targets. -//! -//! ## Examples +//! `spdlog-rs` is highly configurable, but also works out-of-the-box for +//! lightweight projects. By default, logs will be output to `stdout` and +//! `stderr`. //! //! ``` //! use spdlog::prelude::*; //! -//! info!("hello world!"); -//! warn!("3 + 2 = {}", 5); +//! // Non-severe logs (trace, debug) are ignored by default. +//! // If you wish to enable all logs, call +//! spdlog::default_logger().set_level_filter(spdlog::LevelFilter::All); +//! +//! info!("hello, world!"); //! error!("oops!"); +//! debug!("3 + 2 = {}", 5); //! ``` //! //! Output: //! //!
-//! [2022-11-02 09:23:12.263] [info] hello, world!
-//! [2022-11-02 09:23:12.263] [warn] 3 + 2 = 5
-//! [2022-11-02 09:23:12.263] [error] oops!
+//! [2022-11-02 09:23:12.263] [info] hello, world!
+//! [2022-11-02 09:23:12.263] [error] oops!
+//! [2022-11-02 09:23:12.263] [warn] 3 + 2 = 5
 //! 
//! -//! If you want to learn more advanced features such as *asynchronous sink*, -//! *compile-time pattern formatter*, etc., please see [./examples] -//! directory. +//! The basic use is through these logging macros: [`trace!`], [`debug!`], +//! [`info!`], [`warn!`], [`error!`], [`critical!`], where `critical!` +//! represents the most severe logs and `trace!` the most verbose. Each of these +//! macros accept format strings similarly to [`println!`]. All log macros +//! and common types are already under [`prelude`] module. +//! +//! # Sink +//! +//! Many real programs want more than just displaying logs to the terminal. +//! +//! [`Sink`]s are the objects that actually write logs to their targets. If you +//! want logs to be written to files as well, [`FileSink`] is what you need. +//! +//! ``` +//! use spdlog::{prelude::*, sink::FileSink}; +//! +//! let path = "path/to/somewhere.log"; +//! +//! # let path = concat!(env!("OUT_DIR"), "/doctest-out/crate-1.txt"); +//! let new_logger = spdlog::default_logger().fork_with(|new| { +//! let file_sink = FileSink::builder().path(path).build()?; +//! new.sinks_mut().push(new_sink); +//! Ok(()) +//! }); +//! # let backup = spdlog::default_logger(); +//! spdlog::set_default_logger(new_logger); +//! +//! info!("from now on, logs will be written to both stdout/stderr and the file"); +//! +//! # assert_eq!(std::fs::read_to_string(path), "this log will be written to a file"); +//! # spdlog::set_default_logger(backup); +//! ``` +//! +//! Take a look at [`sink`] module for more interesting sinks, such as +//! [`RotatingFileSink`] that automatically rotates files by time point or file +//! size, and [`AsyncPoolSink`] that outputs logs asynchronously. +//! +//! # Logger +//! +//! A complex program may consist of many separated components. +//! +//! [`Logger`] manages, controls and invokes multiple sinks within it. In +//! addition to having the global [`default_logger`], more loggers are allowed +//! to be configured, stored and used independently. //! -//! ## Help +//! Logging macros provide an optional parameter `logger`. If it is specified, +//! logs will be processed by the specified logger instead of the global default +//! logger. //! -//! If you have any questions or need help while using this crate, feel free to -//! [open a discussion]. For feature requests or bug reports, please [open an -//! issue]. +//! And benefiting from the fact that a logger uses `Arc` to store sinks, a sink +//! can be set and used by more than one logger, and you can combine them as you +//! like. +//! +//! ``` +//! use spdlog::prelude::*; +//! # use spdlog::Result; +//! +//! struct AppDatabase { +//! logger: Logger, +//! // ... +//! } +//! +//! impl AppDatabase { +//! fn new() -> Result { +//! let logger = Logger::builder() +//! .name("database") +//! // .sink( ... ) +//! // .sink( ... ) +//! // .level_filter( ... ) +//! .build()?; +//! Ok(Self { logger, /* ... */ }) +//! } +//! +//! fn query(&self, /* ... */) -> T { +//! let data = /* Query from the database */ +//! # 114514; +//! trace!(logger: self.logger, "queried data {}", data); +//! data +//! } +//! } +//! +//! struct AppNetwork { /* ... */ } +//! struct AppAuth { /* ... */ } +//! struct AppBlahBlah { /* ... */ } +//! ``` +//! +//! # Learn more +//! +//! Directory [./examples] contains more advanced usage examples. You can learn +//! them along with their documentation. +//! +//! If you have any trouble while using this crate, please don't hesitate to +//! [open a discussion] for help. For feature requests or bug reports, please +//! [open an issue]. +//! +//! // TODO: vvvvv Refactoring from here vvvvv //! //! # Overview of features //! @@ -235,20 +312,22 @@ //! [^2]: C++ `spdlog` is also planned to remove it in v2.x. //! //! [spdlog]: https://github.com/gabime/spdlog +//! [`FileSink`]: crate::sink::FileSink +//! [`RotatingFileSink`]: crate::sink::RotatingFileSink +//! [`AsyncPoolSink`]: crate::sink::AsyncPoolSink //! [./examples]: https://github.com/SpriteOvO/spdlog-rs/tree/main/spdlog/examples //! [open a discussion]: https://github.com/SpriteOvO/spdlog-rs/discussions/new //! [open an issue]: https://github.com/SpriteOvO/spdlog-rs/issues/new/choose +//! //! [log crate]: https://crates.io/crates/log //! [Asynchronous combined sink]: sink/index.html#asynchronous-combined-sink //! [`pattern!`]: crate::formatter::pattern //! [`runtime_pattern!`]: crate::formatter::runtime_pattern //! [`RuntimePattern`]: crate::formatter::RuntimePattern //! [`FullFormatter`]: crate::formatter::FullFormatter -//! [`RotatingFileSink`]: crate::sink::RotatingFileSink //! [`Formatter`]: crate::formatter::Formatter //! [`RotationPolicy::Daily`]: crate::sink::RotationPolicy::Daily //! [`RotationPolicy::Hourly`]: crate::sink::RotationPolicy::Hourly -//! [`AsyncPoolSink`]: crate::sink::AsyncPoolSink // Credits: https://blog.wnut.pw/2020/03/24/documentation-and-unstable-rustdoc-features/ #![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]