Application level tracing for Rust.

Overview

Tracing β€” Structured, application-level diagnostics

Crates.io Documentation Documentation (master) MIT licensed Build Status Discord chat

Website | Chat | Documentation (master branch)

Overview

tracing is a framework for instrumenting Rust programs to collect structured, event-based diagnostic information. tracing is maintained by the Tokio project, but does not require the tokio runtime to be used.

Usage

In Applications

In order to record trace events, executables have to use a collector implementation compatible with tracing. A collector implements a way of collecting trace data, such as by logging it to standard output. tracing-subscriber's fmt module provides a collector for logging traces with reasonable defaults. Additionally, tracing-subscriber is able to consume messages emitted by log-instrumented libraries and modules.

To use tracing-subscriber, add the following to your Cargo.toml:

[dependencies]
tracing = "0.1"
tracing-subscriber = "0.2"

Then create and install a collector, for example using init():

use tracing::info;
use tracing_subscriber;

fn main() {
    // install global collector configured based on RUST_LOG env var.
    tracing_subscriber::fmt::init();

    let number_of_yaks = 3;
    // this creates a new event, outside of any spans.
    info!(number_of_yaks, "preparing to shave yaks");

    let number_shaved = yak_shave::shave_all(number_of_yaks);
    info!(
        all_yaks_shaved = number_shaved == number_of_yaks,
        "yak shaving completed."
    );
}

Using init() calls set_global_default() so this collector will be used as the default in all threads for the remainder of the duration of the program, similar to how loggers work in the log crate.

For more control, a collector can be built in stages and not set globally, but instead used to locally override the default collector. For example:

use tracing::{info, Level};
use tracing_subscriber;

fn main() {
    let collector = tracing_subscriber::fmt()
        // filter spans/events with level TRACE or higher.
        .with_max_level(Level::TRACE)
        // build but do not install the subscriber.
        .finish();

    tracing::collector::with_default(collector, || {
        info!("This will be logged to stdout");
    });
    info!("This will _not_ be logged to stdout");
}

Any trace events generated outside the context of a collector will not be collected.

This approach allows trace data to be collected by multiple collectors within different contexts in the program. Note that the override only applies to the currently executing thread; other threads will not see the change from with_default.

Once a collector has been set, instrumentation points may be added to the executable using the tracing crate's macros.

In Libraries

Libraries should only rely on the tracing crate and use the provided macros and types to collect whatever information might be useful to downstream consumers.

use std::{error::Error, io};
use tracing::{debug, error, info, span, warn, Level};

// the `#[tracing::instrument]` attribute creates and enters a span
// every time the instrumented function is called. The span is named after the
// the function or method. Parameters passed to the function are recorded as fields.
#[tracing::instrument]
pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
    // this creates an event at the DEBUG level with two fields:
    // - `excitement`, with the key "excitement" and the value "yay!"
    // - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
    //
    // unlike other fields, `message`'s shorthand initialization is just the string itself.
    debug!(excitement = "yay!", "hello! I'm gonna shave a yak.");
    if yak == 3 {
        warn!("could not locate yak!");
        // note that this is intended to demonstrate `tracing`'s features, not idiomatic
        // error handling! in a library or application, you should consider returning
        // a dedicated `YakError`. libraries like snafu or thiserror make this easy.
        return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into());
    } else {
        debug!("yak shaved successfully");
    }
    Ok(())
}

pub fn shave_all(yaks: usize) -> usize {
    // Constructs a new span named "shaving_yaks" at the TRACE level,
    // and a field whose key is "yaks". This is equivalent to writing:
    //
    // let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks);
    //
    // local variables (`yaks`) can be used as field values
    // without an assignment, similar to struct initializers.
    let span = span!(Level::TRACE, "shaving_yaks", yaks);
    let _enter = span.enter();

    info!("shaving yaks");

    let mut yaks_shaved = 0;
    for yak in 1..=yaks {
        let res = shave(yak);
        debug!(yak, shaved = res.is_ok());

        if let Err(ref error) = res {
            // Like spans, events can also use the field initialization shorthand.
            // In this instance, `yak` is the field being initalized.
            error!(yak, error = error.as_ref(), "failed to shave yak!");
        } else {
            yaks_shaved += 1;
        }
        debug!(yaks_shaved);
    }

    yaks_shaved
}
[dependencies]
tracing = "0.1"

Note: Libraries should NOT install a collector by using a method that calls set_global_default(), as this will cause conflicts when executables try to set the default later.

In Asynchronous Code

To trace async fns, the preferred method is using the [#[instrument]] attribute:

use tracing::{info, instrument};
use tokio::{io::AsyncWriteExt, net::TcpStream};
use std::io;

#[instrument]
async fn write(stream: &mut TcpStream) -> io::Result<usize> {
    let result = stream.write(b"hello world\n").await;
    info!("wrote to stream; success={:?}", result.is_ok());
    result
}

The tracing-futures crate must be specified as a dependency to enable async support.

Special handling is needed for the general case of code using std::future::Future or blocks with async/await, as the following example will not work:

async {
    let _s = span.enter();
    // ...
}

The span guard _s will not exit until the future generated by the async block is complete. Since futures and spans can be entered and exited multiple times without them completing, the span remains entered for as long as the future exists, rather than being entered only when it is polled, leading to very confusing and incorrect output. For more details, see the documentation on closing spans.

This problem can be solved using the Future::instrument combinator:

use tracing::Instrument;

let my_future = async {
    // ...
};

my_future
    .instrument(tracing::info_span!("my_future"))
    .await

Future::instrument attaches a span to the future, ensuring that the span's lifetime is as long as the future's.

Under the hood, the #[instrument] macro performs same the explicit span attachment that Future::instrument does.

[#[instrument]]: https://docs.rs/tracing/0.1.11/tracing/attr.instrument.html

Supported Rust Versions

Tracing is built against the latest stable release. The minimum supported version is 1.42. The current Tracing version is not guaranteed to build on Rust versions earlier than the minimum supported version.

Tracing follows the same compiler support policies as the rest of the Tokio project. The current stable Rust compiler and the three most recent minor versions before it will always be supported. For example, if the current stable compiler version is 1.45, the minimum supported version will not be increased past 1.42, three minor versions prior. Increasing the minimum supported compiler version is not considered a semver breaking change as long as doing so complies with this policy.

Getting Help

First, see if the answer to your question can be found in the API documentation. If the answer is not there, there is an active community in the Tracing Discord channel. We would be happy to try to answer your question. Last, if that doesn't work, try opening an issue with the question.

Contributing

🎈 Thanks for your help improving the project! We are so happy to have you! We have a contributing guide to help you get involved in the Tracing project.

Project layout

The tracing crate contains the primary instrumentation API, used for instrumenting libraries and applications to emit trace data. The tracing-core crate contains the core API primitives on which the rest of tracing is instrumented. Authors of trace subscribers may depend on tracing-core, which guarantees a higher level of stability.

Additionally, this repository contains several compatibility and utility libraries built on top of tracing. Some of these crates are in a pre-release state, and are less stable than the tracing and tracing-core crates.

The crates included as part of Tracing are:

Related Crates

In addition to this repository, here are also several third-party crates which are not maintained by the tokio project. These include:

  • tracing-timing implements inter-event timing metrics on top of tracing. It provides a subscriber that records the time elapsed between pairs of tracing events and generates histograms.
  • tracing-honeycomb Provides a layer that reports traces spanning multiple machines to honeycomb.io. Backed by tracing-distributed.
  • tracing-distributed Provides a generic implementation of a layer that reports traces spanning multiple machines to some backend.
  • tracing-actix provides tracing integration for the actix actor framework.
  • tracing-gelf implements a subscriber for exporting traces in Greylog GELF format.
  • tracing-coz provides integration with the coz causal profiler (Linux-only).
  • tracing-bunyan-formatter provides a layer implementation that reports events and spans in bunyan format, enriched with timing information.
  • tide-tracing provides a tide middleware to trace all incoming requests and responses.
  • color-spantrace provides a formatter for rendering span traces in the style of color-backtrace
  • color-eyre provides customized panic and eyre report handlers for eyre::Report for capturing span traces and backtraces with new errors and pretty printing them.
  • spandoc provides a proc macro for constructing spans from doc comments inside of functions.
  • tracing-wasm provides a Collector/Subscriber implementation that reports events and spans via browser console.log and User Timing API (window.performance).
  • test-env-log takes care of initializing tracing for tests, based on environment variables with an env_logger compatible syntax.
  • tracing-unwrap provides convenience methods to report failed unwraps on Result or Option types to a Collector.
  • diesel-tracing provides integration with diesel database connections.
  • tracing-tracy provides a way to collect Tracy profiles in instrumented applications.
  • tracing-elastic-apm provides a layer for reporting traces to Elastic APM.

(if you're the maintainer of a tracing ecosystem crate not in this list, please let us know!)

Note: that some of the ecosystem crates are currently unreleased and undergoing active development. They may be less stable than tracing and tracing-core.

External Resources

This is a list of links to blog posts, conference talks, and tutorials about Tracing.

Blog Posts

Talks

Help us expand this list! If you've written or spoken about Tracing, or know of resources that aren't listed, please open a pull request adding them.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tracing by you, shall be licensed as MIT, without any additional terms or conditions.

Comments
  • futures: add support for std::futures::Future

    futures: add support for std::futures::Future

    This PR adds a std::future::Future implementation to Instrumented<T>~~, but with some caveats:~~ ~~- To support async functions, the inner future must be boxed.~~ ~~- If someone can figure out how to support !Unpin futures without boxing, please do so.~~ Thanks hawkw!

    opened by mbilker 31
  • subscriber: add nested spans in json formatter

    subscriber: add nested spans in json formatter

    Fixes: #704

    Motivation

    Nested spans are not available in json formatter

    Solution

    I added a field spans in the json, with an array of the nested spans. I reused the span representation from the existing span, and pushed all the span representation in a vec using ctx.visit_spans. I didn't remove the span field as it can be useful to have direct access to the current span

    opened by mockersf 24
  • Feature/valuable integration

    Feature/valuable integration

    Start the initial integration of Valuable into tracing by adding it to the visit trait, implementing Value for Valuable and seeing if it all works. For further motivation see the tracking issue: #1570

    For my own testing, I have a project with the following main.rs, I grabbed the Person and Address types from a valuable example:

    use valuable::Valuable;
    use tracing::{info, info_span};
    
    #[derive(Valuable)]
    pub struct Person {
        name: String,
        age: u32,
        addresses: Vec<Address>,
    }
    
    #[derive(Valuable)]
    pub struct Address {
        street: String,
        city: String,
        zip: String,
    }
    
    fn blah(value: &(dyn Valuable + 'static)) -> tracing::Span {
        info_span!("span", v=value)
    }
    
    fn blahblah(person: &Person) -> tracing::Span {
        info_span!("span", v=person)
    }
    
    fn main() {
    
        let person = Person {
            name: "Daniel".to_string(),
            age: 28,
            addresses: vec![
                Address {
                    street: "redacted".to_string(),
                    city: "London".to_string(),
                    zip: "redacted".to_string()
                }
            ]
        };
    
        blah(&person);
        blahblah(&person);
    }
    

    Currently blah works, but blahblah has a compilation error which I'm currently trying to resolve but I rarely touch macros in rust so any help would be appreciated:

    error[E0277]: the trait bound `Person: tracing::Value` is not satisfied
      --> src/main.rs:23:5
       |
    23 |     info_span!("span", v=person)
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `tracing::Value` is not implemented for `Person`
       |
       = note: required because of the requirements on the impl of `tracing::Value` for `&Person`
       = note: required for the cast to the object type `dyn tracing::Value`
       = note: this error originates in the macro `$crate::valueset` (in Nightly builds, run with -Z macro-backtrace for more info)
    
    error[E0277]: the trait bound `Person: tracing::Value` is not satisfied
      --> src/main.rs:41:5
       |
    41 |     info_span!("Greeting", person=person);
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `tracing::Value` is not implemented for `Person`
       |
       = note: required for the cast to the object type `dyn tracing::Value`
       = note: this error originates in the macro `$crate::valueset` (in Nightly builds, run with -Z macro-backtrace for more info)
    
    For more information about this error, try `rustc --explain E0277`.
    error: could not compile `tracing-valuable-test` due to 2 previous errors
    
    opened by xd009642 23
  • subscriber: Introduce Registry; Refactor fmt::Subscriber in terms of Registry + Layers

    subscriber: Introduce Registry; Refactor fmt::Subscriber in terms of Registry + Layers

    Motivation

    (Note: this is a clone of https://github.com/tokio-rs/tracing/pull/412 in order to make reviewing the changes as a cohesive whole easier.)

    This branch introduces:

    • A registry build atop of sharded-slab. Layers are expected to consume this registry through the traits SpanData, LookupSpan, and LookupMetadata. Layer-specific dataβ€”such as formatted spans and eventsβ€”are stored in theExtensions typemap. They are writable via the ExtensionsMut view struct of the typemap. This enables layers to read and write data that they are interested in.
    • The tracing_subscriber::fmt::Subscriber has been re-implemented in terms of tracing_subscriber::registry::Registry.
    • The event/field formatters in this module have been modifiedβ€”in a non-backwards compatible wayβ€”to accept a tracing_subscriber::fmt::FmtContext. A similar structure existed in tracing_subscriber::fmt::Subscriber, but it was not previously publicly exposed.

    Examples of composing layers to mimic the tracing_subscriber::fmt::Subscriber are forthcoming, most likely in a followup PR.

    Resolves #135 Resolves #157 Resolves #391

    opened by davidbarsky 22
  • Impl filter for EnvFilter

    Impl filter for EnvFilter

    Fixes #1868 Follow-up on https://github.com/tokio-rs/tracing/pull/1973

    Motivation

    Filtering by span and field requires using EnvFilter. Per-layer filtering requires the Filter trait.

    Solution

    Implement the Filter trait for EnvFilter

    opened by tfreiberg-fastly 20
  • journald: Add integration tests

    journald: Add integration tests

    Per discussion with @hawkw in #1698 I'm adding a few simple integration tests for the journald subscriber, to have some safety net when implementing the actual issue in #1698.

    These tests send messages of various complexity to the journal, and then use journalctl's JSON output to get them back out, to check whether the message arrives in the systemd journal as it was intended to.

    Motivation

    Increase test coverage for the journald subscriber and codify a known good state before approaching a fix for #1698.

    opened by swsnr 20
  • tracing-journald ignores EMSGSIZE from send()

    tracing-journald ignores EMSGSIZE from send()

    Bug Report

    As far as I can see the current implementation of tracing-journal entirely ignores the error returned from .send():

            // What could we possibly do on error?
            #[cfg(unix)]
            let _ = self.socket.send(&buf);
    

    However, according to "Basics" in the systemd protocol documentation socket datagrams are subject to size limits. If a datagram exceeds the message size socket.send will return an EMSGSIZE error. In this case journal clients should write the payload to a sealed memfd instead and send that memfd to journald.

    tracing-journald doesn't, so it may silently loose messages. On my system the limit appears to be about 213Kb according to /proc/sys/net/core/wmem_max; I say "appears" because I'm not entirely sure that this /proc file is definitely relevant. In any case the limit seems to be system-specific so I don't think tracing can generally assume that "reasonably-sized" messages fit into a single datagram. And I don't think tracing should risk loosing messages.

    I can make a pull request (mostly copying from the working impl in libsystemdrs), but memfds aren't in the standard library and require either a lot of unsafe libc code or a nix dependency, so I'm not sure what the proper course of action is here.

    Cheers, Basti

    opened by swsnr 20
  • High CPU usage when misusing spans

    High CPU usage when misusing spans

    Bug Report

    Version

    β”‚       β”œβ”€β”€ tracing v0.1.10
    β”‚       β”‚   β”œβ”€β”€ tracing-attributes v0.1.5
    β”‚       β”‚   └── tracing-core v0.1.7
    β”‚       β”œβ”€β”€ tracing-futures v0.1.1
    β”‚       β”‚   └── tracing v0.1.10 (*)
    β”‚       └── tracing-subscriber v0.1.6
    β”‚           β”œβ”€β”€ tracing-core v0.1.7 (*)
    β”‚           └── tracing-log v0.1.1
    β”‚               └── tracing-core v0.1.7 (*)
    β”‚           └── tracing-log v0.1.1 (*)
    β”‚   β”œβ”€β”€ tracing v0.1.10 (*)
    β”‚   β”œβ”€β”€ tracing-futures v0.1.1 (*)
    β”‚   β”‚   β”œβ”€β”€ tracing v0.1.10 (*)
    β”‚   β”‚   β”œβ”€β”€ tracing-subscriber v0.1.6 (*)
    β”‚   β”œβ”€β”€ tracing v0.1.10 (*)
    β”‚   β”œβ”€β”€ tracing-futures v0.1.1 (*)
    β”‚   β”œβ”€β”€ tracing v0.1.10 (*)
    β”‚   └── tracing-subscriber v0.1.6 (*)
    β”œβ”€β”€ tracing v0.1.10 (*)
    β”œβ”€β”€ tracing-futures v0.1.1 (*)
    β”œβ”€β”€ tracing-subscriber v0.1.6 (*)
        β”œβ”€β”€ tracing v0.1.10 (*)
        β”œβ”€β”€ tracing-futures v0.1.1 (*)
    

    Platform

    Linux linux-box 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 
    

    Description

    Not sure if this is a bug since the API was not used correctly, but since rust has the motto of fearless concurrency, I thought I might report it anyway. Maybe this can be better documented or caught.

    We have a fairly large project that is using tracing internally. I had this very confusing behaviour where the thing would consume 100% CPU on all cores sometimes. Using flamegraph, I have narrowed this down to tracing, and then tracing spans.

    The issue turned out to be that somebody had created a tracing span on a different thread to the thread where the span was entered. I still don't know what exactly happened then, but tracing did not like it at all!

    There was no crash and the program still executed correctly, but all 12 virtual cores were loaded for about a minute.

    Here is the code that caused so much trouble:

        {
            let current = Span::current();
            let span = debug_span!(parent: current, "spawn_mut");
            let (snd, rcv) = oneshot::channel();
            self.sender
                .send(Box::new(move |res| {
                    let _enter = span.enter();
    

    Here is the fix:

        {
            let current = Span::current();
            let (snd, rcv) = oneshot::channel();
            self.sender
                .send(Box::new(move |res| {
                    let span = debug_span!(parent: current, "spawn_mut");
                    let _enter = span.enter();
    

    I attached a flamegraph of the behaviour I saw.

    flamegraph_tracing_100.zip

    Maybe something can be done in code or in documentation to prevent people from running into the same issue.

    Anyway, feel free to close this if you think it is not worth addressing. And thanks for the awesome library!

    crate/subscriber kind/perf 
    opened by rklaehn 19
  • `debug` in `trace` fails to compile with `log` feature enabled

    `debug` in `trace` fails to compile with `log` feature enabled

    Bug Report

    Version

    └── tracing v0.1.16
        β”œβ”€β”€ tracing-attributes v0.1.9
        └── tracing-core v0.1.11
    

    Platform

    Linux snejugal 4.15.0-111-generic #112-Ubuntu SMP Thu Jul 9 20:32:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
    

    Description

    This is the minimal reproducible example:

    use tracing::trace;
    
    fn main() {
        trace!(foo = debug(42));
    }
    

    When tracing is compiled with default features, this code compiled. However, if tracing is compiled with the log feature, it fails to compile:

    error[E0425]: cannot find function `debug` in this scope
     --> src/main.rs:4:18
      |
    4 |     trace!(foo = debug(42));
      |                  ^^^^^ not found in this scope
      |
    help: possible candidate is found in another module, you can import it into scope
      |
    1 | use tracing::field::debug;
      |
    

    This happens because tracing emits a use for tracing::field::debug when logging through itself, but it doesn't when logging through log:

    expanded code
    use tracing::trace;
    fn main() {
        {
            {
                if !::tracing::dispatcher::has_been_set() {
                    {
                        use ::tracing::log;
                        let level = match *&::tracing::Level::TRACE {
                            ::tracing::Level::ERROR => ::tracing::log::Level::Error,
                            ::tracing::Level::WARN => ::tracing::log::Level::Warn,
                            ::tracing::Level::INFO => ::tracing::log::Level::Info,
                            ::tracing::Level::DEBUG => ::tracing::log::Level::Debug,
                            _ => ::tracing::log::Level::Trace,
                        };
                        if level <= log::STATIC_MAX_LEVEL {
                            let log_meta = log::Metadata::builder()
                                .level(level)
                                .target("tracing_bug")
                                .build();
                            let logger = log::logger();
                            if logger.enabled(&log_meta) {
                                logger.log(
                                    &log::Record::builder()
                                        .file(Some("src/main.rs"))
                                        .module_path(Some("tracing_bug"))
                                        .line(Some(4u32))
                                        .metadata(log_meta)
                                        .args({
                                            ::core::fmt::Arguments::new_v1(
                                                &["foo=", " "],
                                                &match (&debug(42),) { // <=========
                                                    (arg0,) => [::core::fmt::ArgumentV1::new(
                                                        arg0,
                                                        ::core::fmt::Debug::fmt,
                                                    )],
                                                },
                                            )
                                        })
                                        .build(),
                                );
                            }
                        }
                    }
                } else {
                    {}
                };
                if ::tracing::dispatcher::has_been_set()
                    && ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                {
                    #[allow(unused_imports)]
                    use ::tracing::{
                        callsite, Event,
                        field::{Value, ValueSet},
                    };
                    use ::tracing::callsite::Callsite;
                    let callsite = {
                        use ::tracing::{callsite, subscriber::Interest, Metadata, __macro_support::*};
                        struct MyCallsite;
                        static META: Metadata<'static> = {
                            ::tracing_core::metadata::Metadata::new(
                                "event src/main.rs:4",
                                "tracing_bug",
                                ::tracing::Level::TRACE,
                                Some("src/main.rs"),
                                Some(4u32),
                                Some("tracing_bug"),
                                ::tracing_core::field::FieldSet::new(
                                    &["foo"],
                                    ::tracing_core::callsite::Identifier(&MyCallsite),
                                ),
                                ::tracing::metadata::Kind::EVENT,
                            )
                        };
                        static INTEREST: AtomicUsize = AtomicUsize::new(0);
                        static REGISTRATION: Once = Once::new();
                        impl MyCallsite {
                            #[inline]
                            fn interest(&self) -> Interest {
                                match INTEREST.load(Ordering::Relaxed) {
                                    0 => Interest::never(),
                                    2 => Interest::always(),
                                    _ => Interest::sometimes(),
                                }
                            }
                        }
                        impl callsite::Callsite for MyCallsite {
                            fn set_interest(&self, interest: Interest) {
                                let interest = match () {
                                    _ if interest.is_never() => 0,
                                    _ if interest.is_always() => 2,
                                    _ => 1,
                                };
                                INTEREST.store(interest, Ordering::SeqCst);
                            }
                            fn metadata(&self) -> &Metadata {
                                &META
                            }
                        }
                        REGISTRATION.call_once(|| {
                            callsite::register(&MyCallsite);
                        });
                        &MyCallsite
                    };
                    if {
                        let interest = callsite.interest();
                        if interest.is_never() {
                            false
                        } else if interest.is_always() {
                            true
                        } else {
                            let meta = callsite.metadata();
                            ::tracing::is_enabled(meta)
                        }
                    } {
                        let meta = callsite.metadata();
                        Event::dispatch(meta, &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value}; // <=========
                            let mut iter = meta.fields().iter();
                            meta.fields().value_set(&[(
                                &iter.next().expect("FieldSet corrupted (this is a bug)"),
                                Some(&debug(42) as &Value), // <=========
                            )])
                        });
                    }
                }
            }
        };
    }
    

    This actually broke my crate tbot, for which today I had to release a new version adding the needed use. It compiled just fine until hyper and h2, which tbot depends on, switched from log to tracing with the log feature enabled in their latest releases.

    kind/bug crate/tracing 
    opened by SnejUgal 18
  • Instrument attribute with async-trait breaks include_str

    Instrument attribute with async-trait breaks include_str

    Bug Report

    Version

    tracing v0.1.15 tracing-futures v0.2.4

    Platform

    Windows (64-bit)

    Crates

    async-trait v0.1.35

    Description

    When adding #[tracing::instrument] to a function in a #[async_trait::async_trait] trait implementation, include_str will think its in the root of the src folder when its not.

    File tree:

    src/
    +-- lib.rs
    +-- example/
        +-- mod.rs
        +-- text.txt
    

    lib.rs:

    mod example;
    
    #[async_trait::async_trait]
    pub trait Test {
        async fn example(&self);
    }
    

    mod.rs:

    use crate::Test;
    
    #[derive(Debug)]
    pub struct Example {}
    
    
    #[async_trait::async_trait]
    impl Test for Example {
        #[tracing::instrument]
        async fn example(&self) {
            let _text = include_str!("text.txt");
        }
    }
    
    closed/wontfix crate/attributes 
    opened by Txuritan 18
  • Q: How can I have multiple fmt writers with different level?

    Q: How can I have multiple fmt writers with different level?

    I'm trying to migrate from simplelog to tracing, however I have a very special case: I have three writers, different level each (In the real case actually they are three different files).

    In my first attempt, I tried to combine multiple fmt::Layer with Registry:

    use tracing::{debug, info, info_span, trace, trace_span, warn};
    use tracing_subscriber::fmt;
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::Registry;
    
    fn main() {
        let logger = Registry::default()
            .with(fmt::Layer::default())
            .with(fmt::Layer::default())
            .with(fmt::Layer::default());
    
        tracing::subscriber::set_global_default(logger).unwrap();
    
        let x = 1;
        let span = info_span!("info", x);
        let _guard = span.enter();
    
        let y = 2;
        let span = trace_span!("trace", y);
        let _guard = span.enter();
    
        info!("ABC");
        warn!("DEF");
        debug!("1234");
        trace!("5678");
    }
    

    And the output is:

    Feb 22 23:29:02.783  INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
    Feb 22 23:29:02.783  INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
    Feb 22 23:29:02.783  INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
    Feb 22 23:29:02.783  WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
    Feb 22 23:29:02.783  WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
    Feb 22 23:29:02.783  WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
    Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
    Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
    Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
    Feb 22 23:29:02.783 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
    Feb 22 23:29:02.784 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
    Feb 22 23:29:02.784 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
    

    With this approach the I found two issues:

    1. I couldn't apply level filter in the layers
    2. Notice the duplication: x=1x=1x=1 and y=2y=2y=2.

    My final approach is:

    use tracing::{
        debug, info, info_span, metadata::Level, span, trace, trace_span, warn, Event, Subscriber,
    };
    use tracing_subscriber::fmt;
    use tracing_subscriber::layer::{Context, Layer, SubscriberExt};
    use tracing_subscriber::registry::LookupSpan;
    use tracing_subscriber::Registry;
    
    fn main() {
        let logger = Registry::default()
            .with(fmt::Layer::default())
            .with(FmtWriterLayer::new(Level::DEBUG))
            .with(FmtWriterLayer::new(Level::INFO));
    
        tracing::subscriber::set_global_default(logger).unwrap();
    
        let x = 1;
        let span = info_span!("info", x);
        let _guard = span.enter();
    
        let y = 2;
        let span = trace_span!("trace", y);
        let _guard = span.enter();
    
        info!("ABC");
        warn!("DEF");
        debug!("1234");
        trace!("5678");
    }
    
    struct FmtWriterLayer<S>
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        layer: fmt::Layer<S>,
        level: Level,
    }
    
    impl<S> FmtWriterLayer<S>
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn new(level: Level) -> FmtWriterLayer<S> {
            let layer = fmt::Layer::default();
    
            FmtWriterLayer {
                layer,
                level,
            }
        }
    }
    
    impl<S> Layer<S> for FmtWriterLayer<S>
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn new_span(&self, _attrs: &span::Attributes, _id: &span::Id, _ctx: Context<S>) {
            // intentionally not implemented
        }
    
        fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
            self.layer.on_record(id, values, ctx);
        }
    
        fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
            if *event.metadata().level() <= self.level {
                self.layer.on_event(event, ctx);
            }
        }
    }
    

    And the output is:

    Feb 22 23:34:34.345  INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
    Feb 22 23:34:34.345  INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
    Feb 22 23:34:34.345  INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
    Feb 22 23:34:34.345  WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
    Feb 22 23:34:34.346  WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
    Feb 22 23:34:34.346  WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
    Feb 22 23:34:34.346 DEBUG info{x=1}:trace{y=2}: tracing_multifmt: 1234
    Feb 22 23:34:34.346 DEBUG info{x=1}:trace{y=2}: tracing_multifmt: 1234
    Feb 22 23:34:34.346 TRACE info{x=1}:trace{y=2}: tracing_multifmt: 5678
    

    This is almost what I expect, however one small issue is that trace span is printed in all levels.

    So, some questions:

    1. Is this a missing feature? Or is there another way?
    2. In case of missing feature, how would you like to be added? I was thinking that add_writer_with_level could be implemented in fmt::Subscriber. What are your thoughts? Do you have any suggestion?
    opened by oblique 18
  • `SIGSEGV: invalid memory reference` while compiling `tracing-subscriber`

    `SIGSEGV: invalid memory reference` while compiling `tracing-subscriber`

    Bug Report

    Version

    β”‚       β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ tracing v0.1.37
    β”‚       β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ tracing-attributes v0.1.23 (proc-macro)
    β”‚       β”‚   β”‚   β”‚   β”‚   β”‚   └── tracing-core v0.1.30
    β”‚       β”‚   β”‚   β”œβ”€β”€ tracing v0.1.37 (*)
    β”‚       β”‚   β”‚   β”œβ”€β”€ tracing-log v0.1.3
    β”‚       β”‚   β”‚   β”‚   └── tracing-core v0.1.30 (*)
    β”‚       β”‚   β”‚   └── tracing-subscriber v0.3.16
    β”‚       β”‚   β”‚       β”œβ”€β”€ tracing v0.1.37 (*)
    β”‚       β”‚   β”‚       β”œβ”€β”€ tracing-core v0.1.30 (*)
    β”‚       β”‚   β”‚       └── tracing-log v0.1.3 (*)
    

    Platform

    Darwin {redacted} 22.1.0 Darwin Kernel Version 22.1.0: Sun Oct 9 20:15:09 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T6000 arm64

    Compiling for wasm32-unknown-unknown with target feature multivalue enabled.

    Crates

    tracing-subscriber is producing this error.

    Description

    I'm creating a WASM application that uses the multivalue target feature. When compiling, tracing-subscriber produces the following SIGSEGV: invalid memory reference error:

    (Full paths redacted)

    error: could not compile `tracing-subscriber`
    
    Caused by:
      process didn't exit successfully: `rustc --crate-name tracing_subscriber --edition=2018 ~/.cargo/registry/src/github.com-1ecc6299db9ec823/tracing-subscriber-0.3.16/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type lib --emit=dep-info,metadata,link -C opt-level=s -C debuginfo=2 --cfg 'feature="alloc"' --cfg 'feature="ansi"' --cfg 'feature="default"' --cfg 'feature="env-filter"' --cfg 'feature="fmt"' --cfg 'feature="matchers"' --cfg 'feature="nu-ansi-term"' --cfg 'feature="once_cell"' --cfg 'feature="regex"' --cfg 'feature="registry"' --cfg 'feature="sharded-slab"' --cfg 'feature="smallvec"' --cfg 'feature="std"' --cfg 'feature="thread_local"' --cfg 'feature="tracing"' --cfg 'feature="tracing-log"' -C metadata=02605d0ede20c651 -C extra-filename=-02605d0ede20c651 --out-dir ~/target/wasm32-unknown-unknown/release/deps --target wasm32-unknown-unknown -L dependency=~/target/wasm32-unknown-unknown/release/deps -L dependency=~/target/release/deps --extern matchers=~/target/wasm32-unknown-unknown/release/deps/libmatchers-dc0ddd50c7d0fc8f.rmeta --extern nu_ansi_term=~/target/wasm32-unknown-unknown/release/deps/libnu_ansi_term-c5ae853e62481cf8.rmeta --extern once_cell=~/target/wasm32-unknown-unknown/release/deps/libonce_cell-01d0832a0b14f221.rmeta --extern regex=~/target/wasm32-unknown-unknown/release/deps/libregex-7f99960d22a617e7.rmeta --extern sharded_slab=~/target/wasm32-unknown-unknown/release/deps/libsharded_slab-785ee352d047c9c9.rmeta --extern smallvec=~/target/wasm32-unknown-unknown/release/deps/libsmallvec-91a7fecc3a6eebd0.rmeta --extern thread_local=~/target/wasm32-unknown-unknown/release/deps/libthread_local-e2a2e1cb190f0957.rmeta --extern tracing=~/target/wasm32-unknown-unknown/release/deps/libtracing-57fd79ba846a5aef.rmeta --extern tracing_core=~/target/wasm32-unknown-unknown/release/deps/libtracing_core-e5bb5a705add1bec.rmeta --extern tracing_log=~/target/wasm32-unknown-unknown/release/deps/libtracing_log-59f9420371ceb5cd.rmeta --cap-lints allow -C 'link-args=--export-table --export=__stack_pointer' -C target-feature=+mutable-globals -C target-feature=+multivalue` (signal: 11, SIGSEGV: invalid memory reference)
    

    This bug only occurs if the multivalue feature is enabled.

    opened by grilme99 5
  • [tracing_error] Improvement to `SpanTrace::with_span()`

    [tracing_error] Improvement to `SpanTrace::with_span()`

    Feature Request

    The current implementation of with_span() passes in a string containing the formatted equivalent of all the fields, concatenated together. I propose this is changed to pass in the fields as a key/value pair, either as references to the original tracing::Value structs, or at minimum a &str representation of each field/value.

    Motivation

    The current behaviour is: field_a=564 field_b=asdf test=" This is a test=true string with quoutes and a type-o" /*let's pretend we should have a field 'null' but it's Empty */

    If I want to do something with these values, I am forced to parse the string, using the Metadata of the span, to extract the fields and their values (which may not even exist). This is a real pain, and the fact that fields can be missing (tracing::field::Empty), or even recorded multiple times (in which case you have field=one field=two field=three in the resultant string), makes it even worse. I don't think this is a good API for users and so I'd like to propose a change to make it a lot easier

    Proposal

    Instead of passing in a single concat'ed &str, we pass in a key/value pair for each field. Ideally, I think it would be best to pass in the object value (tracing::Value), but this might be too diffucult to implement so it would also be fine to pass in the formatted object value (&str).

    We would change the closure to |metadat: &'static Metadata<'static>, fields: Vec<(&str, &dyn Value)>|, or whatever similar type would work best internally.

    I think the change would need to be made in tracing_error::fmt::fmt_layer::FormattedFields, since that's where they are stored. Unfortunately I'm not familiar with the codebase and debugging hasn't helped much, so I don't really have any concrete changes.

    Alternatives

    Mine (yuck)

    My current approach is to find the fields that each span should have in the metadata, and then parse the formatted string that with_span passes to the closure. I really don't like doing this:

    • It's ugly as hell, and is really hard to make sense of
    • It doesn't work quite often; doesn't handle missing (Empty) fields well and can get strings confused
    • It's slow and inefficient - the fields are formatted into a string just so I can parse the string and pull them out again

    This is my current code (ignore the ui.XXX lines, that's ImGUI):

    let fields = metadata.fields();
    if fields.is_empty(){
        ui.text_disabled("<None>");
    }
    else{
        // List of names of each field
        let names = metadata.fields().iter().map(|f| f.name()).collect_vec();
        // Substring of the formatted span fields
        let mut fields_substr = formatted_span_fields;
        // Loop over in twos; the current field and the next one
        for pair in names.windows(2){
            let (curr_name, next_name) = (pair[0], pair[1]);
            // Check it starts with our current field
            if fields_substr.find(curr_name) != Some(0){
                // warn!(target: GENERAL_WARNING_NON_FATAL, ?fields_substr, ?curr_name, "substring did not begin with current field");
                ui.text_colored(colours.value.tracing_event_field_name, curr_name);
                ui.same_line();
                ui.text_colored(colours.text.normal, "=");
                ui.same_line();
                ui.text_disabled("<Missing>");
                break;
            }
            // Remove the current name, and the equals sign (+1).
            fields_substr = &fields_substr[(curr_name.len()+1)..];
            //Now find where the next field starts in the string
            let next_field_match = format!(" {next_name}=");
            let next_field_index:usize = match fields_substr.find(&next_field_match){
                Some(idx) => idx,
                None => {
                    // warn!(target: GENERAL_WARNING_NON_FATAL, ?fields_substr, ?curr_name, "could not find index of next field");
                    ui.text_colored(colours.value.tracing_event_field_name, curr_name);
                    ui.same_line();
                    ui.text_colored(colours.text.normal, "=");
                    ui.same_line();
                    ui.text_disabled("<Parse Error>");
                    break;
                }
            };
    
            // Now we know the current field starts at [0], and we know where the next field starts, so extract that portion of the string
            // And we have our current value
            // We don't want to include the first char of the next field, so we use a non-inclusive range
            let current_value = &fields_substr[0..next_field_index];
    
            // Now substring again so we are ready for the next iteration. +1 removes the spacing between fields
            fields_substr = &fields_substr[next_field_index + 1..];
    
            // And now display it
            ui.text_colored(colours.value.tracing_event_field_name, curr_name);
            ui.same_line();
            ui.text_colored(colours.text.normal, "=");
            ui.same_line();
            ui.text_colored(colours.value.tracing_event_field_value, current_value);
            ui.same_line();
            }
    
            // Now since [].windows(2) doesn't include the last value, we have to handle that one on it's own
            // The string should be the same if there's 1 field (no for loop called) or if there are >1
            //field_name=value
            // Check it starts with our current field
            let last_name = names.last().expect("we should always have at least 1 field name if we got here");
            if fields_substr.find(last_name) != Some(0){
                ui.text_colored(colours.value.tracing_event_field_name, last_name);
                ui.same_line();
                ui.text_colored(colours.text.normal, "=");
                ui.same_line();
                ui.text_disabled("<Missing>");
            }
            else{
                // Remove the current name, and the equals sign (+1).
                // This should leave us with just the field value (since it is the only field left in the substring)
                fields_substr = &fields_substr[(last_name.len() + 1)..];
                let last_value  = fields_substr;
    
                // And now display it
                ui.text_colored(colours.value.tracing_event_field_name, last_name);
                ui.same_line();
                ui.text_colored(colours.text.normal, "=");
                ui.same_line();
                ui.text_colored(colours.value.tracing_event_field_value, last_value);
            }
            ui.text(formatted_span_fields);
        }
    

    I really don't reccommend this approach, at all.

    We really can't change the parameters

    If the function's parameter API is really important and can't be changed (so the closure must receive a single &str), it would be nice to have it in some sort of easier to parse format, like JSON or even just each field on a new line.

    opened by Ararem 1
  • Support #[track_caller] for Event file name and line number

    Support #[track_caller] for Event file name and line number

    Feature Request

    Crates

    tracing

    Motivation

    We want to ignore utility functions when creating tracing events. i.e. both do_x_in_service_a() and do_y_in_service_a() currently end up with error events in service_error.rs line x handle_service_a_error()

    Proposal

    Instead of using the file!() and line!() macros the core::panic::Location struct should be used to determine the callsite of the event!(...) macro as it takes the #[track_caller] attribute into account.

    Alternatives

    let users of the event!(...) macro and associated macros pass in a file and line number so that it can be adjusted to the desired values.

    opened by TitanNano 0
  • mock: document public APIs in `event` module

    mock: document public APIs in `event` module

    Motivation

    There has been interest around publishing tracing-mock to crates.io for some time. In order to make this possible, documentation and some code clean up is needed.

    The event module needs documentation and examples.

    Solution

    This change adds documentation to the event module and all the public APIs within it. This includes doctests on all the methods which serve as examples.

    Some small API changes are also included

    The methods with_explicit_parent and with_contextual_parent have had the negative case moved into separate methods without_explicit_parent and without_contextual_parent respectively. This removes the need for an Option around the parameter in the original methods - which are likely to be the most used case (the 'without' case where None would have been passed before is not used anywhere in this workspace).

    The method in_scope has been placed behind the tracing-subscriber feature flag as it currently only works with the MockSubscriber, not with the MockCollector. If the feature flag is active and it is used to set a non-empty scope, the MockCollector will panic with unimplemented during validation.

    Refs: #539

    opened by hds 1
  • journald: add support for specifying syslog facility

    journald: add support for specifying syslog facility

    Motivation

    Syslog facility is supported in JournalD this allows using that mechanism. This way JournalD can provide same fields as syslog messages: Syslog identifier and facility.

    Solution

    The Syslog facility is optional and if it is not specified, it is not included in JournalD message. The SyslogFacility enum contains all the fields specified in syslog(3) for facility and numbers are mapped using libc's definition.

    I couldn't find why I needed to bitshift (line 466) the libc's facility values right to get the proper result, but this worked for me.

    opened by oherrala 1
  • Tracing logs created from C++ callback are not captured by test despite using TestWriter

    Tracing logs created from C++ callback are not captured by test despite using TestWriter

    Bug Report

    Version

    rukai@memes foo$ cargo tree | grep tracing
    β”œβ”€β”€ tracing v0.1.37
    β”‚   β”œβ”€β”€ tracing-attributes v0.1.23 (proc-macro)
    β”‚   └── tracing-core v0.1.30
    └── tracing-subscriber v0.3.16
        β”œβ”€β”€ tracing v0.1.37 (*)
        β”œβ”€β”€ tracing-core v0.1.30 (*)
        └── tracing-log v0.1.3
            └── tracing-core v0.1.30 (*)
    

    Platform

    rukai@memes ~$ uname -a
    Linux memes 6.0.12-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 08 Dec 2022 11:03:38 +0000 x86_64 GNU/Linux
    

    Description

    Tracing logs created from C++ callback are not captured by test despite using TestWriter

    I tried this code:

    use cassandra_cpp::Cluster;
    use tracing_subscriber::fmt::TestWriter;
    
    #[test]
    fn foo() {
        tracing_subscriber::fmt()
            .with_writer(TestWriter::new())
            .with_env_filter("warn")
            .try_init()
            .ok();
    
        // This directs cassandra_cpp logs to be logged by the logging crate, tracing picks up logs from the log crate by default
        // Internally a rust callback is passed to the c++ cassandra library
        cassandra_cpp::set_log_logger();
        log::error!("This is captured by the test");
        // This creates an error that is not captured by the test, it goes directly to output.
        // But I can tell its going through tracing because its in the tracing format and removing the tracing init stops the log from being printed
        Cluster::default()
            // there is no database here which results in an error log
            .set_contact_points("127.0.0.1")
            .unwrap()
            .connect()
            .ok();
    }
    
    [dependencies]
    backtrace = "0.3.66"
    cassandra-cpp = "1.2.0"
    log = "0.4.17"
    tracing = "0.1.37"
    tracing-subscriber = { version = "0.3.1", features = ["env-filter"] }
    

    I expected to see this happen: All tracing logs are captured by the test

    Instead, this happened: Only the tracing log created by log::error is captured. The tracing log created by the cassandra_cpp callback is not captured

    Sorry

    Setting up the cassandra_cpp library is a complete pain. If you really really want to, I've used https://aur.archlinux.org/packages/cassandra-cpp-driver on arch, or otherwise there is this script to compile and package the driver on ubuntu https://github.com/Metaswitch/cassandra-rs/blob/main/scripts/install_ubuntu_packages.sh

    But I also dont expect anyone to actually do that.

    Hopefully someone can just be like "oh yeah that'll happen if you try to callback from C++" or something. If thats not the case then I can try and learn enough about C++/FFI to make a minimal reproduction of the issue.

    opened by rukai 1
Releases(tracing-subscriber-0.3.16)
  • tracing-subscriber-0.3.16(Oct 6, 2022)

    This release of tracing-subscriber fixes a regression introduced in v0.3.15 where Option::None's Layer implementation would set the max level hint to OFF. In addition, it adds several new APIs, including the Filter::event_enabled method for filtering events based on fields values, and the ability to log internal errors that occur when writing a log line.

    This release also replaces the dependency on the unmaintained [ansi-term] crate with the [nu-ansi-term] crate, resolving an informational security advisory (RUSTSEC-2021-0139) for [ansi-term]'s maintainance status. This increases the minimum supported Rust version (MSRV) to Rust 1.50+, although the crate should still compile for the previous MSRV of Rust 1.49+ when the ansi feature is not enabled.

    Fixed

    • layer: Option::None's Layer impl always setting the max_level_hint to LevelFilter::OFF (#2321)
    • Compilation with -Z minimal versions (#2246)
    • env-filter: Clarify that disabled level warnings are emitted by tracing-subscriber (#2285)

    Added

    • fmt: Log internal errors to stderr if writing a log line fails (#2102)
    • fmt: FmtLayer::log_internal_errors and FmtSubscriber::log_internal_errors methods for configuring whether internal writer errors are printed to stderr (#2102)
    • fmt: #[must_use] attributes on builders to warn if a Subscriber is configured but not set as the default subscriber (#2239)
    • filter: Filter::event_enabled method for filtering an event based on its fields (#2245, #2251)
    • filter: Targets::default_level accessor ([#2242])

    Changed

    • ansi: Replaced dependency on unmaintained ansi-term crate with nu-ansi-term ((#2287, fixes informational advisory RUSTSEC-2021-0139)
    • tracing-core: updated to 0.1.30
    • Minimum Supported Rust Version (MSRV) increased to Rust 1.50+ (when the ansi) feature flag is enabled (#2287)

    Documented

    • fmt: Correct inaccuracies in fmt::init documentation (#2224)
    • filter: Fix incorrect doc link in filter::Not combinator (#2249)

    Thanks to new contributors @cgbur, @DesmondWillowbrook, @RalfJung, and @poliorcetics, as well as returning contributors @CAD97, @connec, @jswrenn, @guswynn, and @bryangarza, for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.30(Oct 6, 2022)

    This release of tracing-core adds a new on_register_dispatch method to the Subscriber trait to allow the Subscriber to perform initialization after being registered as a Dispatch, and a WeakDispatch type to allow a Subscriber to store its own Dispatch without creating reference count cycles.

    Added

    • Subscriber::on_register_dispatch method (#2269)
    • WeakDispatch type and Dispatch::downgrade() function (#2293)

    Thanks to @jswrenn for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-attributes-0.1.23(Oct 6, 2022)

    This release of tracing-attributes fixes a bug where compiler diagnostic spans for type errors in #[instrument]ed async fns have the location of the #[instrument] attribute rather than the location of the actual error, and a bug where inner attributes in #[instrument]ed functions would cause a compiler error.

    Fixed

    • Fix incorrect handling of inner attributes in #[instrument]ed functions (#2307)
    • Add fake return to improve spans generated for type errors in async fns (#2270)
    • Updated syn dependency to fix compilation with -Z minimal-versions (#2246)

    Thanks to new contributors @compiler-errors and @e-nomem, as well as @CAD97, for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-0.1.37(Oct 6, 2022)

    This release of tracing incorporates changes from tracing-core v0.1.30 and tracing-attributes v0.1.23, including the new Subscriber::on_register_dispatch method for performing late initialization after a Subscriber is registered as a Dispatch, and bugfixes for the #[instrument] attribute. Additionally, it fixes instances of the bare_trait_objects lint, which is now a warning on tracing's MSRV and will become an error in the next edition.

    Fixed

    • attributes: Incorrect handling of inner attributes in #[instrument]ed functions (#2307)
    • attributes: Incorrect location of compiler diagnostic spans generated for type errors in #[instrument]ed async fns (#2270)
    • attributes: Updated syn dependency to fix compilation with -Z minimal-versions (#2246)
    • bare_trait_objects warning in valueset! macro expansion (#2308)

    Added

    • core: Subscriber::on_register_dispatch method (#2269)
    • core: WeakDispatch type and Dispatch::downgrade() function (#2293)

    Changed

    • tracing-core: updated to 0.1.30
    • tracing-attributes: updated to 0.1.23

    Documented

    Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder, @Xiami2012, and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97, for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-opentelemetry-0.18.0(Sep 19, 2022)

  • tracing-core-0.1.29(Jul 29, 2022)

    This release of tracing-core adds PartialEq and Eq implementations for metadata types, and improves error messages when setting the global default subscriber fails.

    Added

    • PartialEq and Eq implementations for Metadata (#2229)
    • PartialEq and Eq implementations for FieldSet (#2229)

    Fixed

    • Fixed unhelpful fmt::Debug output for dispatcher::SetGlobalDefaultError (#2250)
    • Fixed compilation with -Z minimal-versions (#2246)

    Thanks to @jswrenn and @CAD97 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-0.1.36(Jul 29, 2022)

    This release adds support for owned values and fat pointers as arguments to the Span::record method, as well as updating the minimum tracing-core version and several documentation improvements.

    Fixed

    • Incorrect docs in dispatcher::set_default (#2220)
    • Compilation with -Z minimal-versions (#2246)

    Added

    • Support for owned values and fat pointers in Span::record (#2212)
    • Documentation improvements (#2208, #2163)

    Changed

    • tracing-core: updated to 0.1.29

    Thanks to @fredr, @cgbur, @jyn514, @matklad, and @CAD97 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.15(Jul 20, 2022)

    This release fixes a bug where the reload layer would fail to pass through max_level_hint to the underlying layer, potentially breaking filtering.

    Fixed

    • reload: pass through max_level_hint to the inner Layer (#2204)

    Thanks to @guswynn for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.14(Jul 1, 2022)

    This release fixes multiple filtering bugs in the Layer implementations for Option<impl Layer> and Vec<impl Layer>.

    Fixed

    • layer: Layer::event_enabled implementation for Option<impl Layer<S>> returning false when the Option is None, disabling all events globally (#2193)
    • layer: Layer::max_level_hint implementation for Option<impl Layer<S>> incorrectly disabling max level filtering when the option is None (#2195)
    • layer: Layer::max_level_hint implementation for Vec<impl Layer<S>> returning LevelFilter::ERROR rather than LevelFilter::OFF when the Vec is empty (#2195)

    Thanks to @CAD97 and @guswynn for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-opentelemetry-0.17.4(Jul 1, 2022)

    This release adds optional support for recording std::error::Errors using [OpenTelemetry's semantic conventions for exceptions][exn-semconv].

    Added

    • Layer::with_exception_fields to enable emitting exception.message and exception.backtrace semantic-convention fields when an Error is recorded as a span or event field (#2135)
    • Layer::with_exception_field_propagation to enable setting exception.message and exception.backtrace semantic-convention fields on the current span when an event with an Error field is recorded (#2135)

    Thanks to @lilymara-onesignal for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-attributes-0.1.22(Jul 1, 2022)

    This release fixes an issue where using the err or ret arguments to #[instrument] along with an overridden target, such as

    #[instrument(target = "...", err, ret)]
    

    would not propagate the overridden target to the events generated for errors/return values.

    Fixed

    • Error and return value events generated by #[instrument(err)] or #[instrument(ret)] not inheriting an overridden target (#2184)
    • Incorrect default level in documentation (#2119)

    Thanks to new contributor @tbraun96 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.13(Jun 30, 2022)

    This release of tracing-subscriber fixes a compilation failure due to an incorrect tracing-core dependency that was introduced in v0.3.12.

    Changed

    • tracing_core: Updated minimum dependency version to 0.1.28 (#2190)
    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.12(Jun 29, 2022)

    This release of tracing-subscriber adds a new Layer::event_enabled method, which allows Layers to filter events after their field values are recorded; a Filter implementation for reload::Layer, to make using reload with per-layer filtering more ergonomic, and additional inherent method downcasting APIs for the Layered type. In addition, it includes dependency updates, and minor fixes for documentation and feature flagging.

    Added

    • layer: Layer::event_enabled method, which can be implemented to filter events based on their field values (#2008)
    • reload: Filter implementation for reload::Layer (#2159)
    • layer: Layered::downcast_ref and Layered::is inherent methods (#2160)

    Changed

    • parking_lot: Updated dependency on parking_lot to 0.13.0 (#2143)
    • Replaced lazy_static dependency with once_cell ([#2147])

    Fixed

    • Don't enable tracing-core features by default (#2107)
    • Several documentation link and typo fixes (#2064, #2068, #[2077], #2161, #1088)

    Thanks to @ben0x539, @jamesmunns, @georgemp, @james7132, @jswrenn, @CAD97, and @guswynn for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.28(Jun 24, 2022)

    This release of tracing-core adds new Value implementations, including one for String, to allow recording &String as a value without having to call as_str() or similar, and for 128-bit integers (i128 and u128). In addition, it adds new methods and trait implementations for Subscribers.

    Added

    • Value implementation for String (#2164)
    • Value implementation for u128 and i28 (#2166)
    • downcast_ref and is methods for dyn Subscriber + Sync, dyn Subscriber + Send, and dyn Subscriber + Send + Sync (#2160)
    • Subscriber::event_enabled method to enable filtering based on Event field values (#2008)
    • Subscriber implementation for Box<S: Subscriber + ?Sized> and Arc<S: Subscriber + ?Sized> (#2161)

    Thanks to @jswrenn and @CAD97 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-0.1.35(Jun 8, 2022)

    This release reduces the overhead of callsite registration by using new tracing-core APIs.

    Added

    • Use DefaultCallsite to reduce callsite registration overhead (#2083)

    Changed

    • tracing-core: updated to 0.1.27
    Source code(tar.gz)
    Source code(zip)
  • tracing-opentelemetry-0.17.3(Jun 7, 2022)

    This release adds support for emitting thread names and IDs to OpenTelemetry, as well as recording std::error::Error values in a structured manner with their source chain included. Additionally, this release fixes issues related to event and span source code locations.

    Added

    • Layer::with_threads to enable recording thread names/IDs according to OpenTelemetry semantic conventions (#2134)
    • Error::source chain when recording std::error::Error values (#2122)
    • Layer::with_location method (replaces Layer::with_event_location) (#2124)

    Changed

    • std::error::Error values are now recorded using fmt::Display rather than fmt::Debug (#2122)

    Fixed

    • Fixed event source code locations overwriting the parent span's source location (#2099)
    • Fixed Layer::with_event_location not controlling whether locations are emitted for spans as well as events (#2124)

    Deprecated

    • Layer::with_event_location: renamed to Layer::with_location, as it now controls both span and event locations (#2124)

    Thanks to new contributors @lilymara-onesignal, @hubertbudzynski, and @DevinCarr for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.27(Jun 7, 2022)

    This release of tracing-core introduces a new DefaultCallsite type, which can be used by instrumentation crates rather than implementing their own callsite types. Using DefaultCallsite may offer reduced overhead from callsite registration.

    Added

    • DefaultCallsite, a pre-written Callsite implementation for use in instrumentation crates (#2083)
    • ValueSet::len and Record::len methods returning the number of fields in a ValueSet or Record (#2152)

    Changed

    • Replaced lazy_static dependency with once_cell (#2147)

    Documented

    • Added documentation to the callsite module (#2088, #2149)

    Thanks to new contributors @jamesmunns and @james7132 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-attributes-0.1.21(Apr 27, 2022)

    This release adds support for setting explicit parent and follows-from spans in the #[instrument] attribute.

    Added

    • #[instrument(follows_from = ...)] argument for setting one or more follows-from span (#2093)
    • #[instrument(parent = ...)] argument for overriding the generated span's parent (#2091)

    Fixed

    • Extra braces around async blocks in expanded code (causes a Clippy warning) (#2090)
    • Broken documentation links (#2068, #2077)

    Thanks to @jarrodldavis, @ben0x539, and new contributor @jswrenn for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-log-0.1.3(Apr 21, 2022)

    Added

    • log-tracer: Added LogTracer::with_interest_cache to enable a limited form of per-record Interest caching for log records (#1636)

    Changed

    • Updated minimum supported Rust version (MSRV) to Rust 1.49.0 (#1913)

    Fixed

    • log-tracer: Fixed LogTracer not honoring tracing max level filters (#1543)
    • Broken links in documentation (#2068, #2077)

    Thanks to @Millione, @teozkr, @koute, @Folyd, and @ben0x539 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-journald-0.3.0(Apr 21, 2022)

    This is a breaking release which changes the format in which span fields are output to journald. Previously, span field names were prefixed with the depth of the span in the current trace tree. However, these prefixes are unnecessary, as journald has built in support for duplicated field names.

    See PR #1986 for details on this change.

    Changed

    • Removed span field prefixes (#1986)
    • Renamed S{num}_NAME fields to SPAN_NAME (#1986)

    Fixed

    • Fixed broken links in documentation (#2077)

    Thanks to @wiktorsikora and @ben0x539 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.26(Apr 14, 2022)

    This release adds a Value implementation for Box<T: Value> to allow recording boxed values more conveniently. In particular, this should improve the ergonomics of the implementations for dyn std::error::Error trait objects, including those added in v0.1.25.

    Added

    • Value implementation for Box<T> where T: Value (#2071)

    Fixed

    • Broken documentation links (#2068)

    Thanks to new contributor @ben0x539 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-0.1.34(Apr 14, 2022)

    This release includes bug fixes for the "log" support feature and for the use of both scoped and global default dispatchers in the same program.

    Fixed

    • Failure to use the global default dispatcher when a thread sets a local default dispatcher before the global default is set (#2065)
    • log: Compilation errors due to async block/fn futures becoming !Send when the "log" feature flag is enabled (#2073)
    • Broken links in documentation (#2068)

    Thanks to @ben0x539 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.25(Apr 12, 2022)

    This release adds additional Value implementations for std::error::Error trait objects with auto trait bounds (Send and Sync), as Rust will not auto-coerce trait objects. Additionally, it fixes a bug when setting scoped dispatchers that was introduced in the previous release (v0.1.24).

    Added

    • Value implementations for dyn Error + Send + 'static, dyn Error + Send + Sync + 'static, dyn Error + Sync + 'static (#2066)

    Fixed

    • Failure to use the global default dispatcher if a thread has set a scoped default prior to setting the global default, and unset the scoped default after setting the global default (#2065)

    Thanks to @lilyball for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.11(Apr 9, 2022)

    This is a bugfix release for the Filter implementation for EnvFilter added in v0.3.10.

    Fixed

    • env-filter: Added missing Filter::on_record callback to EnvFilter's Filter impl (#2058)
    • env-filter: Fixed method resolution issues when calling EnvFilter methods with both the Filter and Layer traits in scope (#2057)
    • env-filter: Fixed EnvFilter::builder().parse() and other parsing methods returning an error when parsing an empty string (#2052)

    Thanks to new contributor @Ma124 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-0.1.33(Apr 9, 2022)

    This release adds new span_enabled! and event_enabled! variants of the enabled! macro, for testing whether a subscriber would specifically enable a span or an event.

    Added

    • span_enabled! and event_enabled! macros (#1900)
    • Several documentation improvements (#2010, #2012)

    Fixed

    • Compilation warning when compiling for <=32-bit targets (including wasm32) (#2060)

    Thanks to @guswynn, @arifd, @hrxi, @CAD97, and @name1e5s for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-subscriber-0.3.10(Apr 1, 2022)

    This release adds several new features, including a Filter implementation and new builder API for EnvFilter, support for using a Vec<L> where L: Layer as a Layer, and a number of smaller API improvements to make working with dynamic and reloadable layers easier.

    Added

    • registry: Implement Filter for EnvFilter, allowing it to be used with per-layer filtering (#1983)
    • registry: Filter::on_new_span, Filter::on_enter, Filter::on_exit, Filter::on_close and Filter::on_record callbacks to allow Filters to track span states internally (#1973, #2017, #2031)
    • registry: Filtered::filter and Filtered::filter_mut accessors (#1959)
    • registry: Filtered::inner and Filtered::inner_mut accessors to borrow the wrapped Layer (#2034)
    • layer: Implement Layer for Vec<L: Layer>, to allow composing together a dynamically sized list of Layers (#2027)
    • layer: Layer::boxed method to make type-erasing Layers easier (#2026)
    • fmt: fmt::Layer::writer and fmt::Layer::writer_mut accessors (#2034)
    • fmt: fmt::Layer::set_ansi method to allow changing the ANSI formatting configuration at runtime (#2034)
    • env-filter: EnvFilter::builder to configure a new EnvFilter prior to parsing it (#2035)
    • Several documentation fixes and improvements (#1972, #1971, #2023, #2023)

    Fixed

    • fmt: fmt::Layer's auto traits no longer depend on the Subscriber type parameter's auto traits (#2025)
    • env-filter: Fixed missing help text when the ansi feature is disabled (#2029)

    Thanks to new contributors @TimoFreiberg and @wagenet, as well as @CAD97 for contributing to this release!

    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.24(Apr 1, 2022)

    This release fixes a bug where setting NoSubscriber as the local default would not disable the global default subscriber locally.

    Fixed

    • Setting NoSubscriber as the local default now correctly disables the global default subscriber (#2001)
    • Fixed compilation warnings with the "std" feature disabled (#2022)

    Changed

    • Removed unnecessary use of write! and format_args! macros (#1988)
    Source code(tar.gz)
    Source code(zip)
  • tracing-journald-0.2.4(Mar 17, 2022)

  • tracing-appender-0.2.2(Mar 17, 2022)

    This release fixes a bug in RollingFileAppender that could result in a failure to rotate the log file, or in panics in debug mode.

    Fixed

    • rolling: Fixed a panic that prohibited rolling files over. (#1989)
    Source code(tar.gz)
    Source code(zip)
  • tracing-core-0.1.23(Mar 9, 2022)

Owner
Tokio
Rust's asynchronous runtime.
Tokio
Logging implementation for Rust

log A Rust library providing a lightweight logging facade. log documentation A logging facade provides a single logging API that abstracts over the ac

The Rust Programming Language 1.6k Dec 29, 2022
Structured, contextual, extensible, composable logging for Rust

Getting started Introduction FAQ Crate list slog-rs - The Logging for Rust Introduction (please read) slog is an ecosystem of reusable components for

slog-rs 1.4k Jan 3, 2023
A highly configurable logging framework for Rust

log4rs log4rs is a highly configurable logging framework modeled after Java's Logback and log4j libraries. Warning If you are using the file rotation

null 753 Jan 8, 2023
A Rust logger with various features.

Moe Logger (οΌžΟ‰οΌœ) Another logger based on pretty-env-logger and env_logger. Allow writing log to file with features like formatting, file rotation. Usa

Rui Li 4 Sep 24, 2021
godot-logger is an easy-to-use logger for godot-rust projects.

godot-logger is an easy-to-use logger for godot-rust projects. It prints logs to Godot's output console and supports module-specific log levels.

Jan David 10 Nov 17, 2022
Another Key Logger Yet. Rust.

Another Key Logger Yet. Rust. For my very first experience of working with Rust, I decided to manage the keyboard, this time by logging and writing th

(Not) Kearash 0 May 3, 2022
Task-based logging for rust

task_log task_log is a task-based logger. Installing Just add task_log = 0.1.4 to your Cargo.toml's dependency section. Example Let's get right to the

Matt Gleich 2 Feb 28, 2022
A pretty, sensible logger for Rust - ideal for running examples and tests on a crate of choice

sensible-env-logger A pretty, sensible logger for Rust - ideal for running examples and tests on a crate of choice. This is a thin wrapper around pret

Ritvik Nag 3 Aug 9, 2022
πŸ’¬ A couple of functions to make logging in Rust easier.

Rust logging β›” ?? A couple of functions to make logging in Rust easier. Installation ?? Just add the code of code.rs to your project. You can copy/pas

Skwal 2 Apr 7, 2022
A rust library for creating and managing logs of arbitrary binary data

A rust library for creating and managing logs of arbitrary binary data. Presently it's used to collect sensor data. But it should generally be helpful in cases where you need to store timeseries data, in a nearly (but not strictly) append-only fashion.

Yusuf Simonson 1 May 9, 2022
A cool log library built using rust-lang

RustLog A cool log library built using rust-lang Installation: Cargo.toml rustlog = { git = "https://github.com/krishpranav/rustlog" } log = "0.4.17"

Krisna Pranav 2 Jul 21, 2022
Application level tracing for Rust.

Website | Chat | Documentation (master branch) Overview tracing is a framework for instrumenting Rust programs to collect structured, event-based diag

Tokio 3.3k Jan 3, 2023
tracing-glog is a glog-inspired formatter for tracing-subscriber.

tracing-glog tracing-glog is a glog-inspired formatter for tracing-subscriber. tracing-glog should be used with tracing-subscriber, as it is a formatt

David Barsky 7 Oct 8, 2022
Simple tray application which shows battery level for HyperX Cloud Flight Wireless Headset.

HyperX Cloud Flight Battery Monitoring Introduction Simple tray application which shows battery level for HyperX Cloud Flight Wireless Headset. Screen

Stefan Kondinski 18 Dec 27, 2022
A simple GUI rust application that keeps track of how much time you spend on each application.

TimeSpent A simple GUI rust application that keeps track of how much time you spend on each application. Installation Click here to download the Setup

Slacked Lime 4 Sep 23, 2022
Ray Tracing: The Next Week implementation in Rust

rttnw Ray Tracing: The Next Week implementation in Rust How to run Install Rust: Link here. Run project git clone https://github.com/luliic2/rttnw cd

null 20 Apr 26, 2022
A real-time implementation of "Ray Tracing in One Weekend" using nannou and rust-gpu.

Real-time Ray Tracing with nannou & rust-gpu An attempt at a real-time implementation of "Ray Tracing in One Weekend" by Peter Shirley. This was a per

null 89 Dec 23, 2022
Error propagation tracing in Rust.

Propagate Error propagation tracing in Rust. Why Propagate? Being able to trace the cause of an error is critical for many types of software written i

Ben Reeves 10 Sep 23, 2021
Implementation of the great book Ray Tracing in One Weekend in Rust.

Ray Tracing in One Weekend (Rust) Implementation of the great book Ray Tracing in One Weekend in Rust. Fun easy way to pick up and learn Rust (was rou

Stanley Su 6 Dec 29, 2021
Emit ETW events in tracing-enabled Rust applications.

tracing-etw Emit ETW events in tracing-enabled Rust applications. This crate depends on rust_win_etw. There are four ETW events. fn NewSpan(span_id: u

Microsoft 11 Aug 10, 2022