From 020aff6011db884d3c80baf2ec4028037de7e5ec Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 11 Aug 2024 22:47:10 +0800 Subject: [PATCH] use system timezone Signed-off-by: tison --- examples/rolling_file.rs | 2 +- src/append/rolling_file/rolling.rs | 5 +++-- src/append/rolling_file/rotation.rs | 11 +++++++--- src/layout/json.rs | 34 ++++++++++++++++++++++------- src/layout/text.rs | 22 ++++++++++++++----- 5 files changed, 54 insertions(+), 20 deletions(-) diff --git a/examples/rolling_file.rs b/examples/rolling_file.rs index 4686b59..443bcc9 100644 --- a/examples/rolling_file.rs +++ b/examples/rolling_file.rs @@ -38,7 +38,7 @@ fn main() { .dispatch( Dispatch::new() .filter(LevelFilter::Trace) - .layout(JsonLayout) + .layout(JsonLayout::default()) .append(RollingFile::new(writer)), ) .dispatch(Dispatch::new().layout(TextLayout::default()).append(Stdout)) diff --git a/src/append/rolling_file/rolling.rs b/src/append/rolling_file/rolling.rs index d021fbf..c9083e3 100644 --- a/src/append/rolling_file/rolling.rs +++ b/src/append/rolling_file/rolling.rs @@ -275,8 +275,9 @@ impl State { } } - if self.log_filename_prefix.is_none() && self.log_filename_suffix.is_none() - // && Date::parse(filename, &self.date_format).is_err() + if self.log_filename_prefix.is_none() + && self.log_filename_suffix.is_none() + && Zoned::strptime(self.date_format, filename).is_err() { return None; } diff --git a/src/append/rolling_file/rotation.rs b/src/append/rolling_file/rotation.rs index 332ed92..0810306 100644 --- a/src/append/rolling_file/rotation.rs +++ b/src/append/rolling_file/rotation.rs @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use jiff::{RoundMode, ToSpan}; +use jiff::RoundMode; +use jiff::ToSpan; use jiff::Unit; use jiff::Zoned; use jiff::ZonedRound; @@ -36,8 +37,12 @@ impl Rotation { let next_date = match *self { Rotation::Never => return None, - Rotation::Minutely => (current_date + 1.minute()).round(timestamp_round.smallest(Unit::Minute)), - Rotation::Hourly => (current_date + 1.hour()).round(timestamp_round.smallest(Unit::Hour)), + Rotation::Minutely => { + (current_date + 1.minute()).round(timestamp_round.smallest(Unit::Minute)) + } + Rotation::Hourly => { + (current_date + 1.hour()).round(timestamp_round.smallest(Unit::Hour)) + } Rotation::Daily => (current_date + 1.day()).round(timestamp_round.smallest(Unit::Day)), }; let next_date = diff --git a/src/layout/json.rs b/src/layout/json.rs index b62e8c1..96632d7 100644 --- a/src/layout/json.rs +++ b/src/layout/json.rs @@ -14,6 +14,8 @@ use std::fmt::Arguments; +use jiff::tz::TimeZone; +use jiff::Zoned; use log::Record; use serde::Serialize; use serde_json::Map; @@ -26,14 +28,19 @@ use crate::layout::Layout; /// Output format: /// /// ```json -/// {"timestamp":"2024-08-01T13:57:05.099261Z","level":"ERROR","module_path":"rolling_file","file":"rolling_file.rs","line":48,"message":"Hello error!","kvs":{}} -/// {"timestamp":"2024-08-01T13:57:05.099313Z","level":"WARN","module_path":"rolling_file","file":"rolling_file.rs","line":49,"message":"Hello warn!","kvs":{}} -/// {"timestamp":"2024-08-01T13:57:05.099338Z","level":"INFO","module_path":"rolling_file","file":"rolling_file.rs","line":50,"message":"Hello info!","kvs":{}} -/// {"timestamp":"2024-08-01T13:57:05.099362Z","level":"DEBUG","module_path":"rolling_file","file":"rolling_file.rs","line":51,"message":"Hello debug!","kvs":{}} -/// {"timestamp":"2024-08-01T13:57:05.099386Z","level":"TRACE","module_path":"rolling_file","file":"rolling_file.rs","line":52,"message":"Hello trace!","kvs":{}} +/// {"timestamp":"2024-08-11T22:44:57.172051+08:00","level":"ERROR","module_path":"rolling_file","file":"examples/rolling_file.rs","line":51,"message":"Hello error!","kvs":{}} +/// {"timestamp":"2024-08-11T22:44:57.172187+08:00","level":"WARN","module_path":"rolling_file","file":"examples/rolling_file.rs","line":52,"message":"Hello warn!","kvs":{}} +/// {"timestamp":"2024-08-11T22:44:57.172246+08:00","level":"INFO","module_path":"rolling_file","file":"examples/rolling_file.rs","line":53,"message":"Hello info!","kvs":{}} +/// {"timestamp":"2024-08-11T22:44:57.172300+08:00","level":"DEBUG","module_path":"rolling_file","file":"examples/rolling_file.rs","line":54,"message":"Hello debug!","kvs":{}} +/// {"timestamp":"2024-08-11T22:44:57.172353+08:00","level":"TRACE","module_path":"rolling_file","file":"examples/rolling_file.rs","line":55,"message":"Hello trace!","kvs":{}} /// ``` +/// +/// You can customize the timezone of the timestamp by setting the `tz` field with a [`TimeZone`] +/// instance. Otherwise, the system timezone is used. #[derive(Default, Debug, Clone)] -pub struct JsonLayout; +pub struct JsonLayout { + pub tz: Option, +} struct KvCollector<'a> { kvs: &'a mut Map, @@ -54,7 +61,8 @@ impl<'a, 'kvs> log::kv::Visitor<'kvs> for KvCollector<'a> { #[derive(Debug, Clone, Serialize)] struct RecordLine<'a> { - timestamp: jiff::Zoned, + #[serde(serialize_with = "serialize_time_zone")] + timestamp: Zoned, level: &'a str, module_path: &'a str, file: &'a str, @@ -64,6 +72,13 @@ struct RecordLine<'a> { kvs: Map, } +fn serialize_time_zone(timestamp: &Zoned, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.collect_str(×tamp.strftime("%Y-%m-%dT%H:%M:%S.%6f%:z")) +} + fn serialize_args(args: &Arguments, serializer: S) -> Result where S: serde::Serializer, @@ -81,7 +96,10 @@ impl JsonLayout { record.key_values().visit(&mut visitor)?; let record_line = RecordLine { - timestamp: jiff::Zoned::now(), + timestamp: match self.tz.clone() { + Some(tz) => Zoned::now().with_time_zone(tz), + None => Zoned::now(), + }, level: record.level().as_str(), module_path: record.module_path().unwrap_or_default(), file: record.file().unwrap_or_default(), diff --git a/src/layout/text.rs b/src/layout/text.rs index 2cfe6c5..0237a79 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -17,6 +17,8 @@ use std::fmt::Arguments; use colored::Color; use colored::ColoredString; use colored::Colorize; +use jiff::tz::TimeZone; +use jiff::Zoned; use log::Level; use crate::layout::KvDisplay; @@ -27,11 +29,11 @@ use crate::layout::Layout; /// Output format: /// /// ```text -/// 2024-08-02T12:49:03.102343Z ERROR simple_stdio: examples/simple_stdio.rs:32 Hello error! -/// 2024-08-02T12:49:03.102442Z WARN simple_stdio: examples/simple_stdio.rs:33 Hello warn! -/// 2024-08-02T12:49:03.102447Z INFO simple_stdio: examples/simple_stdio.rs:34 Hello info! -/// 2024-08-02T12:49:03.102450Z DEBUG simple_stdio: examples/simple_stdio.rs:35 Hello debug! -/// 2024-08-02T12:49:03.102453Z TRACE simple_stdio: examples/simple_stdio.rs:36 Hello trace! +/// 2024-08-11T22:44:57.172105+08:00 ERROR rolling_file: examples/rolling_file.rs:51 Hello error! +/// 2024-08-11T22:44:57.172219+08:00 WARN rolling_file: examples/rolling_file.rs:52 Hello warn! +/// 2024-08-11T22:44:57.172276+08:00 INFO rolling_file: examples/rolling_file.rs:53 Hello info! +/// 2024-08-11T22:44:57.172329+08:00 DEBUG rolling_file: examples/rolling_file.rs:54 Hello debug! +/// 2024-08-11T22:44:57.172382+08:00 TRACE rolling_file: examples/rolling_file.rs:55 Hello trace! /// ``` /// /// By default, log levels are colored. You can turn on the `no-color` feature flag to disable this @@ -39,9 +41,13 @@ use crate::layout::Layout; /// /// You can also customize the color of each log level by setting the `colors` field with a /// [`LevelColor`] instance. +/// +/// You can customize the timezone of the timestamp by setting the `tz` field with a [`TimeZone`] +/// instance. Otherwise, the system timezone is used. #[derive(Default, Debug, Clone)] pub struct TextLayout { pub colors: LevelColor, + pub tz: Option, } /// Customize the color of each log level. @@ -79,7 +85,11 @@ impl TextLayout { Level::Trace => self.colors.trace, }; - let time = jiff::Zoned::now(); + let time = match self.tz.clone() { + Some(tz) => Zoned::now().with_time_zone(tz), + None => Zoned::now(), + } + .strftime("%Y-%m-%dT%H:%M:%S.%6f%:z"); let level = ColoredString::from(record.level().to_string()).color(color); let module = record.module_path().unwrap_or_default(); let file = record.file().unwrap_or_default();