tracing_opentelemetry_instrumentation_sdk/http/
http_server.rs

1use std::error::Error;
2
3use crate::http::{http_flavor, http_host, url_scheme, user_agent};
4use crate::otel_trace_span;
5use crate::span_type::SpanType;
6use opentelemetry_semantic_conventions::attribute::OTEL_STATUS_CODE;
7use opentelemetry_semantic_conventions::trace::{EXCEPTION_MESSAGE, HTTP_RESPONSE_STATUS_CODE};
8use tracing::field::Empty;
9
10pub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {
11    // [semantic-conventions/.../http-spans.md](https://github.com/open-telemetry/semantic-conventions/blob/v1.25.0/docs/http/http-spans.md)
12    // [semantic-conventions/.../general/attributes.md](https://github.com/open-telemetry/semantic-conventions/blob/v1.25.0/docs/general/attributes.md)
13    // Can not use const or opentelemetry_semantic_conventions::trace::* for name of records
14    let http_method = req.method();
15    otel_trace_span!(
16        "HTTP request",
17        http.request.method = %http_method,
18        http.route = Empty, // to set by router of "webframework" after
19        network.protocol.version = %http_flavor(req.version()),
20        server.address = http_host(req),
21        // server.port = req.uri().port(),
22        http.client.address = Empty, //%$request.connection_info().realip_remote_addr().unwrap_or(""),
23        user_agent.original = user_agent(req),
24        http.response.status_code = Empty, // to set on response
25        url.path = req.uri().path(),
26        url.query = req.uri().query(),
27        url.scheme = url_scheme(req.uri()),
28        otel.name = %http_method, // to set by router of "webframework" after
29        otel.kind = ?opentelemetry::trace::SpanKind::Server,
30        otel.status_code = Empty, // to set on response
31        trace_id = Empty, // to set on response
32        request_id = Empty, // to set
33        exception.message = Empty, // to set on response
34        "span.type" = %SpanType::Web, // non-official open-telemetry key, only supported by Datadog
35    )
36}
37
38pub fn update_span_from_response<B>(span: &tracing::Span, response: &http::Response<B>) {
39    let status = response.status();
40    span.record(HTTP_RESPONSE_STATUS_CODE, status.as_u16());
41
42    if status.is_server_error() {
43        span.record(OTEL_STATUS_CODE, "ERROR");
44        // see [http-spans.md#status](https://github.com/open-telemetry/semantic-conventions/blob/v1.25.0/docs/http/http-spans.md#status)
45        // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
46        // unless there was another error (e.g., network error receiving the response body;
47        // or 3xx codes with max redirects exceeded), in which case status MUST be set to Error.
48        // } else {
49        //     span.record(OTEL_STATUS_CODE, "OK");
50    }
51}
52
53pub fn update_span_from_error<E>(span: &tracing::Span, error: &E)
54where
55    E: Error,
56{
57    span.record(OTEL_STATUS_CODE, "ERROR");
58    //span.record(HTTP_RESPONSE_STATUS_CODE, 500);
59    span.record(EXCEPTION_MESSAGE, error.to_string());
60    error
61        .source()
62        .map(|s| span.record(EXCEPTION_MESSAGE, s.to_string()));
63}
64
65pub fn update_span_from_response_or_error<B, E>(
66    span: &tracing::Span,
67    response: &Result<http::Response<B>, E>,
68) where
69    E: Error,
70{
71    match response {
72        Ok(response) => {
73            update_span_from_response(span, response);
74        }
75        Err(err) => {
76            update_span_from_error(span, err);
77        }
78    }
79}