diff --git a/fpx-lib/Cargo.toml b/fpx-lib/Cargo.toml index 5f3906a41..9c927c54e 100644 --- a/fpx-lib/Cargo.toml +++ b/fpx-lib/Cargo.toml @@ -55,3 +55,7 @@ wasm-bindgen = { version = "0.2", default-features = false, optional = true } [dev-dependencies] http-body-util = { version = "0.1", default-features = false } +tokio = { version = "1.39", default-features = false, features = [ + "macros", + "test-util", +] } diff --git a/fpx-lib/src/api/models/otel.rs b/fpx-lib/src/api/models/otel.rs index 3e5ce2191..477f7fe0c 100644 --- a/fpx-lib/src/api/models/otel.rs +++ b/fpx-lib/src/api/models/otel.rs @@ -1,10 +1,8 @@ -use opentelemetry_proto::tonic::common::v1::{any_value, KeyValueList}; +use opentelemetry_proto::tonic::collector::trace::v1::ExportTraceServiceRequest; +use opentelemetry_proto::tonic::common::v1::{any_value, KeyValue, KeyValueList}; use opentelemetry_proto::tonic::trace::v1::span::{Event, Link}; use opentelemetry_proto::tonic::trace::v1::status::StatusCode; use opentelemetry_proto::tonic::trace::v1::{span, Status}; -use opentelemetry_proto::tonic::{ - collector::trace::v1::ExportTraceServiceRequest, common::v1::KeyValue, -}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -241,7 +239,7 @@ impl From for AttributeMap { impl From> for AttributeMap { fn from(attributes: Vec) -> Self { - let result: BTreeMap> = attributes + let result = attributes .into_iter() .map(|kv| { ( @@ -256,37 +254,42 @@ impl From> for AttributeMap { } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] pub enum AttributeValue { - String(String), - Bool(bool), - Int(i64), - Double(f64), - Array(Vec), - KeyValueList(AttributeMap), - Bytes(Vec), + StringValue(String), + BoolValue(bool), + IntValue(i64), + DoubleValue(f64), + ArrayValue(Vec), + KvlistValue(AttributeMap), + BytesValue(Vec), } impl From for AttributeValue { fn from(value: any_value::Value) -> Self { match value { - any_value::Value::StringValue(val) => AttributeValue::String(val), - any_value::Value::BoolValue(val) => AttributeValue::Bool(val), - any_value::Value::IntValue(val) => AttributeValue::Int(val), - any_value::Value::DoubleValue(val) => AttributeValue::Double(val), - any_value::Value::BytesValue(val) => AttributeValue::Bytes(val), - any_value::Value::ArrayValue(val) => { - let val: Vec<_> = val - .values - .into_iter() - .flat_map(|value| value.value.map(|value| value.into())) - .collect(); - AttributeValue::Array(val) - } - any_value::Value::KvlistValue(val) => AttributeValue::KeyValueList(val.values.into()), + any_value::Value::StringValue(val) => AttributeValue::StringValue(val), + any_value::Value::BoolValue(val) => AttributeValue::BoolValue(val), + any_value::Value::IntValue(val) => AttributeValue::IntValue(val), + any_value::Value::DoubleValue(val) => AttributeValue::DoubleValue(val), + any_value::Value::BytesValue(val) => AttributeValue::BytesValue(val), + any_value::Value::ArrayValue(val) => val.into(), + any_value::Value::KvlistValue(val) => AttributeValue::KvlistValue(val.values.into()), } } } +impl From for AttributeValue { + fn from(value: opentelemetry_proto::tonic::common::v1::ArrayValue) -> Self { + let value: Vec<_> = value + .values + .into_iter() + .flat_map(|value| value.value.map(|value| value.into())) + .collect(); + AttributeValue::ArrayValue(value) + } +} + /// A trace contains a summary of its traces. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct TraceSummary { @@ -364,3 +367,65 @@ impl From for SpanSummary { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn attribute_value_serialize_deserialize() { + struct Test<'a> { + input: AttributeValue, + expected: &'a str, + } + + let mut kv_list = BTreeMap::new(); + kv_list.insert("key1".to_string(), Some(AttributeValue::IntValue(1234))); + kv_list.insert( + "key2".to_string(), + Some(AttributeValue::DoubleValue(1234.1234)), + ); + let kv_list: AttributeMap = AttributeMap(kv_list); + let tests = vec![ + Test { + input: AttributeValue::IntValue(1234), + expected: "{\"intValue\":1234}", + }, + Test { + input: AttributeValue::DoubleValue(1234.1234), + expected: "{\"doubleValue\":1234.1234}", + }, + Test { + input: AttributeValue::StringValue("hello".to_string()), + expected: "{\"stringValue\":\"hello\"}", + }, + Test { + input: AttributeValue::BoolValue(true), + expected: "{\"boolValue\":true}", + }, + Test { + input: AttributeValue::BytesValue(vec![1, 2, 3, 4]), + expected: "{\"bytesValue\":[1,2,3,4]}", + }, + Test { + input: AttributeValue::ArrayValue(vec![ + AttributeValue::IntValue(1234), + AttributeValue::DoubleValue(1234.1234), + ]), + expected: "{\"arrayValue\":[{\"intValue\":1234},{\"doubleValue\":1234.1234}]}", + }, + Test { + input: AttributeValue::KvlistValue(kv_list), + expected: "{\"kvlistValue\":{\"key1\":{\"intValue\":1234},\"key2\":{\"doubleValue\":1234.1234}}}", + }, + ]; + + for test in tests { + let actual = serde_json::to_string(&test.input).unwrap(); + assert_eq!(actual, test.expected); + + let converted_back: AttributeValue = serde_json::from_str(&actual).unwrap(); + assert_eq!(converted_back, test.input); + } + } +} diff --git a/fpx-lib/src/api/models/ts_compat.rs b/fpx-lib/src/api/models/ts_compat.rs index 31065b375..7fa1204c7 100644 --- a/fpx-lib/src/api/models/ts_compat.rs +++ b/fpx-lib/src/api/models/ts_compat.rs @@ -119,13 +119,13 @@ impl From for serde_json::Map for serde_json::Value { fn from(value: AttributeValue) -> Self { match value { - AttributeValue::String(value) => value.into(), - AttributeValue::Bool(value) => value.into(), - AttributeValue::Int(value) => value.into(), - AttributeValue::Double(value) => value.into(), - AttributeValue::Array(values) => values.into(), - AttributeValue::KeyValueList(value) => serde_json::Value::Object(value.into()), - AttributeValue::Bytes(value) => value.into(), + AttributeValue::StringValue(value) => value.into(), + AttributeValue::BoolValue(value) => value.into(), + AttributeValue::IntValue(value) => value.into(), + AttributeValue::DoubleValue(value) => value.into(), + AttributeValue::ArrayValue(values) => values.into(), + AttributeValue::KvlistValue(value) => serde_json::Value::Object(value.into()), + AttributeValue::BytesValue(value) => value.into(), } } } diff --git a/fpx-lib/src/data/util.rs b/fpx-lib/src/data/util.rs index cf97da64c..aa4d24c34 100644 --- a/fpx-lib/src/data/util.rs +++ b/fpx-lib/src/data/util.rs @@ -265,6 +265,7 @@ mod tests { ) } + #[cfg(target_family = "wasm")] #[cfg(feature = "wasm-bindgen")] #[test] fn timestamp_serialize_wasm_bindgen() { diff --git a/scripts/otel_collector/config.yaml b/scripts/otel_collector/config.yaml index c6c85d123..147b7c670 100644 --- a/scripts/otel_collector/config.yaml +++ b/scripts/otel_collector/config.yaml @@ -27,7 +27,7 @@ service: pipelines: traces: receivers: [otlp] - exporters: [debug, otlphttp/fpx-workers] + exporters: [debug, otlphttp] telemetry: logs: