rustfmt icon indicating copy to clipboard operation
rustfmt copied to clipboard

Failing when macro has `%` in it, e.g. Tracing

Open xphoniex opened this issue 3 years ago • 9 comments

Here's a sample code:

            TraceLayer::new_for_http()
                .make_span_with(|request: &Request<Body>| {
                    tracing::info_span!(
                        "request",
                        method = %request.method(),
                        uri = %request.uri(), status = tracing::field::Empty,
                        latency = tracing::field::Empty,
                    )
                })

this uses a macro from tracing to create the Span. However the % in there makes rustfmt fail.

xphoniex avatar Aug 23 '22 16:08 xphoniex

Thanks for reaching out. What version of rustfmt are you using? (run rustfmt --version to find out). I'm using rustfmt 1.5.1-nightly (38659ec6 2022-08-18), and can't reproduce any issues. Are you using any non default config options? Could you please post the larger code snippet.

ytmimi avatar Aug 23 '22 16:08 ytmimi

$ rustfmt --version
rustfmt 1.5.1-stable (4b91a6e 2022-08-08)

reproducible examples: (add tracing = "0.1.36" to Cargo.toml)

fn main() {
    let span = tracing::info_span!("request", method = %request.method(), uri = %request.uri(), status = tracing::field::Empty, latency = tracing::field::Empty,);
}
fn main() {
    let span = tracing::info_span!(
        "request",
        method = %request.method(),
        uri = %request.uri(), status = tracing::field::Empty,
        latency = tracing::field::Empty,
    );
}

expected output:

fn main() {
    let span = tracing::info_span!(
        "request",
        method = %request.method(),
        uri = %request.uri(),
        status = tracing::field::Empty,
        latency = tracing::field::Empty,
    );
}

If you remove the % in examples, you'll get the same output as "expected", obviously without the %. Otherwise, rustfmt doesn't make any change to the two examples.

xphoniex avatar Aug 23 '22 19:08 xphoniex

We actually don't need to to add tracing = "0.1.36" to Cargo.toml to reproduce. I understand now that the issue is that we're not formatting the macro at all, and unfortunately as things currently stand there's not much we can do. You're correct that the % are causing the issue.

Formatting macros is tricky as they can contain arbitrary tokens and in this case the % prevents us from parsing the macro args as valid rust code so we just emit the macro as is. rustfmt isn't programmed to handle cases where macro args don't parse as valid rust code e.g %request.

The only way to handle this would be to special case the info_span! macro and customize how we parse and format its args. Given the team's backlog this is an extremely low priority item.

ytmimi avatar Aug 23 '22 19:08 ytmimi

I'm not familiar with the tracing::info_span! macro, and found some more details on the % by reading the Recorder Fields section of the docs. Looks like ? is also used sometimes.

ytmimi avatar Aug 23 '22 19:08 ytmimi

I'lll just add that while ? is also used, it behaves slightly differently.

One can use any of the following with the first three being equivalent and the fourth through sixth being equivalent.

  • o tracing::info!(?x, "text")
  • x tracing::info!(x = ?x, "text")
  • o tracing::info!(x = format!("{x:?}"), "text")
  • x tracing::info!(%x, "text")
  • x tracing::info!(x = %x, "text")
  • o tracing::info!(x = format!("{x}"), "text")

Only the first, third, and sixth (with o in front of them) are being considered by rustfmt. I am somewhat surprised by the first one since that does not seem like valid rust syntax either.

In case this is done by making exception for the tracing macros, these are the macros I know of where this syntax is permissible:

List of macros
  • span!
  • debug_span!
  • info_span!
  • warn_span!
  • error_span!
  • event!
  • debug!
  • info!
  • warn!
  • error!

mladedav avatar Mar 07 '23 20:03 mladedav

I'm seeing this issue on rustfmt 1.7.0-nightly (f9b16149 2024-04-19), mainly with the ? sigil rather than the %. It seems like not only does the macro itself not get formatted, neither does any of the surrounding code.

saffaffi avatar Apr 20 '24 14:04 saffaffi

@saffaffi the Issues with ? and % are the same. rustfmt can only format a macro calls if it's able to parse their arguments as valid rust syntax. The ?x in the macro call tracing::info!(?x) isn't valid rust.

You won't notice the impact of rustfmt failing to format tracing::info!(?x) because you probably already expect that's how it should be formatted, however, in other cases failing to format a long macro could lead to surrounding code being left unformatted.

It would be best for you to open a new issue and provide a minimal code example that demonstrates the problem you're currently experiencing.

ytmimi avatar Apr 20 '24 14:04 ytmimi