Conditionally disabling `tracing` logging for simulation?

I have a game server that implements the game logic in rust and logs useful information about what is going on via the tracing crate's macros (debug!(), info!(), etc). The game also has an AI which uses monte carlo simulation of future game states to pick moves to make. The AI logic is extremely performance-sensitive, the more simulation rounds I can run, the stronger the AI is able to play.

I've run into two related problems with this setup: 1) adding logging statements is measurably regressing simulation performance in criterion benchmarks and 2) the added logging statements create a lot of log spam, since I run hundreds of thousands of simulated games for every one actual game.

What I really want is to only run the logging code when running a real game and ignore simulated games. Should I just wrap all of my log statements in

if !game.is_simulated() {
  info!("Log something"):
}

?

or is there a better approach here?

Disclaimer: I haven't actually tried to do any dynamic filtering with tracing before so there may be some issues I havent thought of

tracing-subscriber has some utilities for filtering out spans and events without reimplementing a whole subscriber. You'll have to be careful about which strategy you use though, as it's possible to end up accidentally disabling all tracing globally

Here's the documentation about filtering generally in tracing-subscriber:

If there are a fixed set of simulation threads, or you can easily wrap all of the simulation code in a with_default you may be able to just set the subscriber to one that ignores most of your logging for the duration of the simulations. That would probably have the best performance since you would be able to disable the callsites completely for that subscriber. Aiui doing it that way shouldn't affect traces that go to the main subscriber, but I can promise that's the case.

I think you just need to set the right features for tracing

Thanks, I didn't know about wrapping code in with_default(), that does seem to improve things. Unfortunately it does look like there's still about a 10% performance regression from logging even with a subscriber that silently drops all logs. I guess beyond that point I need to start looking at the if statement solution?

You can certainly try it! I wouldn't be surprised if that had a similar performance penalty though

What method did you use to prevent logging on the subscriber?

Just configuring a subscriber that only watches for errors, i.e.

let error_subscriber = tracing_subscriber::fmt().with_max_level(Level::ERROR).finish();
subscriber::with_default(error_subscriber, || {
    // Run simulation
});