diff --git a/Cargo.lock b/Cargo.lock index c19ced6476..407e91a546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2033,6 +2033,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.9" @@ -3454,6 +3463,9 @@ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -4635,6 +4647,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.0" @@ -4642,11 +4664,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cf865b5ddc38e503a29c41c4843e616a73028ae18c637bc3eb2afaef4909c84" dependencies = [ "ansi_term 0.12.1", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] diff --git a/logfmt/Cargo.toml b/logfmt/Cargo.toml index 3d9789ed50..3c50fcfb47 100644 --- a/logfmt/Cargo.toml +++ b/logfmt/Cargo.toml @@ -13,3 +13,4 @@ tracing-subscriber = "0.3" once_cell = { version = "1.4.0", features = ["parking_lot"] } parking_lot = "0.11.2" regex = "1.4.3" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/logfmt/src/lib.rs b/logfmt/src/lib.rs index ee95907761..4b1de785f6 100644 --- a/logfmt/src/lib.rs +++ b/logfmt/src/lib.rs @@ -19,12 +19,18 @@ use tracing_subscriber::{fmt::MakeWriter, layer::Context, registry::LookupSpan, /// looked very small and did not (obviously) work with the tracing subscriber /// /// [logfmt]: https://brandur.org/logfmt -pub struct LogFmtLayer { +pub struct LogFmtLayer +where + W: for<'writer> MakeWriter<'writer>, +{ writer: W, display_target: bool, } -impl LogFmtLayer { +impl LogFmtLayer +where + W: for<'writer> MakeWriter<'writer>, +{ /// Create a new logfmt Layer to pass into tracing_subscriber /// /// Note this layer simply formats and writes to the specified writer. It @@ -68,7 +74,7 @@ impl LogFmtLayer { impl Layer for LogFmtLayer where - W: MakeWriter + 'static, + W: for<'writer> MakeWriter<'writer> + 'static, S: Subscriber + for<'a> LookupSpan<'a>, { fn register_callsite( @@ -78,7 +84,7 @@ where Interest::always() } - fn new_span(&self, attrs: &tracing::span::Attributes<'_>, id: &Id, ctx: Context<'_, S>) { + fn on_new_span(&self, attrs: &tracing::span::Attributes<'_>, id: &Id, ctx: Context<'_, S>) { let writer = self.writer.make_writer(); let metadata = ctx.metadata(id).expect("span should have metadata"); let mut p = FieldPrinter::new(writer, metadata.level(), self.display_target); diff --git a/logfmt/tests/logging.rs b/logfmt/tests/logging.rs index d4f6d04d9c..44d556e384 100644 --- a/logfmt/tests/logging.rs +++ b/logfmt/tests/logging.rs @@ -363,7 +363,7 @@ impl std::io::Write for CapturedWriter { } } -impl MakeWriter for CapturedWriter { +impl MakeWriter<'_> for CapturedWriter { type Writer = Self; fn make_writer(&self) -> Self::Writer { diff --git a/test_helpers/Cargo.toml b/test_helpers/Cargo.toml index 741d47058a..ddfcc04610 100644 --- a/test_helpers/Cargo.toml +++ b/test_helpers/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" dotenv = "0.15.0" parking_lot = "0.11.2" tempfile = "3.1.0" -tracing-subscriber = "0.3" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } observability_deps = { path = "../observability_deps" } diff --git a/trogging/Cargo.toml b/trogging/Cargo.toml index f5eb07dee1..c44c0bc164 100644 --- a/trogging/Cargo.toml +++ b/trogging/Cargo.toml @@ -12,7 +12,7 @@ logfmt = { path = "../logfmt" } observability_deps = { path = "../observability_deps" } thiserror = "1.0.30" tracing-log = "0.1" -tracing-subscriber = "0.3" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } structopt = { version = "0.3.25", optional = true } [dev-dependencies] diff --git a/trogging/src/cli.rs b/trogging/src/cli.rs index c0538d14f9..e1166fd30c 100644 --- a/trogging/src/cli.rs +++ b/trogging/src/cli.rs @@ -105,7 +105,7 @@ impl LoggingConfig { pub fn with_builder(&self, builder: Builder) -> Builder where - W: MakeWriter + Send + Sync + Clone + 'static, + W: for<'writer> MakeWriter<'writer> + Send + Sync + Clone + 'static, { builder .with_log_filter(&self.log_filter) @@ -129,7 +129,7 @@ pub trait LoggingConfigBuilderExt { impl LoggingConfigBuilderExt for Builder where - W: MakeWriter + Send + Sync + Clone + 'static, + W: for<'writer> MakeWriter<'writer> + Send + Sync + Clone + 'static, { fn with_logging_config(self, config: &LoggingConfig) -> Builder { config.with_builder(self) diff --git a/trogging/src/lib.rs b/trogging/src/lib.rs index 95f1f32abf..dc3c7bde92 100644 --- a/trogging/src/lib.rs +++ b/trogging/src/lib.rs @@ -86,7 +86,7 @@ impl Builder { impl Builder { pub fn with_writer(self, make_writer: W2) -> Builder where - W2: MakeWriter + Send + Sync + 'static, + W2: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, { Builder:: { make_writer, @@ -103,7 +103,7 @@ impl Builder { // This needs to be a separate impl block because they place different bounds on the type parameters. impl Builder where - W: MakeWriter + Send + Sync + 'static, + W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, { pub const DEFAULT_LOG_FILTER: &'static str = "warn"; @@ -277,17 +277,30 @@ impl Drop for TroggingGuard { fn make_writer(m: M) -> BoxMakeWriter where - M: MakeWriter + Send + Sync + 'static, + M: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, { - fmt::writer::BoxMakeWriter::new(move || { - std::io::LineWriter::with_capacity( - MAX_LINE_LENGTH, - LimitedWriter(MAX_LINE_LENGTH, m.make_writer()), - ) + BoxMakeWriter::new(MakeWriterHelper { + inner: BoxMakeWriter::new(m), }) } +struct MakeWriterHelper { + inner: BoxMakeWriter, +} + +impl<'a> MakeWriter<'a> for MakeWriterHelper { + type Writer = Box; + + fn make_writer(&'a self) -> Self::Writer { + Box::new(std::io::LineWriter::with_capacity( + MAX_LINE_LENGTH, + LimitedWriter(MAX_LINE_LENGTH, self.inner.make_writer()), + )) + } +} + struct LimitedWriter(usize, W); + impl Write for LimitedWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { if buf.is_empty() { @@ -341,7 +354,7 @@ pub mod test_util { } } - impl MakeWriter for TestWriter { + impl MakeWriter<'_> for TestWriter { type Writer = SynchronizedWriter>; fn make_writer(&self) -> Self::Writer { @@ -356,9 +369,9 @@ pub mod test_util { /// Removes non-determinism by removing timestamps from the log lines. /// It supports the built-in tracing timestamp format and the logfmt timestamps. pub fn without_timestamps(&self) -> String { - // logfmt or fmt::layer() time format + // logfmt (e.g. `time=12345`) or fmt::layer() (e.g. `2021-10-25T13:48:50.555258`) time format let timestamp = regex::Regex::new( - r"(?m)( ?time=[0-9]+|^([A-Z][a-z]{2}) \d{1,2} \d{2}:\d{2}:\d{2}.\d{3} *)", + r"(?m)( ?time=[0-9]+|^(\d{4})-\d{1,2}-\d{1,2}T\d{2}:\d{2}:\d{2}.\d+Z *)", ) .unwrap(); timestamp.replace_all(&self.to_string(), "").to_string() @@ -379,7 +392,7 @@ pub mod test_util { /// the logging macros invoked by the function. pub fn log_test(builder: Builder, f: F) -> Captured where - W: MakeWriter + Send + Sync + 'static, + W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, F: Fn(), { let (writer, output) = TestWriter::new(); @@ -401,7 +414,7 @@ pub mod test_util { /// and returns the captured output. pub fn simple_test(builder: Builder) -> Captured where - W: MakeWriter + Send + Sync + 'static, + W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, { log_test(builder, || { error!("foo"); @@ -598,7 +611,8 @@ ERROR foo #[test] fn line_buffering() { let (test_writer, captured) = TestWriter::new(); - let mut writer = make_writer(test_writer).make_writer(); + let mw = make_writer(test_writer); + let mut writer = mw.make_writer(); writer.write_all("foo".as_bytes()).unwrap(); // wasn't flushed yet because there was no newline yet assert_eq!(captured.to_string(), ""); @@ -611,7 +625,8 @@ ERROR foo // another case when the line buffer flushes even before a newline is when the internal buffer limit let (test_writer, captured) = TestWriter::new(); - let mut writer = make_writer(test_writer).make_writer(); + let mw = make_writer(test_writer); + let mut writer = mw.make_writer(); let long = std::iter::repeat(b'X') .take(MAX_LINE_LENGTH) .collect::>();