@@ -2,10 +2,11 @@ use super::{Cas, SwapError};
2
2
use anyhow:: { Context , Result } ;
3
3
use spin_core:: { async_trait, wasmtime:: component:: Resource } ;
4
4
use spin_resource_table:: Table ;
5
+ use spin_telemetry:: traces:: { self , Blame } ;
5
6
use spin_world:: v2:: key_value;
6
7
use spin_world:: wasi:: keyvalue as wasi_keyvalue;
7
8
use std:: { collections:: HashSet , sync:: Arc } ;
8
- use tracing:: { instrument, Level } ;
9
+ use tracing:: instrument;
9
10
10
11
const DEFAULT_STORE_TABLE_CAPACITY : u32 = 256 ;
11
12
@@ -69,7 +70,11 @@ impl KeyValueDispatch {
69
70
}
70
71
71
72
pub fn get_store < T : ' static > ( & self , store : Resource < T > ) -> anyhow:: Result < & Arc < dyn Store > > {
72
- self . stores . get ( store. rep ( ) ) . context ( "invalid store" )
73
+ let res = self . stores . get ( store. rep ( ) ) . context ( "invalid store" ) ;
74
+ if let Err ( err) = & res {
75
+ traces:: mark_as_error ( err, Some ( Blame :: Host ) ) ;
76
+ }
77
+ res
73
78
}
74
79
75
80
pub fn get_cas < T : ' static > ( & self , cas : Resource < T > ) -> Result < & Arc < dyn Cas > > {
@@ -106,7 +111,7 @@ impl KeyValueDispatch {
106
111
impl key_value:: Host for KeyValueDispatch { }
107
112
108
113
impl key_value:: HostStore for KeyValueDispatch {
109
- #[ instrument( name = "spin_key_value.open" , skip( self ) , err( level = Level :: INFO ) , fields( otel. kind = "client" , kv. backend=self . manager. summary( & name) . unwrap_or( "unknown" . to_string( ) ) ) ) ]
114
+ #[ instrument( name = "spin_key_value.open" , skip( self ) , err, fields( otel. kind = "client" , kv. backend=self . manager. summary( & name) . unwrap_or( "unknown" . to_string( ) ) ) ) ]
110
115
async fn open ( & mut self , name : String ) -> Result < Result < Resource < key_value:: Store > , Error > > {
111
116
Ok ( async {
112
117
if self . allowed_stores . contains ( & name) {
@@ -124,54 +129,54 @@ impl key_value::HostStore for KeyValueDispatch {
124
129
. await )
125
130
}
126
131
127
- #[ instrument( name = "spin_key_value.get" , skip ( self , store , key ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
132
+ #[ instrument( name = "spin_key_value.get" , skip_all , fields( otel. kind = "client" ) ) ]
128
133
async fn get (
129
134
& mut self ,
130
135
store : Resource < key_value:: Store > ,
131
136
key : String ,
132
137
) -> Result < Result < Option < Vec < u8 > > , Error > > {
133
138
let store = self . get_store ( store) ?;
134
- Ok ( store. get ( & key) . await )
139
+ Ok ( store. get ( & key) . await . map_err ( track_error_on_span ) )
135
140
}
136
141
137
- #[ instrument( name = "spin_key_value.set" , skip ( self , store , key , value ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
142
+ #[ instrument( name = "spin_key_value.set" , skip_all , fields( otel. kind = "client" ) ) ]
138
143
async fn set (
139
144
& mut self ,
140
145
store : Resource < key_value:: Store > ,
141
146
key : String ,
142
147
value : Vec < u8 > ,
143
148
) -> Result < Result < ( ) , Error > > {
144
149
let store = self . get_store ( store) ?;
145
- Ok ( store. set ( & key, & value) . await )
150
+ Ok ( store. set ( & key, & value) . await . map_err ( track_error_on_span ) )
146
151
}
147
152
148
- #[ instrument( name = "spin_key_value.delete" , skip ( self , store , key ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
153
+ #[ instrument( name = "spin_key_value.delete" , skip_all , fields( otel. kind = "client" ) ) ]
149
154
async fn delete (
150
155
& mut self ,
151
156
store : Resource < key_value:: Store > ,
152
157
key : String ,
153
158
) -> Result < Result < ( ) , Error > > {
154
159
let store = self . get_store ( store) ?;
155
- Ok ( store. delete ( & key) . await )
160
+ Ok ( store. delete ( & key) . await . map_err ( track_error_on_span ) )
156
161
}
157
162
158
- #[ instrument( name = "spin_key_value.exists" , skip ( self , store , key ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
163
+ #[ instrument( name = "spin_key_value.exists" , skip_all , fields( otel. kind = "client" ) ) ]
159
164
async fn exists (
160
165
& mut self ,
161
166
store : Resource < key_value:: Store > ,
162
167
key : String ,
163
168
) -> Result < Result < bool , Error > > {
164
169
let store = self . get_store ( store) ?;
165
- Ok ( store. exists ( & key) . await )
170
+ Ok ( store. exists ( & key) . await . map_err ( track_error_on_span ) )
166
171
}
167
172
168
- #[ instrument( name = "spin_key_value.get_keys" , skip ( self , store ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
173
+ #[ instrument( name = "spin_key_value.get_keys" , skip_all , fields( otel. kind = "client" ) ) ]
169
174
async fn get_keys (
170
175
& mut self ,
171
176
store : Resource < key_value:: Store > ,
172
177
) -> Result < Result < Vec < String > , Error > > {
173
178
let store = self . get_store ( store) ?;
174
- Ok ( store. get_keys ( ) . await )
179
+ Ok ( store. get_keys ( ) . await . map_err ( track_error_on_span ) )
175
180
}
176
181
177
182
async fn drop ( & mut self , store : Resource < key_value:: Store > ) -> Result < ( ) > {
@@ -180,8 +185,18 @@ impl key_value::HostStore for KeyValueDispatch {
180
185
}
181
186
}
182
187
188
+ /// Make sure that infrastructure related errors are tracked in the current span.
189
+ fn track_error_on_span ( err : Error ) -> Error {
190
+ let blame = match err {
191
+ Error :: NoSuchStore | Error :: AccessDenied => Blame :: Guest ,
192
+ Error :: StoreTableFull | Error :: Other ( _) => Blame :: Host ,
193
+ } ;
194
+ traces:: mark_as_error ( & err, Some ( blame) ) ;
195
+ err
196
+ }
197
+
183
198
fn to_wasi_err ( e : Error ) -> wasi_keyvalue:: store:: Error {
184
- match e {
199
+ match track_error_on_span ( e ) {
185
200
Error :: AccessDenied => wasi_keyvalue:: store:: Error :: AccessDenied ,
186
201
Error :: NoSuchStore => wasi_keyvalue:: store:: Error :: NoSuchStore ,
187
202
Error :: StoreTableFull => wasi_keyvalue:: store:: Error :: Other ( "store table full" . to_string ( ) ) ,
@@ -190,6 +205,7 @@ fn to_wasi_err(e: Error) -> wasi_keyvalue::store::Error {
190
205
}
191
206
192
207
impl wasi_keyvalue:: store:: Host for KeyValueDispatch {
208
+ #[ instrument( name = "wasi_key_value.open" , skip_all, fields( otel. kind = "client" ) ) ]
193
209
async fn open (
194
210
& mut self ,
195
211
identifier : String ,
@@ -217,6 +233,7 @@ impl wasi_keyvalue::store::Host for KeyValueDispatch {
217
233
218
234
use wasi_keyvalue:: store:: Bucket ;
219
235
impl wasi_keyvalue:: store:: HostBucket for KeyValueDispatch {
236
+ #[ instrument( name = "wasi_key_value.get" , skip_all, fields( otel. kind = "client" ) ) ]
220
237
async fn get (
221
238
& mut self ,
222
239
self_ : Resource < Bucket > ,
@@ -226,6 +243,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
226
243
store. get ( & key) . await . map_err ( to_wasi_err)
227
244
}
228
245
246
+ #[ instrument( name = "wasi_key_value.set" , skip_all, fields( otel. kind = "client" ) ) ]
229
247
async fn set (
230
248
& mut self ,
231
249
self_ : Resource < Bucket > ,
@@ -236,6 +254,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
236
254
store. set ( & key, & value) . await . map_err ( to_wasi_err)
237
255
}
238
256
257
+ #[ instrument( name = "wasi_key_value.delete" , skip_all, fields( otel. kind = "client" ) ) ]
239
258
async fn delete (
240
259
& mut self ,
241
260
self_ : Resource < Bucket > ,
@@ -245,6 +264,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
245
264
store. delete ( & key) . await . map_err ( to_wasi_err)
246
265
}
247
266
267
+ #[ instrument( name = "wasi_key_value.exists" , skip_all, fields( otel. kind = "client" ) ) ]
248
268
async fn exists (
249
269
& mut self ,
250
270
self_ : Resource < Bucket > ,
@@ -254,6 +274,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
254
274
store. exists ( & key) . await . map_err ( to_wasi_err)
255
275
}
256
276
277
+ #[ instrument( name = "wasi_key_value.list_keys" , skip_all, fields( otel. kind = "client" ) ) ]
257
278
async fn list_keys (
258
279
& mut self ,
259
280
self_ : Resource < Bucket > ,
@@ -278,7 +299,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
278
299
}
279
300
280
301
impl wasi_keyvalue:: batch:: Host for KeyValueDispatch {
281
- #[ instrument( name = "spin_key_value.get_many" , skip ( self , bucket , keys ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
302
+ #[ instrument( name = "spin_key_value.get_many" , skip_all , fields( otel. kind = "client" ) ) ]
282
303
#[ allow( clippy:: type_complexity) ]
283
304
async fn get_many (
284
305
& mut self ,
@@ -292,7 +313,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
292
313
store. get_many ( keys) . await . map_err ( to_wasi_err)
293
314
}
294
315
295
- #[ instrument( name = "spin_key_value.set_many" , skip ( self , bucket , key_values ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
316
+ #[ instrument( name = "spin_key_value.set_many" , skip_all , fields( otel. kind = "client" ) ) ]
296
317
async fn set_many (
297
318
& mut self ,
298
319
bucket : Resource < wasi_keyvalue:: batch:: Bucket > ,
@@ -305,7 +326,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
305
326
store. set_many ( key_values) . await . map_err ( to_wasi_err)
306
327
}
307
328
308
- #[ instrument( name = "spin_key_value.delete_many" , skip ( self , bucket , keys ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
329
+ #[ instrument( name = "spin_key_value.delete_many" , skip_all , fields( otel. kind = "client" ) ) ]
309
330
async fn delete_many (
310
331
& mut self ,
311
332
bucket : Resource < wasi_keyvalue:: batch:: Bucket > ,
@@ -320,6 +341,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
320
341
}
321
342
322
343
impl wasi_keyvalue:: atomics:: HostCas for KeyValueDispatch {
344
+ #[ instrument( name = "wasi_key_value_cas.new" , skip_all, fields( otel. kind = "client" ) ) ]
323
345
async fn new (
324
346
& mut self ,
325
347
bucket : Resource < wasi_keyvalue:: atomics:: Bucket > ,
@@ -342,6 +364,7 @@ impl wasi_keyvalue::atomics::HostCas for KeyValueDispatch {
342
364
. map ( Resource :: new_own)
343
365
}
344
366
367
+ #[ instrument( name = "wasi_key_value_cas.current" , skip_all, fields( otel. kind = "client" ) ) ]
345
368
async fn current (
346
369
& mut self ,
347
370
cas : Resource < wasi_keyvalue:: atomics:: Cas > ,
@@ -366,7 +389,7 @@ impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
366
389
Ok ( error)
367
390
}
368
391
369
- #[ instrument( name = "spin_key_value.increment" , skip ( self , bucket , key , delta ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
392
+ #[ instrument( name = "spin_key_value.increment" , skip_all , fields( otel. kind = "client" ) ) ]
370
393
async fn increment (
371
394
& mut self ,
372
395
bucket : Resource < wasi_keyvalue:: atomics:: Bucket > ,
@@ -377,7 +400,7 @@ impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
377
400
store. increment ( key, delta) . await . map_err ( to_wasi_err)
378
401
}
379
402
380
- #[ instrument( name = "spin_key_value.swap" , skip ( self , cas_res , value ) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
403
+ #[ instrument( name = "spin_key_value.swap" , skip_all , fields( otel. kind = "client" ) ) ]
381
404
async fn swap (
382
405
& mut self ,
383
406
cas_res : Resource < atomics:: Cas > ,
@@ -424,8 +447,8 @@ use spin_world::v1::key_value::Error as LegacyError;
424
447
use spin_world:: wasi:: keyvalue:: atomics;
425
448
use spin_world:: wasi:: keyvalue:: atomics:: { CasError , HostCas } ;
426
449
427
- fn to_legacy_error ( value : key_value :: Error ) -> LegacyError {
428
- match value {
450
+ fn to_legacy_error ( err : Error ) -> LegacyError {
451
+ match err {
429
452
Error :: StoreTableFull => LegacyError :: StoreTableFull ,
430
453
Error :: NoSuchStore => LegacyError :: NoSuchStore ,
431
454
Error :: AccessDenied => LegacyError :: AccessDenied ,
0 commit comments