Skip to content

Commit cfa16b2

Browse files
committed
Only set span as errored in key-value when it might not be bad user input
Signed-off-by: Ryan Levick <[email protected]>
1 parent 8dec601 commit cfa16b2

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/factor-key-value/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ spin-core = { path = "../core" }
1111
spin-factors = { path = "../factors" }
1212
spin-locked-app = { path = "../locked-app" }
1313
spin-resource-table = { path = "../table" }
14+
spin-telemetry = { path = "../telemetry" }
1415
spin-world = { path = "../world" }
16+
thiserror = { workspace = true }
1517
tokio = { workspace = true, features = ["macros", "sync", "rt"] }
1618
toml = { workspace = true }
1719
tracing = { workspace = true }
18-
thiserror = { workspace = true }
1920

2021
[dev-dependencies]
2122
spin-factors-test = { path = "../factors-test" }

crates/factor-key-value/src/host.rs

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use super::{Cas, SwapError};
22
use anyhow::{Context, Result};
33
use spin_core::{async_trait, wasmtime::component::Resource};
44
use spin_resource_table::Table;
5+
use spin_telemetry::OpenTelemetrySpanExt as _;
56
use spin_world::v2::key_value;
67
use spin_world::wasi::keyvalue as wasi_keyvalue;
78
use std::{collections::HashSet, sync::Arc};
8-
use tracing::{instrument, Level};
9+
use tracing::instrument;
910

1011
const 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 {
106114
impl key_value::Host for KeyValueDispatch {}
107115

108116
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())))]
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+
183202
fn 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

192211
impl 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

218238
use wasi_keyvalue::store::Bucket;
219239
impl 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

280305
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"))]
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

322347
impl 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;
424451
use spin_world::wasi::keyvalue::atomics;
425452
use 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

Comments
 (0)