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