microclaw_engine/internal/observability/
sdk.rs1use opentelemetry::KeyValue;
2use opentelemetry_sdk::Resource;
3use serde_yaml::{Mapping, Value};
4
5#[derive(Clone)]
6pub struct OTelSdkContext {
7 pub resource: Resource,
8 pub service_name: String,
9}
10
11impl OTelSdkContext {
12 pub fn from_observability(map: &Mapping) -> Self {
13 let service_name = get_trimmed(map, "service_name")
14 .unwrap_or("microclaw")
15 .to_string();
16 let resource = Resource::builder_empty()
17 .with_attributes([KeyValue::new("service.name", service_name.clone())])
18 .build();
19 Self {
20 resource,
21 service_name,
22 }
23 }
24}
25
26pub fn get_trimmed<'a>(map: &'a Mapping, key: &str) -> Option<&'a str> {
27 map.get(Value::String(key.to_string()))
28 .and_then(Value::as_str)
29 .map(str::trim)
30 .filter(|s| !s.is_empty())
31}
32
33pub fn get_u64(map: &Mapping, key: &str) -> Option<u64> {
34 map.get(Value::String(key.to_string()))
35 .and_then(Value::as_u64)
36}
37
38pub fn get_bool(map: &Mapping, key: &str) -> Option<bool> {
39 map.get(Value::String(key.to_string()))
40 .and_then(Value::as_bool)
41}
42
43pub fn parse_headers(map: &Mapping) -> Vec<(String, String)> {
44 let mut headers = Vec::new();
45 if let Some(hmap) = map
46 .get(Value::String("otlp_headers".to_string()))
47 .and_then(Value::as_mapping)
48 {
49 for (k, v) in hmap {
50 let Some(key) = k.as_str() else {
51 continue;
52 };
53 let Some(val) = v.as_str() else {
54 continue;
55 };
56 headers.push((key.to_string(), val.to_string()));
57 }
58 }
59 headers
60}