1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Tracing-subscriber layer for libatrace_rust.
16 
17 use ::atrace::AtraceTag;
18 use std::fmt::Write;
19 use tracing::span::Attributes;
20 use tracing::span::Record;
21 use tracing::{Event, Id, Subscriber};
22 use tracing_subscriber::field::Visit;
23 use tracing_subscriber::layer::{Context, Layer};
24 use tracing_subscriber::registry::LookupSpan;
25 
26 /// Subscriber layer that forwards events to ATrace.
27 pub struct AtraceSubscriber {
28     tag: AtraceTag,
29     should_record_fields: bool,
30     should_filter: bool,
31 }
32 
33 impl Default for AtraceSubscriber {
default() -> Self34     fn default() -> Self {
35         Self::new(AtraceTag::App)
36     }
37 }
38 
39 impl AtraceSubscriber {
40     /// Makes a new subscriber with tag.
new(tag: AtraceTag) -> AtraceSubscriber41     pub fn new(tag: AtraceTag) -> AtraceSubscriber {
42         AtraceSubscriber { tag, should_filter: false, should_record_fields: true }
43     }
44 
45     /// Enables event and span filtering. With filtering enabled, this layer would filter events for
46     /// all the layers of the subscriber.
47     /// Use this to speed up the subscriber if it's the only layer. Do not enable if you need other
48     /// layers to receive events when ATrace is disabled.
with_filter(self) -> AtraceSubscriber49     pub fn with_filter(self) -> AtraceSubscriber {
50         AtraceSubscriber { should_filter: true, ..self }
51     }
52 
53     /// Disables recording of field values.
without_fields(self) -> AtraceSubscriber54     pub fn without_fields(self) -> AtraceSubscriber {
55         AtraceSubscriber { should_record_fields: false, ..self }
56     }
57 }
58 
59 // Internal methods.
60 impl AtraceSubscriber {
61     /// Checks that events and spans should be recorded in the span/event notification.
should_process_event(&self) -> bool62     fn should_process_event(&self) -> bool {
63         // If `should_filter == true` we don't need to check the tag - it was already checked by
64         // the layer filter in the `Layer::enabled()` method.
65         // The checks are done in this order:
66         //  * `Layer::register_callsite()` - once per callsite, the result is cached.
67         //  * `Layer::enabled()` - once per span or event construction if the callsite is enabled.
68         //  * `should_process_event()` - on every notification like new span, span enter/exit/record, event.
69         // The first two checks are global, i.e. affect other layers, and only enabled with `should_filter`.
70         // Read more:
71         // https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html#filtering-with-layers
72         self.should_filter || atrace::atrace_is_tag_enabled(self.tag)
73     }
74 }
75 
76 impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Layer<S> for AtraceSubscriber {
register_callsite( &self, _metadata: &'static tracing::Metadata<'static>, ) -> tracing::subscriber::Interest77     fn register_callsite(
78         &self,
79         _metadata: &'static tracing::Metadata<'static>,
80     ) -> tracing::subscriber::Interest {
81         if self.should_filter {
82             // When we return `Interest::sometimes()`, the `enabled()` method would get checked
83             // every time.
84             // We can't use callsite caching (`Interest::never()`) because there's no callback
85             // for when tracing gets enabled - we need to check it every time.
86             tracing::subscriber::Interest::sometimes()
87         } else {
88             // If we do not disable events in the layer, we always receive the notifications.
89             tracing::subscriber::Interest::always()
90         }
91     }
92 
93     // When filtering in this layer is enabled, this method would get called on every event and span.
94     // This filter affects all layers, so if this method returns false, it would disable the event
95     // for others as well.
enabled(&self, _metadata: &tracing::Metadata<'_>, _ctx: Context<'_, S>) -> bool96     fn enabled(&self, _metadata: &tracing::Metadata<'_>, _ctx: Context<'_, S>) -> bool {
97         !self.should_filter || atrace::atrace_is_tag_enabled(self.tag)
98     }
99 
on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>)100     fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
101         if !self.should_record_fields || attrs.fields().is_empty() || !self.should_process_event() {
102             return;
103         }
104 
105         let span = ctx.span(id).unwrap();
106         let mut formatter = FieldFormatter::for_span(span.metadata().name());
107         attrs.record(&mut formatter);
108         span.extensions_mut().insert(formatter);
109     }
110 
on_record(&self, span: &Id, values: &Record, ctx: Context<S>)111     fn on_record(&self, span: &Id, values: &Record, ctx: Context<S>) {
112         if !self.should_record_fields || !self.should_process_event() {
113             return;
114         }
115 
116         values
117             .record(ctx.span(span).unwrap().extensions_mut().get_mut::<FieldFormatter>().unwrap());
118     }
119 
on_enter(&self, id: &Id, ctx: Context<S>)120     fn on_enter(&self, id: &Id, ctx: Context<S>) {
121         if !self.should_process_event() {
122             return;
123         }
124 
125         let span = ctx.span(id).unwrap();
126         if span.fields().is_empty() || !self.should_record_fields {
127             atrace::atrace_begin(self.tag, span.metadata().name());
128         } else {
129             let span_extensions = span.extensions();
130             let formatter = span_extensions.get::<FieldFormatter>().unwrap();
131             atrace::atrace_begin(self.tag, formatter.as_str());
132         }
133     }
134 
on_exit(&self, _id: &Id, _ctx: Context<S>)135     fn on_exit(&self, _id: &Id, _ctx: Context<S>) {
136         if !self.should_process_event() {
137             return;
138         }
139 
140         atrace::atrace_end(self.tag);
141     }
142 
on_event(&self, event: &Event, _ctx: Context<S>)143     fn on_event(&self, event: &Event, _ctx: Context<S>) {
144         if !self.should_process_event() {
145             return;
146         }
147 
148         if self.should_record_fields {
149             let mut formatter = FieldFormatter::for_event();
150             event.record(&mut formatter);
151             atrace::atrace_instant(self.tag, formatter.as_str());
152         } else if let Some(field) = event.metadata().fields().field("message") {
153             struct MessageVisitor<'a> {
154                 tag: AtraceTag,
155                 field: &'a tracing::field::Field,
156             }
157             impl Visit for MessageVisitor<'_> {
158                 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
159                     if field == self.field {
160                         atrace::atrace_instant(self.tag, value);
161                     }
162                 }
163                 fn record_debug(
164                     &mut self,
165                     field: &tracing::field::Field,
166                     value: &dyn std::fmt::Debug,
167                 ) {
168                     if field == self.field {
169                         atrace::atrace_instant(self.tag, &format!("{:?}", value));
170                     }
171                 }
172             }
173             event.record(&mut MessageVisitor { tag: self.tag, field: &field });
174         } else {
175             atrace::atrace_instant(
176                 self.tag,
177                 &format!("{} event", event.metadata().level().as_str()),
178             );
179         }
180     }
181 }
182 
183 struct FieldFormatter {
184     is_event: bool,
185     s: String,
186 }
187 
188 impl FieldFormatter {
new() -> FieldFormatter189     fn new() -> FieldFormatter {
190         const DEFAULT_STR_CAPACITY: usize = 128; // Should fit most events without realloc.
191         FieldFormatter { is_event: true, s: String::with_capacity(DEFAULT_STR_CAPACITY) }
192     }
193 
for_event() -> FieldFormatter194     fn for_event() -> FieldFormatter {
195         FieldFormatter { is_event: true, ..FieldFormatter::new() }
196     }
for_span(span_name: &str) -> FieldFormatter197     fn for_span(span_name: &str) -> FieldFormatter {
198         let mut formatter = FieldFormatter { is_event: false, ..FieldFormatter::new() };
199         formatter.s.push_str(span_name);
200         formatter
201     }
202 
as_str(&self) -> &str203     fn as_str(&self) -> &str {
204         &self.s
205     }
add_delimeter_if_needed(&mut self)206     fn add_delimeter_if_needed(&mut self) {
207         if !self.s.is_empty() {
208             self.s.push_str(", ");
209         }
210     }
211 }
212 
213 impl Visit for FieldFormatter {
record_str(&mut self, field: &tracing::field::Field, value: &str)214     fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
215         self.add_delimeter_if_needed();
216         if self.is_event && field.name() == "message" {
217             self.s.push_str(value);
218         } else {
219             write!(&mut self.s, "{} = \"{}\"", field.name(), value).unwrap();
220         }
221     }
record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug)222     fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
223         self.add_delimeter_if_needed();
224         if self.is_event && field.name() == "message" {
225             write!(&mut self.s, "{:?}", value).unwrap();
226         } else {
227             write!(&mut self.s, "{} = {:?}", field.name(), value).unwrap();
228         }
229     }
230 }
231 
232 #[cfg(test)]
233 use self::tests::mock_atrace as atrace;
234 
235 #[cfg(test)]
236 mod tests {
237     use super::*;
238     use tracing::Level;
239     use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
240 
241     pub mod mock_atrace {
242         use atrace::AtraceTag;
243         use std::cell::RefCell;
244 
245         /// Contains logic to check binding calls.
246         /// Implement this trait in the test with mocking logic and checks in implemented functions.
247         /// Default implementations panic.
248         pub trait ATraceMocker {
atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool249             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
250                 panic!("Unexpected call");
251             }
252 
atrace_begin(&mut self, _tag: AtraceTag, _name: &str)253             fn atrace_begin(&mut self, _tag: AtraceTag, _name: &str) {
254                 panic!("Unexpected call");
255             }
256 
atrace_end(&mut self, _tag: AtraceTag)257             fn atrace_end(&mut self, _tag: AtraceTag) {
258                 panic!("Unexpected call");
259             }
260 
atrace_instant(&mut self, _tag: AtraceTag, _name: &str)261             fn atrace_instant(&mut self, _tag: AtraceTag, _name: &str) {
262                 panic!("Unexpected call");
263             }
264 
265             /// This method should contain checks to be performed at the end of the test.
finish(&self)266             fn finish(&self) {}
267         }
268 
269         struct DefaultMocker;
270         impl ATraceMocker for DefaultMocker {}
271 
272         // Global mock object is thread-local, so that the tests can run safely in parallel.
273         thread_local!(static MOCKER: RefCell<Box<dyn ATraceMocker>> = RefCell::new(Box::new(DefaultMocker{})));
274 
275         /// Sets the global mock object.
set_mocker(mocker: Box<dyn ATraceMocker>)276         fn set_mocker(mocker: Box<dyn ATraceMocker>) {
277             MOCKER.with(|m| *m.borrow_mut() = mocker)
278         }
279 
280         /// Calls the passed method `f` with a mutable reference to the global mock object.
281         /// Example:
282         /// ```
283         /// with_mocker(|mocker| mocker.atrace_begin(tag, name))
284         /// ```
with_mocker<F, R>(f: F) -> R where F: FnOnce(&mut dyn ATraceMocker) -> R,285         fn with_mocker<F, R>(f: F) -> R
286         where
287             F: FnOnce(&mut dyn ATraceMocker) -> R,
288         {
289             MOCKER.with(|m| f(m.borrow_mut().as_mut()))
290         }
291 
292         /// Finish the test and perform final checks in the mocker.
293         /// Calls `finish()` on the global mocker.
294         ///
295         /// Needs to be called manually at the end of each test that uses mocks.
296         ///
297         /// May panic, so it can not be called in `drop()` methods,
298         /// since it may result in double panic.
mocker_finish()299         pub fn mocker_finish() {
300             with_mocker(|m| m.finish())
301         }
302 
303         /// RAII guard that resets the mock to the default implementation.
304         pub struct MockerGuard;
305         impl Drop for MockerGuard {
drop(&mut self)306             fn drop(&mut self) {
307                 set_mocker(Box::new(DefaultMocker {}));
308             }
309         }
310 
311         /// Sets the mock object for the duration of the scope.
312         ///
313         /// Returns a RAII guard that resets the mock back to default on destruction.
set_scoped_mocker<T: ATraceMocker + 'static>(m: T) -> MockerGuard314         pub fn set_scoped_mocker<T: ATraceMocker + 'static>(m: T) -> MockerGuard {
315             set_mocker(Box::new(m));
316             MockerGuard {}
317         }
318 
319         // Wrapped functions that forward calls into mocker.
320 
atrace_is_tag_enabled(tag: AtraceTag) -> bool321         pub fn atrace_is_tag_enabled(tag: AtraceTag) -> bool {
322             with_mocker(|m| m.atrace_is_tag_enabled(tag))
323         }
atrace_begin(tag: AtraceTag, name: &str)324         pub fn atrace_begin(tag: AtraceTag, name: &str) {
325             with_mocker(|m| m.atrace_begin(tag, name))
326         }
327 
atrace_end(tag: AtraceTag)328         pub fn atrace_end(tag: AtraceTag) {
329             with_mocker(|m| m.atrace_end(tag))
330         }
331 
atrace_instant(tag: AtraceTag, name: &str)332         pub fn atrace_instant(tag: AtraceTag, name: &str) {
333             with_mocker(|m| m.atrace_instant(tag, name))
334         }
335     }
336 
337     #[test]
emits_span_begin()338     fn emits_span_begin() {
339         #[derive(Default)]
340         struct CallCheck {
341             begin_count: u32,
342         }
343         impl mock_atrace::ATraceMocker for CallCheck {
344             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
345                 true
346             }
347             fn atrace_begin(&mut self, tag: AtraceTag, name: &str) {
348                 self.begin_count += 1;
349                 assert!(self.begin_count < 2);
350                 assert_eq!(tag, AtraceTag::App);
351                 assert_eq!(name, "test span");
352             }
353             fn atrace_end(&mut self, _tag: AtraceTag) {}
354 
355             fn finish(&self) {
356                 assert_eq!(self.begin_count, 1);
357             }
358         }
359         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
360 
361         let _subscriber_guard = tracing::subscriber::set_default(
362             tracing_subscriber::registry().with(AtraceSubscriber::default()),
363         );
364 
365         let _span = tracing::info_span!("test span").entered();
366 
367         mock_atrace::mocker_finish();
368     }
369 
370     #[test]
emits_span_end()371     fn emits_span_end() {
372         #[derive(Default)]
373         struct CallCheck {
374             end_count: u32,
375         }
376         impl mock_atrace::ATraceMocker for CallCheck {
377             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
378                 true
379             }
380             fn atrace_begin(&mut self, _tag: AtraceTag, _name: &str) {}
381             fn atrace_end(&mut self, tag: AtraceTag) {
382                 self.end_count += 1;
383                 assert!(self.end_count < 2);
384                 assert_eq!(tag, AtraceTag::App);
385             }
386 
387             fn finish(&self) {
388                 assert_eq!(self.end_count, 1);
389             }
390         }
391         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
392 
393         let _subscriber_guard = tracing::subscriber::set_default(
394             tracing_subscriber::registry().with(AtraceSubscriber::default()),
395         );
396 
397         {
398             let _span = tracing::info_span!("test span").entered();
399         }
400 
401         mock_atrace::mocker_finish();
402     }
403 
404     #[test]
span_begin_end_is_ordered()405     fn span_begin_end_is_ordered() {
406         #[derive(Default)]
407         struct CallCheck {
408             begin_count: u32,
409             instant_count: u32,
410             end_count: u32,
411         }
412         impl mock_atrace::ATraceMocker for CallCheck {
413             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
414                 true
415             }
416             fn atrace_begin(&mut self, _tag: AtraceTag, _name: &str) {
417                 assert_eq!(self.end_count, 0);
418                 assert_eq!(self.instant_count, 0);
419 
420                 self.begin_count += 1;
421                 assert!(self.begin_count < 2);
422             }
423             fn atrace_instant(&mut self, _tag: AtraceTag, _name: &str) {
424                 assert_eq!(self.begin_count, 1);
425                 assert_eq!(self.end_count, 0);
426 
427                 self.instant_count += 1;
428                 assert!(self.instant_count < 2);
429             }
430             fn atrace_end(&mut self, _tag: AtraceTag) {
431                 assert_eq!(self.begin_count, 1);
432                 assert_eq!(self.instant_count, 1);
433 
434                 self.end_count += 1;
435                 assert!(self.end_count < 2);
436             }
437 
438             fn finish(&self) {
439                 assert_eq!(self.begin_count, 1);
440                 assert_eq!(self.end_count, 1);
441                 assert_eq!(self.instant_count, 1);
442             }
443         }
444         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
445 
446         let _subscriber_guard = tracing::subscriber::set_default(
447             tracing_subscriber::registry().with(AtraceSubscriber::default()),
448         );
449 
450         {
451             let _span = tracing::info_span!("span").entered();
452             tracing::info!("test info");
453         }
454 
455         mock_atrace::mocker_finish();
456     }
457 
458     #[test]
emits_instant_event()459     fn emits_instant_event() {
460         #[derive(Default)]
461         struct CallCheck {
462             instant_count: u32,
463         }
464         impl mock_atrace::ATraceMocker for CallCheck {
465             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
466                 true
467             }
468             fn atrace_instant(&mut self, tag: AtraceTag, name: &str) {
469                 self.instant_count += 1;
470                 assert!(self.instant_count < 2);
471                 assert_eq!(tag, AtraceTag::App);
472                 assert_eq!(name, "test info");
473             }
474 
475             fn finish(&self) {
476                 assert_eq!(self.instant_count, 1);
477             }
478         }
479         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
480 
481         let _subscriber_guard = tracing::subscriber::set_default(
482             tracing_subscriber::registry().with(AtraceSubscriber::default()),
483         );
484 
485         tracing::info!("test info");
486 
487         mock_atrace::mocker_finish();
488     }
489 
490     #[test]
formats_event_without_message_with_fields_disabled()491     fn formats_event_without_message_with_fields_disabled() {
492         #[derive(Default)]
493         struct CallCheck {
494             instant_count: u32,
495         }
496         impl mock_atrace::ATraceMocker for CallCheck {
497             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
498                 true
499             }
500             fn atrace_instant(&mut self, _tag: AtraceTag, name: &str) {
501                 self.instant_count += 1;
502                 assert!(self.instant_count < 2);
503                 assert_eq!(name, "DEBUG event");
504             }
505 
506             fn finish(&self) {
507                 assert_eq!(self.instant_count, 1);
508             }
509         }
510         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
511 
512         let _subscriber_guard = tracing::subscriber::set_default(
513             tracing_subscriber::registry().with(AtraceSubscriber::default().without_fields()),
514         );
515 
516         tracing::debug!(foo = 1);
517 
518         mock_atrace::mocker_finish();
519     }
520 
521     #[test]
formats_event_without_message_with_fields_enabled()522     fn formats_event_without_message_with_fields_enabled() {
523         #[derive(Default)]
524         struct CallCheck {
525             instant_count: u32,
526         }
527         impl mock_atrace::ATraceMocker for CallCheck {
528             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
529                 true
530             }
531             fn atrace_instant(&mut self, _tag: AtraceTag, name: &str) {
532                 self.instant_count += 1;
533                 assert!(self.instant_count < 2);
534                 assert_eq!(name, "foo = 1");
535             }
536 
537             fn finish(&self) {
538                 assert_eq!(self.instant_count, 1);
539             }
540         }
541         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
542 
543         let _subscriber_guard = tracing::subscriber::set_default(
544             tracing_subscriber::registry().with(AtraceSubscriber::default()),
545         );
546 
547         tracing::debug!(foo = 1);
548 
549         mock_atrace::mocker_finish();
550     }
551 
552     #[test]
can_set_tag()553     fn can_set_tag() {
554         #[derive(Default)]
555         struct CallCheck {
556             begin_count: u32,
557             instant_count: u32,
558             end_count: u32,
559         }
560         impl mock_atrace::ATraceMocker for CallCheck {
561             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
562                 true
563             }
564             fn atrace_begin(&mut self, tag: AtraceTag, _name: &str) {
565                 self.begin_count += 1;
566                 assert!(self.begin_count < 2);
567                 assert_eq!(tag, AtraceTag::WindowManager);
568             }
569             fn atrace_instant(&mut self, tag: AtraceTag, _name: &str) {
570                 self.instant_count += 1;
571                 assert!(self.instant_count < 2);
572                 assert_eq!(tag, AtraceTag::WindowManager);
573             }
574             fn atrace_end(&mut self, tag: AtraceTag) {
575                 self.end_count += 1;
576                 assert!(self.end_count < 2);
577                 assert_eq!(tag, AtraceTag::WindowManager);
578             }
579 
580             fn finish(&self) {
581                 assert_eq!(self.begin_count, 1);
582                 assert_eq!(self.end_count, 1);
583                 assert_eq!(self.instant_count, 1);
584             }
585         }
586         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
587 
588         let _subscriber_guard = tracing::subscriber::set_default(
589             tracing_subscriber::registry().with(AtraceSubscriber::new(AtraceTag::WindowManager)),
590         );
591 
592         {
593             let _span = tracing::info_span!("span").entered();
594             tracing::info!("test info");
595         }
596 
597         mock_atrace::mocker_finish();
598     }
599 
600     #[test]
fields_ignored_when_disabled()601     fn fields_ignored_when_disabled() {
602         #[derive(Default)]
603         struct CallCheck {
604             begin_count: u32,
605             instant_count: u32,
606         }
607         impl mock_atrace::ATraceMocker for CallCheck {
608             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
609                 true
610             }
611             fn atrace_begin(&mut self, _tag: AtraceTag, name: &str) {
612                 self.begin_count += 1;
613                 assert!(self.begin_count < 2);
614                 assert_eq!(name, "test span");
615             }
616             fn atrace_instant(&mut self, _tag: AtraceTag, name: &str) {
617                 self.instant_count += 1;
618                 assert!(self.instant_count < 2);
619                 assert_eq!(name, "test info");
620             }
621             fn atrace_end(&mut self, _tag: AtraceTag) {}
622             fn finish(&self) {
623                 assert_eq!(self.begin_count, 1);
624                 assert_eq!(self.instant_count, 1);
625             }
626         }
627         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
628 
629         let _subscriber_guard = tracing::subscriber::set_default(
630             tracing_subscriber::registry().with(AtraceSubscriber::default().without_fields()),
631         );
632 
633         let _span = tracing::info_span!("test span", bar = "foo").entered();
634         tracing::event!(Level::INFO, foo = "bar", "test info");
635 
636         mock_atrace::mocker_finish();
637     }
638 
639     #[test]
formats_instant_event_fields()640     fn formats_instant_event_fields() {
641         #[derive(Default)]
642         struct CallCheck {
643             instant_count: u32,
644         }
645         impl mock_atrace::ATraceMocker for CallCheck {
646             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
647                 true
648             }
649             fn atrace_instant(&mut self, _tag: AtraceTag, name: &str) {
650                 self.instant_count += 1;
651                 assert!(self.instant_count < 2);
652                 assert_eq!(name, "test info, foo = \"bar\", baz = 5");
653             }
654             fn finish(&self) {
655                 assert_eq!(self.instant_count, 1);
656             }
657         }
658         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
659 
660         let _subscriber_guard = tracing::subscriber::set_default(
661             tracing_subscriber::registry().with(AtraceSubscriber::default()),
662         );
663 
664         tracing::event!(Level::INFO, foo = "bar", baz = 5, "test info");
665 
666         mock_atrace::mocker_finish();
667     }
668 
669     #[test]
formats_span_fields()670     fn formats_span_fields() {
671         #[derive(Default)]
672         struct CallCheck {
673             begin_count: u32,
674         }
675         impl mock_atrace::ATraceMocker for CallCheck {
676             fn atrace_is_tag_enabled(&mut self, _tag: AtraceTag) -> bool {
677                 true
678             }
679             fn atrace_begin(&mut self, _tag: AtraceTag, name: &str) {
680                 self.begin_count += 1;
681                 assert!(self.begin_count < 2);
682                 assert_eq!(name, "test span, foo = \"bar\", baz = 5");
683             }
684             fn atrace_end(&mut self, _tag: AtraceTag) {}
685             fn finish(&self) {
686                 assert_eq!(self.begin_count, 1);
687             }
688         }
689         let _mock_guard = mock_atrace::set_scoped_mocker(CallCheck::default());
690 
691         let _subscriber_guard = tracing::subscriber::set_default(
692             tracing_subscriber::registry().with(AtraceSubscriber::default()),
693         );
694 
695         let _span = tracing::info_span!("test span", foo = "bar", baz = 5).entered();
696 
697         mock_atrace::mocker_finish();
698     }
699 }
700