Skip to content

Commit 1a8d755

Browse files
committed
chore(otlp): Make invalid proto combos unrepresentable
1 parent 5c8dbc8 commit 1a8d755

File tree

9 files changed

+204
-187
lines changed

9 files changed

+204
-187
lines changed

opentelemetry-otlp/CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@
44

55
- Add partial success response handling for OTLP exporters (traces, metrics, logs) per OTLP spec. Exporters now log warnings when the server returns partial success responses with rejected items and error messages. [#865](https://github.com/open-telemetry/opentelemetry-rust/issues/865)
66
- Refactor `internal-logs` feature in `opentelemetry-otlp` to reduce unnecessary dependencies[3191](https://github.com/open-telemetry/opentelemetry-rust/pull/3192)
7+
- **Breaking** Make invalid protocol/transport combinations unrepresentable [#3082](https://github.com/open-telemetry/opentelemetry-rust/issues/3082)
8+
- Removed `protocol` field from `ExportConfig` and `with_protocol()` method from `WithExportConfig` trait
9+
- Added new HTTP-specific `Protocol` enum with `HttpProtobuf` and `HttpJson` variants
10+
- Added `with_protocol()` method to `WithHttpConfig` trait that accepts the HTTP-specific `Protocol` enum
11+
- The `Protocol` enum is now only available and only needed when using HTTP transport
12+
- This change makes invalid protocol/transport combinations (like using HTTP protocol with gRPC transport) impossible to express
13+
- Migration example:
14+
```rust
15+
// Before:
16+
SpanExporter::builder()
17+
.with_http()
18+
.with_protocol(Protocol::HttpBinary) // old Protocol from ExportConfig
19+
.build()
20+
21+
// After:
22+
use opentelemetry_otlp::Protocol;
23+
24+
SpanExporter::builder()
25+
.with_http()
26+
.with_protocol(Protocol::HttpProtobuf) // HTTP-specific Protocol enum
27+
.build()
28+
```
729

830
## 0.31.0
931

opentelemetry-otlp/examples/basic-otlp-http/src/main.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use opentelemetry::{
44
InstrumentationScope, KeyValue,
55
};
66
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
7-
use opentelemetry_otlp::WithExportConfig;
8-
use opentelemetry_otlp::{LogExporter, MetricExporter, Protocol, SpanExporter};
7+
use opentelemetry_otlp::{LogExporter, MetricExporter, SpanExporter};
8+
use opentelemetry_otlp::{Protocol, WithHttpConfig};
99
use opentelemetry_sdk::Resource;
1010
use opentelemetry_sdk::{
1111
logs::SdkLoggerProvider, metrics::SdkMeterProvider, trace::SdkTracerProvider,
@@ -29,7 +29,7 @@ fn get_resource() -> Resource {
2929
fn init_logs() -> SdkLoggerProvider {
3030
let exporter = LogExporter::builder()
3131
.with_http()
32-
.with_protocol(Protocol::HttpBinary)
32+
.with_protocol(Protocol::HttpProtobuf)
3333
.build()
3434
.expect("Failed to create log exporter");
3535

@@ -42,7 +42,7 @@ fn init_logs() -> SdkLoggerProvider {
4242
fn init_traces() -> SdkTracerProvider {
4343
let exporter = SpanExporter::builder()
4444
.with_http()
45-
.with_protocol(Protocol::HttpBinary) //can be changed to `Protocol::HttpJson` to export in JSON format
45+
.with_protocol(Protocol::HttpProtobuf)
4646
.build()
4747
.expect("Failed to create trace exporter");
4848

@@ -55,7 +55,7 @@ fn init_traces() -> SdkTracerProvider {
5555
fn init_metrics() -> SdkMeterProvider {
5656
let exporter = MetricExporter::builder()
5757
.with_http()
58-
.with_protocol(Protocol::HttpBinary) //can be changed to `Protocol::HttpJson` to export in JSON format
58+
.with_protocol(Protocol::HttpProtobuf)
5959
.build()
6060
.expect("Failed to create metric exporter");
6161

opentelemetry-otlp/src/exporter/http/logs.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use super::OtlpHttpClient;
2-
use crate::Protocol;
1+
use super::{OtlpHttpClient, Protocol};
32
use opentelemetry::{otel_debug, otel_warn};
43
use opentelemetry_sdk::error::{OTelSdkError, OTelSdkResult};
54
use opentelemetry_sdk::logs::{LogBatch, LogExporter};
@@ -51,7 +50,15 @@ fn handle_partial_success(response_body: &[u8], protocol: Protocol) {
5150
return;
5251
}
5352
},
54-
_ => match Message::decode(response_body) {
53+
Protocol::HttpProtobuf => match Message::decode(response_body) {
54+
Ok(r) => r,
55+
Err(e) => {
56+
otel_debug!(name: "HttpLogsClient.ResponseParseError", error = e.to_string());
57+
return;
58+
}
59+
},
60+
#[cfg(not(feature = "http-json"))]
61+
Protocol::HttpJson => match Message::decode(response_body) {
5562
Ok(r) => r,
5663
Err(e) => {
5764
otel_debug!(name: "HttpLogsClient.ResponseParseError", error = e.to_string());
@@ -81,15 +88,15 @@ mod tests {
8188
let invalid = vec![0xFF, 0xFF, 0xFF, 0xFF];
8289

8390
// Should not panic - logs debug and returns early
84-
handle_partial_success(&invalid, Protocol::HttpBinary);
91+
handle_partial_success(&invalid, Protocol::HttpProtobuf);
8592
}
8693

8794
#[test]
8895
fn test_handle_empty_response() {
8996
let empty = vec![];
9097

9198
// Should not panic
92-
handle_partial_success(&empty, Protocol::HttpBinary);
99+
handle_partial_success(&empty, Protocol::HttpProtobuf);
93100
}
94101

95102
#[cfg(feature = "http-json")]

opentelemetry-otlp/src/exporter/http/metrics.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use crate::metric::MetricsClient;
2-
use crate::Protocol;
32
use opentelemetry::{otel_debug, otel_warn};
43
use opentelemetry_sdk::error::{OTelSdkError, OTelSdkResult};
54
use opentelemetry_sdk::metrics::data::ResourceMetrics;
65
use prost::Message;
76

8-
use super::OtlpHttpClient;
7+
use super::{OtlpHttpClient, Protocol};
98

109
impl MetricsClient for OtlpHttpClient {
1110
async fn export(&self, metrics: &ResourceMetrics) -> OTelSdkResult {
@@ -47,7 +46,15 @@ fn handle_partial_success(response_body: &[u8], protocol: Protocol) {
4746
return;
4847
}
4948
},
50-
_ => match Message::decode(response_body) {
49+
Protocol::HttpProtobuf => match Message::decode(response_body) {
50+
Ok(r) => r,
51+
Err(e) => {
52+
otel_debug!(name: "HttpMetricsClient.ResponseParseError", error = e.to_string());
53+
return;
54+
}
55+
},
56+
#[cfg(not(feature = "http-json"))]
57+
Protocol::HttpJson => match Message::decode(response_body) {
5158
Ok(r) => r,
5259
Err(e) => {
5360
otel_debug!(name: "HttpMetricsClient.ResponseParseError", error = e.to_string());
@@ -77,15 +84,15 @@ mod tests {
7784
let invalid = vec![0xFF, 0xFF, 0xFF, 0xFF];
7885

7986
// Should not panic - logs debug and returns early
80-
handle_partial_success(&invalid, Protocol::HttpBinary);
87+
handle_partial_success(&invalid, Protocol::HttpProtobuf);
8188
}
8289

8390
#[test]
8491
fn test_handle_empty_response() {
8592
let empty = vec![];
8693

8794
// Should not panic
88-
handle_partial_success(&empty, Protocol::HttpBinary);
95+
handle_partial_success(&empty, Protocol::HttpProtobuf);
8996
}
9097

9198
#[cfg(feature = "http-json")]

0 commit comments

Comments
 (0)