zoo-endpoint 0.1.5

Macro used by zoo consumers for registering handlers. This wraps dropshot's `Endpoint` and adds some extra functionality for tracing.
Documentation
#[doc = r#" handle "xyz" requests "#]
# [tracing :: instrument (skip (rqctx ,) , parent = None , fields (http . request . method = "GET" , http . route = "/a/b/c" , http . response . status_code = 0 , trace . trace_id = tracing :: field :: Empty , trace . parent_id = tracing :: field :: Empty , api_call . id = tracing :: field :: Empty , exception . original_error = tracing :: field :: Empty ,) , err ,)]
# [dropshot :: endpoint { method = GET , path = "/a/b/c" , tags = ["tag1" , "tag2"] , deprecated = false , unpublished = false , content_type = "application/json" , }]
async fn handler_xyz(
    rqctx: dropshot::RequestContext<Arc<Context>>,
) -> Result<(), dropshot::HttpError> {
    let root_span = tracing::Span::current();
    root_span.record("api_call.id", rqctx.request_id.to_string());
    use dropshot::HttpCodedResponse;
    use opentelemetry::trace::TraceContextExt;
    use std::str::FromStr;
    use tracing_opentelemetry::OpenTelemetrySpanExt;
    if let Some(traceparent) = rqctx.request.headers().get("traceparent") {
        if let Ok(tps) = traceparent.to_str() {
            if tps.len() == 55 {
                let segs: Vec<&str> = tps.split('-').collect();
                if segs.len() == 4 {
                    if let Ok(version) = u8::from_str_radix(segs[0], 16) {
                        if let Ok(trace_id) = u128::from_str_radix(segs[1], 16) {
                            if let Ok(parent_id) = u64::from_str_radix(segs[2], 16) {
                                if let Ok(flags) = u8::from_str_radix(segs[3], 16) {
                                    let trace_flags = opentelemetry::trace::TraceFlags::new(flags)
                                        & opentelemetry::trace::TraceFlags::SAMPLED;
                                    let trace_state =
                                        match rqctx.request.headers().get("tracestate") {
                                            Some(trace_state) => {
                                                opentelemetry::trace::TraceState::from_str(
                                                    trace_state.to_str().unwrap_or_default(),
                                                )
                                                .unwrap_or_else(|_| {
                                                    opentelemetry::trace::TraceState::default()
                                                })
                                            }
                                            None => opentelemetry::trace::TraceState::default(),
                                        };
                                    let span_context = opentelemetry::trace::SpanContext::new(
                                        trace_id.into(),
                                        parent_id.into(),
                                        trace_flags,
                                        true,
                                        trace_state,
                                    );
                                    if span_context.is_valid() {
                                        let context = root_span
                                            .context()
                                            .with_remote_span_context(span_context);
                                        root_span.set_parent(context);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    match zoo_endpoint_handler_xyz::handler_xyz(rqctx.context().clone()).await {
        Ok(r) => {
            let status_code = dropshot::HttpResponseOk::<()>::STATUS_CODE;
            root_span.record("http.response.status_code", status_code.as_u16());
            Ok(r)
        }

        Err(e) => {
            root_span.record("exception.original_error", e.to_string());
            let http_err = common::server::handle_anyhow_err_as_http_err(e.into());
            root_span.record("http.response.status_code", http_err.status_code.as_u16());
            Err(http_err.into())
        }
    }
}

mod zoo_endpoint_handler_xyz {
    use super::*;
    #[doc = r#" handle "xyz" requests "#]
    async fn handler_xyz(_rqctx: Arc<Context>) -> Result<()> {
        Ok(())
    }
}