Skip to content

Commit abc7507

Browse files
authored
Merge branch 'main' into set-resource-optimize
2 parents b220635 + 8a9a569 commit abc7507

File tree

18 files changed

+4571
-1305
lines changed

18 files changed

+4571
-1305
lines changed

.github/ISSUE_TEMPLATE/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ contact_links:
44
about: Please ask questions here.
55
- name: Slack
66
url: https://cloud-native.slack.com/archives/C03GDP0H023
7-
about: Or the `#otel-rust` channel in the CNCF Slack instance. (Not terribly responsive.)
7+
about: Or the `#otel-rust` channel in the CNCF Slack instance.
88
- name: "⚠️ Report a security vulnerability"
99
url: "https://github.com/open-telemetry/opentelemetry-rust/security/advisories/new"
1010
about: "Report a security vulnerability."

RELEASING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ A draft PR can be created, but before releasing consider the following:
1616

1717
* Are there any pending pull requests which should be included in the next release?
1818
* Are they blockers?
19-
* Are there any unresolved issues which should be resolved before the next release?
19+
* Are there any unresolved issues which should be resolved before the next release? Check the release [blockers milestone](https://github.com/open-telemetry/opentelemetry-rust/milestones) for every release
2020
* Bring it up at a SIG meeting, this can usually get some of these questions answered sooner than later. It will also
2121
help establish a person to perform the release. Ideally this can be someone different each time to ensure that the
2222
process is documented.

opentelemetry-otlp/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
### Added
1010

11+
- Aded `http/json` support for all signals ([#1585])
12+
13+
[#1585]: https://github.com/open-telemetry/opentelemetry-rust/pull/1585
14+
1115
- Added `DeltaTemporalitySelector` ([#1568])
1216
- Add `webkpi-roots` features to `reqwest` and `tonic` backends
1317

opentelemetry-otlp/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ reqwest = { workspace = true, optional = true }
4242
http = { workspace = true, optional = true }
4343
serde = { workspace = true, features = ["derive"], optional = true }
4444
thiserror = { workspace = true }
45+
serde_json = { workspace = true, optional = true }
4546

4647
[dev-dependencies]
4748
tokio-stream = { workspace = true, features = ["net"] }
@@ -58,7 +59,7 @@ metrics = ["opentelemetry/metrics", "opentelemetry_sdk/metrics", "opentelemetry-
5859
logs = ["opentelemetry/logs", "opentelemetry_sdk/logs", "opentelemetry-proto/logs"]
5960

6061
# add ons
61-
serialize = ["serde"]
62+
serialize = ["serde", "serde_json"]
6263

6364
default = ["grpc-tonic", "trace"]
6465

@@ -71,6 +72,8 @@ tls-webkpi-roots = ["tls", "tonic/tls-webpki-roots"]
7172

7273
# http binary
7374
http-proto = ["prost", "opentelemetry-http", "opentelemetry-proto/gen-tonic-messages", "http", "trace", "metrics"]
75+
# http json
76+
http-json = ["serde_json", "prost", "opentelemetry-http", "opentelemetry-proto/gen-tonic-messages", "opentelemetry-proto/with-serde", "http", "trace", "metrics"]
7477
reqwest-blocking-client = ["reqwest/blocking", "opentelemetry-http/reqwest"]
7578
reqwest-client = ["reqwest", "opentelemetry-http/reqwest"]
7679
reqwest-rustls = ["reqwest", "opentelemetry-http/reqwest-rustls"]

opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ publish = false
99
once_cell = { workspace = true }
1010
opentelemetry = { path = "../../../opentelemetry" }
1111
opentelemetry_sdk = { path = "../../../opentelemetry-sdk", features = ["rt-tokio", "metrics", "logs"] }
12-
opentelemetry-otlp = { path = "../..", features = ["http-proto", "reqwest-client", "logs"] }
12+
opentelemetry-otlp = { path = "../..", features = ["http-proto", "http-json", "reqwest-client", "logs"] }
1313
opentelemetry-appender-tracing = { path = "../../../opentelemetry-appender-tracing", default-features = false}
1414
opentelemetry-semantic-conventions = { path = "../../../opentelemetry-semantic-conventions" }
1515

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

+1-30
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl LogExporter for OtlpHttpClient {
1919
_ => Err(LogError::Other("exporter is already shut down".into())),
2020
})?;
2121

22-
let (body, content_type) = { build_body(batch, &self.resource)? };
22+
let (body, content_type) = {self.build_logs_export_body(batch, &self.resource)?};
2323
let mut request = http::Request::builder()
2424
.method(Method::POST)
2525
.uri(&self.collector_endpoint)
@@ -55,32 +55,3 @@ impl LogExporter for OtlpHttpClient {
5555
self.resource = resource.into();
5656
}
5757
}
58-
59-
#[cfg(feature = "http-proto")]
60-
fn build_body(
61-
logs: Vec<LogData>,
62-
resource: &opentelemetry_proto::transform::common::tonic::ResourceAttributesWithSchema,
63-
) -> LogResult<(Vec<u8>, &'static str)> {
64-
use opentelemetry_proto::tonic::collector::logs::v1::ExportLogsServiceRequest;
65-
use prost::Message;
66-
let resource_logs = logs
67-
.into_iter()
68-
.map(|log_event| (log_event, resource).into())
69-
.collect::<Vec<_>>();
70-
71-
let req = ExportLogsServiceRequest { resource_logs };
72-
let mut buf = vec![];
73-
req.encode(&mut buf).map_err(crate::Error::from)?;
74-
75-
Ok((buf, "application/x-protobuf"))
76-
}
77-
78-
#[cfg(not(feature = "http-proto"))]
79-
fn build_body(
80-
logs: Vec<LogData>,
81-
resource: &opentelemetry_sdk::Resource,
82-
) -> LogResult<(Vec<u8>, &'static str)> {
83-
Err(LogsError::Other(
84-
"No http protocol configured. Enable one via `http-proto`".into(),
85-
))
86-
}

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

+1-20
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl MetricsClient for OtlpHttpClient {
2121
_ => Err(MetricsError::Other("exporter is already shut down".into())),
2222
})?;
2323

24-
let (body, content_type) = build_body(metrics)?;
24+
let (body, content_type) = self.build_metrics_export_body(metrics)?;
2525
let mut request = http::Request::builder()
2626
.method(Method::POST)
2727
.uri(&self.collector_endpoint)
@@ -47,22 +47,3 @@ impl MetricsClient for OtlpHttpClient {
4747
Ok(())
4848
}
4949
}
50-
51-
#[cfg(feature = "http-proto")]
52-
fn build_body(metrics: &mut ResourceMetrics) -> Result<(Vec<u8>, &'static str)> {
53-
use prost::Message;
54-
55-
let req: opentelemetry_proto::tonic::collector::metrics::v1::ExportMetricsServiceRequest =
56-
(&*metrics).into();
57-
let mut buf = vec![];
58-
req.encode(&mut buf).map_err(crate::Error::from)?;
59-
60-
Ok((buf, "application/x-protobuf"))
61-
}
62-
63-
#[cfg(not(feature = "http-proto"))]
64-
fn build_body(metrics: &mut ResourceMetrics) -> Result<(Vec<u8>, &'static str)> {
65-
Err(MetricsError::Other(
66-
"No http protocol configured. Enable one via `http-proto`".into(),
67-
))
68-
}

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

+86-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1+
use super::{default_headers, default_protocol, parse_header_string};
12
use crate::{
23
ExportConfig, Protocol, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS,
34
OTEL_EXPORTER_OTLP_TIMEOUT,
45
};
56
use http::{HeaderName, HeaderValue, Uri};
67
use opentelemetry_http::HttpClient;
78
use opentelemetry_proto::transform::common::tonic::ResourceAttributesWithSchema;
9+
10+
#[cfg(feature = "logs")]
11+
use opentelemetry_sdk::export::logs::LogData;
12+
#[cfg(feature = "trace")]
13+
use opentelemetry_sdk::export::trace::SpanData;
14+
#[cfg(feature = "metrics")]
15+
use opentelemetry_sdk::metrics::data::ResourceMetrics;
16+
use prost::Message;
817
use std::collections::HashMap;
918
use std::env;
1019
use std::str::FromStr;
1120
use std::sync::{Arc, Mutex};
1221
use std::time::Duration;
1322

14-
use super::{default_headers, parse_header_string};
15-
1623
#[cfg(feature = "metrics")]
1724
mod metrics;
1825

@@ -23,7 +30,7 @@ mod logs;
2330
mod trace;
2431

2532
/// Configuration of the http transport
26-
#[cfg(feature = "http-proto")]
33+
#[cfg(any(feature = "http-proto", feature = "http-json"))]
2734
#[derive(Debug)]
2835
#[cfg_attr(
2936
all(
@@ -99,7 +106,7 @@ impl Default for HttpExporterBuilder {
99106
fn default() -> Self {
100107
HttpExporterBuilder {
101108
exporter_config: ExportConfig {
102-
protocol: Protocol::HttpBinary,
109+
protocol: default_protocol(),
103110
..ExportConfig::default()
104111
},
105112
http_config: HttpConfig {
@@ -111,6 +118,12 @@ impl Default for HttpExporterBuilder {
111118
}
112119

113120
impl HttpExporterBuilder {
121+
/// Specify the OTLP protocol to be used by the exporter
122+
pub fn with_protocol(mut self, protocol: Protocol) -> Self {
123+
self.exporter_config.protocol = protocol;
124+
self
125+
}
126+
114127
/// Assign client implementation
115128
pub fn with_http_client<T: HttpClient + 'static>(mut self, client: T) -> Self {
116129
self.http_config.client = Some(Arc::new(client));
@@ -182,7 +195,13 @@ impl HttpExporterBuilder {
182195
add_header_from_string(&input, &mut headers);
183196
}
184197

185-
Ok(OtlpHttpClient::new(http_client, endpoint, headers, timeout))
198+
Ok(OtlpHttpClient::new(
199+
http_client,
200+
endpoint,
201+
headers,
202+
self.exporter_config.protocol,
203+
timeout,
204+
))
186205
}
187206

188207
/// Create a log exporter with the current configuration
@@ -255,6 +274,7 @@ struct OtlpHttpClient {
255274
client: Mutex<Option<Arc<dyn HttpClient>>>,
256275
collector_endpoint: Uri,
257276
headers: HashMap<HeaderName, HeaderValue>,
277+
protocol: Protocol,
258278
_timeout: Duration,
259279
#[allow(dead_code)]
260280
// <allow dead> would be removed once we support set_resource for metrics and traces.
@@ -267,16 +287,77 @@ impl OtlpHttpClient {
267287
client: Arc<dyn HttpClient>,
268288
collector_endpoint: Uri,
269289
headers: HashMap<HeaderName, HeaderValue>,
290+
protocol: Protocol,
270291
timeout: Duration,
271292
) -> Self {
272293
OtlpHttpClient {
273294
client: Mutex::new(Some(client)),
274295
collector_endpoint,
275296
headers,
297+
protocol,
276298
_timeout: timeout,
277299
resource: ResourceAttributesWithSchema::default(),
278300
}
279301
}
302+
303+
#[cfg(feature = "trace")]
304+
fn build_trace_export_body(
305+
&self,
306+
spans: Vec<SpanData>,
307+
) -> opentelemetry::trace::TraceResult<(Vec<u8>, &'static str)> {
308+
use opentelemetry_proto::tonic::collector::trace::v1::ExportTraceServiceRequest;
309+
310+
let req = ExportTraceServiceRequest {
311+
resource_spans: spans.into_iter().map(Into::into).collect(),
312+
};
313+
match self.protocol {
314+
#[cfg(feature = "http-json")]
315+
Protocol::HttpJson => match serde_json::to_string_pretty(&req) {
316+
Ok(json) => Ok((json.into(), "application/json")),
317+
Err(e) => Err(opentelemetry::trace::TraceError::from(e.to_string())),
318+
},
319+
_ => Ok((req.encode_to_vec(), "application/x-protobuf")),
320+
}
321+
}
322+
323+
#[cfg(feature = "logs")]
324+
fn build_logs_export_body(
325+
&self,
326+
logs: Vec<LogData>,
327+
) -> opentelemetry::logs::LogResult<(Vec<u8>, &'static str)> {
328+
use opentelemetry_proto::tonic::collector::logs::v1::ExportLogsServiceRequest;
329+
330+
let req = ExportLogsServiceRequest {
331+
resource_logs: logs.into_iter().map(Into::into).collect(),
332+
};
333+
match self.protocol {
334+
#[cfg(feature = "http-json")]
335+
Protocol::HttpJson => match serde_json::to_string_pretty(&req) {
336+
Ok(json) => Ok((json.into(), "application/json")),
337+
Err(e) => Err(opentelemetry::logs::LogError::from(e.to_string())),
338+
},
339+
_ => Ok((req.encode_to_vec(), "application/x-protobuf")),
340+
}
341+
}
342+
343+
#[cfg(feature = "metrics")]
344+
fn build_metrics_export_body(
345+
&self,
346+
metrics: &mut ResourceMetrics,
347+
) -> opentelemetry::metrics::Result<(Vec<u8>, &'static str)> {
348+
use opentelemetry_proto::tonic::collector::metrics::v1::ExportMetricsServiceRequest;
349+
350+
let req: ExportMetricsServiceRequest = (&*metrics).into();
351+
352+
match self.protocol {
353+
#[cfg(feature = "http-json")]
354+
Protocol::HttpJson => match serde_json::to_string_pretty(&req) {
355+
Ok(json) => Ok((json.into(), "application/json")),
356+
Err(e) => Err(opentelemetry::metrics::MetricsError::Other(e.to_string())),
357+
},
358+
_ => Ok((req.encode_to_vec(), "application/x-protobuf")),
359+
}
360+
}
280361
}
281362

282363
fn build_endpoint_uri(endpoint: &str, path: &str) -> Result<Uri, crate::Error> {

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

+2-23
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
use futures_core::future::BoxFuture;
44
use http::{header::CONTENT_TYPE, Method};
5-
use opentelemetry::trace::{TraceError, TraceResult};
5+
use opentelemetry::trace::TraceError;
66
use opentelemetry_sdk::export::trace::{ExportResult, SpanData, SpanExporter};
77

88
use super::OtlpHttpClient;
@@ -21,7 +21,7 @@ impl SpanExporter for OtlpHttpClient {
2121
Err(err) => return Box::pin(std::future::ready(Err(err))),
2222
};
2323

24-
let (body, content_type) = match build_body(batch) {
24+
let (body, content_type) = match self.build_trace_export_body(batch) {
2525
Ok(body) => body,
2626
Err(e) => return Box::pin(std::future::ready(Err(e))),
2727
};
@@ -67,24 +67,3 @@ impl SpanExporter for OtlpHttpClient {
6767
let _ = self.client.lock().map(|mut c| c.take());
6868
}
6969
}
70-
71-
#[cfg(feature = "http-proto")]
72-
fn build_body(spans: Vec<SpanData>) -> TraceResult<(Vec<u8>, &'static str)> {
73-
use opentelemetry_proto::tonic::collector::trace::v1::ExportTraceServiceRequest;
74-
use prost::Message;
75-
76-
let req = ExportTraceServiceRequest {
77-
resource_spans: spans.into_iter().map(Into::into).collect(),
78-
};
79-
let mut buf = vec![];
80-
req.encode(&mut buf).map_err(crate::Error::from)?;
81-
82-
Ok((buf, "application/x-protobuf"))
83-
}
84-
85-
#[cfg(not(feature = "http-proto"))]
86-
fn build_body(spans: Vec<SpanData>) -> TraceResult<(Vec<u8>, &'static str)> {
87-
Err(TraceError::Other(
88-
"No http protocol configured. Enable one via `http-proto`".into(),
89-
))
90-
}

0 commit comments

Comments
 (0)