Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace chrono with time #95

Merged
merged 3 commits into from Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,22 @@
## v0.12.0
- Replaces the semingly unmainted chrono library with the time crate.
- Addresses through this update
- RUSTSEC-2020-0159 (chrono)
- RUSTSEC-2020-0071 (time)
- `ConfigBuilder::set_time_to_local` is replaced by `ConfigBuilder::set_time_offset_to_local`.
- This function requires the new (and by default activated) `local-offset` feature.
- This function may fail, for more information read the docs.
- simplelog will not determine the local offset dynamically anymore, but only once, when this config option is set.
- Due to safety reasons there is no way to provide this property currently.
- `ConfigBuilder::set_time_offset` now takes a `time::UtcOffset` instead of a `chrono::FixedOffset`.
- `ConfigBuilder::set_time_format` has been replaced by three new variants
- `ConfigBuilder::set_time_format_rfc2822` sets the time format to use the format described by rfc2822.
- `ConfigBuilder::set_time_format_rfc3339` sets the time format to use the format described by rfc3339.
- `ConfigBuilder::set_time_format_custom` sets the time format to a custom time format best created using `time::macros::format_description`.
- Runtime provided time format configuration is possible, but difficult due to lifetime constraints.
- Fixing this will require a solution to https://github.com/time-rs/time/issues/429
- *Note*: The default format is unchanged "[hour]:[minute]:[second]"

## v0.11.0
- Add colored log levels using `ansi_term` (PR #88, credits to @manio)
- Add target padding (PR #85, credits to @bytebeamio)
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "simplelog"
version = "0.11.2"
version = "0.12.0-alpha1"
edition = "2018"
authors = ["Drakulix <github@drakulix.de>"]
description = "A simple and easy-to-use logging facility for Rust's log crate"
Expand All @@ -20,11 +20,12 @@ include = [

[features]
test = []
default = ["termcolor"]
default = ["termcolor", "local-offset"]
local-offset = ["time/local-offset"]

[dependencies]
log = { version = "0.4.*", features = ["std"] }
termcolor = { version = "1.1.*", optional = true }
paris = { version = "~1.5", optional = true }
ansi_term = { version = "0.12", optional = true }
chrono = "0.4.1"
time = { version = "0.3.7", features = ["formatting", "macros"] }
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -42,7 +42,7 @@ fn main() {
### Results in
```
$ cargo run --example usage
Compiling simplelog v0.10.0 (file:///home/drakulix/Projects/simplelog)
Compiling simplelog v0.12.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.10.0"
simplelog = "^0.12.0"
```
to your `Cargo.toml`

Expand Down
83 changes: 61 additions & 22 deletions src/config.rs
Expand Up @@ -2,10 +2,10 @@
use log::Level;
use log::LevelFilter;

pub use chrono::offset::{FixedOffset, Local, Offset, TimeZone, Utc};
use std::borrow::Cow;
#[cfg(feature = "termcolor")]
use termcolor::Color;
pub use time::{format_description::FormatItem, macros::format_description, UtcOffset};

#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the level
Expand Down Expand Up @@ -51,6 +51,13 @@ pub enum ThreadLogMode {
Both,
}

#[derive(Debug, Clone)]
pub(crate) enum TimeFormat {
Rfc2822,
Rfc3339,
Custom(&'static [time::format_description::FormatItem<'static>]),
}

/// Configuration for the Loggers
///
/// All loggers print the message in the following form:
Expand All @@ -72,9 +79,8 @@ pub struct Config {
pub(crate) target: LevelFilter,
pub(crate) target_padding: TargetPadding,
pub(crate) location: LevelFilter,
pub(crate) time_format: Cow<'static, str>,
pub(crate) time_offset: FixedOffset,
pub(crate) time_local: bool,
pub(crate) time_format: TimeFormat,
pub(crate) time_offset: UtcOffset,
pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>,
pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>,
#[cfg(feature = "termcolor")]
Expand Down Expand Up @@ -167,34 +173,68 @@ impl ConfigBuilder {
self
}

/// Set time chrono [strftime] format string.
/// Sets the time format to a custom representation.
///
/// The easiest way to satisfy the static lifetime of the argument is to directly use the
/// re-exported [`time::macros::format_description`] macro.
///
/// *Note*: The default time format is "[hour]:[minute]:[second]".
///
/// The syntax for the format_description macro can be found in the
/// [`time` crate book](https://time-rs.github.io/book/api/format-description.html).
///
/// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
pub fn set_time_format_str(&mut self, time_format: &'static str) -> &mut ConfigBuilder {
self.0.time_format = Cow::Borrowed(time_format);
/// # Usage
///
/// ```
/// # use simplelog::{ConfigBuilder, format_description};
/// let config = ConfigBuilder::new()
/// .set_time_format_custom(format_description!("[hour]:[minute]:[second].[subsecond]"))
/// .build();
/// ```
pub fn set_time_format_custom(
&mut self,
time_format: &'static [FormatItem<'static>],
) -> &mut ConfigBuilder {
self.0.time_format = TimeFormat::Custom(time_format);
self
}

/// Set time chrono [strftime] format string.
///
/// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
pub fn set_time_format(&mut self, time_format: String) -> &mut ConfigBuilder {
self.0.time_format = Cow::Owned(time_format);
/// Set time format string to use rfc2822.
pub fn set_time_format_rfc2822(&mut self) -> &mut ConfigBuilder {
self.0.time_format = TimeFormat::Rfc2822;
self
}

/// Set offset used for logging time (default is 0)
pub fn set_time_offset(&mut self, time_offset: FixedOffset) -> &mut ConfigBuilder {
self.0.time_offset = time_offset;
/// Set time format string to use rfc3339.
pub fn set_time_format_rfc3339(&mut self) -> &mut ConfigBuilder {
self.0.time_format = TimeFormat::Rfc3339;
self
}

/// set if you log in local timezone or UTC (default is UTC)
pub fn set_time_to_local(&mut self, local: bool) -> &mut ConfigBuilder {
self.0.time_local = local;
/// Set offset used for logging time (default is UTC)
pub fn set_time_offset(&mut self, offset: UtcOffset) -> &mut ConfigBuilder {
self.0.time_offset = offset;
self
}

/// Sets the offset used to the current local time offset
/// (overriding values previously set by [`ConfigBuilder::set_time_offset`]).
///
/// This function may fail if the offset cannot be determined soundly.
/// This may be the case, when the program is multi-threaded by the time of calling this function.
/// One can opt-out of this behavior by setting `RUSTFLAGS="--cfg unsound_local_offset"`.
/// Doing so is not recommended, completely untested and may cause unexpected segfaults.
#[cfg(feature = "local-offset")]
pub fn set_time_offset_to_local(&mut self) -> Result<&mut ConfigBuilder, &mut ConfigBuilder> {
match UtcOffset::current_local_offset() {
Ok(offset) => {
self.0.time_offset = offset;
Ok(self)
}
Err(_) => Err(self),
}
}

/// set if you want to write colors in the logfile (default is Off)
#[cfg(feature = "ansi_term")]
pub fn set_write_log_enable_colors(&mut self, local: bool) -> &mut ConfigBuilder {
Expand Down Expand Up @@ -284,9 +324,8 @@ impl Default for Config {
target: LevelFilter::Debug,
target_padding: TargetPadding::Off,
location: LevelFilter::Trace,
time_format: Cow::Borrowed("%H:%M:%S"),
time_offset: FixedOffset::east(0),
time_local: false,
time_format: TimeFormat::Custom(format_description!("[hour]:[minute]:[second]")),
time_offset: UtcOffset::UTC,
filter_allow: Cow::Borrowed(&[]),
filter_ignore: Cow::Borrowed(&[]),
write_log_enable_colors: false,
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Expand Up @@ -25,7 +25,8 @@ mod config;
mod loggers;

pub use self::config::{
Config, ConfigBuilder, LevelPadding, TargetPadding, ThreadLogMode, ThreadPadding,
format_description, Config, ConfigBuilder, FormatItem, LevelPadding, TargetPadding,
ThreadLogMode, ThreadPadding,
};
#[cfg(feature = "test")]
pub use self::loggers::TestLogger;
Expand Down
21 changes: 15 additions & 6 deletions src/loggers/logging.rs
@@ -1,4 +1,4 @@
use crate::config::TargetPadding;
use crate::config::{TargetPadding, TimeFormat};
use crate::{Config, LevelPadding, ThreadLogMode, ThreadPadding};
use log::{LevelFilter, Record};
use std::io::{Error, Write};
Expand Down Expand Up @@ -65,13 +65,22 @@ pub fn write_time<W>(write: &mut W, config: &Config) -> Result<(), Error>
where
W: Write + Sized,
{
let cur_time = if config.time_local {
(chrono::Local::now() + config.time_offset).format(&*config.time_format)
} else {
(chrono::Utc::now() + config.time_offset).format(&*config.time_format)
use time::error::Format;
use time::format_description::well_known::*;

let time = time::OffsetDateTime::now_utc().to_offset(config.time_offset);
let res = match config.time_format {
TimeFormat::Rfc2822 => time.format_into(write, &Rfc2822),
TimeFormat::Rfc3339 => time.format_into(write, &Rfc3339),
TimeFormat::Custom(format) => time.format_into(write, &format),
};
match res {
Err(Format::StdIo(err)) => return Err(err),
Err(err) => panic!("Invalid time format: {}", err),
_ => {}
};

write!(write, "{} ", cur_time)?;
write!(write, " ")?;
Ok(())
}

Expand Down
18 changes: 12 additions & 6 deletions src/loggers/testlog.rs
Expand Up @@ -8,7 +8,7 @@
//! Module providing the TestLogger Implementation

use super::logging::should_skip;
use crate::{Config, LevelPadding, SharedLogger};
use crate::{config::TimeFormat, Config, LevelPadding, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};

use std::thread;
Expand Down Expand Up @@ -128,12 +128,18 @@ pub fn log(config: &Config, record: &Record<'_>) {

#[inline(always)]
pub fn write_time(config: &Config) {
let cur_time = if config.time_local {
chrono::Local::now().naive_local() + config.time_offset
} else {
chrono::Utc::now().naive_utc() + config.time_offset
use time::format_description::well_known::*;

let time = time::OffsetDateTime::now_utc().to_offset(config.time_offset);
let res = match config.time_format {
TimeFormat::Rfc2822 => time.format(&Rfc2822),
TimeFormat::Rfc3339 => time.format(&Rfc3339),
TimeFormat::Custom(format) => time.format(&format),
};
match res {
Ok(time) => println!("{} ", time),
Err(err) => panic!("Invalid time format: {}", err),
};
print!("{} ", cur_time.format(&*config.time_format));
}

#[inline(always)]
Expand Down