Skip to content

Commit 60b8532

Browse files
committed
feat: add tracing-flame
1 parent 8058ba8 commit 60b8532

3 files changed

Lines changed: 76 additions & 12 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ default = ["log"]
3737
# TODO: use "dep:{tracing-subscriber,evn_logger}" once our MSRV is 1.60 or higher.
3838
trace = ["tracing-subscriber", "tracing-subscriber/ansi", "tracing-subscriber/tracing-log", "test-log-macros/trace"]
3939
log = ["env_logger", "test-log-macros/log"]
40+
tracing-flame = ["trace", "dep:tracing-flame"]
4041
# Enable unstable features. These are generally exempt from any semantic
4142
# versioning guarantees.
4243
unstable = ["test-log-macros/unstable"]
@@ -49,6 +50,8 @@ test-log-macros = {version = "0.2.15", path = "macros"}
4950
tracing-subscriber = {version = "0.3.17", default-features = false, optional = true, features = ["env-filter", "fmt"]}
5051
env_logger = {version = "0.11", default-features = false, optional = true}
5152

53+
tracing-flame = { version = "0.2.0", optional = true }
54+
5255
[dev-dependencies]
5356
logging = {version = "0.4.8", package = "log"}
5457
test-case = {version = "3.1"}

macros/src/lib.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
extern crate proc_macro;
55

66
use proc_macro::TokenStream;
7-
use proc_macro2::TokenStream as Tokens;
7+
use proc_macro2::{Ident, TokenStream as Tokens};
88

99
use quote::quote;
1010

@@ -58,7 +58,7 @@ fn try_test(attr: TokenStream, input: ItemFn) -> syn::Result<Tokens> {
5858

5959
let (attribute_args, ignored_attrs) = parse_attrs(attrs)?;
6060
let logging_init = expand_logging_init(&attribute_args);
61-
let tracing_init = expand_tracing_init(&attribute_args);
61+
let tracing_init = expand_tracing_init(&sig.ident, &attribute_args);
6262

6363
let result = quote! {
6464
#[#inner_test]
@@ -75,13 +75,21 @@ fn try_test(attr: TokenStream, input: ItemFn) -> syn::Result<Tokens> {
7575
// The alternative would be to use fully qualified call syntax in
7676
// all initialization code, but that's much harder to control.
7777
mod init {
78-
pub fn init() {
78+
pub struct Guard<T> {
79+
tracing: T,
80+
}
81+
82+
pub fn init() -> Guard<impl std::any::Any> {
7983
#logging_init
80-
#tracing_init
84+
Guard {
85+
tracing: {
86+
#tracing_init
87+
},
88+
}
8189
}
8290
}
8391

84-
init::init();
92+
let _ = init::init();
8593

8694
#block
8795
}
@@ -176,7 +184,7 @@ fn expand_logging_init(_attribute_args: &AttributeArgs) -> Tokens {
176184

177185
/// Expand the initialization code for the `tracing` crate.
178186
#[cfg(feature = "trace")]
179-
fn expand_tracing_init(attribute_args: &AttributeArgs) -> Tokens {
187+
fn expand_tracing_init(name: &Ident, attribute_args: &AttributeArgs) -> Tokens {
180188
let env_filter = if let Some(default_log_filter) = &attribute_args.default_log_filter {
181189
quote! {
182190
::test_log::tracing_subscriber::EnvFilter::builder()
@@ -191,12 +199,16 @@ fn expand_tracing_init(attribute_args: &AttributeArgs) -> Tokens {
191199
quote! { ::test_log::tracing_subscriber::EnvFilter::from_default_env() }
192200
};
193201

202+
let name = name.to_string();
203+
194204
quote! {
195-
::test_log::tracing::init(#env_filter);
205+
let base = module_path!().split("::").map(std::path::Path::new).collect::<std::path::PathBuf>();
206+
let name = format!("{}/{}", base.display(), #name);
207+
Some(::test_log::tracing::init(&name, #env_filter))
196208
}
197209
}
198210

199211
#[cfg(not(feature = "trace"))]
200-
fn expand_tracing_init(_attribute_args: &AttributeArgs) -> Tokens {
212+
fn expand_tracing_init(_name: &Ident, _attribute_args: &AttributeArgs) -> Tokens {
201213
quote! {}
202214
}

src/tracing.rs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,66 @@
11
//! Support for tracing
22
33
use std::env::var_os;
4+
use std::fs::File;
5+
use std::io::BufWriter;
6+
use std::path::Path;
47
use tracing_subscriber::fmt::format::FmtSpan;
8+
use tracing_subscriber::layer::SubscriberExt;
9+
use tracing_subscriber::util::SubscriberInitExt;
10+
11+
#[derive(Default)]
12+
pub struct TracingGuard {
13+
#[cfg(feature = "tracing-flame")]
14+
_flame: Option<tracing_flame::FlushGuard<BufWriter<File>>>,
15+
}
516

617
/// Initialize the tracing
7-
pub fn init(env_filter: impl Into<tracing_subscriber::EnvFilter>) {
18+
pub fn init(name: &str, env_filter: impl Into<tracing_subscriber::EnvFilter>) -> TracingGuard {
19+
let env_filter = env_filter.into();
820
let event_filter = eval_event_filter();
921

10-
let _ = tracing_subscriber::FmtSubscriber::builder()
11-
.with_env_filter(env_filter)
22+
let fmt = tracing_subscriber::fmt::layer()
23+
.with_ansi(true)
1224
.with_span_events(event_filter)
25+
.with_level(true)
1326
.with_test_writer()
14-
.try_init();
27+
.compact();
28+
29+
let layered = tracing_subscriber::registry().with(env_filter).with(fmt);
30+
31+
#[cfg(feature = "tracing-flame")]
32+
{
33+
return match std::env::var("TEST_LOG_FLAMES").ok() {
34+
Some(base) => {
35+
let path = format!("{base}/{name}.folded");
36+
let path = Path::new(&path);
37+
38+
// ensure we have the parent dir
39+
if let Some(parent) = path.parent() {
40+
let _ = std::fs::create_dir_all(parent);
41+
}
42+
43+
let (flame, guard) =
44+
tracing_flame::FlameLayer::with_file(path).expect("Unable to initialize tracing-flame");
45+
46+
let _ = layered.with(flame).try_init();
47+
48+
TracingGuard {
49+
_flame: Some(guard),
50+
}
51+
},
52+
None => {
53+
let _ = layered.try_init();
54+
TracingGuard::default()
55+
},
56+
};
57+
}
58+
59+
#[cfg(not(feature = "tracing-flame"))]
60+
{
61+
let layered = layered.with(env_filter).with(fmt).try_init();
62+
TracingGuard::default()
63+
}
1564
}
1665

1766
fn eval_event_filter() -> FmtSpan {

0 commit comments

Comments
 (0)