@@ -2,17 +2,22 @@ use http_body_util::{combinators::BoxBody, BodyExt, Full};
22use hyper:: { body:: Incoming , service:: service_fn, Request , Response , StatusCode } ;
33use hyper_util:: rt:: { TokioExecutor , TokioIo } ;
44use opentelemetry:: {
5- global,
5+ global:: { self , BoxedTracer } ,
66 trace:: { FutureExt , Span , SpanKind , TraceContextExt , Tracer } ,
77 Context , KeyValue ,
88} ;
99use opentelemetry_http:: { Bytes , HeaderExtractor } ;
1010use opentelemetry_sdk:: { propagation:: TraceContextPropagator , trace:: SdkTracerProvider } ;
1111use opentelemetry_semantic_conventions:: trace;
1212use opentelemetry_stdout:: SpanExporter ;
13- use std:: { convert:: Infallible , net:: SocketAddr } ;
13+ use std:: { convert:: Infallible , net:: SocketAddr , sync :: OnceLock } ;
1414use tokio:: net:: TcpListener ;
1515
16+ fn get_tracer ( ) -> & ' static BoxedTracer {
17+ static TRACER : OnceLock < BoxedTracer > = OnceLock :: new ( ) ;
18+ TRACER . get_or_init ( || global:: tracer ( "example/server" ) )
19+ }
20+
1621// Utility function to extract the context from the incoming request headers
1722fn extract_context_from_request ( req : & Request < Incoming > ) -> Context {
1823 global:: get_text_map_propagator ( |propagator| {
@@ -24,11 +29,11 @@ fn extract_context_from_request(req: &Request<Incoming>) -> Context {
2429async fn handle_health_check (
2530 _req : Request < Incoming > ,
2631) -> Result < Response < BoxBody < Bytes , hyper:: Error > > , Infallible > {
27- let tracer = global :: tracer ( "example/server" ) ;
32+ let tracer = get_tracer ( ) ;
2833 let mut span = tracer
2934 . span_builder ( "health_check" )
3035 . with_kind ( SpanKind :: Internal )
31- . start ( & tracer) ;
36+ . start ( tracer) ;
3237 span. add_event ( "Health check accessed" , vec ! [ ] ) ;
3338
3439 let res = Response :: new (
@@ -44,11 +49,11 @@ async fn handle_health_check(
4449async fn handle_echo (
4550 req : Request < Incoming > ,
4651) -> Result < Response < BoxBody < Bytes , hyper:: Error > > , Infallible > {
47- let tracer = global :: tracer ( "example/server" ) ;
52+ let tracer = get_tracer ( ) ;
4853 let mut span = tracer
4954 . span_builder ( "echo" )
5055 . with_kind ( SpanKind :: Internal )
51- . start ( & tracer) ;
56+ . start ( tracer) ;
5257 span. add_event ( "Echoing back the request" , vec ! [ ] ) ;
5358
5459 let res = Response :: new ( req. into_body ( ) . boxed ( ) ) ;
@@ -63,11 +68,11 @@ async fn router(
6368 let parent_cx = extract_context_from_request ( & req) ;
6469 let response = {
6570 // Create a span parenting the remote client span.
66- let tracer = global :: tracer ( "example/server" ) ;
71+ let tracer = get_tracer ( ) ;
6772 let mut span = tracer
6873 . span_builder ( "router" )
6974 . with_kind ( SpanKind :: Server )
70- . start_with_context ( & tracer, & parent_cx) ;
75+ . start_with_context ( tracer, & parent_cx) ;
7176
7277 span. add_event ( "dispatching request" , vec ! [ ] ) ;
7378
@@ -88,7 +93,7 @@ async fn router(
8893 response
8994}
9095
91- fn init_tracer ( ) {
96+ fn init_tracer ( ) -> SdkTracerProvider {
9297 global:: set_text_map_propagator ( TraceContextPropagator :: new ( ) ) ;
9398
9499 // Setup tracerprovider with stdout exporter
@@ -97,14 +102,15 @@ fn init_tracer() {
97102 . with_simple_exporter ( SpanExporter :: default ( ) )
98103 . build ( ) ;
99104
100- global:: set_tracer_provider ( provider) ;
105+ global:: set_tracer_provider ( provider. clone ( ) ) ;
106+ provider
101107}
102108
103109#[ tokio:: main]
104110async fn main ( ) {
105111 use hyper_util:: server:: conn:: auto:: Builder ;
106112
107- init_tracer ( ) ;
113+ let provider = init_tracer ( ) ;
108114 let addr = SocketAddr :: from ( ( [ 127 , 0 , 0 , 1 ] , 3000 ) ) ;
109115 let listener = TcpListener :: bind ( addr) . await . unwrap ( ) ;
110116
@@ -116,4 +122,6 @@ async fn main() {
116122 eprintln ! ( "{err}" ) ;
117123 }
118124 }
125+
126+ provider. shutdown ( ) . expect ( "Shutdown provider failed" ) ;
119127}
0 commit comments