diff --git a/opentelemetry-otlp/CHANGELOG.md b/opentelemetry-otlp/CHANGELOG.md index 5295ae9ee0..c5540cc0eb 100644 --- a/opentelemetry-otlp/CHANGELOG.md +++ b/opentelemetry-otlp/CHANGELOG.md @@ -21,6 +21,8 @@ now use `.with_resource(RESOURCE::default())` to configure Resource when using - **Breaking** [1869](https://github.com/open-telemetry/opentelemetry-rust/pull/1869) The OTLP logs exporter now overrides the [InstrumentationScope::name](https://github.com/open-telemetry/opentelemetry-proto/blob/b3060d2104df364136d75a35779e6bd48bac449a/opentelemetry/proto/common/v1/common.proto#L73) field with the `target` from `LogRecord`, if target is populated. - Groups batch of `LogRecord` and `Span` by their resource and instrumentation scope before exporting, for better efficiency [#1873](https://github.com/open-telemetry/opentelemetry-rust/pull/1873). +- Fixing the OTLP HTTP/JSON exporter. [#1882](https://github.com/open-telemetry/opentelemetry-rust/pull/1882) - The exporter was broken in the + previous release. ## v0.16.0 diff --git a/opentelemetry-otlp/Cargo.toml b/opentelemetry-otlp/Cargo.toml index f031791aa6..2a04fa9956 100644 --- a/opentelemetry-otlp/Cargo.toml +++ b/opentelemetry-otlp/Cargo.toml @@ -71,7 +71,6 @@ tls-webpki-roots = ["tls", "tonic/tls-webpki-roots"] # http binary http-proto = ["prost", "opentelemetry-http", "opentelemetry-proto/gen-tonic-messages", "http", "trace", "metrics"] -# http json This does not work today due to known issue. See https://github.com/open-telemetry/opentelemetry-rust/issues/1763. http-json = ["serde_json", "prost", "opentelemetry-http", "opentelemetry-proto/gen-tonic-messages", "opentelemetry-proto/with-serde", "http", "trace", "metrics"] reqwest-blocking-client = ["reqwest/blocking", "opentelemetry-http/reqwest"] reqwest-client = ["reqwest", "opentelemetry-http/reqwest"] diff --git a/opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml b/opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml index 2c5e2d69cf..89c1e2d62f 100644 --- a/opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml +++ b/opentelemetry-otlp/examples/basic-otlp-http/Cargo.toml @@ -9,7 +9,7 @@ publish = false once_cell = { workspace = true } opentelemetry = { path = "../../../opentelemetry" } opentelemetry_sdk = { path = "../../../opentelemetry-sdk", features = ["rt-tokio", "metrics", "logs"] } -opentelemetry-otlp = { path = "../..", features = ["http-proto", "reqwest-client", "logs"] } +opentelemetry-otlp = { path = "../..", features = ["http-proto", "http-json", "reqwest-client", "logs"] } opentelemetry-appender-tracing = { path = "../../../opentelemetry-appender-tracing", default-features = false} opentelemetry-semantic-conventions = { path = "../../../opentelemetry-semantic-conventions" } diff --git a/opentelemetry-otlp/examples/basic-otlp-http/README.md b/opentelemetry-otlp/examples/basic-otlp-http/README.md index 2608deafce..ac2c4f26c0 100644 --- a/opentelemetry-otlp/examples/basic-otlp-http/README.md +++ b/opentelemetry-otlp/examples/basic-otlp-http/README.md @@ -1,9 +1,9 @@ # Basic OTLP exporter Example This example shows how to setup OpenTelemetry OTLP exporter for logs, metrics -and traces to exports them to the [OpenTelemetry +and traces to export them to the [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) via OTLP -over HTTP/protobuf. The Collector then sends the data to the appropriate +using different protocols such as HTTP/json and HTTP/protobuf. The Collector then sends the data to the appropriate backend, in this case, the logging Exporter, which displays data to console. ## Usage diff --git a/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs b/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs index 4e73537ce8..fae8aaa9e1 100644 --- a/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs +++ b/opentelemetry-otlp/examples/basic-otlp-http/src/main.rs @@ -32,6 +32,7 @@ fn init_logs() -> Result .with_exporter( opentelemetry_otlp::new_exporter() .http() + .with_protocol(opentelemetry_otlp::Protocol::HttpBinary) .with_endpoint("http://localhost:4318/v1/logs"), ) .install_batch(opentelemetry_sdk::runtime::Tokio) @@ -43,6 +44,7 @@ fn init_tracer_provider() -> Result { .with_exporter( opentelemetry_otlp::new_exporter() .http() + .with_protocol(opentelemetry_otlp::Protocol::HttpBinary) .with_endpoint("http://localhost:4318/v1/traces"), ) .with_trace_config(Config::default().with_resource(RESOURCE.clone())) @@ -55,6 +57,7 @@ fn init_metrics() -> Result s, Err(e) => return Err(e), // Handle the error or return it }; - + // Attempt to serialize the intValue field if let Err(e) = state.serialize_field("intValue", &i.to_string()) { return Err(e); // Handle the error or return it } - + // Finalize the struct serialization state.end() - }, + } Some(value) => value.serialize(serializer), None => serializer.serialize_none(), }, @@ -74,76 +74,77 @@ pub(crate) mod serializers { } pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - struct ValueVisitor; + where + D: Deserializer<'de>, + { + struct ValueVisitor; - impl<'de> de::Visitor<'de> for ValueVisitor { - type Value = AnyValue; + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = AnyValue; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a JSON object for AnyValue") - } + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a JSON object for AnyValue") + } - fn visit_map(self, mut map: V) -> Result - where - V: de::MapAccess<'de>, - { - let mut value: Option = None; + fn visit_map(self, mut map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mut value: Option = None; - while let Some(key) = map.next_key::()? { - let key_str = key.as_str(); - match key_str { - "stringValue" => { - let s = map.next_value()?; - value = Some(any_value::Value::StringValue(s)); - }, - "boolValue" => { - let b = map.next_value()?; - value = Some(any_value::Value::BoolValue(b)); - }, - "intValue" => { - let value_str = map.next_value::()?; - let int_value = value_str.parse::() - .map_err(de::Error::custom)?; - value = Some(any_value::Value::IntValue(int_value)); - }, - "doubleValue" => { - let d = map.next_value()?; - value = Some(any_value::Value::DoubleValue(d)); - }, - "arrayValue" => { - let a = map.next_value()?; - value = Some(any_value::Value::ArrayValue(a)); - }, - "kvlistValue" => { - let kv = map.next_value()?; - value = Some(any_value::Value::KvlistValue(kv)); - }, - "bytesValue" => { - let bytes = map.next_value()?; - value = Some(any_value::Value::BytesValue(bytes)); - }, - _ => { - //skip unknown keys, and handle error later. - continue + while let Some(key) = map.next_key::()? { + let key_str = key.as_str(); + match key_str { + "stringValue" => { + let s = map.next_value()?; + value = Some(any_value::Value::StringValue(s)); + } + "boolValue" => { + let b = map.next_value()?; + value = Some(any_value::Value::BoolValue(b)); + } + "intValue" => { + let value_str = map.next_value::()?; + let int_value = value_str.parse::().map_err(de::Error::custom)?; + value = Some(any_value::Value::IntValue(int_value)); + } + "doubleValue" => { + let d = map.next_value()?; + value = Some(any_value::Value::DoubleValue(d)); + } + "arrayValue" => { + let a = map.next_value()?; + value = Some(any_value::Value::ArrayValue(a)); + } + "kvlistValue" => { + let kv = map.next_value()?; + value = Some(any_value::Value::KvlistValue(kv)); + } + "bytesValue" => { + let bytes = map.next_value()?; + value = Some(any_value::Value::BytesValue(bytes)); + } + _ => { + //skip unknown keys, and handle error later. + continue; + } } } - } - if let Some(v) = value { - Ok(AnyValue { value: Some(v) }) - } else { - Err(de::Error::custom("Invalid data for AnyValue, no known keys found")) + if let Some(v) = value { + Ok(AnyValue { value: Some(v) }) + } else { + Err(de::Error::custom( + "Invalid data for AnyValue, no known keys found", + )) + } } } + + let value = deserializer.deserialize_map(ValueVisitor)?; + Ok(Some(value)) } - let value = deserializer.deserialize_map(ValueVisitor)?; - Ok(Some(value)) -} - pub fn serialize_u64_to_string(value: &u64, serializer: S) -> Result where S: Serializer, @@ -167,7 +168,7 @@ where let s = value.to_string(); serializer.serialize_str(&s) } - + pub fn deserialize_string_to_i64<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>,