relay_event_schema/protocol/contexts/
otel.rs1use relay_protocol::{Annotated, Empty, FromValue, IntoValue, Object, Value};
2
3use crate::processor::ProcessValue;
4
5#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
9pub struct OtelContext {
10 #[metastructure(pii = "maybe", max_depth = 7, max_bytes = 8192)]
14 attributes: Annotated<Object<Value>>,
15
16 #[metastructure(pii = "maybe", max_depth = 7, max_bytes = 8192)]
20 resource: Annotated<Object<Value>>,
21
22 #[metastructure(additional_properties, retain = true, pii = "maybe")]
24 pub other: Object<Value>,
25}
26
27impl super::DefaultContext for OtelContext {
28 fn default_key() -> &'static str {
29 "otel"
30 }
31
32 fn from_context(context: super::Context) -> Option<Self> {
33 match context {
34 super::Context::Otel(c) => Some(*c),
35 _ => None,
36 }
37 }
38
39 fn cast(context: &super::Context) -> Option<&Self> {
40 match context {
41 super::Context::Otel(c) => Some(c),
42 _ => None,
43 }
44 }
45
46 fn cast_mut(context: &mut super::Context) -> Option<&mut Self> {
47 match context {
48 super::Context::Otel(c) => Some(c),
49 _ => None,
50 }
51 }
52
53 fn into_context(self) -> super::Context {
54 super::Context::Otel(Box::new(self))
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::protocol::Context;
62
63 #[test]
64 fn test_otel_context_roundtrip() {
65 let json = r#"{
66 "attributes": {
67 "app.payment.amount": 394.25,
68 "rpc.grpc.status_code": "1",
69 "rpc.method": "Charge",
70 "rpc.service": "hipstershop.PaymentService",
71 "rpc.system": "grpc"
72 },
73 "resource": {
74 "process.command": "/usr/src/app/index.js",
75 "process.command_line": "/usr/local/bin/node /usr/src/app/index.js",
76 "process.executable.name": "node",
77 "process.pid": 1,
78 "process.runtime.description": "Node.js",
79 "process.runtime.name": "nodejs",
80 "process.runtime.version": "16.18.0",
81 "service.name": "paymentservice",
82 "telemetry.sdk.language": "nodejs",
83 "telemetry.sdk.name": "opentelemetry",
84 "telemetry.sdk.version": "1.7.0"
85 },
86 "other": "value",
87 "type": "otel"
88}"#;
89 let context = Annotated::new(Context::Otel(Box::new(OtelContext {
90 attributes: Annotated::new(Object::from([
91 (
92 "app.payment.amount".to_string(),
93 Annotated::new(Value::F64(394.25)),
94 ),
95 (
96 "rpc.grpc.status_code".to_string(),
97 Annotated::new(Value::String("1".to_string())),
98 ),
99 (
100 "rpc.method".to_string(),
101 Annotated::new(Value::String("Charge".to_string())),
102 ),
103 (
104 "rpc.service".to_string(),
105 Annotated::new(Value::String("hipstershop.PaymentService".to_string())),
106 ),
107 (
108 "rpc.system".to_string(),
109 Annotated::new(Value::String("grpc".to_string())),
110 ),
111 ])),
112 resource: Annotated::new(Object::from([
113 (
114 "process.command".to_string(),
115 Annotated::new(Value::String("/usr/src/app/index.js".to_string())),
116 ),
117 (
118 "process.command_line".to_string(),
119 Annotated::new(Value::String(
120 "/usr/local/bin/node /usr/src/app/index.js".to_string(),
121 )),
122 ),
123 (
124 "process.executable.name".to_string(),
125 Annotated::new(Value::String("node".to_string())),
126 ),
127 ("process.pid".to_string(), Annotated::new(Value::I64(1))),
128 (
129 "process.runtime.description".to_string(),
130 Annotated::new(Value::String("Node.js".to_string())),
131 ),
132 (
133 "process.runtime.name".to_string(),
134 Annotated::new(Value::String("nodejs".to_string())),
135 ),
136 (
137 "process.runtime.version".to_string(),
138 Annotated::new(Value::String("16.18.0".to_string())),
139 ),
140 (
141 "service.name".to_string(),
142 Annotated::new(Value::String("paymentservice".to_string())),
143 ),
144 (
145 "telemetry.sdk.language".to_string(),
146 Annotated::new(Value::String("nodejs".to_string())),
147 ),
148 (
149 "telemetry.sdk.name".to_string(),
150 Annotated::new(Value::String("opentelemetry".to_string())),
151 ),
152 (
153 "telemetry.sdk.version".to_string(),
154 Annotated::new(Value::String("1.7.0".to_string())),
155 ),
156 ])),
157 other: {
158 let mut map = Object::new();
159 map.insert(
160 "other".to_string(),
161 Annotated::new(Value::String("value".to_string())),
162 );
163 map
164 },
165 })));
166
167 assert_eq!(context, Annotated::from_json(json).unwrap());
168 assert_eq!(json, context.to_json_pretty().unwrap());
169 }
170}