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