1use std::collections::HashSet;
2use syn::{punctuated::Punctuated, Expr, Ident, LitInt, LitStr, Path, Token};
3
4use proc_macro2::TokenStream;
5use quote::{quote, quote_spanned, ToTokens};
6use syn::ext::IdentExt as _;
7use syn::parse::{Parse, ParseStream};
8
9#[derive(Clone, Default, Debug)]
12pub(crate) struct EventArgs {
13 level: Option<Level>,
14 pub(crate) mode: FormatMode,
15}
16
17#[derive(Clone, Default, Debug)]
18pub(crate) struct InstrumentArgs {
19 level: Option<Level>,
20 pub(crate) name: Option<LitStrOrIdent>,
21 target: Option<LitStrOrIdent>,
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 parse_warnings: Vec<syn::Error>,
31}
32
33impl InstrumentArgs {
34 pub(crate) fn level(&self) -> Level {
35 self.level.clone().unwrap_or(Level::Info)
36 }
37
38 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 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 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
75impl Parse for InstrumentArgs {
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 if args.name.is_some() {
93 return Err(input.error("expected only a single `name` argument"));
94 }
95 args.name = Some(input.parse()?);
96 } else if lookahead.peek(kw::target) {
97 if args.target.is_some() {
98 return Err(input.error("expected only a single `target` argument"));
99 }
100 let target = input.parse::<StrArg<kw::target>>()?.value;
101 args.target = Some(target);
102 } else if lookahead.peek(kw::parent) {
103 if args.target.is_some() {
104 return Err(input.error("expected only a single `parent` argument"));
105 }
106 let parent = input.parse::<ExprArg<kw::parent>>()?;
107 args.parent = Some(parent.value);
108 } else if lookahead.peek(kw::follows_from) {
109 if args.target.is_some() {
110 return Err(input.error("expected only a single `follows_from` argument"));
111 }
112 let follows_from = input.parse::<ExprArg<kw::follows_from>>()?;
113 args.follows_from = Some(follows_from.value);
114 } else if lookahead.peek(kw::level) {
115 if args.level.is_some() {
116 return Err(input.error("expected only a single `level` argument"));
117 }
118 args.level = Some(input.parse()?);
119 } else if lookahead.peek(kw::skip) {
120 if !args.skips.is_empty() {
121 return Err(input.error("expected only a single `skip` argument"));
122 }
123 if args.skip_all {
124 return Err(input.error("expected either `skip` or `skip_all` argument"));
125 }
126 let Skips(skips) = input.parse()?;
127 args.skips = skips;
128 } else if lookahead.peek(kw::skip_all) {
129 if args.skip_all {
130 return Err(input.error("expected only a single `skip_all` argument"));
131 }
132 if !args.skips.is_empty() {
133 return Err(input.error("expected either `skip` or `skip_all` argument"));
134 }
135 let _ = input.parse::<kw::skip_all>()?;
136 args.skip_all = true;
137 } else if lookahead.peek(kw::fields) {
138 if args.fields.is_some() {
139 return Err(input.error("expected only a single `fields` argument"));
140 }
141 args.fields = Some(input.parse()?);
142 } else if lookahead.peek(kw::err) {
143 let _ = input.parse::<kw::err>();
144 let err_args = EventArgs::parse(input)?;
145 args.err_args = Some(err_args);
146 } else if lookahead.peek(kw::ret) {
147 let _ = input.parse::<kw::ret>()?;
148 let ret_args = EventArgs::parse(input)?;
149 args.ret_args = Some(ret_args);
150 } else if lookahead.peek(Token![,]) {
151 let _ = input.parse::<Token![,]>()?;
152 } else {
153 args.parse_warnings.push(lookahead.error());
158 let _ = input.parse::<proc_macro2::TokenTree>();
161 }
162 }
163 Ok(args)
164 }
165}
166
167impl EventArgs {
168 pub(crate) fn level(&self, default: Level) -> Level {
169 self.level.clone().unwrap_or(default)
170 }
171}
172
173impl Parse for EventArgs {
174 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
175 if !input.peek(syn::token::Paren) {
176 return Ok(Self::default());
177 }
178 let content;
179 let _ = syn::parenthesized!(content in input);
180 let mut result = Self::default();
181 let mut parse_one_arg =
182 || {
183 let lookahead = content.lookahead1();
184 if lookahead.peek(kw::level) {
185 if result.level.is_some() {
186 return Err(content.error("expected only a single `level` argument"));
187 }
188 result.level = Some(content.parse()?);
189 } else if result.mode != FormatMode::default() {
190 return Err(content.error("expected only a single format argument"));
191 } else if let Some(ident) = content.parse::<Option<Ident>>()? {
192 match ident.to_string().as_str() {
193 "Debug" => result.mode = FormatMode::Debug,
194 "Display" => result.mode = FormatMode::Display,
195 _ => return Err(syn::Error::new(
196 ident.span(),
197 "unknown event formatting mode, expected either `Debug` or `Display`",
198 )),
199 }
200 }
201 Ok(())
202 };
203 parse_one_arg()?;
204 if !content.is_empty() {
205 if content.lookahead1().peek(Token![,]) {
206 let _ = content.parse::<Token![,]>()?;
207 parse_one_arg()?;
208 } else {
209 return Err(content.error("expected `,` or `)`"));
210 }
211 }
212 Ok(result)
213 }
214}
215
216#[derive(Debug, Clone)]
217pub(super) enum LitStrOrIdent {
218 LitStr(LitStr),
219 Ident(Ident),
220}
221
222impl ToTokens for LitStrOrIdent {
223 fn to_tokens(&self, tokens: &mut TokenStream) {
224 match self {
225 LitStrOrIdent::LitStr(target) => target.to_tokens(tokens),
226 LitStrOrIdent::Ident(ident) => ident.to_tokens(tokens),
227 }
228 }
229}
230
231impl Parse for LitStrOrIdent {
232 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
233 input
234 .parse::<LitStr>()
235 .map(LitStrOrIdent::LitStr)
236 .or_else(|_| input.parse::<Ident>().map(LitStrOrIdent::Ident))
237 }
238}
239
240struct StrArg<T> {
241 value: LitStrOrIdent,
242 _p: std::marker::PhantomData<T>,
243}
244
245impl<T: Parse> Parse for StrArg<T> {
246 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
247 let _ = input.parse::<T>()?;
248 let _ = input.parse::<Token![=]>()?;
249 let value = input.parse()?;
250 Ok(Self {
251 value,
252 _p: std::marker::PhantomData,
253 })
254 }
255}
256
257struct ExprArg<T> {
258 value: Expr,
259 _p: std::marker::PhantomData<T>,
260}
261
262impl<T: Parse> Parse for ExprArg<T> {
263 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
264 let _ = input.parse::<T>()?;
265 let _ = input.parse::<Token![=]>()?;
266 let value = input.parse()?;
267 Ok(Self {
268 value,
269 _p: std::marker::PhantomData,
270 })
271 }
272}
273
274struct Skips(HashSet<Ident>);
275
276impl Parse for Skips {
277 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
278 let _ = input.parse::<kw::skip>();
279 let content;
280 let _ = syn::parenthesized!(content in input);
281 let names = content.parse_terminated(Ident::parse_any, Token![,])?;
282 let mut skips = HashSet::new();
283 for name in names {
284 if skips.contains(&name) {
285 return Err(syn::Error::new(
286 name.span(),
287 "tried to skip the same field twice",
288 ));
289 } else {
290 skips.insert(name);
291 }
292 }
293 Ok(Self(skips))
294 }
295}
296
297#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
298pub(crate) enum FormatMode {
299 #[default]
300 Default,
301 Display,
302 Debug,
303}
304
305#[derive(Clone, Debug)]
306pub(crate) struct Fields(pub(crate) Punctuated<Field, Token![,]>);
307
308#[derive(Clone, Debug)]
309pub(crate) struct Field {
310 pub(crate) name: Punctuated<Ident, Token![.]>,
311 pub(crate) value: Option<Expr>,
312 pub(crate) kind: FieldKind,
313}
314
315#[derive(Clone, Debug, Eq, PartialEq)]
316pub(crate) enum FieldKind {
317 Debug,
318 Display,
319 Value,
320}
321
322impl Parse for Fields {
323 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
324 let _ = input.parse::<kw::fields>();
325 let content;
326 let _ = syn::parenthesized!(content in input);
327 let fields = content.parse_terminated(Field::parse, Token![,])?;
328 Ok(Self(fields))
329 }
330}
331
332impl ToTokens for Fields {
333 fn to_tokens(&self, tokens: &mut TokenStream) {
334 self.0.to_tokens(tokens)
335 }
336}
337
338impl Parse for Field {
339 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
340 let mut kind = FieldKind::Value;
341 if input.peek(Token![%]) {
342 input.parse::<Token![%]>()?;
343 kind = FieldKind::Display;
344 } else if input.peek(Token![?]) {
345 input.parse::<Token![?]>()?;
346 kind = FieldKind::Debug;
347 };
348 let name = Punctuated::parse_separated_nonempty_with(input, Ident::parse_any)?;
349 let value = if input.peek(Token![=]) {
350 input.parse::<Token![=]>()?;
351 if input.peek(Token![%]) {
352 input.parse::<Token![%]>()?;
353 kind = FieldKind::Display;
354 } else if input.peek(Token![?]) {
355 input.parse::<Token![?]>()?;
356 kind = FieldKind::Debug;
357 };
358 Some(input.parse()?)
359 } else {
360 None
361 };
362 Ok(Self { name, value, kind })
363 }
364}
365
366impl ToTokens for Field {
367 fn to_tokens(&self, tokens: &mut TokenStream) {
368 if let Some(ref value) = self.value {
369 let name = &self.name;
370 let kind = &self.kind;
371 tokens.extend(quote! {
372 #name = #kind #value
373 })
374 } else if self.kind == FieldKind::Value {
375 let name = &self.name;
381 tokens.extend(quote!(#name = tracing::field::Empty))
382 } else {
383 self.kind.to_tokens(tokens);
384 self.name.to_tokens(tokens);
385 }
386 }
387}
388
389impl ToTokens for FieldKind {
390 fn to_tokens(&self, tokens: &mut TokenStream) {
391 match self {
392 FieldKind::Debug => tokens.extend(quote! { ? }),
393 FieldKind::Display => tokens.extend(quote! { % }),
394 _ => {}
395 }
396 }
397}
398
399#[derive(Clone, Debug)]
400pub(crate) enum Level {
401 Trace,
402 Debug,
403 Info,
404 Warn,
405 Error,
406 Path(Path),
407}
408
409impl Parse for Level {
410 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
411 let _ = input.parse::<kw::level>()?;
412 let _ = input.parse::<Token![=]>()?;
413 let lookahead = input.lookahead1();
414 if lookahead.peek(LitStr) {
415 let str: LitStr = input.parse()?;
416 match str.value() {
417 s if s.eq_ignore_ascii_case("trace") => Ok(Level::Trace),
418 s if s.eq_ignore_ascii_case("debug") => Ok(Level::Debug),
419 s if s.eq_ignore_ascii_case("info") => Ok(Level::Info),
420 s if s.eq_ignore_ascii_case("warn") => Ok(Level::Warn),
421 s if s.eq_ignore_ascii_case("error") => Ok(Level::Error),
422 _ => Err(input.error(
423 "unknown verbosity level, expected one of \"trace\", \
424 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5",
425 )),
426 }
427 } else if lookahead.peek(LitInt) {
428 fn is_level(lit: &LitInt, expected: u64) -> bool {
429 match lit.base10_parse::<u64>() {
430 Ok(value) => value == expected,
431 Err(_) => false,
432 }
433 }
434 let int: LitInt = input.parse()?;
435 match &int {
436 i if is_level(i, 1) => Ok(Level::Trace),
437 i if is_level(i, 2) => Ok(Level::Debug),
438 i if is_level(i, 3) => Ok(Level::Info),
439 i if is_level(i, 4) => Ok(Level::Warn),
440 i if is_level(i, 5) => Ok(Level::Error),
441 _ => Err(input.error(
442 "unknown verbosity level, expected one of \"trace\", \
443 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5",
444 )),
445 }
446 } else if lookahead.peek(Ident) {
447 Ok(Self::Path(input.parse()?))
448 } else {
449 Err(lookahead.error())
450 }
451 }
452}
453
454impl ToTokens for Level {
455 fn to_tokens(&self, tokens: &mut TokenStream) {
456 match self {
457 Level::Trace => tokens.extend(quote!(tracing::Level::TRACE)),
458 Level::Debug => tokens.extend(quote!(tracing::Level::DEBUG)),
459 Level::Info => tokens.extend(quote!(tracing::Level::INFO)),
460 Level::Warn => tokens.extend(quote!(tracing::Level::WARN)),
461 Level::Error => tokens.extend(quote!(tracing::Level::ERROR)),
462 Level::Path(ref pat) => tokens.extend(quote!(#pat)),
463 }
464 }
465}
466
467mod kw {
468 syn::custom_keyword!(fields);
469 syn::custom_keyword!(skip);
470 syn::custom_keyword!(skip_all);
471 syn::custom_keyword!(level);
472 syn::custom_keyword!(target);
473 syn::custom_keyword!(parent);
474 syn::custom_keyword!(follows_from);
475 syn::custom_keyword!(name);
476 syn::custom_keyword!(err);
477 syn::custom_keyword!(ret);
478}