diff --git a/CHANGELOG.md b/CHANGELOG.md index b422cf6..32cd3fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [0.16.0] - 2024-03-11 + +### Added + +- Support for opentelemetry 0.21 +- `tracing_opentelemetry_0_20` and `tracing_opentelemetry_0_21` features +- `tracing_opentelemetry` is now an alias for the latest version of otel(so `tracing_opentelemetry_0_21`) + +Opentelemetry 0.20 support can be enabled by enabling the `tracing_opentelemetry_0_20` feature instead of tracing_opentelemetry. +We are going to support at least the last 3 versions of opentelemetry. After that we mightremove support for older otel version without it being a breaking change. + +--- + ## [0.15.1] - 2023-10-20 ### Added @@ -324,7 +337,9 @@ Request::rest(&bridge).send() The old API is still available but deprecated. It will be removed soon. -[Unreleased]: https://github.com/primait/bridge.rs/compare/0.15.1...HEAD + +[Unreleased]: https://github.com/primait/bridge.rs/compare/0.16.0...HEAD +[0.16.0]: https://github.com/primait/bridge.rs/compare/0.15.1-rc.0...0.16.0 [0.15.1]: https://github.com/primait/bridge.rs/compare/0.15.0...0.15.1 [0.15.0]: https://github.com/primait/bridge.rs/compare/0.14.6...0.15.0 [0.14.6]: https://github.com/primait/bridge.rs/compare/0.14.5...0.14.6 diff --git a/Cargo.toml b/Cargo.toml index 00a6b0d..2cee29e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,16 +6,22 @@ license = "MIT" name = "prima_bridge" readme = "README.md" repository = "https://github.com/primait/bridge.rs" -version = "0.15.1-rc.0" +version = "0.16.0" # See https://github.com/rust-lang/rust/issues/107557 rust-version = "1.72" [features] -auth0 = ["rand", "redis", "jsonwebtoken", "chrono", "chrono-tz", "aes", "cbc", "dashmap", "tracing"] default = ["tracing_opentelemetry"] + +auth0 = ["rand", "redis", "jsonwebtoken", "chrono", "chrono-tz", "aes", "cbc", "dashmap", "tracing"] gzip = ["reqwest/gzip"] redis-tls = ["redis/tls", "redis/tokio-native-tls-comp"] -tracing_opentelemetry = ["opentelemetry", "tracing", "tracing-opentelemetry"] +tracing_opentelemetry = [ "tracing_opentelemetry_0_21" ] + +tracing_opentelemetry_0_20 = ["_any_otel_version", "tracing", "tracing-opentelemetry_0_21_pkg", "opentelemetry_0_20_pkg"] +tracing_opentelemetry_0_21 = ["_any_otel_version", "tracing", "tracing-opentelemetry_0_22_pkg", "opentelemetry_0_21_pkg", "opentelemetry_sdk_0_21_pkg"] + +_any_otel_version = [] [dependencies] aes = {version = "0.8", optional = true} @@ -28,7 +34,6 @@ dashmap = {version = "5.1", optional = true} futures = "0.3" futures-util = "0.3" jsonwebtoken = {version = "9.0", optional = true} -opentelemetry = {version = ">=0.17, <=0.20", optional = true} rand = {version = "0.8", optional = true} redis = {version = "0.23", features = ["tokio-comp"], optional = true} reqwest = {version = "0.11", features = ["json", "multipart", "stream"]} @@ -37,12 +42,17 @@ serde_json = "1.0" thiserror = "1.0" tokio = {version = "1.16", features = ["macros", "rt-multi-thread", "fs"]} tracing = {version = "0.1", optional = true} -tracing-opentelemetry = {version = ">=0.17, <=0.21", optional = true} uuid = {version = ">=0.7.0, <2.0.0", features = ["serde", "v4"]} reqwest-middleware = "0.2.3" http = "0.2.9" +opentelemetry_0_20_pkg = { package = "opentelemetry", version = "0.20", optional = true } +opentelemetry_0_21_pkg = { package = "opentelemetry", version = "0.21", optional = true } +opentelemetry_sdk_0_21_pkg = { package = "opentelemetry_sdk", version = "0.21", optional = true } +tracing-opentelemetry_0_21_pkg = { package = "tracing-opentelemetry", version = "0.21", optional = true } +tracing-opentelemetry_0_22_pkg = { package = "tracing-opentelemetry", version = "0.22", optional = true } + [dev-dependencies] flate2 = "1.0" mockito = "1.0" diff --git a/Makefile.toml b/Makefile.toml index a359fce..4b55c2c 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -18,13 +18,21 @@ command = "cargo" args = ["fmt", "--", "--check"] [tasks.test] -dependencies = ["test-base", "test-auth0"] +dependencies = ["test-base", "test-auth0", "test-otel-0_20", "test-otel-0_21"] [tasks.test-base] command = "cargo" args = ["test", "--features", "gzip", "${@}"] dependencies = ["build"] +[tasks.test-otel-0_20] +command = "cargo" +args = ["test", "--no-default-features", "--features", "tracing_opentelemetry_0_20"] + +[tasks.test-otel-0_21] +command = "cargo" +args = ["test", "--no-default-features", "--features", "tracing_opentelemetry_0_21"] + [tasks.test-auth0] command = "cargo" args = ["test", "--features=auth0,gzip", "${@}"] @@ -43,4 +51,4 @@ env = { "RUSTDOCFLAGS" = "-Dwarnings" } [tasks.release] description = "Task to release the package to crates.io" command = "cargo" -args = ["publish", "--no-verify"] \ No newline at end of file +args = ["publish", "--no-verify"] diff --git a/examples/rest_multipart.rs b/examples/rest_multipart.rs index 0274e91..3c2c943 100644 --- a/examples/rest_multipart.rs +++ b/examples/rest_multipart.rs @@ -5,7 +5,7 @@ //! ```shell //! cargo run --example rest_multipart //! ``` -use std::{collections::HashSet, iter::FromIterator}; +use std::collections::HashSet; use prima_bridge::{prelude::*, MultipartFile, MultipartFormFileField, RestMultipart}; diff --git a/src/auth0/token.rs b/src/auth0/token.rs index f2b663c..7842f98 100644 --- a/src/auth0/token.rs +++ b/src/auth0/token.rs @@ -54,7 +54,8 @@ impl Token { // the exact issued_at (iat) and expiration (exp) // reference: https://www.iana.org/assignments/jwt/jwt.xhtml let issue_date: DateTime = Utc::now(); - let expire_date: DateTime = Utc::now() + Duration::seconds(response.expires_in as i64); + let expire_date: DateTime = + Utc::now() + Duration::try_seconds(response.expires_in as i64).unwrap_or(Duration::max_value()); Ok(Self { token: access_token, diff --git a/src/lib.rs b/src/lib.rs index 1effb38..b619567 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,17 @@ //! pass around. //! //! The bridge implement a type state pattern to build the external request. +//! +//! ### Features +//! * `auth0` - enable auth0 integration, allowing bridge.rs to retrieve tokens from auth0 for authentication +//! * `gzip` - provides response body gzip decompression. +//! * `redis-tls` - add support for connecting to redis with tls +//! * `tracing-opentelemetry` adds support for integration with opentelemetry. +//! This feature is an alias for the `tracing_opentelemetry_0_21` feature. +//! `tracing_opentelemetry_0_20` is also available as to support the 0.20 opentelemetry +//! libraries. +//! +//! We are going to support at least the last 3 versions of opentelemetry. After that we mightremove support for older otel version without it being a breaking change. use errors::PrimaBridgeError; use http::{header::HeaderName, HeaderValue, Method}; diff --git a/src/request/mod.rs b/src/request/mod.rs index 168fb83..1f6362d 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -17,7 +17,7 @@ use crate::{BridgeClient, BridgeImpl, Response}; mod body; mod request_type; -#[cfg(feature = "tracing_opentelemetry")] +#[cfg(feature = "_any_otel_version")] mod otel; pub enum RequestType { @@ -139,7 +139,7 @@ pub trait DeliverableRequest<'a>: Sized + Sealed + 'a { fn get_all_headers(&self) -> HeaderMap { let mut additional_headers = self.get_custom_headers().clone(); - #[cfg(feature = "tracing_opentelemetry")] + #[cfg(feature = "_any_otel_version")] additional_headers.extend(self.tracing_headers()); #[cfg(feature = "auth0")] additional_headers.extend(self.get_auth0_headers()); @@ -244,7 +244,7 @@ pub trait DeliverableRequest<'a>: Sized + Sealed + 'a { }) } - #[cfg(feature = "tracing_opentelemetry")] + #[cfg(feature = "_any_otel_version")] fn tracing_headers(&self) -> HeaderMap { use std::collections::HashMap; @@ -266,7 +266,7 @@ pub trait DeliverableRequest<'a>: Sized + Sealed + 'a { .collect() } - #[cfg(not(feature = "tracing_opentelemetry"))] + #[cfg(not(feature = "_any_otel_version"))] fn tracing_headers(&self) -> Vec<(HeaderName, HeaderValue)> { vec![] } diff --git a/src/request/otel.rs b/src/request/otel.rs index bffdd14..f9758e2 100644 --- a/src/request/otel.rs +++ b/src/request/otel.rs @@ -1,9 +1,31 @@ -use opentelemetry::{ - propagation::{Injector, TextMapPropagator}, - sdk::propagation::TraceContextPropagator, -}; -use tracing_opentelemetry::OpenTelemetrySpanExt; - -pub fn inject_context(injector: &mut dyn Injector) { - TraceContextPropagator::new().inject_context(&tracing::Span::current().context(), injector); +#[cfg(not(feature = "tracing_opentelemetry_0_21"))] +#[cfg(feature = "tracing_opentelemetry_0_20")] +mod otel_0_20 { + pub use opentelemetry_0_20_pkg::{ + propagation::{Injector, TextMapPropagator}, + sdk::propagation::TraceContextPropagator, + }; + pub use tracing_opentelemetry_0_21_pkg::OpenTelemetrySpanExt; + + pub fn inject_context(injector: &mut dyn Injector) { + TraceContextPropagator::new().inject_context(&tracing::Span::current().context(), injector); + } +} + +#[cfg(feature = "tracing_opentelemetry_0_21")] +mod otel_0_21 { + pub use opentelemetry_0_21_pkg::propagation::{Injector, TextMapPropagator}; + pub use opentelemetry_sdk_0_21_pkg::propagation::TraceContextPropagator; + pub use tracing_opentelemetry_0_22_pkg::OpenTelemetrySpanExt; + + pub fn inject_context(injector: &mut dyn Injector) { + TraceContextPropagator::new().inject_context(&tracing::Span::current().context(), injector); + } } + +#[cfg(not(feature = "tracing_opentelemetry_0_21"))] +#[cfg(feature = "tracing_opentelemetry_0_20")] +pub use otel_0_20::inject_context; + +#[cfg(feature = "tracing_opentelemetry_0_21")] +pub use otel_0_21::inject_context; diff --git a/src/request/request_type/graphql.rs b/src/request/request_type/graphql.rs index ca0e4a5..39dadf6 100644 --- a/src/request/request_type/graphql.rs +++ b/src/request/request_type/graphql.rs @@ -1,5 +1,5 @@ use std::collections::{HashMap, VecDeque}; -use std::convert::TryInto; + use std::time::Duration; use async_trait::async_trait; @@ -43,7 +43,7 @@ impl<'a, Client: BridgeClient> GraphQLRequest<'a, Client> { Ok(Self { id: Uuid::new_v4(), bridge, - body: serde_json::to_string(&graphql_body.into())?.try_into()?, + body: Body::from(serde_json::to_string(&graphql_body.into())?), method: Method::POST, path: Default::default(), timeout: Duration::from_secs(60), @@ -81,7 +81,7 @@ impl<'a, Client: BridgeClient> GraphQLRequest<'a, Client> { Ok(Self { id: Uuid::new_v4(), bridge, - body: serde_json::to_string(&body_with_injected_variables)?.try_into()?, + body: Body::from(serde_json::to_string(&body_with_injected_variables)?), method: Method::POST, path: Default::default(), timeout: Duration::from_secs(60), @@ -105,7 +105,7 @@ impl<'a, Client: BridgeClient> DeliverableRequest<'a> for GraphQLRequest<'a, Cli fn json_body(self, body: &B) -> PrimaBridgeResult { Ok(Self { - body: serde_json::to_string(body)?.try_into()?, + body: Body::from(serde_json::to_string(body)?), ..self }) } @@ -334,7 +334,7 @@ mod tests { use super::*; use crate::Bridge; use serde::Deserialize; - use serde_json::{json, Value}; + use serde_json::json; use std::str::FromStr; #[derive(Deserialize)] diff --git a/src/request/request_type/rest.rs b/src/request/request_type/rest.rs index 675ab39..f3c14ee 100644 --- a/src/request/request_type/rest.rs +++ b/src/request/request_type/rest.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::time::Duration; use std::{borrow::Cow, collections::HashSet}; @@ -72,7 +71,7 @@ impl<'a, Client: BridgeClient> DeliverableRequest<'a> for RestRequest<'a, Client let mut custom_headers = self.custom_headers; custom_headers.append(CONTENT_TYPE, HeaderValue::from_static("application/json")); Ok(Self { - body: Some(serde_json::to_string(body)?.try_into()?), + body: Some(Body::from(serde_json::to_string(body)?)), custom_headers, ..self })