miden_node_utils/tracing/
grpc.rs1macro_rules! rpc_span {
3 ($service:literal, $method:literal) => {
4 tracing::info_span!(
5 concat!($service, "/", $method),
6 rpc.service = $service,
7 rpc.method = $method
8 )
9 };
10}
11
12#[derive(Copy, Clone)]
16pub enum TracedComponent {
17 Rpc,
18 BlockProducer,
19 StoreRpc,
20 StoreBlockProducer,
21 StoreNtxBuilder,
22 RemoteProver,
23 RemoteProverProxy,
24}
25
26pub fn traced_span_fn<T>(component: TracedComponent) -> fn(&http::Request<T>) -> tracing::Span {
33 match component {
34 TracedComponent::Rpc => rpc_trace_fn,
35 TracedComponent::BlockProducer => block_producer_trace_fn,
36 TracedComponent::StoreRpc => store_rpc_trace_fn,
37 TracedComponent::StoreBlockProducer => store_block_producer_trace_fn,
38 TracedComponent::StoreNtxBuilder => store_ntx_builder_trace_fn,
39 TracedComponent::RemoteProver => remote_prover_trace_fn,
40 TracedComponent::RemoteProverProxy => remote_prover_proxy_trace_fn,
41 }
42}
43
44fn rpc_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
45 let span = match request.uri().path().rsplit('/').next() {
46 Some("CheckNullifiers") => rpc_span!("rpc.rpc", "CheckNullifiers"),
47 Some("CheckNullifiersByPrefix") => rpc_span!("rpc.rpc", "CheckNullifiersByPrefix"),
48 Some("GetBlockHeaderByNumber") => rpc_span!("rpc.rpc", "GetBlockHeaderByNumber"),
49 Some("SyncStorageMaps") => rpc_span!("rpc.rpc", "SyncStorageMaps"),
50 Some("SyncAccountVault") => rpc_span!("rpc.rpc", "SyncAccountVault"),
51 Some("SyncState") => rpc_span!("rpc.rpc", "SyncState"),
52 Some("SyncNotes") => rpc_span!("rpc.rpc", "SyncNotes"),
53 Some("GetNotesById") => rpc_span!("rpc.rpc", "GetNotesById"),
54 Some("SubmitProvenTransaction") => rpc_span!("rpc.rpc", "SubmitProvenTransaction"),
55 Some("GetAccountDetails") => rpc_span!("rpc.rpc", "GetAccountDetails"),
56 Some("GetBlockByNumber") => rpc_span!("rpc.rpc", "GetBlockByNumber"),
57 Some("GetAccountProofs") => rpc_span!("rpc.rpc", "GetAccountProofs"),
58 Some("Status") => rpc_span!("rpc.rpc", "Status"),
59 _ => rpc_span!("rpc.rpc", "Unknown"),
60 };
61 add_network_attributes(span, request)
62}
63
64fn block_producer_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
65 let span = match request.uri().path().rsplit('/').next() {
66 Some("SubmitProvenTransaction") => {
67 rpc_span!("block-producer.rpc", "SubmitProvenTransaction")
68 },
69 Some("Status") => rpc_span!("block-producer.rpc", "Status"),
70 _ => {
71 rpc_span!("block-producer.rpc", "Unknown")
72 },
73 };
74
75 let span = add_otel_span_attributes(span, request);
76 add_network_attributes(span, request)
77}
78
79fn store_rpc_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
80 let method = request.uri().path().rsplit('/').next().unwrap_or("Unknown");
81 let span = match method {
82 "CheckNullifiers" => rpc_span!("store.rpc.rpc", "CheckNullifiers"),
83 "CheckNullifiersByPrefix" => rpc_span!("store.rpc.rpc", "CheckNullifiersByPrefix"),
84 "GetAccountDetails" => rpc_span!("store.rpc.rpc", "GetAccountDetails"),
85 "GetAccountProofs" => rpc_span!("store.rpc.rpc", "GetAccountProofs"),
86 "GetBlockByNumber" => rpc_span!("store.rpc.rpc", "GetBlockByNumber"),
87 "GetBlockHeaderByNumber" => rpc_span!("store.rpc.rpc", "GetBlockHeaderByNumber"),
88 "GetNotesById" => rpc_span!("store.rpc.rpc", "GetNotesById"),
89 "SyncNotes" => rpc_span!("store.rpc.rpc", "SyncNotes"),
90 "SyncState" => rpc_span!("store.rpc.rpc", "SyncState"),
91 "Status" => rpc_span!("store.rpc.rpc", "Status"),
92 _ => rpc_span!("store.rpc.rpc", "Unknown"),
93 };
94
95 let span = add_otel_span_attributes(span, request);
96 add_network_attributes(span, request)
97}
98
99fn store_block_producer_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
100 let method = request.uri().path().rsplit('/').next().unwrap_or("Unknown");
101 let span = match method {
102 "ApplyBlock" => rpc_span!("store.block-producer.rpc", "ApplyBlock"),
103 "GetBlockHeaderByNumber" => rpc_span!("store.block-producer.rpc", "GetBlockHeaderByNumber"),
104 "GetBlockInputs" => rpc_span!("store.block-producer.rpc", "GetBlockInputs"),
105 "GetBatchInputs" => rpc_span!("store.block-producer.rpc", "GetBatchInputs"),
106 "GetTransactionInputs" => rpc_span!("store.block-producer.rpc", "GetTransactionInputs"),
107 _ => rpc_span!("store.block-producer.rpc", "Unknown"),
108 };
109
110 let span = add_otel_span_attributes(span, request);
111 add_network_attributes(span, request)
112}
113
114fn store_ntx_builder_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
115 let method = request.uri().path().rsplit('/').next().unwrap_or("Unknown");
116 let span = match method {
117 "GetBlockHeaderByNumber" => rpc_span!("store.ntx-builder.rpc", "GetBlockHeaderByNumber"),
118 "GetUnconsumedNetworkNotes" => {
119 rpc_span!("store.ntx-builder.rpc", "GetUnconsumedNetworkNotes")
120 },
121 "GetCurrentBlockchainData" => {
122 rpc_span!("store.ntx-builder.rpc", "GetCurrentBlockchainData")
123 },
124 "GetNetworkAccountDetailsByPrefix" => {
125 rpc_span!("store.ntx-builder.rpc", "GetNetworkAccountDetailsByPrefix")
126 },
127 _ => rpc_span!("store.ntx-builder.rpc", "Unknown"),
128 };
129
130 let span = add_otel_span_attributes(span, request);
131 add_network_attributes(span, request)
132}
133
134fn remote_prover_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
135 let method = request.uri().path().rsplit('/').next().unwrap_or("Unknown");
136 let span = match method {
137 "Prove" => rpc_span!("remote-prover.rpc", "Prove"),
138 "Status" => rpc_span!("remote-prover.rpc", "Status"),
139 _ => rpc_span!("remote-prover.rpc", "Unknown"),
140 };
141
142 let span = add_otel_span_attributes(span, request);
143 add_network_attributes(span, request)
144}
145
146fn remote_prover_proxy_trace_fn<T>(request: &http::Request<T>) -> tracing::Span {
147 let method = request.uri().path().rsplit('/').next().unwrap_or("Unknown");
148 let span = if method == "Status" {
149 rpc_span!("remote-prover-proxy.rpc", "Status")
150 } else {
151 rpc_span!("remote-prover-proxy.rpc", "Unknown")
152 };
153
154 let span = add_otel_span_attributes(span, request);
155 add_network_attributes(span, request)
156}
157
158fn add_otel_span_attributes<T>(span: tracing::Span, request: &http::Request<T>) -> tracing::Span {
162 let otel_ctx = opentelemetry::global::get_text_map_propagator(|propagator| {
168 propagator.extract(&MetadataExtractor(&tonic::metadata::MetadataMap::from_headers(
169 request.headers().clone(),
170 )))
171 });
172 tracing_opentelemetry::OpenTelemetrySpanExt::set_parent(&span, otel_ctx);
173
174 span
175}
176
177fn add_network_attributes<T>(span: tracing::Span, request: &http::Request<T>) -> tracing::Span {
181 use super::OpenTelemetrySpanExt;
182 span.set_attribute("rpc.system", "grpc");
184 if let Some(host) = request.uri().host() {
185 span.set_attribute("server.address", host);
186 }
187 if let Some(host_port) = request.uri().port() {
188 span.set_attribute("server.port", host_port.as_u16());
189 }
190 let remote_addr = request
191 .extensions()
192 .get::<tonic::transport::server::TcpConnectInfo>()
193 .and_then(tonic::transport::server::TcpConnectInfo::remote_addr);
194 if let Some(addr) = remote_addr {
195 span.set_attribute("client.address", addr.ip());
196 span.set_attribute("client.port", addr.port());
197 span.set_attribute("network.peer.address", addr.ip());
198 span.set_attribute("network.peer.port", addr.port());
199 span.set_attribute("network.transport", "tcp");
200 match addr.ip() {
201 std::net::IpAddr::V4(_) => span.set_attribute("network.type", "ipv4"),
202 std::net::IpAddr::V6(_) => span.set_attribute("network.type", "ipv6"),
203 }
204 }
205
206 span
207}
208
209#[derive(Copy, Clone)]
211pub struct OtelInterceptor;
212
213impl tonic::service::Interceptor for OtelInterceptor {
214 fn call(
215 &mut self,
216 mut request: tonic::Request<()>,
217 ) -> Result<tonic::Request<()>, tonic::Status> {
218 use tracing_opentelemetry::OpenTelemetrySpanExt;
219 let ctx = tracing::Span::current().context();
220 opentelemetry::global::get_text_map_propagator(|propagator| {
221 propagator.inject_context(&ctx, &mut MetadataInjector(request.metadata_mut()));
222 });
223
224 Ok(request)
225 }
226}
227
228struct MetadataExtractor<'a>(&'a tonic::metadata::MetadataMap);
229impl opentelemetry::propagation::Extractor for MetadataExtractor<'_> {
230 fn get(&self, key: &str) -> Option<&str> {
233 self.0.get(key).and_then(|metadata| metadata.to_str().ok())
234 }
235
236 fn keys(&self) -> Vec<&str> {
238 self.0
239 .keys()
240 .map(|key| match key {
241 tonic::metadata::KeyRef::Ascii(v) => v.as_str(),
242 tonic::metadata::KeyRef::Binary(v) => v.as_str(),
243 })
244 .collect::<Vec<_>>()
245 }
246}
247
248struct MetadataInjector<'a>(&'a mut tonic::metadata::MetadataMap);
249impl opentelemetry::propagation::Injector for MetadataInjector<'_> {
250 fn set(&mut self, key: &str, value: String) {
253 if let Ok(key) = tonic::metadata::MetadataKey::from_bytes(key.as_bytes())
254 && let Ok(val) = tonic::metadata::MetadataValue::try_from(&value)
255 {
256 self.0.insert(key, val);
257 }
258 }
259}