Log only when called from a specific function

For example, let's say there is a function A that contains a logging action:

function A() {
    tracing::debug!("abc");
}

Now, assume that function B can call A(), and function C can also call A().
Is there a way to make the logging occur when A is called from B, but not when it is called from C?
I don't want to touch function A here.

I don't know if there's a tracing-specific solution (maybe the callers could adjust log level?)

In Rust you can hack such things by adding #[track_caller] and inspecting std::panic::Location.

1 Like

Thanks for the answer.
So, you mean using std::panic::Location::caller() and then applying an if condition to only log in specific callers. Am I correct?

you need to either modify A, or modify B and C, in general, unless, e.g. B and C are already instrumented.

if B and C are instrumented with spans, then you can just set a filter (e.g EnvFilter) based on their spans. e.g.

#[instrument]
fn A() { C(); }

#[instrument]
fn B() { C(); }

fn C() { tracing::debug!("abc"); }

fn main() {
	tracing_subscriber::fmt()
		.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
		.init();
	A();
	B();
}

you can either set the filter in code, or with environment variable, e.g.:

$ RUST_LOG=[b]=debug cargo run
   Compiling playground v0.1.0 (/tmp/playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/playground`
2025-03-08T07:37:51.455939Z DEBUG b: playground: abc
$ RUST_LOG=[a]=debug cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/playground`
2025-03-08T07:37:57.169951Z DEBUG a: playground: abc

if B and C cannot be instrumented, then it's unavoidable to make some changes to A, in order to figure out the caller's identity.

with #[track_caller], Location::caller() gives you a Location, from which you can get the file name, line number and column number, but it's up to you to map the file name and line number to functios names.

an alternative way is to capture the runtime callstack and walk up the stack frames to figure out the caller funciton, but this only works if you don't strip off the debug symbols, and you might need to use a crate (e.g. backtrace) for that, since BacktraceFrame in the standard library needs nightly feature, and is very limited.

1 Like