LCOV - differential code coverage report
Current view: top level - libs/tracing-utils/src - lib.rs (source / functions) Coverage Total Hit UBC CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 90.9 % 88 80 8 80
Current Date: 2024-01-09 02:06:09 Functions: 100.0 % 5 5 5
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

           TLA  Line data    Source code
       1                 : //! Helper functions to set up OpenTelemetry tracing.
       2                 : //!
       3                 : //! This comes in two variants, depending on whether you have a Tokio runtime available.
       4                 : //! If you do, call `init_tracing()`. It sets up the trace processor and exporter to use
       5                 : //! the current tokio runtime. If you don't have a runtime available, or you don't want
       6                 : //! to share the runtime with the tracing tasks, call `init_tracing_without_runtime()`
       7                 : //! instead. It sets up a dedicated single-threaded Tokio runtime for the tracing tasks.
       8                 : //!
       9                 : //! Example:
      10                 : //!
      11                 : //! ```rust,no_run
      12                 : //! use tracing_subscriber::prelude::*;
      13                 : //! use tracing_opentelemetry::OpenTelemetryLayer;
      14                 : //!
      15                 : //! #[tokio::main]
      16                 : //! async fn main() {
      17                 : //!     // Set up logging to stderr
      18                 : //!     let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
      19                 : //!         .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info"));
      20                 : //!     let fmt_layer = tracing_subscriber::fmt::layer()
      21                 : //!         .with_target(false)
      22                 : //!         .with_writer(std::io::stderr);
      23                 : //!
      24                 : //!     // Initialize OpenTelemetry. Exports tracing spans as OpenTelemetry traces
      25                 : //!     let otlp_layer = tracing_utils::init_tracing("my_application").await.map(OpenTelemetryLayer::new);
      26                 : //!
      27                 : //!     // Put it all together
      28                 : //!     tracing_subscriber::registry()
      29                 : //!         .with(env_filter)
      30                 : //!         .with(otlp_layer)
      31                 : //!         .with(fmt_layer)
      32                 : //!         .init();
      33                 : //! }
      34                 : //! ```
      35                 : #![deny(unsafe_code)]
      36                 : #![deny(clippy::undocumented_unsafe_blocks)]
      37                 : 
      38                 : use opentelemetry::sdk::Resource;
      39                 : use opentelemetry::KeyValue;
      40                 : use opentelemetry_otlp::WithExportConfig;
      41                 : use opentelemetry_otlp::{OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT};
      42                 : 
      43                 : pub use tracing_opentelemetry::OpenTelemetryLayer;
      44                 : 
      45                 : pub mod http;
      46                 : 
      47                 : /// Set up OpenTelemetry exporter, using configuration from environment variables.
      48                 : ///
      49                 : /// `service_name` is set as the OpenTelemetry 'service.name' resource (see
      50                 : /// <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service>)
      51                 : ///
      52                 : /// We try to follow the conventions for the environment variables specified in
      53                 : /// <https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/>
      54                 : ///
      55                 : /// However, we only support a subset of those options:
      56                 : ///
      57                 : /// - OTEL_SDK_DISABLED is supported. The default is "false", meaning tracing
      58                 : ///   is enabled by default. Set it to "true" to disable.
      59                 : ///
      60                 : /// - We use the OTLP exporter, with HTTP protocol. Most of the OTEL_EXPORTER_OTLP_*
      61                 : ///   settings specified in
      62                 : ///   <https://opentelemetry.io/docs/reference/specification/protocol/exporter/>
      63                 : ///   are supported, as they are handled by the `opentelemetry-otlp` crate.
      64                 : ///   Settings related to other exporters have no effect.
      65                 : ///
      66                 : /// - Some other settings are supported by the `opentelemetry` crate.
      67                 : ///
      68                 : /// If you need some other setting, please test if it works first. And perhaps
      69                 : /// add a comment in the list above to save the effort of testing for the next
      70                 : /// person.
      71                 : ///
      72                 : /// This doesn't block, but is marked as 'async' to hint that this must be called in
      73                 : /// asynchronous execution context.
      74 CBC          23 : pub async fn init_tracing(service_name: &str) -> Option<opentelemetry::sdk::trace::Tracer> {
      75              23 :     if std::env::var("OTEL_SDK_DISABLED") == Ok("true".to_string()) {
      76 UBC           0 :         return None;
      77 CBC          23 :     };
      78              23 :     Some(init_tracing_internal(service_name.to_string()))
      79              23 : }
      80                 : 
      81                 : /// Like `init_tracing`, but creates a separate tokio Runtime for the tracing
      82                 : /// tasks.
      83             544 : pub fn init_tracing_without_runtime(
      84             544 :     service_name: &str,
      85             544 : ) -> Option<opentelemetry::sdk::trace::Tracer> {
      86             544 :     if std::env::var("OTEL_SDK_DISABLED") == Ok("true".to_string()) {
      87 UBC           0 :         return None;
      88 CBC         544 :     };
      89             544 : 
      90             544 :     // The opentelemetry batch processor and the OTLP exporter needs a Tokio
      91             544 :     // runtime. Create a dedicated runtime for them. One thread should be
      92             544 :     // enough.
      93             544 :     //
      94             544 :     // (Alternatively, instead of batching, we could use the "simple
      95             544 :     // processor", which doesn't need Tokio, and use "reqwest-blocking"
      96             544 :     // feature for the OTLP exporter, which also doesn't need Tokio.  However,
      97             544 :     // batching is considered best practice, and also I have the feeling that
      98             544 :     // the non-Tokio codepaths in the opentelemetry crate are less used and
      99             544 :     // might be more buggy, so better to stay on the well-beaten path.)
     100             544 :     //
     101             544 :     // We leak the runtime so that it keeps running after we exit the
     102             544 :     // function.
     103             544 :     let runtime = Box::leak(Box::new(
     104             544 :         tokio::runtime::Builder::new_multi_thread()
     105             544 :             .enable_all()
     106             544 :             .thread_name("otlp runtime thread")
     107             544 :             .worker_threads(1)
     108             544 :             .build()
     109             544 :             .unwrap(),
     110             544 :     ));
     111             544 :     let _guard = runtime.enter();
     112             544 : 
     113             544 :     Some(init_tracing_internal(service_name.to_string()))
     114             544 : }
     115                 : 
     116             567 : fn init_tracing_internal(service_name: String) -> opentelemetry::sdk::trace::Tracer {
     117             567 :     // Set up exporter from the OTEL_EXPORTER_* environment variables
     118             567 :     let mut exporter = opentelemetry_otlp::new_exporter().http().with_env();
     119             567 : 
     120             567 :     // XXX opentelemetry-otlp v0.18.0 has a bug in how it uses the
     121             567 :     // OTEL_EXPORTER_OTLP_ENDPOINT env variable. According to the
     122             567 :     // OpenTelemetry spec at
     123             567 :     // <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#endpoint-urls-for-otlphttp>,
     124             567 :     // the full exporter URL is formed by appending "/v1/traces" to the value
     125             567 :     // of OTEL_EXPORTER_OTLP_ENDPOINT. However, opentelemetry-otlp only does
     126             567 :     // that with the grpc-tonic exporter. Other exporters, like the HTTP
     127             567 :     // exporter, use the URL from OTEL_EXPORTER_OTLP_ENDPOINT as is, without
     128             567 :     // appending "/v1/traces".
     129             567 :     //
     130             567 :     // See https://github.com/open-telemetry/opentelemetry-rust/pull/950
     131             567 :     //
     132             567 :     // Work around that by checking OTEL_EXPORTER_OTLP_ENDPOINT, and setting
     133             567 :     // the endpoint url with the "/v1/traces" path ourselves. If the bug is
     134             567 :     // fixed in a later version, we can remove this code. But if we don't
     135             567 :     // remember to remove this, it won't do any harm either, as the crate will
     136             567 :     // just ignore the OTEL_EXPORTER_OTLP_ENDPOINT setting when the endpoint
     137             567 :     // is set directly with `with_endpoint`.
     138             567 :     if std::env::var(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT).is_err() {
     139             567 :         if let Ok(mut endpoint) = std::env::var(OTEL_EXPORTER_OTLP_ENDPOINT) {
     140 UBC           0 :             if !endpoint.ends_with('/') {
     141               0 :                 endpoint.push('/');
     142               0 :             }
     143               0 :             endpoint.push_str("v1/traces");
     144               0 :             exporter = exporter.with_endpoint(endpoint);
     145 CBC         567 :         }
     146 UBC           0 :     }
     147                 : 
     148                 :     // Propagate trace information in the standard W3C TraceContext format.
     149 CBC         567 :     opentelemetry::global::set_text_map_propagator(
     150             567 :         opentelemetry::sdk::propagation::TraceContextPropagator::new(),
     151             567 :     );
     152             567 : 
     153             567 :     opentelemetry_otlp::new_pipeline()
     154             567 :         .tracing()
     155             567 :         .with_exporter(exporter)
     156             567 :         .with_trace_config(
     157             567 :             opentelemetry::sdk::trace::config().with_resource(Resource::new(vec![KeyValue::new(
     158             567 :                 opentelemetry_semantic_conventions::resource::SERVICE_NAME,
     159             567 :                 service_name,
     160             567 :             )])),
     161             567 :         )
     162             567 :         .install_batch(opentelemetry::runtime::Tokio)
     163             567 :         .expect("could not initialize opentelemetry exporter")
     164             567 : }
     165                 : 
     166                 : // Shutdown trace pipeline gracefully, so that it has a chance to send any
     167                 : // pending traces before we exit.
     168             563 : pub fn shutdown_tracing() {
     169             563 :     opentelemetry::global::shutdown_tracer_provider();
     170             563 : }
        

Generated by: LCOV version 2.1-beta