11// Copyright 2024 Oxide Computer Company
22//! Opentelemetry tracing support
33//!
4+ // XXX Not sure if we want to just mimic reqwest-tracing
5+ // or not...
46//! Fields that we want to produce to provide comparable
5- //! functionality to reqwest-tracing[1 ]:
7+ //! functionality to [ reqwest-tracing]:
68//!
7- //! - http.request.method
8- //! - url.scheme
9- //! - server.address
10- //! - server.port
11- //! - otel.kind
12- //! - otel.name
13- //! - otel.status_code
14- //! - user_agent.original
15- //! - http.response.status_code
16- //! - error.message
17- //! - error.cause_chain
9+ //! - [ ] error.cause_chain
10+ //! - [ ] error.message
11+ //! - [x] http.request.method
12+ //! - [x] http.response.status_code
13+ //! - [x] otel.kind (showing up as span.kind?)
14+ //! - [x] otel.name
15+ //! - [ ] otel.status_code (needs investigation)
16+ //! - [x] server.address
17+ //! - [x] server.port
18+ //! - [ ] url.scheme
19+ //! - [x] user_agent.original
1820//!
19- //! [1] <https://docs.rs/reqwest-tracing/0.5.4/reqwest_tracing/macro.reqwest_otel_span.html>
21+ //! Where possible we use the [opentelemetry-semantic-conventions] crate for naming.
22+ //!
23+ //! [reqwest-tracing]: https://docs.rs/reqwest-tracing/0.5.4/reqwest_tracing/macro.reqwest_otel_span.html
24+ //! [opentelemetry-semantic-conventions]:
25+ //! <https://docs.rs/opentelemetry-semantic-conventions/latest/opentelemetry_semantic_conventions/trace/index.html>
2026
2127use opentelemetry:: {
2228 global, trace:: Span , trace:: Tracer , trace:: TracerProvider ,
2329} ;
2430use opentelemetry_http:: HeaderExtractor ;
2531use opentelemetry_semantic_conventions:: trace;
2632
27- // - url.scheme
28- // - server.address
29- // - server.port
30- // - user_agent.original
3133#[ derive( Debug , Clone , serde:: Serialize ) ]
3234pub ( crate ) struct RequestInfo {
3335 pub id : String ,
@@ -39,16 +41,14 @@ pub(crate) struct RequestInfo {
3941 pub user_agent : String ,
4042}
4143
42- // - http.response.status_code
43- // - error.message
44- // - error.cause_chain
45- // - otel.status_code
4644pub ( crate ) struct ResponseInfo < ' a > {
4745 pub status_code : u16 ,
4846 pub message : String ,
4947 pub error : Option < & ' a crate :: handler:: HandlerError > ,
5048}
5149
50+ /// Generate an opentelementry Context based on the headers
51+ /// in the incoming hyper request.
5252fn extract_context_from_request (
5353 request : & hyper:: Request < hyper:: body:: Incoming > ,
5454) -> opentelemetry:: Context {
@@ -57,6 +57,7 @@ fn extract_context_from_request(
5757 } )
5858}
5959
60+ /// Create an opentelemetry Span to represent the handling of the incoming request.
6061pub fn create_request_span (
6162 request : & hyper:: Request < hyper:: body:: Incoming > ,
6263) -> opentelemetry:: global:: BoxedSpan {
@@ -74,8 +75,14 @@ pub fn create_request_span(
7475 . start_with_context ( & tracer, & parent_cx)
7576}
7677
78+ /// This trait contains all functionality needed for dropshot to annotate
79+ /// opentelemetry spans with information about a request and the corresponding response.
7780pub trait TraceDropshot {
81+ /// Attach attributes to the span based on the provided
82+ /// RequestInfo
7883 fn trace_request ( & mut self , request : RequestInfo ) ;
84+ /// Attach the information from the ResponseInfo to the span
85+ /// including marking the span as an error if an error occurred.
7986 fn trace_response ( & mut self , response : ResponseInfo ) ;
8087}
8188
@@ -84,30 +91,28 @@ impl TraceDropshot for opentelemetry::global::BoxedSpan {
8491 self . set_attributes ( vec ! [
8592 // Rename to dropshot.id ????
8693 opentelemetry:: KeyValue :: new( "http.id" . to_string( ) , request. id) ,
94+ opentelemetry:: KeyValue :: new( trace:: URL_PATH , request. path) ,
8795 opentelemetry:: KeyValue :: new(
88- "http.method" . to_string ( ) ,
96+ trace :: HTTP_REQUEST_METHOD ,
8997 request. method,
9098 ) ,
91- opentelemetry:: KeyValue :: new( "http.path" . to_string( ) , request. path) ,
9299 opentelemetry:: KeyValue :: new(
93- "server.address" . to_string ( ) ,
100+ trace :: SERVER_ADDRESS ,
94101 request. local_addr. ip( ) . to_string( ) ,
95102 ) ,
96103 opentelemetry:: KeyValue :: new(
97- "server.port" . to_string ( ) ,
104+ trace :: SERVER_PORT ,
98105 request. local_addr. port( ) . to_string( ) ,
99106 ) ,
100107 opentelemetry:: KeyValue :: new(
101- "user_agent.original" . to_string ( ) ,
108+ trace :: USER_AGENT_ORIGINAL ,
102109 request. user_agent,
103110 ) ,
104111 ] ) ;
105112 }
106113
107- // - [x] http.response.status_code
108- // - [x] error.message
109- // - [ ] error.cause_chain
110- // - [ ] otel.status_code
114+ /// TODO: Do we want to differentiate between 4xx vs 5xx errors
115+ /// and not mark 4xx spans as error spans?
111116 fn trace_response ( & mut self , response : ResponseInfo ) {
112117 self . set_attributes ( vec ! [
113118 opentelemetry:: KeyValue :: new(
0 commit comments