@@ -56,9 +56,8 @@ async fn main() -> Result<(), String> {
56
56
57
57
// For simplicity, we'll configure an "info"-level logger that writes to
58
58
// stderr assuming that it's a terminal.
59
- let config_logging = ConfigLogging :: StderrTerminal {
60
- level : ConfigLoggingLevel :: Info ,
61
- } ;
59
+ let config_logging =
60
+ ConfigLogging :: StderrTerminal { level : ConfigLoggingLevel :: Info } ;
62
61
let log = config_logging
63
62
. to_logger ( "example-basic" )
64
63
. map_err ( |error| format ! ( "failed to create logger: {}" , error) ) ?;
@@ -68,14 +67,16 @@ async fn main() -> Result<(), String> {
68
67
api. register ( example_api_get_counter) . unwrap ( ) ;
69
68
api. register ( example_api_put_counter) . unwrap ( ) ;
70
69
api. register ( example_api_get) . unwrap ( ) ;
70
+ api. register ( example_api_error) . unwrap ( ) ;
71
71
72
72
// The functions that implement our API endpoints will share this context.
73
73
let api_context = ExampleContext :: new ( ) ;
74
74
75
75
// Set up the server.
76
- let server = HttpServerStarter :: new ( & config_dropshot, api, api_context, & log)
77
- . map_err ( |error| format ! ( "failed to create server: {}" , error) ) ?
78
- . start ( ) ;
76
+ let server =
77
+ HttpServerStarter :: new ( & config_dropshot, api, api_context, & log)
78
+ . map_err ( |error| format ! ( "failed to create server: {}" , error) ) ?
79
+ . start ( ) ;
79
80
80
81
// Wait for the server to stop. Note that there's not any code to shut down
81
82
// this server, so we should never get past this point.
@@ -93,9 +94,7 @@ struct ExampleContext {
93
94
impl ExampleContext {
94
95
/// Return a new ExampleContext.
95
96
pub fn new ( ) -> ExampleContext {
96
- ExampleContext {
97
- counter : AtomicU64 :: new ( 0 ) ,
98
- }
97
+ ExampleContext { counter : AtomicU64 :: new ( 0 ) }
99
98
}
100
99
}
101
100
@@ -109,7 +108,26 @@ struct CounterValue {
109
108
counter : u64 ,
110
109
}
111
110
112
- /// Fetch the current value of the counter.
111
+ /// Helper function for propagating a traceparent using hyper
112
+ async fn traced_request (
113
+ uri : & str ,
114
+ cx : & Context ,
115
+ ) -> hyper:: Request < Full < Bytes > > {
116
+ let mut req = hyper:: Request :: builder ( )
117
+ . uri ( uri)
118
+ . method ( hyper:: Method :: GET )
119
+ . header ( "accept" , "application/json" )
120
+ . header ( "content-type" , "application/json" ) ;
121
+ global:: get_text_map_propagator ( |propagator| {
122
+ propagator. inject_context (
123
+ & cx,
124
+ & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) ,
125
+ )
126
+ } ) ;
127
+ req. body ( Full :: new ( Bytes :: from ( "" . to_string ( ) ) ) ) . unwrap ( )
128
+ }
129
+
130
+ /// Do a bunch of work to show off otel tracing
113
131
#[ endpoint {
114
132
method = GET ,
115
133
path = "/get" ,
@@ -119,10 +137,11 @@ async fn example_api_get(
119
137
rqctx : RequestContext < ExampleContext > ,
120
138
) -> Result < HttpResponseOk < CounterValue > , HttpError > {
121
139
let trace_context = opentelemetry:: Context :: new ( ) ;
122
- let parent_context = opentelemetry:: trace:: TraceContextExt :: with_remote_span_context (
123
- & trace_context,
124
- rqctx. span_context . clone ( ) ,
125
- ) ;
140
+ let parent_context =
141
+ opentelemetry:: trace:: TraceContextExt :: with_remote_span_context (
142
+ & trace_context,
143
+ rqctx. span_context . clone ( ) ,
144
+ ) ;
126
145
127
146
let client = Client :: builder ( TokioExecutor :: new ( ) ) . build_http ( ) ;
128
147
let tracer = global:: tracer ( "" ) ;
@@ -139,25 +158,48 @@ async fn example_api_get(
139
158
. header ( "accept" , "application/json" )
140
159
. header ( "content-type" , "application/json" ) ;
141
160
global:: get_text_map_propagator ( |propagator| {
142
- propagator. inject_context ( & cx, & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) )
161
+ propagator. inject_context (
162
+ & cx,
163
+ & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) ,
164
+ )
143
165
} ) ;
144
166
let _res = client
145
167
. request ( req. body ( Full :: new ( Bytes :: from ( "" . to_string ( ) ) ) ) . unwrap ( ) )
146
- . await
147
- . unwrap ( ) ;
168
+ . await ;
148
169
149
170
let mut req = hyper:: Request :: builder ( )
150
171
. uri ( "http://localhost:4000/counter" )
151
172
. method ( hyper:: Method :: GET )
152
173
. header ( "accept" , "application/json" )
153
174
. header ( "content-type" , "application/json" ) ;
154
175
global:: get_text_map_propagator ( |propagator| {
155
- propagator. inject_context ( & cx, & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) )
176
+ propagator. inject_context (
177
+ & cx,
178
+ & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) ,
179
+ )
156
180
} ) ;
157
181
let _res = client
158
182
. request ( req. body ( Full :: new ( Bytes :: from ( "" . to_string ( ) ) ) ) . unwrap ( ) )
159
- . await
160
- . unwrap ( ) ;
183
+ . await ;
184
+
185
+ let mut req = hyper:: Request :: builder ( )
186
+ . uri ( "http://localhost:4000/does-not-exist" )
187
+ . method ( hyper:: Method :: GET )
188
+ . header ( "accept" , "application/json" )
189
+ . header ( "content-type" , "application/json" )
190
+ . header ( "user-agent" , "dropshot-otel-example" ) ;
191
+ global:: get_text_map_propagator ( |propagator| {
192
+ propagator. inject_context (
193
+ & cx,
194
+ & mut HeaderInjector ( req. headers_mut ( ) . unwrap ( ) ) ,
195
+ )
196
+ } ) ;
197
+ let _res = client
198
+ . request ( req. body ( Full :: new ( Bytes :: from ( "" . to_string ( ) ) ) ) . unwrap ( ) )
199
+ . await ;
200
+
201
+ let req = traced_request ( "http://localhost:4000/error" , & cx) . await ;
202
+ let _res = client. request ( req) . await ;
161
203
162
204
let api_context = rqctx. context ( ) ;
163
205
Ok ( HttpResponseOk ( CounterValue {
@@ -180,6 +222,18 @@ async fn example_api_get_counter(
180
222
} ) )
181
223
}
182
224
225
+ /// Cause an error!
226
+ #[ endpoint {
227
+ method = GET ,
228
+ path = "/error" ,
229
+ } ]
230
+ async fn example_api_error (
231
+ _rqctx : RequestContext < ExampleContext > ,
232
+ ) -> Result < HttpResponseOk < CounterValue > , HttpError > {
233
+ //XXX Why does this create a 499 rather than a 500 error???
234
+ panic ! ( "This handler is totally broken!" ) ;
235
+ }
236
+
183
237
/// Update the current value of the counter. Note that the special value of 10
184
238
/// is not allowed (just to demonstrate how to generate an error).
185
239
#[ endpoint {
@@ -200,9 +254,7 @@ async fn example_api_put_counter(
200
254
format ! ( "do not like the number {}" , updated_value. counter) ,
201
255
) )
202
256
} else {
203
- api_context
204
- . counter
205
- . store ( updated_value. counter , Ordering :: SeqCst ) ;
257
+ api_context. counter . store ( updated_value. counter , Ordering :: SeqCst ) ;
206
258
Ok ( HttpResponseUpdatedNoContent ( ) )
207
259
}
208
260
}
0 commit comments