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