Skip to content

Commit

Permalink
Merge b73a10c into 9e46c41
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Jun 17, 2019
2 parents 9e46c41 + b73a10c commit 05efed3
Show file tree
Hide file tree
Showing 13 changed files with 597 additions and 211 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,11 @@
## v0.6.0
- Add time offset parameter (defaults to UTC)
- Add thread_id output (credits to @kurtlawrence)
- Pad log level
- Add TestLogger (credits to @AlexW-GH)
- Add stream configuration to TermLogger
- Implement allow- and ignore-filtering (credits to @ryankurte)

## v0.5.3
- Fix minimal chrono version / update to chrono v0.4.1 (PR #27, credits to @samueltardieu)

Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
@@ -1,6 +1,7 @@
[package]
name = "simplelog"
version = "0.5.3"
version = "0.6.0"
edition = "2018"
authors = ["Drakulix <github@drakulix.de>"]
description = "A simple and easy-to-use logging facility for Rust's log crate"
documentation = "https://docs.rs/simplelog/"
Expand All @@ -18,6 +19,7 @@ include = [
]

[features]
test = []
default = ["term"]

[dependencies]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -27,7 +27,7 @@ use std::fs::File;
fn main() {
CombinedLogger::init(
vec![
TermLogger::new(LevelFilter::Warn, Config::default()).unwrap(),
TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap(),
WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_binary.log").unwrap()),
]
).unwrap();
Expand All @@ -42,7 +42,7 @@ fn main() {
### Results in
```
$ cargo run --example usage
Compiling simplelog v0.5.0 (file:///home/drakulix/Projects/simplelog)
Compiling simplelog v0.6.0 (file:///home/drakulix/Projects/simplelog)
Running `target/debug/examples/usage`
[ERROR] Bright red error
```
Expand All @@ -57,7 +57,7 @@ and my_rust_binary.log
Just add
```
[dependencies]
simplelog = "^0.5.0"
simplelog = "^0.6.0"
```
to your `Cargo.toml`

Expand Down
19 changes: 10 additions & 9 deletions examples/usage.rs
@@ -1,17 +1,18 @@
#[macro_use] extern crate log;
extern crate simplelog;

use simplelog::*;
use log::*;

use std::fs::File;

fn main() {
CombinedLogger::init(
vec![
TermLogger::new(LevelFilter::Warn, Config::default()).unwrap(),
WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_binary.log").unwrap()),
]
).unwrap();
CombinedLogger::init(vec![
TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap(),
WriteLogger::new(
LevelFilter::Info,
Config::default(),
File::create("my_rust_binary.log").unwrap(),
),
])
.unwrap();

error!("Bright red error");
info!("This only appears in the log file");
Expand Down
20 changes: 20 additions & 0 deletions src/config.rs
@@ -1,5 +1,7 @@
use log::Level;

pub use chrono::offset::{FixedOffset, Local, Offset, TimeZone, Utc};

/// Configuration for the Loggers
///
/// All loggers print the message in the following form:
Expand All @@ -20,22 +22,40 @@ pub struct Config {
pub time: Option<Level>,
///At which level and below the level itself shall be logged
pub level: Option<Level>,
///At which level and below the thread id shall be logged. Default DEBUG
pub thread: Option<Level>,
///At which level and below the target shall be logged
pub target: Option<Level>,
///At which level and below a source code reference shall be logged
pub location: Option<Level>,
///A chrono strftime string. See: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
pub time_format: Option<&'static str>,
/// Chrono Offset used for logging time (default is UTC)
pub offset: FixedOffset,
/// Allowed module filters.
/// If specified, only records from modules starting with one of these entries will be printed
///
/// For example, `filter_allow: Some(&["tokio::uds"])` would allow only logging from the `tokio` crates `uds` module.
pub filter_allow: Option<&'static [&'static str]>,
/// Denied module filters.
/// If specified, records from modules starting with one of these entries will be ignored
///
/// For example, `filter_ignore: Some(&["tokio::uds"])` would deny logging from the `tokio` crates `uds` module.
pub filter_ignore: Option<&'static [&'static str]>,
}

impl Default for Config {
fn default() -> Config {
Config {
time: Some(Level::Error),
level: Some(Level::Error),
thread: Some(Level::Debug),
target: Some(Level::Debug),
location: Some(Level::Trace),
time_format: None,
offset: Utc.fix(),
filter_allow: None,
filter_ignore: None,
}
}
}
177 changes: 112 additions & 65 deletions src/lib.rs
Expand Up @@ -12,31 +12,30 @@
//! - `TermLogger` (advanced terminal logger, that splits to stdout/err and has color support) (can be excluded on unsupported platforms)
//! - `WriteLogger` (logs to a given struct implementing `Write`, e.g. a file)
//! - `CombinedLogger` (can be used to form combinations of the above loggers)
//! - `TestLogger` (specialized logger for tests. Uses print!() / println!() for tests to be able to capture the output)
//!
//! Only one Logger should be initialized of the start of your program
//! through the `Logger::init(...)` method. For the actual calling syntax
//! take a look at the documentation of the specific implementation(s) you wanna use.
//!

#![deny(missing_docs)]

#[cfg_attr(test, macro_use)]
extern crate log;
#[cfg(feature = "term")]
extern crate term;
extern crate chrono;
#![deny(missing_docs, rust_2018_idioms)]

mod config;
mod loggers;

pub use self::config::Config;
pub use self::loggers::{SimpleLogger, WriteLogger, CombinedLogger};
#[cfg(feature = "test")]
pub use self::loggers::TestLogger;
pub use self::loggers::{CombinedLogger, SimpleLogger, WriteLogger};
#[cfg(feature = "term")]
pub use self::loggers::{TermLogger, TermLogError};
pub use self::loggers::{TermLogError, TermLogger, TerminalMode};

pub use log::{Level, LevelFilter};

use log::Log;
#[cfg(test)]
use log::*;

/// Trait to have a common interface to obtain the Level of Loggers
///
Expand Down Expand Up @@ -75,87 +74,135 @@ pub trait SharedLogger: Log {
fn config(&self) -> Option<&Config>;

/// Returns the logger as a Log trait object
fn as_log(self: Box<Self>) -> Box<Log>;
fn as_log(self: Box<Self>) -> Box<dyn Log>;
}

#[cfg(test)]
mod tests {
use std::io::Read;
use std::fs::File;
use std::io::Read;

use super::*;

#[test]
fn test() {
let mut i = 0;

CombinedLogger::init(
{
let mut vec = Vec::new();
let mut conf = Config {
time: None,
level: None,
target: None,
location: None,
time_format: None,
};

for elem in vec![None, Some(Level::Trace), Some(Level::Debug), Some(Level::Info), Some(Level::Warn), Some(Level::Error)]
{
conf.location = elem;
conf.target = elem;
conf.level = elem;
conf.time = elem;
i += 1;

//error
vec.push(SimpleLogger::new(LevelFilter::Error, conf) as Box<SharedLogger>);
vec.push(TermLogger::new(LevelFilter::Error, conf).unwrap() as Box<SharedLogger>);
vec.push(WriteLogger::new(LevelFilter::Error, conf, File::create(&format!("error_{}.log", i)).unwrap()) as Box<SharedLogger>);

//warn
vec.push(SimpleLogger::new(LevelFilter::Warn, conf) as Box<SharedLogger>);
vec.push(TermLogger::new(LevelFilter::Warn, conf).unwrap() as Box<SharedLogger>);
vec.push(WriteLogger::new(LevelFilter::Warn, conf, File::create(&format!("warn_{}.log", i)).unwrap()) as Box<SharedLogger>);

//info
vec.push(SimpleLogger::new(LevelFilter::Info, conf) as Box<SharedLogger>);
vec.push(TermLogger::new(LevelFilter::Info, conf).unwrap() as Box<SharedLogger>);
vec.push(WriteLogger::new(LevelFilter::Info, conf, File::create(&format!("info_{}.log", i)).unwrap()) as Box<SharedLogger>);

//debug
vec.push(SimpleLogger::new(LevelFilter::Debug, conf) as Box<SharedLogger>);
vec.push(TermLogger::new(LevelFilter::Debug, conf).unwrap() as Box<SharedLogger>);
vec.push(WriteLogger::new(LevelFilter::Debug, conf, File::create(&format!("debug_{}.log", i)).unwrap()) as Box<SharedLogger>);

//trace
vec.push(SimpleLogger::new(LevelFilter::Trace, conf) as Box<SharedLogger>);
vec.push(TermLogger::new(LevelFilter::Trace, conf).unwrap() as Box<SharedLogger>);
vec.push(WriteLogger::new(LevelFilter::Trace, conf, File::create(&format!("trace_{}.log", i)).unwrap()) as Box<SharedLogger>);
}

vec
CombinedLogger::init({
let mut vec = Vec::new();
let mut conf = Config::default();

for elem in vec![
None,
Some(Level::Trace),
Some(Level::Debug),
Some(Level::Info),
Some(Level::Warn),
Some(Level::Error),
] {
conf.location = elem;
conf.target = elem;
conf.level = elem;
conf.time = elem;
i += 1;

//error
vec.push(SimpleLogger::new(LevelFilter::Error, conf) as Box<dyn SharedLogger>);
vec.push(
TermLogger::new(LevelFilter::Error, conf, TerminalMode::Mixed).unwrap()
as Box<dyn SharedLogger>,
);
vec.push(WriteLogger::new(
LevelFilter::Error,
conf,
File::create(&format!("error_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);

//warn
vec.push(SimpleLogger::new(LevelFilter::Warn, conf) as Box<dyn SharedLogger>);
vec.push(
TermLogger::new(LevelFilter::Warn, conf, TerminalMode::Mixed).unwrap()
as Box<dyn SharedLogger>,
);
vec.push(WriteLogger::new(
LevelFilter::Warn,
conf,
File::create(&format!("warn_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);

//info
vec.push(SimpleLogger::new(LevelFilter::Info, conf) as Box<dyn SharedLogger>);
vec.push(
TermLogger::new(LevelFilter::Info, conf, TerminalMode::Mixed).unwrap()
as Box<dyn SharedLogger>,
);
vec.push(WriteLogger::new(
LevelFilter::Info,
conf,
File::create(&format!("info_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);

//debug
vec.push(SimpleLogger::new(LevelFilter::Debug, conf) as Box<dyn SharedLogger>);
vec.push(
TermLogger::new(LevelFilter::Debug, conf, TerminalMode::Mixed).unwrap()
as Box<dyn SharedLogger>,
);
vec.push(WriteLogger::new(
LevelFilter::Debug,
conf,
File::create(&format!("debug_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);

//trace
vec.push(SimpleLogger::new(LevelFilter::Trace, conf) as Box<dyn SharedLogger>);
vec.push(
TermLogger::new(LevelFilter::Trace, conf, TerminalMode::Mixed).unwrap()
as Box<dyn SharedLogger>,
);
vec.push(WriteLogger::new(
LevelFilter::Trace,
conf,
File::create(&format!("trace_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
}
).unwrap();

vec
})
.unwrap();

error!("Test Error");
warn!("Test Warning");
info!("Test Information");
debug!("Test Debug");
trace!("Test Trace");

for j in 1..i
{
for j in 1..i {
let mut error = String::new();
File::open(&format!("error_{}.log", j)).unwrap().read_to_string(&mut error).unwrap();
File::open(&format!("error_{}.log", j))
.unwrap()
.read_to_string(&mut error)
.unwrap();
let mut warn = String::new();
File::open(&format!("warn_{}.log", j)).unwrap().read_to_string(&mut warn).unwrap();
File::open(&format!("warn_{}.log", j))
.unwrap()
.read_to_string(&mut warn)
.unwrap();
let mut info = String::new();
File::open(&format!("info_{}.log", j)).unwrap().read_to_string(&mut info).unwrap();
File::open(&format!("info_{}.log", j))
.unwrap()
.read_to_string(&mut info)
.unwrap();
let mut debug = String::new();
File::open(&format!("debug_{}.log", j)).unwrap().read_to_string(&mut debug).unwrap();
File::open(&format!("debug_{}.log", j))
.unwrap()
.read_to_string(&mut debug)
.unwrap();
let mut trace = String::new();
File::open(&format!("trace_{}.log", j)).unwrap().read_to_string(&mut trace).unwrap();
File::open(&format!("trace_{}.log", j))
.unwrap()
.read_to_string(&mut trace)
.unwrap();

assert!(error.contains("Test Error"));
assert!(!error.contains("Test Warning"));
Expand Down

0 comments on commit 05efed3

Please sign in to comment.