trace_tools/subscriber/layer/
mod.rs

1// Copyright 2022 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4mod flamegraph;
5mod log;
6
7pub use self::{flamegraph::FlamegraphLayer, log::LogLayer};
8
9use crate::{util::Flamegrapher, Error};
10
11use fern_logger::LoggerConfig;
12
13use tracing::Metadata;
14
15use std::path::Path;
16
17/// Creates a new [`FlamegraphLayer`].
18///
19/// The given path describes the desired output location of the folded stack file that is generated by
20/// this layer during runtime. This file can then be used to produce a flamegraph by a [`Flamegrapher`]
21/// instance, or by the [`inferno`] tool.
22///
23/// Returns a `Result` of the tuple containing the [`FlamegraphLayer`] and a [`Flamegrapher`] that
24/// can be used to produce the flamegraph image at the end of profiling. This can be ignored if you just
25/// need the folded stack file, or will use [`inferno`] externally for the graph generation.
26///
27/// # Errors
28/// This function can fail in the following ways:
29///  - There was an error creating/truncating the folded stack file at the given location.
30///
31/// # Panics
32/// This function will panic if the program is not built with `--cfg tokio_unstable`.
33pub fn flamegraph_layer<P: AsRef<Path>>(stack_filename: P) -> Result<(FlamegraphLayer, Flamegrapher), Error> {
34    #![allow(clippy::assertions_on_constants)]
35    assert!(
36        cfg!(tokio_unstable),
37        "task tracing requires building with RUSTFLAGS=\"--cfg tokio_unstable\"!"
38    );
39
40    FlamegraphLayer::new(stack_filename)
41}
42
43/// Filter function for the [`FlamegraphLayer`].
44///
45/// Ignores any [`Event`](tracing::Event)s, and registers [`Span`](tracing::Span)s that have either been
46/// instrumented internally by `tokio`, or with [`observe`](trace_tools_attributes::observe).
47pub(crate) fn flamegraph_filter(meta: &Metadata<'_>) -> bool {
48    if meta.is_event() {
49        return false;
50    }
51
52    meta.name().starts_with("runtime") || meta.target().starts_with("tokio") || meta.target() == "trace_tools::observe"
53}
54
55/// Creates a new [`LogLayer`], using the parameters provided by the given [`LoggerConfig`].
56///
57/// This should allow the subscriber to perform logging in an identical fashion to the functionality provided
58/// in [`fern_logger`].
59///
60/// # Errors
61/// This function can fail in the following ways:
62///  - An [`io::Error`](std::io::Error) was encountered when creating any log files required by the config.
63pub fn log_layer(config: LoggerConfig) -> Result<LogLayer, Error> {
64    LogLayer::new(config)
65}
66
67/// Filter function for the log layer. Registers all [`Event`](tracing::Event)s with the layer.
68pub(crate) fn log_filter(meta: &tracing::Metadata<'_>) -> bool {
69    meta.is_event()
70}
71
72/// Creates a new [`console_subscriber::ConsoleLayer`].
73#[cfg(feature = "tokio-console")]
74pub fn console_layer() -> Result<console_subscriber::ConsoleLayer, Error> {
75    #![allow(clippy::assertions_on_constants)]
76    assert!(
77        cfg!(tokio_unstable),
78        "task tracing requires building with RUSTFLAGS=\"--cfg tokio_unstable\"!"
79    );
80
81    let (layer, server) = console_subscriber::ConsoleLayer::builder().with_default_env().build();
82
83    std::thread::Builder::new()
84        .name("console_subscriber".into())
85        .spawn(move || {
86            let runtime = tokio::runtime::Builder::new_current_thread()
87                .enable_io()
88                .enable_time()
89                .build()
90                .expect("console subscriber runtime initialization failed");
91
92            runtime.block_on(async move { server.serve().await.expect("console subscriber server failed") });
93        })
94        .expect("console subscriber could not spawn thread");
95
96    Ok(layer)
97}
98
99/// Filter function for the console layer.
100///
101/// Registers relevant [`Event`](tracing::Event)s and [`Span`](tracing::Span)s. This is identical to the
102/// filter function used in `tokio`'s `console_subscriber`.
103#[cfg(feature = "tokio-console")]
104pub(crate) fn console_filter(meta: &tracing::Metadata<'_>) -> bool {
105    if meta.is_event() {
106        return meta.target().starts_with("runtime") || meta.target().starts_with("tokio");
107    }
108
109    meta.name().starts_with("runtime") || meta.target().starts_with("tokio")
110}