1
1
//! Implementation for the Spin HTTP engine.
2
2
3
3
mod handler;
4
+ mod instrument;
4
5
mod tls;
5
6
mod wagi;
6
7
@@ -25,6 +26,7 @@ use hyper::{
25
26
Request , Response ,
26
27
} ;
27
28
use hyper_util:: rt:: tokio:: TokioIo ;
29
+ use instrument:: { finalize_http_span, http_span} ;
28
30
use spin_app:: { AppComponent , APP_DESCRIPTION_KEY } ;
29
31
use spin_core:: { Engine , OutboundWasiHttpHandler } ;
30
32
use spin_http:: {
@@ -42,10 +44,17 @@ use tokio::{
42
44
net:: TcpListener ,
43
45
task,
44
46
} ;
45
- use tracing:: { log, Instrument } ;
46
- use wasmtime_wasi_http:: { body:: HyperIncomingBody as Body , WasiHttpView } ;
47
+ use tracing:: { field:: Empty , log, Instrument } ;
48
+ use wasmtime_wasi_http:: {
49
+ body:: { HyperIncomingBody as Body , HyperOutgoingBody } ,
50
+ WasiHttpView ,
51
+ } ;
47
52
48
- use crate :: { handler:: HttpHandlerExecutor , wagi:: WagiHttpExecutor } ;
53
+ use crate :: {
54
+ handler:: HttpHandlerExecutor ,
55
+ instrument:: { instrument_error, MatchedRoute } ,
56
+ wagi:: WagiHttpExecutor ,
57
+ } ;
49
58
50
59
pub use tls:: TlsConfig ;
51
60
@@ -240,19 +249,22 @@ impl HttpTrigger {
240
249
req. uri( )
241
250
) ;
242
251
243
- let path = req. uri ( ) . path ( ) ;
252
+ let path = req. uri ( ) . path ( ) . to_string ( ) ;
244
253
245
254
// Handle well-known spin paths
246
255
if let Some ( well_known) = path. strip_prefix ( spin_http:: WELL_KNOWN_PREFIX ) {
247
256
return match well_known {
248
- "health" => Ok ( Response :: new ( body:: full ( Bytes :: from_static ( b"OK" ) ) ) ) ,
249
- "info" => self . app_info ( ) ,
257
+ "health" => Ok ( MatchedRoute :: with_response_extension (
258
+ Response :: new ( body:: full ( Bytes :: from_static ( b"OK" ) ) ) ,
259
+ path,
260
+ ) ) ,
261
+ "info" => self . app_info ( path) ,
250
262
_ => Self :: not_found ( NotFoundRouteKind :: WellKnown ) ,
251
263
} ;
252
264
}
253
265
254
266
// Route to app component
255
- match self . router . route ( path) {
267
+ match self . router . route ( & path) {
256
268
Ok ( component_id) => {
257
269
let trigger = self . component_trigger_configs . get ( component_id) . unwrap ( ) ;
258
270
@@ -293,10 +305,14 @@ impl HttpTrigger {
293
305
}
294
306
} ;
295
307
match res {
296
- Ok ( res) => Ok ( res) ,
308
+ Ok ( res) => Ok ( MatchedRoute :: with_response_extension (
309
+ res,
310
+ raw_route. to_string ( ) ,
311
+ ) ) ,
297
312
Err ( e) => {
298
313
log:: error!( "Error processing request: {:?}" , e) ;
299
- Self :: internal_error ( None )
314
+ instrument_error ( & e) ;
315
+ Self :: internal_error ( None , raw_route. to_string ( ) )
300
316
}
301
317
}
302
318
}
@@ -305,24 +321,30 @@ impl HttpTrigger {
305
321
}
306
322
307
323
/// Returns spin status information.
308
- fn app_info ( & self ) -> Result < Response < Body > > {
324
+ fn app_info ( & self , route : String ) -> Result < Response < Body > > {
309
325
let info = AppInfo :: new ( self . engine . app ( ) ) ;
310
326
let body = serde_json:: to_vec_pretty ( & info) ?;
311
- Ok ( Response :: builder ( )
312
- . header ( "content-type" , "application/json" )
313
- . body ( body:: full ( body. into ( ) ) ) ?)
327
+ Ok ( MatchedRoute :: with_response_extension (
328
+ Response :: builder ( )
329
+ . header ( "content-type" , "application/json" )
330
+ . body ( body:: full ( body. into ( ) ) ) ?,
331
+ route,
332
+ ) )
314
333
}
315
334
316
335
/// Creates an HTTP 500 response.
317
- fn internal_error ( body : Option < & str > ) -> Result < Response < Body > > {
336
+ fn internal_error ( body : Option < & str > , route : String ) -> Result < Response < Body > > {
318
337
let body = match body {
319
338
Some ( body) => body:: full ( Bytes :: copy_from_slice ( body. as_bytes ( ) ) ) ,
320
339
None => body:: empty ( ) ,
321
340
} ;
322
341
323
- Ok ( Response :: builder ( )
324
- . status ( StatusCode :: INTERNAL_SERVER_ERROR )
325
- . body ( body) ?)
342
+ Ok ( MatchedRoute :: with_response_extension (
343
+ Response :: builder ( )
344
+ . status ( StatusCode :: INTERNAL_SERVER_ERROR )
345
+ . body ( body) ?,
346
+ route,
347
+ ) )
326
348
}
327
349
328
350
/// Creates an HTTP 404 response.
@@ -351,38 +373,7 @@ impl HttpTrigger {
351
373
. keep_alive ( true )
352
374
. serve_connection (
353
375
TokioIo :: new ( stream) ,
354
- service_fn ( move |request| {
355
- let self_ = self_. clone ( ) ;
356
- let span = tracing:: info_span!(
357
- "handle_http_request" ,
358
- "otel.kind" = "server" ,
359
- "http.request.method" = %request. method( ) ,
360
- "network.peer.address" = %addr. ip( ) ,
361
- "network.peer.port" = %addr. port( ) ,
362
- "network.protocol.name" = "http" ,
363
- "url.path" = request. uri( ) . path( ) ,
364
- "url.query" = request. uri( ) . query( ) . unwrap_or( "" ) ,
365
- "url.scheme" = request. uri( ) . scheme_str( ) . unwrap_or( "" ) ,
366
- "client.address" = request. headers( ) . get( "x-forwarded-for" ) . and_then( |val| val. to_str( ) . ok( ) ) ,
367
- // TODO(Caleb): Recorded later
368
- // "error.type" = Empty,
369
- // "http.response.status_code" = Empty,
370
- // "http.route" = Empty,
371
- ) ;
372
- async move {
373
- self_
374
- . handle (
375
- request. map ( |body : Incoming | {
376
- body. map_err ( wasmtime_wasi_http:: hyper_response_error)
377
- . boxed ( )
378
- } ) ,
379
- Scheme :: HTTP ,
380
- addr,
381
- )
382
- . instrument ( span)
383
- . await
384
- }
385
- } ) ,
376
+ service_fn ( move |request| self_. clone ( ) . instrumented_service_fn ( addr, request) ) ,
386
377
)
387
378
. await
388
379
{
@@ -391,6 +382,30 @@ impl HttpTrigger {
391
382
} ) ;
392
383
}
393
384
385
+ async fn instrumented_service_fn (
386
+ self : Arc < Self > ,
387
+ addr : SocketAddr ,
388
+ request : Request < Incoming > ,
389
+ ) -> Result < Response < HyperOutgoingBody > > {
390
+ let span = http_span ! ( request, addr) ;
391
+ let method = request. method ( ) . to_string ( ) ;
392
+ async {
393
+ let result = self
394
+ . handle (
395
+ request. map ( |body : Incoming | {
396
+ body. map_err ( wasmtime_wasi_http:: hyper_response_error)
397
+ . boxed ( )
398
+ } ) ,
399
+ Scheme :: HTTP ,
400
+ addr,
401
+ )
402
+ . await ;
403
+ finalize_http_span ( result, method)
404
+ }
405
+ . instrument ( span)
406
+ . await
407
+ }
408
+
394
409
async fn serve ( self , listen_addr : SocketAddr ) -> Result < ( ) > {
395
410
let self_ = Arc :: new ( self ) ;
396
411
0 commit comments