Skip to main content

miden_node_utils/
panic.rs

1use std::any::Any;
2
3use http::{Response, StatusCode, header};
4use http_body_util::Full;
5pub use tower_http::catch_panic::CatchPanicLayer;
6
7use crate::tracing::OpenTelemetrySpanExt;
8
9/// Custom callback that is used by Tower to fulfill the
10/// [`tower_http::catch_panic::ResponseForPanic`] trait.
11///
12/// This should be added to tonic server builder as a layer via [`CatchPanicLayer::custom()`].
13#[track_caller]
14pub fn catch_panic_layer_fn(err: Box<dyn Any + Send + 'static>) -> Response<Full<bytes::Bytes>> {
15    // Log the panic error details.
16    let err = stringify_panic_error(err);
17    tracing::error!(panic = true, error = %err, "panic");
18
19    // Mark the current span as failed for OpenTelemetry.
20    let wrapped = anyhow::Error::msg(err.clone());
21    tracing::Span::current().set_error(wrapped.as_ref());
22
23    // Return generic error response.
24    Response::builder()
25        .status(StatusCode::INTERNAL_SERVER_ERROR)
26        .header(header::CONTENT_TYPE, "application/grpc")
27        .body(Full::from(""))
28        .unwrap()
29}
30
31/// Converts a dynamic panic-related error into a string.
32fn stringify_panic_error(err: Box<dyn Any + Send + 'static>) -> String {
33    if let Some(&msg) = err.downcast_ref::<&str>() {
34        msg.to_string()
35    } else if let Ok(msg) = err.downcast::<String>() {
36        *msg
37    } else {
38        "unknown".to_string()
39    }
40}