From de8de61b76dd0a90dfa546ad2bdc113ee47b94e3 Mon Sep 17 00:00:00 2001 From: tison Date: Fri, 26 Sep 2025 20:20:07 +0800 Subject: [PATCH 1/2] refactor: print timestamp in RFC3339 format Signed-off-by: tison --- CHANGELOG.md | 5 +++++ src/diagnostic/fastrace.rs | 10 +++++----- src/layout/google_cloud_logging.rs | 4 +++- src/layout/json.rs | 23 +++++++++++++++-------- src/layout/logfmt.rs | 3 +++ src/layout/text.rs | 3 +++ 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fd311f..0991166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,11 @@ All notable changes to this project will be documented in this file. * `EnvFilter`'s constructors (`from_env`, etc.) are moved to `EnvFilterBuilder`. * Upgrade to opentelemetry 0.31.0. +### Notable changes + +* Timestamp format in `TextLayout`, `JsonLayout`, and `LogfmtLayout` is changed from RFC 9557 to RFC 3339 format. + * That is, from "2025-01-10T15:22:37.868815+08:00[Asia/Shanghai]" to "2025-01-10T15:22:37.868815+08:00". + ## [0.27.0] 2025-08-18 ### Notable changes diff --git a/src/diagnostic/fastrace.rs b/src/diagnostic/fastrace.rs index b7a172a..6670e7c 100644 --- a/src/diagnostic/fastrace.rs +++ b/src/diagnostic/fastrace.rs @@ -21,11 +21,11 @@ use crate::diagnostic::Visitor; /// Output format: /// /// ```text -/// 2025-01-10T15:22:37.868815+08:00[Asia/Shanghai] ERROR fastrace: fastrace.rs:39 Hello syslog error! trace_id=37f9c45f918cbb477089afb0d7162e7e -/// 2025-01-10T15:22:37.868890+08:00[Asia/Shanghai] WARN fastrace: fastrace.rs:40 Hello syslog warn! trace_id=37f9c45f918cbb477089afb0d7162e7e -/// 2025-01-10T15:22:37.868921+08:00[Asia/Shanghai] INFO fastrace: fastrace.rs:41 Hello syslog info! trace_id=37f9c45f918cbb477089afb0d7162e7e -/// 2025-01-10T15:22:37.868949+08:00[Asia/Shanghai] DEBUG fastrace: fastrace.rs:42 Hello syslog debug! trace_id=37f9c45f918cbb477089afb0d7162e7e -/// 2025-01-10T15:22:37.868976+08:00[Asia/Shanghai] TRACE fastrace: fastrace.rs:43 Hello syslog trace! trace_id=37f9c45f918cbb477089afb0d7162e7e +/// 2025-01-10T15:22:37.868815+08:00 ERROR fastrace: fastrace.rs:39 Hello syslog error! trace_id=37f9c45f918cbb477089afb0d7162e7e +/// 2025-01-10T15:22:37.868890+08:00 WARN fastrace: fastrace.rs:40 Hello syslog warn! trace_id=37f9c45f918cbb477089afb0d7162e7e +/// 2025-01-10T15:22:37.868921+08:00 INFO fastrace: fastrace.rs:41 Hello syslog info! trace_id=37f9c45f918cbb477089afb0d7162e7e +/// 2025-01-10T15:22:37.868949+08:00 DEBUG fastrace: fastrace.rs:42 Hello syslog debug! trace_id=37f9c45f918cbb477089afb0d7162e7e +/// 2025-01-10T15:22:37.868976+08:00 TRACE fastrace: fastrace.rs:43 Hello syslog trace! trace_id=37f9c45f918cbb477089afb0d7162e7e /// ``` /// /// ## Example diff --git a/src/layout/google_cloud_logging.rs b/src/layout/google_cloud_logging.rs index 651a533..608de03 100644 --- a/src/layout/google_cloud_logging.rs +++ b/src/layout/google_cloud_logging.rs @@ -224,6 +224,8 @@ where impl Layout for GoogleCloudLoggingLayout { fn format(&self, record: &Record, diags: &[Box]) -> Result, Error> { + let timestamp = jiff::Timestamp::now(); + let mut visitor = KvCollector { layout: self, payload_fields: BTreeMap::new(), @@ -243,7 +245,7 @@ impl Layout for GoogleCloudLoggingLayout { let record_line = RecordLine { extra_fields: visitor.payload_fields, - timestamp: jiff::Timestamp::now(), + timestamp, severity: record.level().as_str(), message: record.args(), labels: visitor.labels, diff --git a/src/layout/json.rs b/src/layout/json.rs index 9f2c7c5..0b6b546 100644 --- a/src/layout/json.rs +++ b/src/layout/json.rs @@ -16,9 +16,9 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::fmt::Arguments; -use jiff::Timestamp; use jiff::Zoned; use jiff::tz::TimeZone; +use jiff::{Timestamp, TimestampDisplayWithOffset}; use log::Record; use serde::Serialize; use serde_json::Map; @@ -102,8 +102,8 @@ impl Visitor for DiagsCollector<'_> { #[derive(Debug, Clone, Serialize)] struct RecordLine<'a> { - #[serde(serialize_with = "serialize_time_zone")] - timestamp: Zoned, + #[serde(serialize_with = "serialize_timestamp")] + timestamp: TimestampDisplayWithOffset, level: &'a str, target: &'a str, file: &'a str, @@ -116,7 +116,10 @@ struct RecordLine<'a> { diags: BTreeMap, } -fn serialize_time_zone(timestamp: &Zoned, serializer: S) -> Result +fn serialize_timestamp( + timestamp: &TimestampDisplayWithOffset, + serializer: S, +) -> Result where S: serde::Serializer, { @@ -134,6 +137,13 @@ impl Layout for JsonLayout { fn format(&self, record: &Record, diags: &[Box]) -> Result, Error> { let diagnostics = diags; + let time = match self.tz.clone() { + Some(tz) => Timestamp::now().to_zoned(tz), + None => Zoned::now(), + }; + let (time, offset) = (time.timestamp(), time.offset()); + let timestamp = time.display_with_offset(offset); + let mut kvs = Map::new(); let mut kvs_visitor = KvCollector { kvs: &mut kvs }; record @@ -148,10 +158,7 @@ impl Layout for JsonLayout { } let record_line = RecordLine { - timestamp: match self.tz.clone() { - Some(tz) => Timestamp::now().to_zoned(tz), - None => Zoned::now(), - }, + timestamp, level: record.level().as_str(), target: record.target(), file: record.file().unwrap_or_default(), diff --git a/src/layout/logfmt.rs b/src/layout/logfmt.rs index f52cf26..4cfcf15 100644 --- a/src/layout/logfmt.rs +++ b/src/layout/logfmt.rs @@ -120,6 +120,9 @@ impl Layout for LogfmtLayout { Some(tz) => Timestamp::now().to_zoned(tz), None => Zoned::now(), }; + let (time, offset) = (time.timestamp(), time.offset()); + let time = time.display_with_offset(offset); + let level = record.level().to_string(); let target = record.target(); let file = filename(record); diff --git a/src/layout/text.rs b/src/layout/text.rs index 69e40d1..f71844f 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -187,6 +187,9 @@ impl Layout for TextLayout { Some(tz) => Timestamp::now().to_zoned(tz), None => Zoned::now(), }; + let (time, offset) = (time.timestamp(), time.offset()); + let time = time.display_with_offset(offset); + let level = self.format_record_level(record.level()); let target = record.target(); let file = filename(record); From eaa62547a601654f92eb8c30bfacc9fb11cfce77 Mon Sep 17 00:00:00 2001 From: tison Date: Fri, 26 Sep 2025 20:25:50 +0800 Subject: [PATCH 2/2] tighter form Signed-off-by: tison --- src/layout/json.rs | 5 ++--- src/layout/logfmt.rs | 5 ++--- src/layout/text.rs | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/layout/json.rs b/src/layout/json.rs index 0b6b546..d4ec4b7 100644 --- a/src/layout/json.rs +++ b/src/layout/json.rs @@ -138,11 +138,10 @@ impl Layout for JsonLayout { let diagnostics = diags; let time = match self.tz.clone() { - Some(tz) => Timestamp::now().to_zoned(tz), None => Zoned::now(), + Some(tz) => Timestamp::now().to_zoned(tz), }; - let (time, offset) = (time.timestamp(), time.offset()); - let timestamp = time.display_with_offset(offset); + let timestamp = time.timestamp().display_with_offset(time.offset()); let mut kvs = Map::new(); let mut kvs_visitor = KvCollector { kvs: &mut kvs }; diff --git a/src/layout/logfmt.rs b/src/layout/logfmt.rs index 4cfcf15..5f4f37d 100644 --- a/src/layout/logfmt.rs +++ b/src/layout/logfmt.rs @@ -117,11 +117,10 @@ impl Visitor for KvFormatter { impl Layout for LogfmtLayout { fn format(&self, record: &Record, diags: &[Box]) -> Result, Error> { let time = match self.tz.clone() { - Some(tz) => Timestamp::now().to_zoned(tz), None => Zoned::now(), + Some(tz) => Timestamp::now().to_zoned(tz), }; - let (time, offset) = (time.timestamp(), time.offset()); - let time = time.display_with_offset(offset); + let time = time.timestamp().display_with_offset(time.offset()); let level = record.level().to_string(); let target = record.target(); diff --git a/src/layout/text.rs b/src/layout/text.rs index f71844f..a6f803e 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -184,11 +184,10 @@ impl Visitor for KvWriter { impl Layout for TextLayout { fn format(&self, record: &Record, diags: &[Box]) -> Result, Error> { let time = match self.tz.clone() { - Some(tz) => Timestamp::now().to_zoned(tz), None => Zoned::now(), + Some(tz) => Timestamp::now().to_zoned(tz), }; - let (time, offset) = (time.timestamp(), time.offset()); - let time = time.display_with_offset(offset); + let time = time.timestamp().display_with_offset(time.offset()); let level = self.format_record_level(record.level()); let target = record.target();