diff --git a/opentelemetry-otlp/Cargo.toml b/opentelemetry-otlp/Cargo.toml index c7fe540089..0eac9430d1 100644 --- a/opentelemetry-otlp/Cargo.toml +++ b/opentelemetry-otlp/Cargo.toml @@ -65,6 +65,7 @@ default = ["grpc-tonic", "trace", "metrics", "logs"] # grpc using tonic grpc-tonic = ["tonic", "prost", "http", "tokio", "opentelemetry-proto/gen-tonic"] gzip-tonic = ["tonic/gzip"] +zstd-tonic = ["tonic/zstd"] tls = ["tonic/tls"] tls-roots = ["tls", "tonic/tls-roots"] tls-webpki-roots = ["tls", "tonic/tls-webpki-roots"] diff --git a/opentelemetry-otlp/src/exporter/mod.rs b/opentelemetry-otlp/src/exporter/mod.rs index dac2cd1daa..d138527d8f 100644 --- a/opentelemetry-otlp/src/exporter/mod.rs +++ b/opentelemetry-otlp/src/exporter/mod.rs @@ -98,12 +98,15 @@ impl Default for ExportConfig { pub enum Compression { /// Compresses data using gzip. Gzip, + /// Compresses data using zstd. + Zstd, } impl Display for Compression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Compression::Gzip => write!(f, "gzip"), + Compression::Zstd => write!(f, "zstd"), } } } @@ -114,6 +117,7 @@ impl FromStr for Compression { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { "gzip" => Ok(Compression::Gzip), + "zstd" => Ok(Compression::Zstd), _ => Err(Error::UnsupportedCompressionAlgorithm(s.to_string())), } } diff --git a/opentelemetry-otlp/src/exporter/tonic/mod.rs b/opentelemetry-otlp/src/exporter/tonic/mod.rs index 244d16b62d..69ecb4fe79 100644 --- a/opentelemetry-otlp/src/exporter/tonic/mod.rs +++ b/opentelemetry-otlp/src/exporter/tonic/mod.rs @@ -52,8 +52,16 @@ impl TryFrom<Compression> for tonic::codec::CompressionEncoding { #[cfg(feature = "gzip-tonic")] Compression::Gzip => Ok(tonic::codec::CompressionEncoding::Gzip), #[cfg(not(feature = "gzip-tonic"))] - Compression::Gzip => Err(crate::Error::UnsupportedCompressionAlgorithm( - value.to_string(), + Compression::Gzip => Err(crate::Error::FeatureRequiredForCompressionAlgorithm( + "gzip-tonic", + Compression::Gzip, + )), + #[cfg(feature = "zstd-tonic")] + Compression::Zstd => Ok(tonic::codec::CompressionEncoding::Zstd), + #[cfg(not(feature = "zstd-tonic"))] + Compression::Zstd => Err(crate::Error::FeatureRequiredForCompressionAlgorithm( + "zstd-tonic", + Compression::Zstd, )), } } @@ -399,7 +407,7 @@ fn parse_headers_from_env(signal_headers_var: &str) -> HeaderMap { #[cfg(test)] mod tests { use crate::exporter::tests::run_env_test; - #[cfg(feature = "gzip-tonic")] + #[cfg(feature = "grpc-tonic")] use crate::exporter::Compression; use crate::TonicExporterBuilder; use crate::{OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS}; @@ -438,7 +446,7 @@ mod tests { #[test] #[cfg(feature = "gzip-tonic")] - fn test_with_compression() { + fn test_with_gzip_compression() { // metadata should merge with the current one with priority instead of just replacing it let mut metadata = MetadataMap::new(); metadata.insert("foo", "bar".parse().unwrap()); @@ -446,6 +454,26 @@ mod tests { assert_eq!(builder.tonic_config.compression.unwrap(), Compression::Gzip); } + #[test] + #[cfg(feature = "zstd-tonic")] + fn test_with_zstd_compression() { + let builder = TonicExporterBuilder::default().with_compression(Compression::Zstd); + assert_eq!(builder.tonic_config.compression.unwrap(), Compression::Zstd); + } + + #[test] + #[cfg(feature = "grpc-tonic")] + fn test_convert_compression() { + #[cfg(feature = "gzip-tonic")] + assert!(tonic::codec::CompressionEncoding::try_from(Compression::Gzip).is_ok()); + #[cfg(not(feature = "gzip-tonic"))] + assert!(tonic::codec::CompressionEncoding::try_from(Compression::Gzip).is_err()); + #[cfg(feature = "zstd-tonic")] + assert!(tonic::codec::CompressionEncoding::try_from(Compression::Zstd).is_ok()); + #[cfg(not(feature = "zstd-tonic"))] + assert!(tonic::codec::CompressionEncoding::try_from(Compression::Zstd).is_err()); + } + #[test] fn test_parse_headers_from_env() { run_env_test( diff --git a/opentelemetry-otlp/src/lib.rs b/opentelemetry-otlp/src/lib.rs index 28a13a2ca8..cb3077d23c 100644 --- a/opentelemetry-otlp/src/lib.rs +++ b/opentelemetry-otlp/src/lib.rs @@ -97,6 +97,7 @@ //! For users uses `tonic` as grpc layer: //! * `grpc-tonic`: Use `tonic` as grpc layer. This is enabled by default. //! * `gzip-tonic`: Use gzip compression for `tonic` grpc layer. +//! * `zstd-tonic`: Use zstd compression for `tonic` grpc layer. //! * `tls-tonic`: Enable TLS. //! * `tls-roots`: Adds system trust roots to rustls-based gRPC clients using the rustls-native-certs crate //! * `tls-webkpi-roots`: Embeds Mozilla's trust roots to rustls-based gRPC clients using the webkpi-roots crate @@ -372,6 +373,11 @@ pub enum Error { /// Unsupported compression algorithm. #[error("unsupported compression algorithm '{0}'")] UnsupportedCompressionAlgorithm(String), + + /// Feature required to use the specified compression algorithm. + #[cfg(any(not(feature = "gzip-tonic"), not(feature = "zstd-tonic")))] + #[error("feature '{0}' is required to use the compression algorithm '{1}'")] + FeatureRequiredForCompressionAlgorithm(&'static str, Compression), } #[cfg(feature = "grpc-tonic")]