@@ -2,10 +2,11 @@ use super::{Cas, SwapError};
22use anyhow:: { Context , Result } ;
33use spin_core:: { async_trait, wasmtime:: component:: Resource } ;
44use spin_resource_table:: Table ;
5+ use spin_telemetry:: OpenTelemetrySpanExt as _;
56use spin_world:: v2:: key_value;
67use spin_world:: wasi:: keyvalue as wasi_keyvalue;
78use std:: { collections:: HashSet , sync:: Arc } ;
8- use tracing:: { instrument, Level } ;
9+ use tracing:: instrument;
910
1011const DEFAULT_STORE_TABLE_CAPACITY : u32 = 256 ;
1112
@@ -69,7 +70,14 @@ impl KeyValueDispatch {
6970 }
7071
7172 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+ let current_span = tracing:: Span :: current ( ) ;
76+ current_span. set_status ( spin_telemetry:: opentelemetry:: trace:: Status :: error (
77+ err. to_string ( ) ,
78+ ) ) ;
79+ }
80+ res
7381 }
7482
7583 pub fn get_cas < T : ' static > ( & self , cas : Resource < T > ) -> Result < & Arc < dyn Cas > > {
@@ -106,7 +114,7 @@ impl KeyValueDispatch {
106114impl key_value:: Host for KeyValueDispatch { }
107115
108116impl 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( ) ) ) ) ]
117+ #[ instrument( name = "spin_key_value.open" , skip( self ) , err, fields( otel. kind = "client" , kv. backend=self . manager. summary( & name) . unwrap_or( "unknown" . to_string( ) ) ) ) ]
110118 async fn open ( & mut self , name : String ) -> Result < Result < Resource < key_value:: Store > , Error > > {
111119 Ok ( async {
112120 if self . allowed_stores . contains ( & name) {
@@ -124,54 +132,54 @@ impl key_value::HostStore for KeyValueDispatch {
124132 . await )
125133 }
126134
127- #[ instrument( name = "spin_key_value.get" , skip( self , store, key) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
135+ #[ instrument( name = "spin_key_value.get" , skip( self , store, key) , fields( otel. kind = "client" ) ) ]
128136 async fn get (
129137 & mut self ,
130138 store : Resource < key_value:: Store > ,
131139 key : String ,
132140 ) -> Result < Result < Option < Vec < u8 > > , Error > > {
133141 let store = self . get_store ( store) ?;
134- Ok ( store. get ( & key) . await )
142+ Ok ( store. get ( & key) . await . map_err ( track_error_on_span ) )
135143 }
136144
137- #[ instrument( name = "spin_key_value.set" , skip( self , store, key, value) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
145+ #[ instrument( name = "spin_key_value.set" , skip( self , store, key, value) , fields( otel. kind = "client" ) ) ]
138146 async fn set (
139147 & mut self ,
140148 store : Resource < key_value:: Store > ,
141149 key : String ,
142150 value : Vec < u8 > ,
143151 ) -> Result < Result < ( ) , Error > > {
144152 let store = self . get_store ( store) ?;
145- Ok ( store. set ( & key, & value) . await )
153+ Ok ( store. set ( & key, & value) . await . map_err ( track_error_on_span ) )
146154 }
147155
148- #[ instrument( name = "spin_key_value.delete" , skip( self , store, key) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
156+ #[ instrument( name = "spin_key_value.delete" , skip( self , store, key) , fields( otel. kind = "client" ) ) ]
149157 async fn delete (
150158 & mut self ,
151159 store : Resource < key_value:: Store > ,
152160 key : String ,
153161 ) -> Result < Result < ( ) , Error > > {
154162 let store = self . get_store ( store) ?;
155- Ok ( store. delete ( & key) . await )
163+ Ok ( store. delete ( & key) . await . map_err ( track_error_on_span ) )
156164 }
157165
158- #[ instrument( name = "spin_key_value.exists" , skip( self , store, key) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
166+ #[ instrument( name = "spin_key_value.exists" , skip( self , store, key) , fields( otel. kind = "client" ) ) ]
159167 async fn exists (
160168 & mut self ,
161169 store : Resource < key_value:: Store > ,
162170 key : String ,
163171 ) -> Result < Result < bool , Error > > {
164172 let store = self . get_store ( store) ?;
165- Ok ( store. exists ( & key) . await )
173+ Ok ( store. exists ( & key) . await . map_err ( track_error_on_span ) )
166174 }
167175
168- #[ instrument( name = "spin_key_value.get_keys" , skip( self , store) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
176+ #[ instrument( name = "spin_key_value.get_keys" , skip( self , store) , fields( otel. kind = "client" ) ) ]
169177 async fn get_keys (
170178 & mut self ,
171179 store : Resource < key_value:: Store > ,
172180 ) -> Result < Result < Vec < String > , Error > > {
173181 let store = self . get_store ( store) ?;
174- Ok ( store. get_keys ( ) . await )
182+ Ok ( store. get_keys ( ) . await . map_err ( track_error_on_span ) )
175183 }
176184
177185 async fn drop ( & mut self , store : Resource < key_value:: Store > ) -> Result < ( ) > {
@@ -180,8 +188,19 @@ impl key_value::HostStore for KeyValueDispatch {
180188 }
181189}
182190
191+ /// Make sure that infrastructure related errors are tracked in the current span.
192+ fn track_error_on_span ( err : Error ) -> Error {
193+ if let Error :: Other ( _) | Error :: StoreTableFull = & err {
194+ let current_span = tracing:: Span :: current ( ) ;
195+ current_span. set_status ( spin_telemetry:: opentelemetry:: trace:: Status :: error (
196+ err. to_string ( ) ,
197+ ) ) ;
198+ }
199+ err
200+ }
201+
183202fn to_wasi_err ( e : Error ) -> wasi_keyvalue:: store:: Error {
184- match e {
203+ match track_error_on_span ( e ) {
185204 Error :: AccessDenied => wasi_keyvalue:: store:: Error :: AccessDenied ,
186205 Error :: NoSuchStore => wasi_keyvalue:: store:: Error :: NoSuchStore ,
187206 Error :: StoreTableFull => wasi_keyvalue:: store:: Error :: Other ( "store table full" . to_string ( ) ) ,
@@ -190,6 +209,7 @@ fn to_wasi_err(e: Error) -> wasi_keyvalue::store::Error {
190209}
191210
192211impl wasi_keyvalue:: store:: Host for KeyValueDispatch {
212+ #[ instrument( name = "wasi_key_value.open" , skip( self , identifier) , fields( otel. kind = "client" ) ) ]
193213 async fn open (
194214 & mut self ,
195215 identifier : String ,
@@ -217,6 +237,7 @@ impl wasi_keyvalue::store::Host for KeyValueDispatch {
217237
218238use wasi_keyvalue:: store:: Bucket ;
219239impl wasi_keyvalue:: store:: HostBucket for KeyValueDispatch {
240+ #[ instrument( name = "wasi_key_value.get" , skip( self , self_, key) , fields( otel. kind = "client" ) ) ]
220241 async fn get (
221242 & mut self ,
222243 self_ : Resource < Bucket > ,
@@ -226,6 +247,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
226247 store. get ( & key) . await . map_err ( to_wasi_err)
227248 }
228249
250+ #[ instrument( name = "wasi_key_value.set" , skip( self , self_, key, value) , fields( otel. kind = "client" ) ) ]
229251 async fn set (
230252 & mut self ,
231253 self_ : Resource < Bucket > ,
@@ -236,6 +258,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
236258 store. set ( & key, & value) . await . map_err ( to_wasi_err)
237259 }
238260
261+ #[ instrument( name = "wasi_key_value.delete" , skip( self , self_, key) , fields( otel. kind = "client" ) ) ]
239262 async fn delete (
240263 & mut self ,
241264 self_ : Resource < Bucket > ,
@@ -245,6 +268,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
245268 store. delete ( & key) . await . map_err ( to_wasi_err)
246269 }
247270
271+ #[ instrument( name = "wasi_key_value.exists" , skip( self , self_, key) , fields( otel. kind = "client" ) ) ]
248272 async fn exists (
249273 & mut self ,
250274 self_ : Resource < Bucket > ,
@@ -254,6 +278,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
254278 store. exists ( & key) . await . map_err ( to_wasi_err)
255279 }
256280
281+ #[ instrument( name = "wasi_key_value.list_keys" , skip( self , self_, cursor) , fields( otel. kind = "client" ) ) ]
257282 async fn list_keys (
258283 & mut self ,
259284 self_ : Resource < Bucket > ,
@@ -278,7 +303,7 @@ impl wasi_keyvalue::store::HostBucket for KeyValueDispatch {
278303}
279304
280305impl 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" ) ) ]
306+ #[ instrument( name = "spin_key_value.get_many" , skip( self , bucket, keys) , fields( otel. kind = "client" ) ) ]
282307 #[ allow( clippy:: type_complexity) ]
283308 async fn get_many (
284309 & mut self ,
@@ -292,7 +317,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
292317 store. get_many ( keys) . await . map_err ( to_wasi_err)
293318 }
294319
295- #[ instrument( name = "spin_key_value.set_many" , skip( self , bucket, key_values) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
320+ #[ instrument( name = "spin_key_value.set_many" , skip( self , bucket, key_values) , fields( otel. kind = "client" ) ) ]
296321 async fn set_many (
297322 & mut self ,
298323 bucket : Resource < wasi_keyvalue:: batch:: Bucket > ,
@@ -305,7 +330,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
305330 store. set_many ( key_values) . await . map_err ( to_wasi_err)
306331 }
307332
308- #[ instrument( name = "spin_key_value.delete_many" , skip( self , bucket, keys) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
333+ #[ instrument( name = "spin_key_value.delete_many" , skip( self , bucket, keys) , fields( otel. kind = "client" ) ) ]
309334 async fn delete_many (
310335 & mut self ,
311336 bucket : Resource < wasi_keyvalue:: batch:: Bucket > ,
@@ -320,6 +345,7 @@ impl wasi_keyvalue::batch::Host for KeyValueDispatch {
320345}
321346
322347impl wasi_keyvalue:: atomics:: HostCas for KeyValueDispatch {
348+ #[ instrument( name = "wasi_key_value_cas.new" , skip( self , bucket, key) , fields( otel. kind = "client" ) ) ]
323349 async fn new (
324350 & mut self ,
325351 bucket : Resource < wasi_keyvalue:: atomics:: Bucket > ,
@@ -342,6 +368,7 @@ impl wasi_keyvalue::atomics::HostCas for KeyValueDispatch {
342368 . map ( Resource :: new_own)
343369 }
344370
371+ #[ instrument( name = "wasi_key_value_cas.current" , skip( self , cas) , fields( otel. kind = "client" ) ) ]
345372 async fn current (
346373 & mut self ,
347374 cas : Resource < wasi_keyvalue:: atomics:: Cas > ,
@@ -366,7 +393,7 @@ impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
366393 Ok ( error)
367394 }
368395
369- #[ instrument( name = "spin_key_value.increment" , skip( self , bucket, key, delta) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
396+ #[ instrument( name = "spin_key_value.increment" , skip( self , bucket, key, delta) , fields( otel. kind = "client" ) ) ]
370397 async fn increment (
371398 & mut self ,
372399 bucket : Resource < wasi_keyvalue:: atomics:: Bucket > ,
@@ -377,7 +404,7 @@ impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
377404 store. increment ( key, delta) . await . map_err ( to_wasi_err)
378405 }
379406
380- #[ instrument( name = "spin_key_value.swap" , skip( self , cas_res, value) , err ( level = Level :: INFO ) , fields( otel. kind = "client" ) ) ]
407+ #[ instrument( name = "spin_key_value.swap" , skip( self , cas_res, value) , fields( otel. kind = "client" ) ) ]
381408 async fn swap (
382409 & mut self ,
383410 cas_res : Resource < atomics:: Cas > ,
@@ -424,8 +451,8 @@ use spin_world::v1::key_value::Error as LegacyError;
424451use spin_world:: wasi:: keyvalue:: atomics;
425452use spin_world:: wasi:: keyvalue:: atomics:: { CasError , HostCas } ;
426453
427- fn to_legacy_error ( value : key_value :: Error ) -> LegacyError {
428- match value {
454+ fn to_legacy_error ( err : Error ) -> LegacyError {
455+ match err {
429456 Error :: StoreTableFull => LegacyError :: StoreTableFull ,
430457 Error :: NoSuchStore => LegacyError :: NoSuchStore ,
431458 Error :: AccessDenied => LegacyError :: AccessDenied ,
0 commit comments