Skip to content

Commit

Permalink
Ensure our AttributeValue matches the OTEL one (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
hatchan authored Aug 29, 2024
1 parent 0bc105f commit ea6fbd7
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 34 deletions.
4 changes: 4 additions & 0 deletions fpx-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
] }
117 changes: 91 additions & 26 deletions fpx-lib/src/api/models/otel.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -241,7 +239,7 @@ impl From<KeyValueList> for AttributeMap {

impl From<Vec<KeyValue>> for AttributeMap {
fn from(attributes: Vec<KeyValue>) -> Self {
let result: BTreeMap<String, Option<AttributeValue>> = attributes
let result = attributes
.into_iter()
.map(|kv| {
(
Expand All @@ -256,37 +254,42 @@ impl From<Vec<KeyValue>> 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<AttributeValue>),
KeyValueList(AttributeMap),
Bytes(Vec<u8>),
StringValue(String),
BoolValue(bool),
IntValue(i64),
DoubleValue(f64),
ArrayValue(Vec<AttributeValue>),
KvlistValue(AttributeMap),
BytesValue(Vec<u8>),
}

impl From<any_value::Value> 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<opentelemetry_proto::tonic::common::v1::ArrayValue> 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 {
Expand Down Expand Up @@ -364,3 +367,65 @@ impl From<Span> 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);
}
}
}
14 changes: 7 additions & 7 deletions fpx-lib/src/api/models/ts_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ impl From<crate::api::models::otel::AttributeMap> for serde_json::Map<String, se
impl From<AttributeValue> 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(),
}
}
}
1 change: 1 addition & 0 deletions fpx-lib/src/data/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ mod tests {
)
}

#[cfg(target_family = "wasm")]
#[cfg(feature = "wasm-bindgen")]
#[test]
fn timestamp_serialize_wasm_bindgen() {
Expand Down
2 changes: 1 addition & 1 deletion scripts/otel_collector/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug, otlphttp/fpx-workers]
exporters: [debug, otlphttp]

telemetry:
logs:
Expand Down

0 comments on commit ea6fbd7

Please sign in to comment.