Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement FromStr and Display for Protocol #2758

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions opentelemetry-otlp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- The `OTEL_EXPORTER_OTLP_TIMEOUT`, `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`, `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` and `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` are changed from seconds to miliseconds.
- Fixed `.with_headers()` in `HttpExporterBuilder` to correctly support multiple key/value pairs. [#2699](https://github.com/open-telemetry/opentelemetry-rust/pull/2699)
- Implement `FromStr` and `Display` for `opentelemetry_otlp::Protocol`. [#2758](https://github.com/open-telemetry/opentelemetry-rust/pull/2758)

## 0.28.0

Expand Down
6 changes: 3 additions & 3 deletions opentelemetry-otlp/src/exporter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ pub const OTEL_EXPORTER_OTLP_PROTOCOL_DEFAULT: &str = OTEL_EXPORTER_OTLP_PROTOCO
/// Default protocol if no features are enabled.
pub const OTEL_EXPORTER_OTLP_PROTOCOL_DEFAULT: &str = "";

const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF: &str = "http/protobuf";
const OTEL_EXPORTER_OTLP_PROTOCOL_GRPC: &str = "grpc";
const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON: &str = "http/json";
pub(crate) const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF: &str = "http/protobuf";
pub(crate) const OTEL_EXPORTER_OTLP_PROTOCOL_GRPC: &str = "grpc";
pub(crate) const OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON: &str = "http/json";

/// Max waiting time for the backend to process each signal batch, defaults to 10 seconds.
pub const OTEL_EXPORTER_OTLP_TIMEOUT: &str = "OTEL_EXPORTER_OTLP_TIMEOUT";
Expand Down
56 changes: 56 additions & 0 deletions opentelemetry-otlp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ mod metric;
#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
mod span;

use std::fmt::Display;
use std::str::FromStr;

pub use crate::exporter::Compression;
pub use crate::exporter::ExportConfig;
#[cfg(feature = "trace")]
Expand Down Expand Up @@ -257,6 +260,9 @@ pub use crate::exporter::{
OTEL_EXPORTER_OTLP_TIMEOUT_DEFAULT,
};

use exporter::OTEL_EXPORTER_OTLP_PROTOCOL_GRPC;
use exporter::OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON;
use exporter::OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF;
use opentelemetry_sdk::ExportError;

/// Type to indicate the builder does not have a client set.
Expand Down Expand Up @@ -352,6 +358,10 @@ pub enum Error {
#[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),

/// Unsupported protocol.
#[error("unsupported protocol '{0}'")]
UnsupportedProtocol(String),
}

#[cfg(feature = "grpc-tonic")]
Expand Down Expand Up @@ -396,7 +406,53 @@ pub enum Protocol {
HttpJson,
}

impl Display for Protocol {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind adding a Display implementation for Protocol?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After seeing the Compression implementation within this library had both FromStr and Display, I felt it was most correct to add Display to match the FromStr here too.

If you have concerns, I am happy to remove it - the FromStr is the functionality I need at present (as per above comment).

fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Protocol::Grpc => write!(f, "{}", OTEL_EXPORTER_OTLP_PROTOCOL_GRPC),
Protocol::HttpBinary => write!(f, "{}", OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF),
Protocol::HttpJson => write!(f, "{}", OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON),
}
}
}

impl FromStr for Protocol {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? Why would a user have this awkward construct:

.with_protocol("grpc".parse::<Protocol>().unwrap())

when they could simply do this:

.with_protocol(Protocol::Grpc)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agree if hard coded then users should use the enum variant.

I am working on a downstream SDK which uses opentelemetry, tracing and log. We configure an otel exporter and are working to support setting the protocol via environment, which is not yet supported by this library (although in future perhaps I can also contribute a solution to that issue).

Other downstream packages to set up an exporter, like init-tracing-opentelemetry, also have similar code doing this conversion.

It feels most correct to have the FromStr implementation here in the library for all downstream implementations to re-use. This is also how the Compression type is already parsed from env within this library.

type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
OTEL_EXPORTER_OTLP_PROTOCOL_GRPC => Ok(Protocol::Grpc),
OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_PROTOBUF => Ok(Protocol::HttpBinary),
OTEL_EXPORTER_OTLP_PROTOCOL_HTTP_JSON => Ok(Protocol::HttpJson),
_ => Err(Error::UnsupportedProtocol(s.to_string())),
}
}
}

#[derive(Debug, Default)]
#[doc(hidden)]
/// Placeholder type when no exporter pipeline has been configured in telemetry pipeline.
pub struct NoExporterConfig(());

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_parse_protocol() {
assert_eq!("grpc".parse::<Protocol>().unwrap(), Protocol::Grpc);
assert_eq!(
"http/protobuf".parse::<Protocol>().unwrap(),
Protocol::HttpBinary
);
assert_eq!("http/json".parse::<Protocol>().unwrap(), Protocol::HttpJson);
assert!("invalid".parse::<Protocol>().is_err());
}

#[test]
fn test_display_protocol() {
assert_eq!(Protocol::Grpc.to_string(), "grpc");
assert_eq!(Protocol::HttpBinary.to_string(), "http/protobuf");
assert_eq!(Protocol::HttpJson.to_string(), "http/json");
}
}
Loading