| 321 | // context, hence the `async`. |
| 322 | #[allow(clippy::unused_async)] |
| 323 | pub async fn configure<F>(config: TracingConfig<F>) -> Result<TracingHandle, anyhow::Error> |
| 324 | where |
| 325 | F: Fn(&tracing::Metadata<'_>) -> sentry_tracing::EventFilter + Send + Sync + 'static, |
| 326 | { |
| 327 | let stderr_log_layer: Box<dyn Layer<Registry> + Send + Sync> = match config.stderr_log.format { |
| 328 | StderrLogFormat::Text { prefix } => { |
| 329 | // See: https://no-color.org/ |
| 330 | let no_color = std::env::var_os("NO_COLOR").unwrap_or_else(|| "".into()) != ""; |
| 331 | Box::new( |
| 332 | fmt::layer() |
| 333 | .with_writer(io::stderr) |
| 334 | .event_format(PrefixFormat { |
| 335 | inner: format(), |
| 336 | prefix, |
| 337 | }) |
| 338 | .with_ansi(!no_color && io::stderr().is_terminal()), |
| 339 | ) |
| 340 | } |
| 341 | StderrLogFormat::Json => Box::new( |
| 342 | fmt::layer() |
| 343 | .with_writer(io::stderr) |
| 344 | .json() |
| 345 | .with_current_span(true), |
| 346 | ), |
| 347 | }; |
| 348 | let (stderr_log_filter, stderr_log_filter_reloader) = reload::Layer::new({ |
| 349 | let mut filter = config.stderr_log.filter; |
| 350 | for directive in LOGGING_DEFAULTS.iter() { |
| 351 | filter = filter.add_directive(directive.clone()); |
| 352 | } |
| 353 | filter |
| 354 | }); |
| 355 | // Add rate limiting for OpenTelemetry internal logs to prevent log spam |
| 356 | // when there are issues with the OpenTelemetry pipeline (e.g., channel full, |
| 357 | // connection errors). This only affects logs from "opentelemetry*" targets. |
| 358 | let otel_rate_limit_filter = OpenTelemetryRateLimitingFilter::new(Duration::from_secs( |
| 359 | OPENTELEMETRY_RATE_LIMIT_BACKOFF_SECS, |
| 360 | )); |
| 361 | // IMPORTANT: The order matters here. The outer filter's `max_level_hint()` is used |
| 362 | // to determine the global tracing level. The `otel_rate_limit_filter` doesn't provide |
| 363 | // a `max_level_hint()` (defaults to TRACE), so the `stderr_log_filter` (EnvFilter) |
| 364 | // must be the outer filter to ensure the correct max level is reported. |
| 365 | let stderr_log_layer = stderr_log_layer |
| 366 | .with_filter(otel_rate_limit_filter) |
| 367 | .with_filter(stderr_log_filter); |
| 368 | let stderr_log_reloader = Arc::new(move |mut filter: EnvFilter, defaults: Vec<Directive>| { |
| 369 | for directive in &defaults { |
| 370 | filter = filter.add_directive(directive.clone()); |
| 371 | } |
| 372 | Ok(stderr_log_filter_reloader.reload(filter)?) |
| 373 | }); |
| 374 | |
| 375 | let (otel_layer, otel_reloader): (_, Reloader) = if let Some(otel_config) = config.opentelemetry |
| 376 | { |
| 377 | opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new()); |
| 378 | |
| 379 | // Manually set up an OpenSSL-backed, h2, proxied `Channel`, |
| 380 | // with the timeout configured according to: |