miden_node_utils/tracing/
grpc.rs1use tracing::field;
2
3use crate::tracing::OpenTelemetrySpanExt;
4
5#[track_caller]
13pub fn grpc_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
14 let mut path_segments = request.uri().path().rsplit('/');
16
17 let method = path_segments.next().unwrap_or_default();
18 let service = path_segments.next().unwrap_or_default();
19
20 let span = match method {
23 "SyncState" | "SyncNullifiers" => tracing::debug_span!(
24 "rpc",
25 otel.name = field::Empty,
26 rpc.service = service,
27 rpc.method = method
28 ),
29 _ => tracing::info_span!(
30 "rpc",
31 otel.name = field::Empty,
32 rpc.service = service,
33 rpc.method = method
34 ),
35 };
36
37 let otel_name = format!("{service}/{method}");
39 span.record("otel.name", otel_name);
40
41 let otel_ctx = opentelemetry::global::get_text_map_propagator(|propagator| {
43 propagator.extract(&MetadataExtractor(&tonic::metadata::MetadataMap::from_headers(
44 request.headers().clone(),
45 )))
46 });
47 let _ = tracing_opentelemetry::OpenTelemetrySpanExt::set_parent(&span, otel_ctx);
48
49 span.set_attribute("rpc.system", "grpc");
55 if let Some(host) = request.uri().host() {
56 span.set_attribute("server.address", host);
57 }
58 if let Some(host_port) = request.uri().port() {
59 span.set_attribute("server.port", host_port.as_u16());
60 }
61 let remote_addr = request
62 .extensions()
63 .get::<tonic::transport::server::TcpConnectInfo>()
64 .and_then(tonic::transport::server::TcpConnectInfo::remote_addr);
65 if let Some(addr) = remote_addr {
66 span.set_attribute("client.address", addr.ip());
67 span.set_attribute("client.port", addr.port());
68 span.set_attribute("network.peer.address", addr.ip());
69 span.set_attribute("network.peer.port", addr.port());
70 span.set_attribute("network.transport", "tcp");
71 match addr.ip() {
72 std::net::IpAddr::V4(_) => span.set_attribute("network.type", "ipv4"),
73 std::net::IpAddr::V6(_) => span.set_attribute("network.type", "ipv6"),
74 }
75 }
76
77 span
78}
79
80#[derive(Copy, Clone)]
82pub struct OtelInterceptor;
83
84impl tonic::service::Interceptor for OtelInterceptor {
85 fn call(
86 &mut self,
87 mut request: tonic::Request<()>,
88 ) -> Result<tonic::Request<()>, tonic::Status> {
89 use tracing_opentelemetry::OpenTelemetrySpanExt;
90 let ctx = tracing::Span::current().context();
91 opentelemetry::global::get_text_map_propagator(|propagator| {
92 propagator.inject_context(&ctx, &mut MetadataInjector(request.metadata_mut()));
93 });
94
95 Ok(request)
96 }
97}
98
99struct MetadataExtractor<'a>(&'a tonic::metadata::MetadataMap);
100impl opentelemetry::propagation::Extractor for MetadataExtractor<'_> {
101 fn get(&self, key: &str) -> Option<&str> {
104 self.0.get(key).and_then(|metadata| metadata.to_str().ok())
105 }
106
107 fn keys(&self) -> Vec<&str> {
109 self.0
110 .keys()
111 .map(|key| match key {
112 tonic::metadata::KeyRef::Ascii(v) => v.as_str(),
113 tonic::metadata::KeyRef::Binary(v) => v.as_str(),
114 })
115 .collect::<Vec<_>>()
116 }
117}
118
119struct MetadataInjector<'a>(&'a mut tonic::metadata::MetadataMap);
120impl opentelemetry::propagation::Injector for MetadataInjector<'_> {
121 fn set(&mut self, key: &str, value: String) {
124 if let Ok(key) = tonic::metadata::MetadataKey::from_bytes(key.as_bytes())
125 && let Ok(val) = tonic::metadata::MetadataValue::try_from(&value)
126 {
127 self.0.insert(key, val);
128 }
129 }
130}