diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef6ae5d..440eed9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,21 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable + - name: Run cargo build (trace only) + uses: actions-rs/cargo@v1 + with: + command: build + args: --no-default-features --features trace + - name: Run cargo build (logs only) + uses: actions-rs/cargo@v1 + with: + command: build + args: --no-default-features --features logs + - name: Run cargo build (metrics only) + uses: actions-rs/cargo@v1 + with: + command: build + args: --no-default-features --features metrics - name: Run cargo test uses: actions-rs/cargo@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c636cd..18749b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +- Upgrade `opentelemetry` and `opentelemetry_sdk` to `v0.24`. +- Upgrade `opentelemetry-http` to `v0.13`. +- Upgrade `opentelemetry-semantic-conventions` to `v0.16`. +- Upgrade `http` to `1` and `reqwest` to `0.12`. +- Add `trace` feature and enable `trace`, `logs` and `metrics` by default. This mimicks opentelemetry. + ## [0.33.0] - 2024-06-09 - Add support for exporting logs, e.g. using one of the `opentelemetry-appender-*` crates. diff --git a/Cargo.toml b/Cargo.toml index 1f374f9..79cb633 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,28 +23,33 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] +default = ["trace", "metrics", "logs"] +trace = ["opentelemetry_sdk/trace"] +metrics = ["opentelemetry_sdk/metrics"] +logs = ["opentelemetry_sdk/logs"] +live-metrics = ["trace", "futures-util", "sysinfo"] +# Deprecated features: These don't enable anything in +# opentelemetry-application-insights. They only enable features in dependency +# crates. reqwest-blocking-client = ["reqwest-client"] reqwest-blocking-client-rustls = ["reqwest-client-rustls"] reqwest-client = ["opentelemetry-http/reqwest", "reqwest/native-tls"] reqwest-client-vendored-tls = ["opentelemetry-http/reqwest", "reqwest/native-tls-vendored"] reqwest-client-rustls = ["opentelemetry-http/reqwest", "reqwest/rustls-tls"] -metrics = ["opentelemetry_sdk/metrics"] -logs = ["opentelemetry_sdk/logs"] -live-metrics = ["futures-util", "sysinfo"] [dependencies] async-trait = "0.1" bytes = "1" chrono = "0.4" flate2 = "1" -http = "0.2" +http = "1" once_cell = "1" futures-util = { version = "0.3", default-features = false, optional = true } -opentelemetry = "0.23" -opentelemetry_sdk = "0.23" -opentelemetry-http = "0.12" -opentelemetry-semantic-conventions = "0.15" -reqwest = { version = "0.11", default-features = false, features = ["blocking"], optional = true } +opentelemetry = "0.24" +opentelemetry_sdk = "0.24" +opentelemetry-http = "0.13" +opentelemetry-semantic-conventions = "0.16" +reqwest = { version = "0.12", default-features = false, features = ["blocking"], optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_repr = "0.1" @@ -56,15 +61,13 @@ async-std = { version = "1.12.0", features = ["attributes"] } doc-comment = "0.3.3" env_logger = "0.11.3" insta = "1.39.0" -isahc = "1.7.2" log = { version = "0.4", features = ["kv", "kv_sval"] } -opentelemetry_sdk = { version = "0.23", features = ["rt-async-std", "rt-tokio", "rt-tokio-current-thread", "logs_level_enabled"] } -opentelemetry-http = { version = "0.12", features = ["reqwest"] } -opentelemetry-appender-log = { version = "0.4", features = ["with-serde"] } -opentelemetry-application-insights = { path = ".", features = ["logs", "live-metrics"] } +opentelemetry_sdk = { version = "0.24", features = ["rt-async-std", "rt-tokio", "rt-tokio-current-thread", "logs_level_enabled"] } +opentelemetry-http = { version = "0.13", features = ["reqwest"] } +opentelemetry-appender-log = { version = "0.5", features = ["with-serde"] } rand = "0.8.5" regex = "1.10.5" -reqwest = { version = "0.11", features = ["blocking"] } +reqwest = { version = "0.12", features = ["blocking"] } test-case = "3.3.1" tokio = { version = "1.38.0", features = ["rt-multi-thread", "macros", "process", "time"] } version-sync = { version = "0.9.5", default-features = false, features = ["html_root_url_updated", "contains_regex"] } @@ -76,10 +79,6 @@ github = { repository = "frigus02/opentelemetry-application-insights", workflow name = "attributes" required-features = ["opentelemetry-http/reqwest"] -[[example]] -name = "http_client_isahc" -required-features = ["opentelemetry_sdk/rt-async-std", "opentelemetry-http/isahc"] - [[example]] name = "http_client_reqwest" required-features = ["opentelemetry_sdk/rt-tokio", "opentelemetry-http/reqwest"] diff --git a/examples/attributes.rs b/examples/attributes.rs index 38ac877..bc0f7b9 100644 --- a/examples/attributes.rs +++ b/examples/attributes.rs @@ -40,26 +40,26 @@ fn main() { let client_provider = opentelemetry_application_insights::new_pipeline_from_env() .expect("env var APPLICATIONINSIGHTS_CONNECTION_STRING should exist") .with_client(reqwest::blocking::Client::new()) - .with_trace_config( - opentelemetry_sdk::trace::config().with_resource(Resource::new(vec![ + .with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource( + Resource::new(vec![ KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "example-attributes"), KeyValue::new(semcov::resource::SERVICE_NAME, "client"), KeyValue::new(semcov::resource::DEVICE_ID, "123"), KeyValue::new(semcov::resource::DEVICE_MODEL_NAME, "Foo Phone"), - ])), - ) + ]), + )) .build_simple(); let client_tracer = client_provider.tracer("example-attributes"); let server_provider = opentelemetry_application_insights::new_pipeline_from_env() .expect("env var APPLICATIONINSIGHTS_CONNECTION_STRING should exist") .with_client(reqwest::blocking::Client::new()) - .with_trace_config( - opentelemetry_sdk::trace::config().with_resource(Resource::new(vec![ + .with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource( + Resource::new(vec![ KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "example-attributes"), KeyValue::new(semcov::resource::SERVICE_NAME, "server"), - ])), - ) + ]), + )) .build_simple(); let server_tracer = server_provider.tracer("example-attributes"); diff --git a/examples/http_client_isahc.rs b/examples/http_client_isahc.rs deleted file mode 100644 index 11b1fdb..0000000 --- a/examples/http_client_isahc.rs +++ /dev/null @@ -1,15 +0,0 @@ -use opentelemetry::trace::Tracer as _; - -#[async_std::main] -async fn main() { - env_logger::init(); - - let tracer = opentelemetry_application_insights::new_pipeline_from_env() - .expect("env var APPLICATIONINSIGHTS_CONNECTION_STRING should exist") - .with_client(isahc::HttpClient::new().unwrap()) - .install_batch(opentelemetry_sdk::runtime::AsyncStd); - - tracer.in_span("isahc-client", |_cx| {}); - - opentelemetry::global::shutdown_tracer_provider(); -} diff --git a/examples/logs.rs b/examples/logs.rs index 3d018be..cc3fd5b 100644 --- a/examples/logs.rs +++ b/examples/logs.rs @@ -24,12 +24,10 @@ async fn main() -> Result<(), Box> { .expect("connection string is valid"); let logger_provider = opentelemetry_sdk::logs::LoggerProvider::builder() .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio) - .with_config( - opentelemetry_sdk::logs::config().with_resource(Resource::new(vec![ - KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), - KeyValue::new(semcov::resource::SERVICE_NAME, "client"), - ])), - ) + .with_resource(Resource::new(vec![ + KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), + KeyValue::new(semcov::resource::SERVICE_NAME, "client"), + ])) .build(); let otel_log_appender = opentelemetry_appender_log::OpenTelemetryLogBridge::new(&logger_provider); diff --git a/examples/metrics.rs b/examples/metrics.rs index 3f9ab01..ac523a6 100644 --- a/examples/metrics.rs +++ b/examples/metrics.rs @@ -1,4 +1,4 @@ -use opentelemetry::{global, metrics::Unit, KeyValue}; +use opentelemetry::{global, KeyValue}; use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; use rand::{thread_rng, Rng}; use std::{error::Error, time::Duration}; @@ -24,7 +24,7 @@ async fn main() -> Result<(), Box> { // Observable let _cpu_utilization_gauge = meter .f64_observable_gauge("system.cpu.utilization") - .with_unit(Unit::new("1")) + .with_unit("1") .with_callback(|instrument| { let mut rng = thread_rng(); instrument.observe( @@ -37,7 +37,7 @@ async fn main() -> Result<(), Box> { // Recorder let server_duration = meter .u64_histogram("http.server.duration") - .with_unit(Unit::new("milliseconds")) + .with_unit("milliseconds") .init(); let mut rng = thread_rng(); for _ in 1..10 { diff --git a/src/convert.rs b/src/convert.rs index f88347e..9f444f9 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,18 +1,24 @@ -use crate::models::{serialize_ms_links, Properties, SeverityLevel, MS_LINKS_KEY}; +#[cfg(any(feature = "trace", feature = "logs"))] +use crate::models::Properties; +#[cfg(feature = "trace")] +use crate::models::{serialize_ms_links, SeverityLevel, MS_LINKS_KEY}; use chrono::{DateTime, SecondsFormat, Utc}; +#[cfg(feature = "trace")] +use opentelemetry::trace::{Link, Status}; +#[cfg(any(feature = "trace", feature = "logs"))] +use opentelemetry::KeyValue; +use opentelemetry::Value; #[cfg(feature = "logs")] use opentelemetry::{logs::AnyValue, Key}; -use opentelemetry::{ - trace::{Link, Status}, - KeyValue, Value, -}; +#[cfg(any(feature = "trace", feature = "logs"))] use opentelemetry_sdk::Resource; -use std::{ - borrow::Cow, - collections::HashMap, - time::{Duration, SystemTime}, -}; +#[cfg(any(feature = "trace", feature = "logs"))] +use std::collections::HashMap; +#[cfg(feature = "trace")] +use std::time::Duration; +use std::{borrow::Cow, time::SystemTime}; +#[cfg(feature = "trace")] pub(crate) fn duration_to_string(duration: Duration) -> String { let micros = duration.as_micros(); let s = micros / 1_000_000 % 60; @@ -30,14 +36,16 @@ pub(crate) fn time_to_string(time: SystemTime) -> String { DateTime::::from(time).to_rfc3339_opts(SecondsFormat::Millis, true) } +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) fn attrs_to_properties<'a, T>( attributes: &'a [T], resource: Option<&Resource>, - links: &[Link], + #[cfg(feature = "trace")] links: &[Link], ) -> Option where &'a T: Into>, { + #[allow(unused_mut)] let mut properties: Properties = attributes .iter() .map(|kv| kv.into()) @@ -51,6 +59,7 @@ where .map(|(k, v)| (k.into(), v.as_str().into())) .collect(); + #[cfg(feature = "trace")] if !links.is_empty() { properties.insert(MS_LINKS_KEY.into(), serialize_ms_links(links).into()); } @@ -58,6 +67,7 @@ where Some(properties).filter(|x| !x.is_empty()) } +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) fn attrs_to_map<'a, T>(attributes: &'a [T]) -> HashMap<&str, &dyn AttrValue> where &'a T: Into>, @@ -69,6 +79,7 @@ where .collect() } +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) fn attrs_map_to_properties( attributes: HashMap<&str, &dyn AttrValue>, ) -> Option { @@ -81,6 +92,7 @@ pub(crate) fn attrs_map_to_properties( Some(properties).filter(|x| !x.is_empty()) } +#[cfg(feature = "trace")] pub(crate) fn status_to_result_code(status: &Status) -> i32 { // Since responseCode is a required field for RequestData, we map the span status to come kind // of result code representation. Numbers 1-3 were chosen because in opentelemetry@0.17.0 @@ -92,6 +104,7 @@ pub(crate) fn status_to_result_code(status: &Status) -> i32 { } } +#[cfg(feature = "trace")] pub(crate) fn value_to_severity_level(value: &dyn AttrValue) -> Option { match value.as_str().as_ref() { // Convert from `tracing` Level. @@ -105,8 +118,10 @@ pub(crate) fn value_to_severity_level(value: &dyn AttrValue) -> Option(&'a str, &'a dyn AttrValue); +#[cfg(any(feature = "trace", feature = "logs"))] impl<'a> From<&'a KeyValue> for AttrKeyValue<'a> { fn from(kv: &'a KeyValue) -> Self { AttrKeyValue(kv.key.as_str(), &kv.value as &dyn AttrValue) diff --git a/src/lib.rs b/src/lib.rs index a984386..09cf4ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,10 @@ //! //! # Usage //! +//! ## Trace +//! +//! This requires the **trace** feature (enabled by default). +//! //! Configure a OpenTelemetry pipeline using the Application Insights exporter and start creating //! spans (this example requires the **opentelemetry-http/reqwest** feature): //! @@ -24,6 +28,104 @@ //! } //! ``` //! +//! ## Logs +//! +//! This requires the **logs** feature (enabled by default). +//! +//! ```no_run +//! use log::{Level, info}; +//! use opentelemetry_appender_log::OpenTelemetryLogBridge; +//! use opentelemetry_sdk::logs::{LoggerProvider, BatchLogProcessor}; +//! +//! #[tokio::main] +//! async fn main() { +//! // Setup exporter +//! let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap(); +//! let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string( +//! connection_string, +//! reqwest::Client::new(), +//! ) +//! .expect("valid connection string"); +//! let logger_provider = LoggerProvider::builder() +//! .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio) +//! .build(); +//! let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider); +//! log::set_boxed_logger(Box::new(otel_log_appender)).unwrap(); +//! log::set_max_level(Level::Info.to_level_filter()); +//! +//! // Log +//! let fruit = "apple"; +//! let price = 2.99; +//! info!("{fruit} costs {price}"); +//! +//! // Export remaining logs before exiting +//! let _ = logger_provider.shutdown(); +//! } +//! ``` +//! +//! ## Metrics +//! +//! This requires the **metrics** feature (enabled by default). +//! +//! ```no_run +//! use opentelemetry::global; +//! use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; +//! use std::time::Duration; +//! +//! #[tokio::main] +//! async fn main() { +//! // Setup exporter +//! let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap(); +//! let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string( +//! connection_string, +//! reqwest::Client::new(), +//! ) +//! .expect("valid connection string"); +//! let reader = PeriodicReader::builder(exporter, opentelemetry_sdk::runtime::Tokio).build(); +//! let meter_provider = SdkMeterProvider::builder().with_reader(reader).build(); +//! global::set_meter_provider(meter_provider); +//! +//! // Record value +//! let meter = global::meter("example"); +//! let histogram = meter.f64_histogram("pi").init(); +//! histogram.record(3.14, &[]); +//! +//! // Simulate work, during which metrics will periodically be reported. +//! tokio::time::sleep(Duration::from_secs(300)).await; +//! } +//! ``` +//! +//! ## Live Metrics +//! +//! This requires the **live-metrics** feature _and_ the `build_batch`/`install_batch` methods. +//! +//! Enable live metrics collection: . +//! +//! Metrics are based on traces. See attribute mapping below for how traces are mapped to requests, +//! dependencies and exceptions and how they are deemed "successful" or not. +//! +//! To configure role, instance, and machine name provide `service.name`, `service.instance.id`, and +//! `host.name` resource attributes respectively in the trace config. +//! +//! Sample telemetry is not supported, yet. +//! +//! ```no_run +//! use opentelemetry::trace::Tracer as _; +//! +//! #[tokio::main] +//! async fn main() { +//! let tracer = opentelemetry_application_insights::new_pipeline_from_env() +//! .expect("env var APPLICATIONINSIGHTS_CONNECTION_STRING is valid connection string") +//! .with_client(reqwest::Client::new()) +//! .with_live_metrics(true) +//! .install_batch(opentelemetry_sdk::runtime::Tokio); +//! +//! // ... send traces ... +//! +//! opentelemetry::global::shutdown_tracer_provider(); +//! } +//! ``` +//! //! ## Simple or Batch //! //! The functions `build_simple` and `install_simple` build/install a trace pipeline using the @@ -59,8 +161,6 @@ //! client that works with your chosen runtime. The [`opentelemetry-http`] crate comes with support //! for: //! -//! - [`isahc`]: enable the **opentelemetry-http/isahc** feature and configure the exporter with -//! `with_client(isahc::HttpClient::new()?)`. //! - [`reqwest`]: enable the **opentelemetry-http/reqwest** feature and configure the exporter //! with either `with_client(reqwest::Client::new())` or //! `with_client(reqwest::blocking::Client::new())`. @@ -69,122 +169,10 @@ //! [`async-std`]: https://crates.io/crates/async-std //! [`opentelemetry-http`]: https://crates.io/crates/opentelemetry-http //! [`reqwest`]: https://crates.io/crates/reqwest -//! [`isahc`]: https://crates.io/crates/isahc //! [`tokio`]: https://crates.io/crates/tokio //! //! Alternatively you can bring any other HTTP client by implementing the `HttpClient` trait. //! -#![cfg_attr( - feature = "logs", - doc = r#" -## Logs - -This requires the **logs** feature. - -```no_run -use log::{Level, info}; -use opentelemetry_appender_log::OpenTelemetryLogBridge; -use opentelemetry_sdk::logs::{LoggerProvider, BatchLogProcessor}; - -#[tokio::main] -async fn main() { - // Setup exporter - let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap(); - let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string( - connection_string, - reqwest::Client::new(), - ) - .expect("valid connection string"); - let logger_provider = LoggerProvider::builder() - .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio) - .build(); - let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider); - log::set_boxed_logger(Box::new(otel_log_appender)).unwrap(); - log::set_max_level(Level::Info.to_level_filter()); - - // Log - let fruit = "apple"; - let price = 2.99; - info!("{fruit} costs {price}"); - - // Export remaining logs before exiting - let _ = logger_provider.shutdown(); -} -``` -"# -)] -#![cfg_attr( - feature = "metrics", - doc = r#" -## Metrics - -This requires the **metrics** feature. - -```no_run -use opentelemetry::global; -use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; -use std::time::Duration; - -#[tokio::main] -async fn main() { - // Setup exporter - let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap(); - let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string( - connection_string, - reqwest::Client::new(), - ) - .expect("valid connection string"); - let reader = PeriodicReader::builder(exporter, opentelemetry_sdk::runtime::Tokio).build(); - let meter_provider = SdkMeterProvider::builder().with_reader(reader).build(); - global::set_meter_provider(meter_provider); - - // Record value - let meter = global::meter("example"); - let histogram = meter.f64_histogram("pi").init(); - histogram.record(3.14, &[]); - - // Simulate work, during which metrics will periodically be reported. - tokio::time::sleep(Duration::from_secs(300)).await; -} -``` -"# -)] -#![cfg_attr( - feature = "live-metrics", - doc = r#" -## Live Metrics - -Enable live metrics collection: . - -Metrics are based on traces. See attribute mapping below for how traces are mapped to requests, -dependencies and exceptions and how they are deemed "successful" or not. - -To configure role, instance, and machine name provide `service.name`, `service.instance.id`, and -`host.name` resource attributes respectively in the trace config. - -Sample telemetry is not supported, yet. - -This requires the **live-metrics** feature _and_ the `build_batch`/`install_batch` methods. - -```no_run -use opentelemetry::trace::Tracer as _; - -#[tokio::main] -async fn main() { - let tracer = opentelemetry_application_insights::new_pipeline_from_env() - .expect("env var APPLICATIONINSIGHTS_CONNECTION_STRING is valid connection string") - .with_client(reqwest::Client::new()) - .with_live_metrics(true) - .install_batch(opentelemetry_sdk::runtime::Tokio); - - // ... send traces ... - - opentelemetry::global::shutdown_tracer_provider(); -} -``` -"# -)] -//! //! # Attribute mapping //! //! OpenTelemetry and Application Insights are using different terminology. This crate tries its @@ -247,11 +235,11 @@ async fn main() { //! | `SpanKind::Server` + `http.request.method` + `http.route` | Context: Operation Name (`ai.operation.name`) | //! | `ai.*` | Context: AppInsights Tag (`ai.*`) | //! | `url.full` | Dependency Data | -//! | `db.statement` | Dependency Data | +//! | `db.query.text` | Dependency Data | //! | `http.request.header.host` | Dependency Target | //! | `server.address` + `server.port` | Dependency Target | //! | `network.peer.address` + `network.peer.port` | Dependency Target | -//! | `db.name` | Dependency Target | +//! | `db.namespace` | Dependency Target | //! | `http.response.status_code` | Dependency Result code | //! | `db.system` | Dependency Type | //! | `messaging.system` | Dependency Type | @@ -275,6 +263,8 @@ async fn main() { //! //! | Attribute | Deprecated attribute | //! | --------------------------- | ------------------------------------------ | +//! | `db.namespace` | `db.name` | +//! | `db.query.text` | `db.statement` | //! | `http.request.method` | `http.method` | //! | `http.request.header.host` | `http.host` | //! | `http.response.status_code` | `http.status_code` | @@ -349,6 +339,7 @@ async fn main() { //! //! [`Aggregation`]: https://docs.rs/opentelemetry/0.20.0/opentelemetry/sdk/metrics/data/trait.Aggregation.html #![doc(html_root_url = "https://docs.rs/opentelemetry-application-insights/0.33.0")] +#![allow(clippy::needless_doctest_main)] #![deny(missing_docs, unreachable_pub, missing_debug_implementations)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(test, deny(warnings))] @@ -365,6 +356,7 @@ mod quick_pulse; #[cfg(doctest)] mod readme_test; mod tags; +#[cfg(feature = "trace")] mod trace; mod uploader; #[cfg(feature = "live-metrics")] @@ -374,22 +366,30 @@ mod uploader_quick_pulse; use connection_string::DEFAULT_LIVE_ENDPOINT; use connection_string::{ConnectionString, DEFAULT_BREEZE_ENDPOINT}; pub use models::context_tag_keys::attrs; +#[cfg(feature = "trace")] use opentelemetry::{global, trace::TracerProvider as _, KeyValue, Value}; pub use opentelemetry_http::HttpClient; +use opentelemetry_sdk::export::ExportError; #[cfg(feature = "metrics")] use opentelemetry_sdk::metrics::reader::{AggregationSelector, DefaultAggregationSelector}; +#[cfg(any(feature = "trace", feature = "logs"))] +use opentelemetry_sdk::Resource; +#[cfg(feature = "trace")] use opentelemetry_sdk::{ - export::ExportError, runtime::RuntimeChannel, trace::{Config, Tracer, TracerProvider}, - Resource, }; +#[cfg(feature = "trace")] use opentelemetry_semantic_conventions as semcov; #[cfg(feature = "live-metrics")] use quick_pulse::QuickPulseManager; -use std::{convert::TryInto, error::Error as StdError, fmt::Debug, sync::Arc}; +#[cfg(feature = "trace")] +use std::convert::TryInto; +use std::{error::Error as StdError, fmt::Debug, sync::Arc}; /// Create a new Application Insights exporter pipeline builder +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] #[deprecated( since = "0.27.0", note = "use new_pipeline_from_connection_string() or new_pipeline_from_env() instead" @@ -420,6 +420,8 @@ pub fn new_pipeline(instrumentation_key: String) -> PipelineBuilder<()> { /// # Ok(()) /// # } /// ``` +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] pub fn new_pipeline_from_connection_string( connection_string: impl AsRef, ) -> Result, Box> { @@ -449,6 +451,8 @@ pub fn new_pipeline_from_connection_string( /// # Ok(()) /// # } /// ``` +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] pub fn new_pipeline_from_env( ) -> Result, Box> { let connection_string: ConnectionString = @@ -467,6 +471,8 @@ pub fn new_pipeline_from_env( } /// Application Insights exporter pipeline builder +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] #[derive(Debug)] pub struct PipelineBuilder { client: C, @@ -480,6 +486,8 @@ pub struct PipelineBuilder { sample_rate: Option, } +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] impl PipelineBuilder { /// Set HTTP client, which the exporter will use to send telemetry to Application Insights. /// @@ -621,6 +629,8 @@ impl PipelineBuilder { } } +#[cfg(feature = "trace")] +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] impl PipelineBuilder where C: HttpClient + 'static, @@ -635,7 +645,6 @@ where sample_rate: self.sample_rate.unwrap_or(100.0), #[cfg(feature = "metrics")] aggregation_selector: Box::new(DefaultAggregationSelector::new()), - #[cfg(feature = "logs")] resource: Resource::empty(), } } @@ -720,10 +729,11 @@ pub struct Exporter { client: Arc, endpoint: Arc, instrumentation_key: String, + #[cfg(feature = "trace")] sample_rate: f64, #[cfg(feature = "metrics")] aggregation_selector: Box, - #[cfg(feature = "logs")] + #[cfg(any(feature = "trace", feature = "logs"))] resource: Resource, } @@ -733,8 +743,9 @@ impl Debug for Exporter { debug .field("client", &self.client) .field("endpoint", &self.endpoint) - .field("instrumentation_key", &self.instrumentation_key) - .field("sample_rate", &self.sample_rate); + .field("instrumentation_key", &self.instrumentation_key); + #[cfg(feature = "trace")] + debug.field("sample_rate", &self.sample_rate); debug.finish() } } @@ -750,10 +761,11 @@ impl Exporter { .expect("appending /v2/track should always work"), ), instrumentation_key, + #[cfg(feature = "trace")] sample_rate: 100.0, #[cfg(feature = "metrics")] aggregation_selector: Box::new(DefaultAggregationSelector::new()), - #[cfg(feature = "logs")] + #[cfg(any(feature = "trace", feature = "logs"))] resource: Resource::empty(), } } @@ -771,10 +783,11 @@ impl Exporter { .expect("appending /v2/track should always work"), ), instrumentation_key: connection_string.instrumentation_key, + #[cfg(feature = "trace")] sample_rate: 100.0, #[cfg(feature = "metrics")] aggregation_selector: Box::new(DefaultAggregationSelector::new()), - #[cfg(feature = "logs")] + #[cfg(any(feature = "trace", feature = "logs"))] resource: Resource::empty(), }) } @@ -796,6 +809,8 @@ impl Exporter { /// between 0 and 1 and match the rate given to the sampler. /// /// Default: 1.0 + #[cfg(feature = "trace")] + #[cfg_attr(docsrs, doc(cfg(feature = "trace")))] pub fn with_sample_rate(mut self, sample_rate: f64) -> Self { // Application Insights expects the sample rate as a percentage. self.sample_rate = sample_rate * 100.0; diff --git a/src/logs.rs b/src/logs.rs index 843b561..902e6ff 100644 --- a/src/logs.rs +++ b/src/logs.rs @@ -14,7 +14,7 @@ use opentelemetry_sdk::{ Resource, }; use opentelemetry_semantic_conventions as semcov; -use std::{sync::Arc, time::SystemTime}; +use std::{borrow::Cow, sync::Arc, time::SystemTime}; fn is_exception(log: &LogData) -> bool { if let Some(attrs) = &log.record.attributes { @@ -28,15 +28,15 @@ fn is_exception(log: &LogData) -> bool { } impl Exporter { - fn create_envelope_for_log(&self, log: LogData) -> Envelope { + fn create_envelope_for_log(&self, log: &LogData) -> Envelope { let (data, name) = if is_exception(&log) { ( - Data::Exception((&log).into()), + Data::Exception(log.into()), "Microsoft.ApplicationInsights.Exception", ) } else { ( - Data::Message((&log).into()), + Data::Message(log.into()), "Microsoft.ApplicationInsights.Message", ) }; @@ -64,12 +64,12 @@ impl LogExporter for Exporter where C: HttpClient + 'static, { - async fn export(&mut self, batch: Vec) -> LogResult<()> { + async fn export<'a>(&mut self, batch: Vec>) -> LogResult<()> { let client = Arc::clone(&self.client); let endpoint = Arc::clone(&self.endpoint); let envelopes: Vec<_> = batch .into_iter() - .map(|log| self.create_envelope_for_log(log)) + .map(|log| self.create_envelope_for_log(&log)) .collect(); crate::uploader::send(client.as_ref(), endpoint.as_ref(), envelopes).await?; @@ -149,11 +149,14 @@ impl From<&LogData> for MessageData { .map(|v| v.as_str().into_owned()) .unwrap_or_else(|| "".into()) .into(), - properties: log - .record - .attributes - .as_ref() - .and_then(|attrs| attrs_to_properties(attrs, None, &[])), + properties: log.record.attributes.as_ref().and_then(|attrs| { + attrs_to_properties( + attrs, + None, + #[cfg(feature = "trace")] + &[], + ) + }), } } } diff --git a/src/metrics.rs b/src/metrics.rs index fa5b67f..cdd90c7 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -8,16 +8,14 @@ use async_trait::async_trait; use opentelemetry::{ global, metrics::{MetricsError, Result as MetricsResult}, + KeyValue, }; use opentelemetry_http::HttpClient; -use opentelemetry_sdk::{ - metrics::{ - data::{ExponentialHistogram, Gauge, Histogram, Metric, ResourceMetrics, Sum, Temporality}, - exporter::PushMetricsExporter, - reader::{AggregationSelector, TemporalitySelector}, - Aggregation, InstrumentKind, - }, - AttributeSet, +use opentelemetry_sdk::metrics::{ + data::{ExponentialHistogram, Gauge, Histogram, Metric, ResourceMetrics, Sum, Temporality}, + exporter::PushMetricsExporter, + reader::{AggregationSelector, TemporalitySelector}, + Aggregation, InstrumentKind, }; use std::{convert::TryInto, sync::Arc, time::SystemTime}; @@ -78,7 +76,7 @@ where .iter() .map(|kv| (&kv.key, &kv.value)), ) - .chain(data.attrs.iter()) + .chain(data.attrs.iter().map(|kv| (&kv.key, &kv.value))) .map(|(k, v)| (k.as_str().into(), v.into())) .collect(); envelopes.push(Envelope { @@ -113,7 +111,7 @@ where struct EnvelopeData { time: SystemTime, data: DataPoint, - attrs: AttributeSet, + attrs: Vec, } trait ToF64Lossy { diff --git a/src/models/data.rs b/src/models/data.rs index bc9c601..32a4886 100644 --- a/src/models/data.rs +++ b/src/models/data.rs @@ -1,23 +1,31 @@ #[cfg(feature = "metrics")] use crate::models::MetricData; -use crate::models::{EventData, ExceptionData, MessageData, RemoteDependencyData, RequestData}; +#[cfg(feature = "trace")] +use crate::models::{EventData, RemoteDependencyData, RequestData}; +#[cfg(any(feature = "trace", feature = "logs"))] +use crate::models::{ExceptionData, MessageData}; use serde::Serialize; /// Data struct to contain both B and C sections. #[derive(Debug, Serialize)] #[serde(tag = "baseType", content = "baseData")] pub(crate) enum Data { + #[cfg(feature = "trace")] #[serde(rename = "EventData")] Event(EventData), + #[cfg(any(feature = "trace", feature = "logs"))] #[serde(rename = "ExceptionData")] Exception(ExceptionData), + #[cfg(any(feature = "trace", feature = "logs"))] #[serde(rename = "MessageData")] Message(MessageData), #[cfg(feature = "metrics")] #[serde(rename = "MetricData")] Metric(MetricData), + #[cfg(feature = "trace")] #[serde(rename = "RemoteDependencyData")] RemoteDependency(RemoteDependencyData), + #[cfg(feature = "trace")] #[serde(rename = "RequestData")] Request(RequestData), } diff --git a/src/models/mod.rs b/src/models/mod.rs index 694b0ca..4a91b7d 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -3,36 +3,52 @@ mod data; #[cfg(feature = "metrics")] mod data_point; mod envelope; +#[cfg(feature = "trace")] mod event_data; +#[cfg(any(feature = "trace", feature = "logs"))] mod exception_data; +#[cfg(any(feature = "trace", feature = "logs"))] mod exception_details; +#[cfg(any(feature = "trace", feature = "logs"))] mod message_data; #[cfg(feature = "metrics")] mod metric_data; +#[cfg(feature = "trace")] mod ms_link; #[cfg(feature = "live-metrics")] mod quick_pulse; +#[cfg(feature = "trace")] mod remote_dependency_data; +#[cfg(feature = "trace")] mod request_data; mod sanitize; +#[cfg(any(feature = "trace", feature = "logs"))] mod severity_level; pub(crate) use data::*; #[cfg(feature = "metrics")] pub(crate) use data_point::*; pub(crate) use envelope::*; +#[cfg(feature = "trace")] pub(crate) use event_data::*; +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) use exception_data::*; +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) use exception_details::*; +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) use message_data::*; #[cfg(feature = "metrics")] pub(crate) use metric_data::*; +#[cfg(feature = "trace")] pub(crate) use ms_link::*; #[cfg(feature = "live-metrics")] pub(crate) use quick_pulse::*; +#[cfg(feature = "trace")] pub(crate) use remote_dependency_data::*; +#[cfg(feature = "trace")] pub(crate) use request_data::*; pub(crate) use sanitize::*; +#[cfg(any(feature = "trace", feature = "logs"))] pub(crate) use severity_level::*; #[cfg(test)] diff --git a/src/quick_pulse.rs b/src/quick_pulse.rs index 09d25e6..c5275d7 100644 --- a/src/quick_pulse.rs +++ b/src/quick_pulse.rs @@ -134,7 +134,7 @@ impl SpanProcessor for QuickPulseManager { Ok(()) } - fn shutdown(&mut self) -> TraceResult<()> { + fn shutdown(&self) -> TraceResult<()> { self.message_sender .try_send(Message::Stop) .map_err(Error::QuickPulseShutdown)?; diff --git a/src/tags.rs b/src/tags.rs index ec7cf4e..401f3fa 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -2,21 +2,23 @@ use crate::{ convert::AttrValue, models::context_tag_keys::{self as tags, Tags, TAG_KEY_LOOKUP}, }; -use opentelemetry::{ - trace::{SpanId, SpanKind}, - InstrumentationLibrary, Key, -}; +#[cfg(feature = "trace")] +use opentelemetry::trace::{SpanId, SpanKind}; +#[cfg(feature = "metrics")] +use opentelemetry::KeyValue; +use opentelemetry::{InstrumentationLibrary, Key}; #[cfg(feature = "logs")] use opentelemetry_sdk::export::logs::LogData; -#[cfg(feature = "metrics")] -use opentelemetry_sdk::AttributeSet; -use opentelemetry_sdk::{export::trace::SpanData, Resource}; +#[cfg(feature = "trace")] +use opentelemetry_sdk::export::trace::SpanData; +use opentelemetry_sdk::Resource; use opentelemetry_semantic_conventions as semcov; use std::collections::HashMap; -pub(crate) fn get_tags_for_span(span: &SpanData) -> Tags { +#[cfg(feature = "trace")] +pub(crate) fn get_tags_for_span(span: &SpanData, resource: &Resource) -> Tags { let mut tags = Tags::new(); - build_tags_from_resource_attrs(&mut tags, &span.resource, &span.instrumentation_lib); + build_tags_from_resource_attrs(&mut tags, resource, &span.instrumentation_lib); let attrs_map = build_tags_from_attrs( &mut tags, @@ -43,7 +45,7 @@ pub(crate) fn get_tags_for_span(span: &SpanData) -> Tags { .get(semcov::trace::HTTP_REQUEST_METHOD) .or_else(|| { #[allow(deprecated)] - attrs_map.get(semcov::trace::HTTP_METHOD) + attrs_map.get(semcov::attribute::HTTP_METHOD) }); let route = attrs_map.get(semcov::trace::HTTP_ROUTE); if let (Some(method), Some(route)) = (method, route) { @@ -57,9 +59,10 @@ pub(crate) fn get_tags_for_span(span: &SpanData) -> Tags { tags } -pub(crate) fn get_tags_for_event(span: &SpanData) -> Tags { +#[cfg(feature = "trace")] +pub(crate) fn get_tags_for_event(span: &SpanData, resource: &Resource) -> Tags { let mut tags = Tags::new(); - build_tags_from_resource_attrs(&mut tags, &span.resource, &span.instrumentation_lib); + build_tags_from_resource_attrs(&mut tags, resource, &span.instrumentation_lib); tags.insert(tags::OPERATION_ID, span.span_context.trace_id().to_string()); tags.insert( @@ -73,13 +76,15 @@ pub(crate) fn get_tags_for_event(span: &SpanData) -> Tags { pub(crate) fn get_tags_for_metric( resource: &Resource, scope: &InstrumentationLibrary, - attrs: &AttributeSet, + attrs: &Vec, ) -> Tags { let mut tags = Tags::new(); build_tags_from_resource_attrs(&mut tags, resource, scope); build_tags_from_attrs( &mut tags, - attrs.iter().map(|(k, v)| (k, v as &dyn AttrValue)), + attrs + .iter() + .map(|kv| (&kv.key, &kv.value as &dyn AttrValue)), ); tags } diff --git a/src/trace.rs b/src/trace.rs index 20878c1..7f08f21 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -15,7 +15,10 @@ use opentelemetry::{ Value, }; use opentelemetry_http::HttpClient; -use opentelemetry_sdk::export::trace::{ExportResult, SpanData, SpanExporter}; +use opentelemetry_sdk::{ + export::trace::{ExportResult, SpanData, SpanExporter}, + Resource, +}; use opentelemetry_semantic_conventions as semcov; use std::{borrow::Cow, collections::HashMap, future::Future, pin::Pin, sync::Arc, time::Duration}; @@ -63,13 +66,13 @@ pub(crate) const EVENT_NAME_CUSTOM: &str = "ai.custom"; pub(crate) const EVENT_NAME_EXCEPTION: &str = "exception"; impl Exporter { - fn create_envelopes_for_span(&self, span: SpanData) -> Vec { + fn create_envelopes_for_span(&self, span: SpanData, resource: &Resource) -> Vec { let mut result = Vec::with_capacity(1 + span.events.len()); let (data, tags, name) = match span.span_kind { SpanKind::Server | SpanKind::Consumer => { - let data: RequestData = (&span).into(); - let tags = get_tags_for_span(&span); + let data: RequestData = SpanAndResource(&span, resource).into(); + let tags = get_tags_for_span(&span, resource); ( Data::Request(data), tags, @@ -77,8 +80,8 @@ impl Exporter { ) } SpanKind::Client | SpanKind::Producer | SpanKind::Internal => { - let data: RemoteDependencyData = (&span).into(); - let tags = get_tags_for_span(&span); + let data: RemoteDependencyData = SpanAndResource(&span, resource).into(); + let tags = get_tags_for_span(&span, resource); ( Data::RemoteDependency(data), tags, @@ -115,7 +118,7 @@ impl Exporter { time: time_to_string(event.timestamp).into(), sample_rate: Some(self.sample_rate), i_key: Some(self.instrumentation_key.clone().into()), - tags: Some(get_tags_for_event(&span)), + tags: Some(get_tags_for_event(&span, resource)), data: Some(data), }); } @@ -124,6 +127,7 @@ impl Exporter { } } +#[cfg_attr(docsrs, doc(cfg(feature = "trace")))] impl SpanExporter for Exporter where C: HttpClient + 'static, @@ -134,7 +138,7 @@ where let endpoint = Arc::clone(&self.endpoint); let envelopes: Vec<_> = batch .into_iter() - .flat_map(|span| self.create_envelopes_for_span(span)) + .flat_map(|span| self.create_envelopes_for_span(span, &self.resource)) .collect(); Box::pin(async move { @@ -142,6 +146,10 @@ where Ok(()) }) } + + fn set_resource(&mut self, resource: &Resource) { + self.resource = resource.clone(); + } } fn get_url_path_and_query<'v>(attrs: &HashMap<&str, &'v Value>) -> Option> { @@ -155,7 +163,7 @@ fn get_url_path_and_query<'v>(attrs: &HashMap<&str, &'v Value>) -> Option(attrs: &HashMap<&str, &'v Value>) -> Option> attrs.get(semcov::trace::SERVER_ADDRESS).or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_HOST_NAME, + semcov::attribute::NET_HOST_NAME, ) }), attrs.get(semcov::trace::SERVER_PORT).or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_HOST_PORT, + semcov::attribute::NET_HOST_PORT, ) }), ) { @@ -204,8 +212,12 @@ pub(crate) fn is_remote_dependency_success(span: &SpanData) -> Option { } } -impl From<&SpanData> for RequestData { - fn from(span: &SpanData) -> RequestData { +struct SpanAndResource<'a>(&'a SpanData, &'a Resource); + +impl<'a> From> for RequestData { + fn from(s: SpanAndResource<'a>) -> RequestData { + let span = s.0; + let resource = s.1; let mut data = RequestData { ver: 2, id: span.span_context.span_id().to_string().into(), @@ -216,11 +228,7 @@ impl From<&SpanData> for RequestData { success: is_request_success(span), source: None, url: None, - properties: attrs_to_properties( - &span.attributes, - Some(&span.resource), - &span.links.links, - ), + properties: attrs_to_properties(&span.attributes, Some(resource), &span.links.links), }; let attrs: HashMap<&str, &Value> = span @@ -231,7 +239,7 @@ impl From<&SpanData> for RequestData { if let Some(&method) = attrs.get(semcov::trace::HTTP_REQUEST_METHOD).or_else(|| { #[allow(deprecated)] - attrs.get(semcov::trace::HTTP_METHOD) + attrs.get(semcov::attribute::HTTP_METHOD) }) { data.name = Some(if let Some(route) = attrs.get(semcov::trace::HTTP_ROUTE) { format!("{} {}", method.as_str(), route.as_str()).into() @@ -244,7 +252,7 @@ impl From<&SpanData> for RequestData { data.response_code = status_code.into(); } else if let Some(&status_code) = attrs.get( #[allow(deprecated)] - semcov::trace::HTTP_STATUS_CODE, + semcov::attribute::HTTP_STATUS_CODE, ) { data.response_code = status_code.into(); } @@ -253,7 +261,7 @@ impl From<&SpanData> for RequestData { data.url = Some(url.into()); } else if let Some(&url) = attrs.get( #[allow(deprecated)] - semcov::trace::HTTP_URL, + semcov::attribute::HTTP_URL, ) { data.url = Some(url.into()); } else if let Some(target) = get_url_path_and_query(&attrs) { @@ -266,7 +274,7 @@ impl From<&SpanData> for RequestData { attrs.get(semcov::trace::URL_SCHEME).or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::HTTP_SCHEME, + semcov::attribute::HTTP_SCHEME, ) }), get_server_host(&attrs), @@ -287,7 +295,7 @@ impl From<&SpanData> for RequestData { data.source = Some(peer_addr.into()); } else if let Some(&peer_addr) = attrs.get( #[allow(deprecated)] - semcov::trace::NET_SOCK_PEER_ADDR, + semcov::attribute::NET_SOCK_PEER_ADDR, ) { data.source = Some(peer_addr.into()); } else if let Some(&peer_ip) = attrs.get(DEPRECATED_NET_PEER_IP) { @@ -298,8 +306,10 @@ impl From<&SpanData> for RequestData { } } -impl From<&SpanData> for RemoteDependencyData { - fn from(span: &SpanData) -> RemoteDependencyData { +impl<'a> From> for RemoteDependencyData { + fn from(s: SpanAndResource<'a>) -> RemoteDependencyData { + let span = s.0; + let resource = s.1; let mut data = RemoteDependencyData { ver: 2, id: Some(span.span_context.span_id().to_string().into()), @@ -310,11 +320,7 @@ impl From<&SpanData> for RemoteDependencyData { data: None, target: None, type_: None, - properties: attrs_to_properties( - &span.attributes, - Some(&span.resource), - &span.links.links, - ), + properties: attrs_to_properties(&span.attributes, Some(resource), &span.links.links), }; let attrs: HashMap<&str, &Value> = span @@ -327,7 +333,7 @@ impl From<&SpanData> for RemoteDependencyData { data.result_code = Some(status_code.into()); } else if let Some(&status_code) = attrs.get( #[allow(deprecated)] - semcov::trace::HTTP_STATUS_CODE, + semcov::attribute::HTTP_STATUS_CODE, ) { data.result_code = Some(status_code.into()); } @@ -336,10 +342,15 @@ impl From<&SpanData> for RemoteDependencyData { data.data = Some(url.into()); } else if let Some(&url) = attrs.get( #[allow(deprecated)] - semcov::trace::HTTP_URL, + semcov::attribute::HTTP_URL, ) { data.data = Some(url.into()); - } else if let Some(&statement) = attrs.get(semcov::trace::DB_STATEMENT) { + } else if let Some(&statement) = attrs.get(semcov::attribute::DB_QUERY_TEXT).or_else(|| { + attrs.get( + #[allow(deprecated)] + semcov::attribute::DB_STATEMENT, + ) + }) { data.data = Some(statement.into()); } @@ -354,19 +365,19 @@ impl From<&SpanData> for RemoteDependencyData { .or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_SOCK_PEER_NAME, + semcov::attribute::NET_SOCK_PEER_NAME, ) }) .or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_PEER_NAME, + semcov::attribute::NET_PEER_NAME, ) }) .or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_SOCK_PEER_ADDR, + semcov::attribute::NET_SOCK_PEER_ADDR, ) }) .or_else(|| attrs.get(DEPRECATED_NET_PEER_IP)) @@ -378,13 +389,13 @@ impl From<&SpanData> for RemoteDependencyData { .or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_SOCK_PEER_PORT, + semcov::attribute::NET_SOCK_PEER_PORT, ) }) .or_else(|| { attrs.get( #[allow(deprecated)] - semcov::trace::NET_PEER_PORT, + semcov::attribute::NET_PEER_PORT, ) }) { @@ -392,7 +403,12 @@ impl From<&SpanData> for RemoteDependencyData { } else { data.target = Some(peer_name.into()); } - } else if let Some(&db_name) = attrs.get(semcov::trace::DB_NAME) { + } else if let Some(&db_name) = attrs.get(semcov::attribute::DB_NAMESPACE).or_else(|| { + attrs.get( + #[allow(deprecated)] + semcov::attribute::DB_NAME, + ) + }) { data.target = Some(db_name.into()); } diff --git a/tests/http_requests.rs b/tests/http_requests.rs index d4a0943..a2e90b3 100644 --- a/tests/http_requests.rs +++ b/tests/http_requests.rs @@ -32,26 +32,26 @@ fn traces() { let client_provider = new_pipeline_from_connection_string(CONNECTION_STRING) .expect("connection string is valid") .with_client(client.clone()) - .with_trace_config( - opentelemetry_sdk::trace::config().with_resource(Resource::new(vec![ + .with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource( + Resource::new(vec![ KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), KeyValue::new(semcov::resource::SERVICE_NAME, "client"), KeyValue::new(semcov::resource::DEVICE_ID, "123"), KeyValue::new(semcov::resource::DEVICE_MODEL_NAME, "device"), - ])), - ) + ]), + )) .build_simple(); let client_tracer = client_provider.tracer("test"); let server_provider = new_pipeline_from_connection_string(CONNECTION_STRING) .expect("connection string is valid") .with_client(client) - .with_trace_config( - opentelemetry_sdk::trace::config().with_resource(Resource::new(vec![ + .with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource( + Resource::new(vec![ KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), KeyValue::new(semcov::resource::SERVICE_NAME, "server"), - ])), - ) + ]), + )) .build_simple(); let server_tracer = server_provider.tracer("test"); @@ -186,12 +186,10 @@ async fn logs() { .expect("connection string is valid"); let logger_provider = opentelemetry_sdk::logs::LoggerProvider::builder() .with_batch_exporter(exporter, opentelemetry_sdk::runtime::TokioCurrentThread) - .with_config( - opentelemetry_sdk::logs::config().with_resource(Resource::new(vec![ - KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), - KeyValue::new(semcov::resource::SERVICE_NAME, "client"), - ])), - ) + .with_resource(Resource::new(vec![ + KeyValue::new(semcov::resource::SERVICE_NAMESPACE, "test"), + KeyValue::new(semcov::resource::SERVICE_NAME, "client"), + ])) .build(); let otel_log_appender = diff --git a/tests/snapshots/http_requests__live_metrics.snap b/tests/snapshots/http_requests__live_metrics.snap index 218cd87..aad651a 100644 --- a/tests/snapshots/http_requests__live_metrics.snap +++ b/tests/snapshots/http_requests__live_metrics.snap @@ -21,7 +21,7 @@ x-ms-qps-role-name: unknown_service "RoleName": "unknown_service", "StreamId": "STRIPPED", "Timestamp": "STRIPPED", - "Version": "opentelemetry:0.23.0" + "Version": "opentelemetry:0.24.1" } @@ -87,7 +87,7 @@ content-encoding: gzip "RoleName": "unknown_service", "StreamId": "STRIPPED", "Timestamp": "STRIPPED", - "Version": "opentelemetry:0.23.0" + "Version": "opentelemetry:0.24.1" } ] @@ -144,7 +144,7 @@ content-encoding: gzip "RoleName": "unknown_service", "StreamId": "STRIPPED", "Timestamp": "STRIPPED", - "Version": "opentelemetry:0.23.0" + "Version": "opentelemetry:0.24.1" } ] @@ -165,7 +165,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "resultCode": "2", "success": false, @@ -178,7 +178,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED" @@ -201,7 +201,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED", "ai.operation.parentId": "STRIPPED" }, @@ -217,7 +217,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "responseCode": "2", "success": false, @@ -230,7 +230,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED" @@ -245,7 +245,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "responseCode": "0", "success": true, @@ -258,7 +258,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED" diff --git a/tests/snapshots/http_requests__logs.snap b/tests/snapshots/http_requests__logs.snap index 9a4b190..3a14c30 100644 --- a/tests/snapshots/http_requests__logs.snap +++ b/tests/snapshots/http_requests__logs.snap @@ -121,7 +121,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "resultCode": "0", "type": "InProc", @@ -134,7 +134,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED" diff --git a/tests/snapshots/http_requests__traces_batch_async_std.snap b/tests/snapshots/http_requests__traces_batch_async_std.snap index 7f9c51e..238c5d3 100644 --- a/tests/snapshots/http_requests__traces_batch_async_std.snap +++ b/tests/snapshots/http_requests__traces_batch_async_std.snap @@ -18,7 +18,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "resultCode": "0", "type": "InProc", @@ -31,7 +31,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED" diff --git a/tests/snapshots/http_requests__traces_batch_tokio.snap b/tests/snapshots/http_requests__traces_batch_tokio.snap index 11c88ab..b6bc4d4 100644 --- a/tests/snapshots/http_requests__traces_batch_tokio.snap +++ b/tests/snapshots/http_requests__traces_batch_tokio.snap @@ -18,7 +18,7 @@ content-encoding: gzip "service.name": "unknown_service", "telemetry.sdk.language": "rust", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "0.23.0" + "telemetry.sdk.version": "0.24.1" }, "resultCode": "0", "type": "InProc", @@ -31,7 +31,7 @@ content-encoding: gzip "sampleRate": 100.0, "tags": { "ai.cloud.role": "unknown_service", - "ai.internal.sdkVersion": "opentelemetry:0.23.0", + "ai.internal.sdkVersion": "opentelemetry:0.24.1", "ai.operation.id": "STRIPPED" }, "time": "STRIPPED"