From c0f14582adf37fc11ae9d5afcd4606c1a59a2610 Mon Sep 17 00:00:00 2001 From: satyam Date: Sun, 24 Nov 2024 15:36:01 +0530 Subject: [PATCH 1/2] update crates version --- Cargo.toml | 24 ++++++------- src/lib.rs | 92 ++++++++++++++++++++++++++++--------------------- src/resource.rs | 47 +++++++++++++++++-------- src/trace.rs | 39 ++++++++++----------- 4 files changed, 115 insertions(+), 87 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index afd0c60..4b19921 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,19 +12,19 @@ resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } -tracing-opentelemetry = "0.26.0" -opentelemetry = { version = "0.25.0", features = ["trace", "logs"] } -opentelemetry_sdk = { version = "0.25.0", features = ["metrics", "rt-tokio"] } -opentelemetry-otlp = { version = "0.25.0", features = ["trace", "logs"] } -opentelemetry-semantic-conventions = "0.25.0" anyhow = "1.0" -thiserror = "1.0" -derive_builder = "0.20.0" +derive_builder = "0.20" +opentelemetry = "0.27" +opentelemetry-semantic-conventions = {version = "0.27", features=["semconv_experimental"]} +thiserror = "2.0" +tracing-opentelemetry = "0.28" +tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } +opentelemetry_sdk = { version = "0.27", features = ["metrics", "rt-tokio"] } +opentelemetry-otlp = { version = "0.27", features = ["trace", "logs"] } [dev-dependencies] -tokio = { version = "1.38", features = ["rt","macros"] } +tokio = { version = "1.4", features = ["rt", "macros"] } tracing = "0.1" -testcontainers = "0.22.0" -reqwest = { version = "0.12.3", features = ["blocking", "json"] } -serde_json = "1.0" \ No newline at end of file +testcontainers = "0.22" +reqwest = { version = "0.12", features = ["blocking", "json"] } +serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs index ec55faa..c290851 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ //! # OpenTelemetry Logging with Tokio Tracing -//! +//! //! This crate provides a convienent way to initialize the OpenTelemetry logger //! with otlp endpoint. It uses the [`opentelemetry`] and [`tracing`] //! crates to provide structured, context-aware logging for Rust applications. -//! +//! //! Simply add the following to your `Cargo.toml`: //! ```toml //! [dependencies] @@ -11,11 +11,11 @@ //! otlp-logger = "0.4" //! tokio = { version = "1.38", features = ["rt", "macros"] } //! ``` -//! +//! //! Because this crate uses the batching function of the OpenTelemetry SDK, it is //! required to use the `tokio` runtime. Due to this requirement, the [`tokio`] crate //! must be added as a dependency in your `Cargo.toml` file. -//! +//! //! In your code initialize the logger with: //! ```rust //! #[tokio::main] @@ -23,17 +23,17 @@ //! // Initialize the OpenTelemetry logger using environment variables //! otlp_logger::init().await; //! // ... your application code -//! -//! // and optionally call open telemetry logger shutdown to make sure all the +//! +//! // and optionally call open telemetry logger shutdown to make sure all the //! // data is sent to the configured endpoint before the application exits //! otlp_logger::shutdown(); //! } //! ``` -//! +//! //! If the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable is set, the //! OpenTelemetry logger will be used. Otherwise, the logger will default to //! only stdout. -//! +//! //! The OpenTelemetry logger can be configured with the following environment //! variables: //! - `OTEL_EXPORTER_OTLP_ENDPOINT`: The endpoint to send OTLP data to. @@ -42,16 +42,16 @@ //! - `OTEL_SERVICE_VERSION`: The version of the service. //! - `OTEL_SERVICE_INSTANCE_ID`: The instance ID of the service. //! - `OTEL_DEPLOYMENT_ENVIRONMENT`: The deployment environment of the service. -//! +//! //! The OpenTelemetry logger can also be configured with the `OtlpConfig` struct, which //! can be passed to the `init_with_config` function. The `OtlpConfig` struct can be built //! with the `OtlpConfigBuilder` struct. -//! +//! //! Once the logger is initialized, you can use the [`tracing`] macros to log //! messages. For example: //! ```rust //! use tracing::{info, error}; -//! +//! //! #[tokio::main] //! async fn main() { //! otlp_logger::init().await; @@ -59,14 +59,14 @@ //! error!("This is an error message"); //! } //! ``` -//! +//! //! Traces and logs are sent to the configured OTLP endpoint. The traces //! and log levels are configured via the RUST_LOG environment variable. //! This behavior can be overridden by setting the `trace_level` or //! `stdout_level` fields in the `OtlpConfig` struct. //! ```rust //! use otlp_logger::{OtlpConfigBuilder, LevelFilter}; -//! +//! //! #[tokio::main] //! async fn main() { //! let config = OtlpConfigBuilder::default() @@ -75,16 +75,16 @@ //! .stdout_level(LevelFilter::ERROR) //! .build() //! .expect("failed to create otlp config builder"); -//! +//! //! otlp_logger::init_with_config(config).await.expect("failed to initialize logger"); -//! +//! //! // ... your application code -//! +//! //! // shutdown the logger //! otlp_logger::shutdown(); //! } //! ``` -//! +//! //! [`tokio`]: https://crates.io/crates/tokio //! [`tracing`]: https://crates.io/crates/tracing //! [`opentelemetry`]: https://crates.io/crates/opentelemetry @@ -106,17 +106,16 @@ mod trace; use resource::*; use trace::*; - #[derive(Default, Builder)] #[builder(setter(into), default)] -pub struct OtlpConfig { +pub struct OtlpConfig { service_name: Option, service_namespace: Option, service_version: Option, service_instant_id: Option, - deployment_environment: Option, - otlp_endpoint: Option, - trace_level: Option, + deployment_environment: Option, + otlp_endpoint: Option, + trace_level: Option, stdout_level: Option, } @@ -129,11 +128,14 @@ impl OtlpConfig { fn init_otel(config: &OtlpConfig) -> Result<()> { opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new()); - let otlp_endpoint = config.otlp_endpoint.as_ref().context("OTLP endpoint not set")?; + let otlp_endpoint = config + .otlp_endpoint + .as_ref() + .context("OTLP endpoint not set")?; let resource = otel_resource(config); - let tracer = otel_tracer(otlp_endpoint, resource.clone())?; + let tracer: opentelemetry_sdk::trace::Tracer = otel_tracer(otlp_endpoint, resource.clone())?; let traces_layer = tracing_opentelemetry::layer() .with_tracer(tracer) .with_filter(define_filter_level(config.trace_level)); @@ -238,9 +240,18 @@ mod tests { assert_eq!(config.service_name, Some("test-service".to_string())); assert_eq!(config.service_namespace, Some("test-namespace".to_string())); assert_eq!(config.service_version, Some("test-version".to_string())); - assert_eq!(config.service_instant_id, Some("test-instant-id".to_string())); - assert_eq!(config.deployment_environment, Some("test-environment".to_string())); - assert_eq!(config.otlp_endpoint, Some("http://localhost:4317".to_string())); + assert_eq!( + config.service_instant_id, + Some("test-instant-id".to_string()) + ); + assert_eq!( + config.deployment_environment, + Some("test-environment".to_string()) + ); + assert_eq!( + config.otlp_endpoint, + Some("http://localhost:4317".to_string()) + ); assert_eq!(config.trace_level, Some(LevelFilter::DEBUG)); assert_eq!(config.stdout_level, Some(LevelFilter::WARN)); } @@ -248,35 +259,36 @@ mod tests { #[test] fn test_config_builder_some() { let config = OtlpConfig::builder() - .otlp_endpoint("http://localhost:4317".to_string()) - .trace_level(LevelFilter::INFO) - .stdout_level(LevelFilter::ERROR) - .build() - .expect("failed to configure otlp-logger"); + .otlp_endpoint("http://localhost:4317".to_string()) + .trace_level(LevelFilter::INFO) + .stdout_level(LevelFilter::ERROR) + .build() + .expect("failed to configure otlp-logger"); assert_eq!(config.service_name, None); assert_eq!(config.service_namespace, None); assert_eq!(config.service_version, None); assert_eq!(config.service_instant_id, None); assert_eq!(config.deployment_environment, None); - assert_eq!(config.otlp_endpoint, Some("http://localhost:4317".to_string())); + assert_eq!( + config.otlp_endpoint, + Some("http://localhost:4317".to_string()) + ); assert_eq!(config.trace_level, Some(LevelFilter::INFO)); - assert_eq!(config.stdout_level, Some(LevelFilter::ERROR)); + assert_eq!(config.stdout_level, Some(LevelFilter::ERROR)); } #[test] fn test_config_builder_none() { - let config = OtlpConfig::builder() - .build() - .unwrap(); + let config = OtlpConfig::builder().build().unwrap(); assert_eq!(config.service_name, None); assert_eq!(config.service_namespace, None); assert_eq!(config.service_version, None); assert_eq!(config.service_instant_id, None); assert_eq!(config.deployment_environment, None); - assert_eq!(config.otlp_endpoint, None); + assert_eq!(config.otlp_endpoint, None); assert_eq!(config.trace_level, None); - assert_eq!(config.stdout_level, None); + assert_eq!(config.stdout_level, None); } -} \ No newline at end of file +} diff --git a/src/resource.rs b/src/resource.rs index 2c80d2b..59ee29c 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -4,13 +4,15 @@ use std::env::args_os; use std::process::id; use opentelemetry::{KeyValue, StringValue, Value}; -use opentelemetry_sdk::{resource::{ResourceDetector, SdkProvidedResourceDetector, TelemetryResourceDetector}, Resource}; +use opentelemetry_sdk::{ + resource::{ResourceDetector, SdkProvidedResourceDetector, TelemetryResourceDetector}, + Resource, +}; use opentelemetry_semantic_conventions::resource as otel_resource; use crate::OtlpConfig; pub fn otel_resource(config: &OtlpConfig) -> Resource { - let os_resource = detect_os(); let process_resource = detect_process(); let telemetry_resource = TelemetryResourceDetector.detect(Duration::from_secs(0)); @@ -18,19 +20,34 @@ pub fn otel_resource(config: &OtlpConfig) -> Resource { let mut provided = Vec::new(); if let Some(service_name) = &config.service_name { - provided.push(KeyValue::new(otel_resource::SERVICE_NAME, service_name.clone())); + provided.push(KeyValue::new( + otel_resource::SERVICE_NAME, + service_name.clone(), + )); } if let Some(service_namespace) = &config.service_namespace { - provided.push(KeyValue::new(otel_resource::SERVICE_NAMESPACE, service_namespace.clone())); + provided.push(KeyValue::new( + otel_resource::SERVICE_NAMESPACE, + service_namespace.clone(), + )); } if let Some(service_version) = &config.service_version { - provided.push(KeyValue::new(otel_resource::SERVICE_VERSION, service_version.clone())); + provided.push(KeyValue::new( + otel_resource::SERVICE_VERSION, + service_version.clone(), + )); } if let Some(service_instant_id) = &config.service_instant_id { - provided.push(KeyValue::new(otel_resource::SERVICE_INSTANCE_ID, service_instant_id.clone())); + provided.push(KeyValue::new( + otel_resource::SERVICE_INSTANCE_ID, + service_instant_id.clone(), + )); } if let Some(deployment_environment) = &config.deployment_environment { - provided.push(KeyValue::new(otel_resource::DEPLOYMENT_ENVIRONMENT_NAME, deployment_environment.clone())); + provided.push(KeyValue::new( + otel_resource::DEPLOYMENT_ENVIRONMENT_NAME, + deployment_environment.clone(), + )); } let app = Resource::new(provided); @@ -43,7 +60,10 @@ pub fn otel_resource(config: &OtlpConfig) -> Resource { } fn detect_os() -> Resource { - Resource::new(vec![KeyValue::new(otel_resource::OS_TYPE, std::env::consts::OS)]) + Resource::new(vec![KeyValue::new( + otel_resource::OS_TYPE, + std::env::consts::OS, + )]) } fn detect_process() -> Resource { @@ -52,7 +72,9 @@ fn detect_process() -> Resource { .into_iter() .map(|arg| arg.to_string_lossy().into_owned().into()) .collect::>(); - let current_exe = std::env::current_exe().map(|exe| exe.display().to_string()).unwrap_or_default(); + let current_exe = std::env::current_exe() + .map(|exe| exe.display().to_string()) + .unwrap_or_default(); Resource::new(vec![ KeyValue::new( opentelemetry_semantic_conventions::resource::PROCESS_COMMAND_ARGS, @@ -62,9 +84,6 @@ fn detect_process() -> Resource { opentelemetry_semantic_conventions::resource::PROCESS_PID, id() as i64, ), - KeyValue::new( - otel_resource::PROCESS_EXECUTABLE_NAME, - current_exe - ), + KeyValue::new(otel_resource::PROCESS_EXECUTABLE_NAME, current_exe), ]) -} \ No newline at end of file +} diff --git a/src/trace.rs b/src/trace.rs index 3278b5f..a4b6f30 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -1,24 +1,21 @@ -use anyhow::{Context, Result}; - -use opentelemetry::trace::TracerProvider as _; +use anyhow::Result; +use opentelemetry::global; +use opentelemetry::trace::TracerProvider; +use opentelemetry_otlp::SpanExporter; use opentelemetry_otlp::WithExportConfig; -use opentelemetry_sdk::{trace as sdktrace, Resource}; - +use opentelemetry_sdk::trace::Config; +use opentelemetry_sdk::trace::Tracer; +use opentelemetry_sdk::{runtime, trace as sdktrace, Resource}; -pub fn otel_tracer(endpoint: &str, resource: Resource) -> Result { - opentelemetry_otlp::new_pipeline() - .tracing() - .with_exporter( - opentelemetry_otlp::new_exporter() - .tonic() - .with_endpoint(endpoint) - ) - .with_trace_config(sdktrace::Config::default().with_resource(resource)) - .with_batch_config( - sdktrace::BatchConfigBuilder::default().build(), - ) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .map( |p| p.tracer_builder("tracing").build() ) - .context("Unable to initialize metrics OtlpPipeline") +pub fn otel_tracer(endpoint: &str, resource: Resource) -> Result { + let exporter = SpanExporter::builder() + .with_tonic() + .with_endpoint(endpoint) + .build()?; + let provider: sdktrace::TracerProvider = sdktrace::TracerProvider::builder() + .with_config(Config::default().with_resource(resource)) + .with_batch_exporter(exporter, runtime::Tokio) + .build(); + global::set_tracer_provider(provider.clone()); + Ok(provider.tracer("tracing-otel-subscriber")) } - From 48bc63001a51e2f9d3a279795e5741b942736132 Mon Sep 17 00:00:00 2001 From: satyam Date: Sun, 24 Nov 2024 15:39:39 +0530 Subject: [PATCH 2/2] updated crates --- Cargo.toml | 12 ++++++------ src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b19921..8add93c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,15 +12,15 @@ resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0" -derive_builder = "0.20" -opentelemetry = "0.27" -opentelemetry-semantic-conventions = {version = "0.27", features=["semconv_experimental"]} -thiserror = "2.0" -tracing-opentelemetry = "0.28" tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } +tracing-opentelemetry = "0.28" +opentelemetry = "0.27" opentelemetry_sdk = { version = "0.27", features = ["metrics", "rt-tokio"] } opentelemetry-otlp = { version = "0.27", features = ["trace", "logs"] } +opentelemetry-semantic-conventions = {version = "0.27", features=["semconv_experimental"]} +anyhow = "1.0" +thiserror = "2.0" +derive_builder = "0.20" [dev-dependencies] tokio = { version = "1.4", features = ["rt", "macros"] } diff --git a/src/lib.rs b/src/lib.rs index c290851..ee1946f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,7 +135,7 @@ fn init_otel(config: &OtlpConfig) -> Result<()> { let resource = otel_resource(config); - let tracer: opentelemetry_sdk::trace::Tracer = otel_tracer(otlp_endpoint, resource.clone())?; + let tracer = otel_tracer(otlp_endpoint, resource.clone())?; let traces_layer = tracing_opentelemetry::layer() .with_tracer(tracer) .with_filter(define_filter_level(config.trace_level));