1 use std::collections::HashSet; 2 use syn::{punctuated::Punctuated, Expr, Ident, LitInt, LitStr, Path, Token}; 3 4 use proc_macro2::TokenStream; 5 use quote::{quote, quote_spanned, ToTokens}; 6 use syn::ext::IdentExt as _; 7 use syn::parse::{Parse, ParseStream}; 8 9 /// Arguments to `#[instrument(err(...))]` and `#[instrument(ret(...))]` which describe how the 10 /// return value event should be emitted. 11 #[derive(Clone, Default, Debug)] 12 pub(crate) struct EventArgs { 13 level: Option<Level>, 14 pub(crate) mode: FormatMode, 15 } 16 17 #[derive(Clone, Default, Debug)] 18 pub(crate) struct InstrumentArgs { 19 level: Option<Level>, 20 pub(crate) name: Option<LitStr>, 21 target: Option<LitStr>, 22 pub(crate) parent: Option<Expr>, 23 pub(crate) follows_from: Option<Expr>, 24 pub(crate) skips: HashSet<Ident>, 25 pub(crate) skip_all: bool, 26 pub(crate) fields: Option<Fields>, 27 pub(crate) err_args: Option<EventArgs>, 28 pub(crate) ret_args: Option<EventArgs>, 29 /// Errors describing any unrecognized parse inputs that we skipped. 30 parse_warnings: Vec<syn::Error>, 31 } 32 33 impl InstrumentArgs { level(&self) -> Level34 pub(crate) fn level(&self) -> Level { 35 self.level.clone().unwrap_or(Level::Info) 36 } 37 target(&self) -> impl ToTokens38 pub(crate) fn target(&self) -> impl ToTokens { 39 if let Some(ref target) = self.target { 40 quote!(#target) 41 } else { 42 quote!(module_path!()) 43 } 44 } 45 46 /// Generate "deprecation" warnings for any unrecognized attribute inputs 47 /// that we skipped. 48 /// 49 /// For backwards compatibility, we need to emit compiler warnings rather 50 /// than errors for unrecognized inputs. Generating a fake deprecation is 51 /// the only way to do this on stable Rust right now. warnings(&self) -> impl ToTokens52 pub(crate) fn warnings(&self) -> impl ToTokens { 53 let warnings = self.parse_warnings.iter().map(|err| { 54 let msg = format!("found unrecognized input, {}", err); 55 let msg = LitStr::new(&msg, err.span()); 56 // TODO(eliza): This is a bit of a hack, but it's just about the 57 // only way to emit warnings from a proc macro on stable Rust. 58 // Eventually, when the `proc_macro::Diagnostic` API stabilizes, we 59 // should definitely use that instead. 60 quote_spanned! {err.span()=> 61 #[warn(deprecated)] 62 { 63 #[deprecated(since = "not actually deprecated", note = #msg)] 64 const TRACING_INSTRUMENT_WARNING: () = (); 65 let _ = TRACING_INSTRUMENT_WARNING; 66 } 67 } 68 }); 69 quote! { 70 { #(#warnings)* } 71 } 72 } 73 } 74 75 impl Parse for InstrumentArgs { parse(input: ParseStream<'_>) -> syn::Result<Self>76 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 77 let mut args = Self::default(); 78 while !input.is_empty() { 79 let lookahead = input.lookahead1(); 80 if lookahead.peek(kw::name) { 81 if args.name.is_some() { 82 return Err(input.error("expected only a single `name` argument")); 83 } 84 let name = input.parse::<StrArg<kw::name>>()?.value; 85 args.name = Some(name); 86 } else if lookahead.peek(LitStr) { 87 // XXX: apparently we support names as either named args with an 88 // sign, _or_ as unnamed string literals. That's weird, but 89 // changing it is apparently breaking. 90 if args.name.is_some() { 91 return Err(input.error("expected only a single `name` argument")); 92 } 93 args.name = Some(input.parse()?); 94 } else if lookahead.peek(kw::target) { 95 if args.target.is_some() { 96 return Err(input.error("expected only a single `target` argument")); 97 } 98 let target = input.parse::<StrArg<kw::target>>()?.value; 99 args.target = Some(target); 100 } else if lookahead.peek(kw::parent) { 101 if args.target.is_some() { 102 return Err(input.error("expected only a single `parent` argument")); 103 } 104 let parent = input.parse::<ExprArg<kw::parent>>()?; 105 args.parent = Some(parent.value); 106 } else if lookahead.peek(kw::follows_from) { 107 if args.target.is_some() { 108 return Err(input.error("expected only a single `follows_from` argument")); 109 } 110 let follows_from = input.parse::<ExprArg<kw::follows_from>>()?; 111 args.follows_from = Some(follows_from.value); 112 } else if lookahead.peek(kw::level) { 113 if args.level.is_some() { 114 return Err(input.error("expected only a single `level` argument")); 115 } 116 args.level = Some(input.parse()?); 117 } else if lookahead.peek(kw::skip) { 118 if !args.skips.is_empty() { 119 return Err(input.error("expected only a single `skip` argument")); 120 } 121 if args.skip_all { 122 return Err(input.error("expected either `skip` or `skip_all` argument")); 123 } 124 let Skips(skips) = input.parse()?; 125 args.skips = skips; 126 } else if lookahead.peek(kw::skip_all) { 127 if args.skip_all { 128 return Err(input.error("expected only a single `skip_all` argument")); 129 } 130 if !args.skips.is_empty() { 131 return Err(input.error("expected either `skip` or `skip_all` argument")); 132 } 133 let _ = input.parse::<kw::skip_all>()?; 134 args.skip_all = true; 135 } else if lookahead.peek(kw::fields) { 136 if args.fields.is_some() { 137 return Err(input.error("expected only a single `fields` argument")); 138 } 139 args.fields = Some(input.parse()?); 140 } else if lookahead.peek(kw::err) { 141 let _ = input.parse::<kw::err>(); 142 let err_args = EventArgs::parse(input)?; 143 args.err_args = Some(err_args); 144 } else if lookahead.peek(kw::ret) { 145 let _ = input.parse::<kw::ret>()?; 146 let ret_args = EventArgs::parse(input)?; 147 args.ret_args = Some(ret_args); 148 } else if lookahead.peek(Token![,]) { 149 let _ = input.parse::<Token![,]>()?; 150 } else { 151 // We found a token that we didn't expect! 152 // We want to emit warnings for these, rather than errors, so 153 // we'll add it to the list of unrecognized inputs we've seen so 154 // far and keep going. 155 args.parse_warnings.push(lookahead.error()); 156 // Parse the unrecognized token tree to advance the parse 157 // stream, and throw it away so we can keep parsing. 158 let _ = input.parse::<proc_macro2::TokenTree>(); 159 } 160 } 161 Ok(args) 162 } 163 } 164 165 impl EventArgs { level(&self, default: Level) -> Level166 pub(crate) fn level(&self, default: Level) -> Level { 167 self.level.clone().unwrap_or(default) 168 } 169 } 170 171 impl Parse for EventArgs { parse(input: ParseStream<'_>) -> syn::Result<Self>172 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 173 if !input.peek(syn::token::Paren) { 174 return Ok(Self::default()); 175 } 176 let content; 177 let _ = syn::parenthesized!(content in input); 178 let mut result = Self::default(); 179 let mut parse_one_arg = 180 || { 181 let lookahead = content.lookahead1(); 182 if lookahead.peek(kw::level) { 183 if result.level.is_some() { 184 return Err(content.error("expected only a single `level` argument")); 185 } 186 result.level = Some(content.parse()?); 187 } else if result.mode != FormatMode::default() { 188 return Err(content.error("expected only a single format argument")); 189 } else if let Some(ident) = content.parse::<Option<Ident>>()? { 190 match ident.to_string().as_str() { 191 "Debug" => result.mode = FormatMode::Debug, 192 "Display" => result.mode = FormatMode::Display, 193 _ => return Err(syn::Error::new( 194 ident.span(), 195 "unknown event formatting mode, expected either `Debug` or `Display`", 196 )), 197 } 198 } 199 Ok(()) 200 }; 201 parse_one_arg()?; 202 if !content.is_empty() { 203 if content.lookahead1().peek(Token![,]) { 204 let _ = content.parse::<Token![,]>()?; 205 parse_one_arg()?; 206 } else { 207 return Err(content.error("expected `,` or `)`")); 208 } 209 } 210 Ok(result) 211 } 212 } 213 214 struct StrArg<T> { 215 value: LitStr, 216 _p: std::marker::PhantomData<T>, 217 } 218 219 impl<T: Parse> Parse for StrArg<T> { parse(input: ParseStream<'_>) -> syn::Result<Self>220 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 221 let _ = input.parse::<T>()?; 222 let _ = input.parse::<Token![=]>()?; 223 let value = input.parse()?; 224 Ok(Self { 225 value, 226 _p: std::marker::PhantomData, 227 }) 228 } 229 } 230 231 struct ExprArg<T> { 232 value: Expr, 233 _p: std::marker::PhantomData<T>, 234 } 235 236 impl<T: Parse> Parse for ExprArg<T> { parse(input: ParseStream<'_>) -> syn::Result<Self>237 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 238 let _ = input.parse::<T>()?; 239 let _ = input.parse::<Token![=]>()?; 240 let value = input.parse()?; 241 Ok(Self { 242 value, 243 _p: std::marker::PhantomData, 244 }) 245 } 246 } 247 248 struct Skips(HashSet<Ident>); 249 250 impl Parse for Skips { parse(input: ParseStream<'_>) -> syn::Result<Self>251 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 252 let _ = input.parse::<kw::skip>(); 253 let content; 254 let _ = syn::parenthesized!(content in input); 255 let names = content.parse_terminated(Ident::parse_any, Token![,])?; 256 let mut skips = HashSet::new(); 257 for name in names { 258 if skips.contains(&name) { 259 return Err(syn::Error::new( 260 name.span(), 261 "tried to skip the same field twice", 262 )); 263 } else { 264 skips.insert(name); 265 } 266 } 267 Ok(Self(skips)) 268 } 269 } 270 271 #[derive(Clone, Debug, Hash, PartialEq, Eq)] 272 pub(crate) enum FormatMode { 273 Default, 274 Display, 275 Debug, 276 } 277 278 impl Default for FormatMode { default() -> Self279 fn default() -> Self { 280 FormatMode::Default 281 } 282 } 283 284 #[derive(Clone, Debug)] 285 pub(crate) struct Fields(pub(crate) Punctuated<Field, Token![,]>); 286 287 #[derive(Clone, Debug)] 288 pub(crate) struct Field { 289 pub(crate) name: Punctuated<Ident, Token![.]>, 290 pub(crate) value: Option<Expr>, 291 pub(crate) kind: FieldKind, 292 } 293 294 #[derive(Clone, Debug, Eq, PartialEq)] 295 pub(crate) enum FieldKind { 296 Debug, 297 Display, 298 Value, 299 } 300 301 impl Parse for Fields { parse(input: ParseStream<'_>) -> syn::Result<Self>302 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 303 let _ = input.parse::<kw::fields>(); 304 let content; 305 let _ = syn::parenthesized!(content in input); 306 let fields = content.parse_terminated(Field::parse, Token![,])?; 307 Ok(Self(fields)) 308 } 309 } 310 311 impl ToTokens for Fields { to_tokens(&self, tokens: &mut TokenStream)312 fn to_tokens(&self, tokens: &mut TokenStream) { 313 self.0.to_tokens(tokens) 314 } 315 } 316 317 impl Parse for Field { parse(input: ParseStream<'_>) -> syn::Result<Self>318 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 319 let mut kind = FieldKind::Value; 320 if input.peek(Token![%]) { 321 input.parse::<Token![%]>()?; 322 kind = FieldKind::Display; 323 } else if input.peek(Token![?]) { 324 input.parse::<Token![?]>()?; 325 kind = FieldKind::Debug; 326 }; 327 let name = Punctuated::parse_separated_nonempty_with(input, Ident::parse_any)?; 328 let value = if input.peek(Token![=]) { 329 input.parse::<Token![=]>()?; 330 if input.peek(Token![%]) { 331 input.parse::<Token![%]>()?; 332 kind = FieldKind::Display; 333 } else if input.peek(Token![?]) { 334 input.parse::<Token![?]>()?; 335 kind = FieldKind::Debug; 336 }; 337 Some(input.parse()?) 338 } else { 339 None 340 }; 341 Ok(Self { name, value, kind }) 342 } 343 } 344 345 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)346 fn to_tokens(&self, tokens: &mut TokenStream) { 347 if let Some(ref value) = self.value { 348 let name = &self.name; 349 let kind = &self.kind; 350 tokens.extend(quote! { 351 #name = #kind #value 352 }) 353 } else if self.kind == FieldKind::Value { 354 // XXX(eliza): I don't like that fields without values produce 355 // empty fields rather than local variable shorthand...but, 356 // we've released a version where field names without values in 357 // `instrument` produce empty field values, so changing it now 358 // is a breaking change. agh. 359 let name = &self.name; 360 tokens.extend(quote!(#name = tracing::field::Empty)) 361 } else { 362 self.kind.to_tokens(tokens); 363 self.name.to_tokens(tokens); 364 } 365 } 366 } 367 368 impl ToTokens for FieldKind { to_tokens(&self, tokens: &mut TokenStream)369 fn to_tokens(&self, tokens: &mut TokenStream) { 370 match self { 371 FieldKind::Debug => tokens.extend(quote! { ? }), 372 FieldKind::Display => tokens.extend(quote! { % }), 373 _ => {} 374 } 375 } 376 } 377 378 #[derive(Clone, Debug)] 379 pub(crate) enum Level { 380 Trace, 381 Debug, 382 Info, 383 Warn, 384 Error, 385 Path(Path), 386 } 387 388 impl Parse for Level { parse(input: ParseStream<'_>) -> syn::Result<Self>389 fn parse(input: ParseStream<'_>) -> syn::Result<Self> { 390 let _ = input.parse::<kw::level>()?; 391 let _ = input.parse::<Token![=]>()?; 392 let lookahead = input.lookahead1(); 393 if lookahead.peek(LitStr) { 394 let str: LitStr = input.parse()?; 395 match str.value() { 396 s if s.eq_ignore_ascii_case("trace") => Ok(Level::Trace), 397 s if s.eq_ignore_ascii_case("debug") => Ok(Level::Debug), 398 s if s.eq_ignore_ascii_case("info") => Ok(Level::Info), 399 s if s.eq_ignore_ascii_case("warn") => Ok(Level::Warn), 400 s if s.eq_ignore_ascii_case("error") => Ok(Level::Error), 401 _ => Err(input.error( 402 "unknown verbosity level, expected one of \"trace\", \ 403 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5", 404 )), 405 } 406 } else if lookahead.peek(LitInt) { 407 fn is_level(lit: &LitInt, expected: u64) -> bool { 408 match lit.base10_parse::<u64>() { 409 Ok(value) => value == expected, 410 Err(_) => false, 411 } 412 } 413 let int: LitInt = input.parse()?; 414 match &int { 415 i if is_level(i, 1) => Ok(Level::Trace), 416 i if is_level(i, 2) => Ok(Level::Debug), 417 i if is_level(i, 3) => Ok(Level::Info), 418 i if is_level(i, 4) => Ok(Level::Warn), 419 i if is_level(i, 5) => Ok(Level::Error), 420 _ => Err(input.error( 421 "unknown verbosity level, expected one of \"trace\", \ 422 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5", 423 )), 424 } 425 } else if lookahead.peek(Ident) { 426 Ok(Self::Path(input.parse()?)) 427 } else { 428 Err(lookahead.error()) 429 } 430 } 431 } 432 433 impl ToTokens for Level { to_tokens(&self, tokens: &mut TokenStream)434 fn to_tokens(&self, tokens: &mut TokenStream) { 435 match self { 436 Level::Trace => tokens.extend(quote!(tracing::Level::TRACE)), 437 Level::Debug => tokens.extend(quote!(tracing::Level::DEBUG)), 438 Level::Info => tokens.extend(quote!(tracing::Level::INFO)), 439 Level::Warn => tokens.extend(quote!(tracing::Level::WARN)), 440 Level::Error => tokens.extend(quote!(tracing::Level::ERROR)), 441 Level::Path(ref pat) => tokens.extend(quote!(#pat)), 442 } 443 } 444 } 445 446 mod kw { 447 syn::custom_keyword!(fields); 448 syn::custom_keyword!(skip); 449 syn::custom_keyword!(skip_all); 450 syn::custom_keyword!(level); 451 syn::custom_keyword!(target); 452 syn::custom_keyword!(parent); 453 syn::custom_keyword!(follows_from); 454 syn::custom_keyword!(name); 455 syn::custom_keyword!(err); 456 syn::custom_keyword!(ret); 457 } 458