Skip to content

Commit 5fea155

Browse files
committed
feat(wasi-observe): A WASI Observe host component
Signed-off-by: Caleb Schoepp <caleb.schoepp@fermyon.com>
1 parent a22119c commit 5fea155

File tree

53 files changed

+1997
-100
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1997
-100
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ openssl = { version = "0.10" }
8686
anyhow = { workspace = true, features = ["backtrace"] }
8787
conformance = { path = "tests/conformance-tests" }
8888
conformance-tests = { workspace = true }
89+
fake-opentelemetry-collector = "0.21.1"
8990
hex = "0.4"
9091
http-body-util = { workspace = true }
9192
hyper = { workspace = true }

crates/factor-key-value/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ anyhow = { workspace = true }
99
lru = "0.12"
1010
serde = { workspace = true }
1111
spin-core = { path = "../core" }
12+
spin-factor-observe = { path = "../factor-observe" }
1213
spin-factors = { path = "../factors" }
1314
spin-locked-app = { path = "../locked-app" }
1415
spin-world = { path = "../world" }

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::{Context, Result};
22
use spin_core::{async_trait, wasmtime::component::Resource};
3-
use spin_world::v2::key_value;
3+
use spin_factor_observe::ObserveContext;
4+
use spin_world::{v2::key_value, wasi::observe};
45
use std::{collections::HashSet, sync::Arc};
56
use table::Table;
67
use tracing::{instrument, Level};
@@ -36,22 +37,25 @@ pub struct KeyValueDispatch {
3637
allowed_stores: HashSet<String>,
3738
manager: Arc<dyn StoreManager>,
3839
stores: Table<Arc<dyn Store>>,
40+
observe_context: Option<ObserveContext>,
3941
}
4042

4143
impl KeyValueDispatch {
4244
pub fn new(allowed_stores: HashSet<String>, manager: Arc<dyn StoreManager>) -> Self {
43-
Self::new_with_capacity(allowed_stores, manager, DEFAULT_STORE_TABLE_CAPACITY)
45+
Self::new_with_capacity(allowed_stores, manager, DEFAULT_STORE_TABLE_CAPACITY, None)
4446
}
4547

4648
pub fn new_with_capacity(
4749
allowed_stores: HashSet<String>,
4850
manager: Arc<dyn StoreManager>,
4951
capacity: u32,
52+
observe_context: Option<ObserveContext>,
5053
) -> Self {
5154
Self {
5255
allowed_stores,
5356
manager,
5457
stores: Table::new(capacity),
58+
observe_context,
5559
}
5660
}
5761

@@ -71,6 +75,9 @@ impl key_value::Host for KeyValueDispatch {}
7175
impl key_value::HostStore for KeyValueDispatch {
7276
#[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())))]
7377
async fn open(&mut self, name: String) -> Result<Result<Resource<key_value::Store>, Error>> {
78+
if let Some(observe_context) = self.observe_context.as_ref() {
79+
observe_context.reparent_tracing_span()
80+
}
7481
Ok(async {
7582
if self.allowed_stores.contains(&name) {
7683
let store = self
@@ -91,6 +98,9 @@ impl key_value::HostStore for KeyValueDispatch {
9198
store: Resource<key_value::Store>,
9299
key: String,
93100
) -> Result<Result<Option<Vec<u8>>, Error>> {
101+
if let Some(observe_context) = self.observe_context.as_ref() {
102+
observe_context.reparent_tracing_span()
103+
}
94104
let store = self.get_store(store)?;
95105
Ok(store.get(&key).await)
96106
}
@@ -102,6 +112,9 @@ impl key_value::HostStore for KeyValueDispatch {
102112
key: String,
103113
value: Vec<u8>,
104114
) -> Result<Result<(), Error>> {
115+
if let Some(observe_context) = self.observe_context.as_ref() {
116+
observe_context.reparent_tracing_span()
117+
}
105118
let store = self.get_store(store)?;
106119
Ok(store.set(&key, &value).await)
107120
}
@@ -112,6 +125,9 @@ impl key_value::HostStore for KeyValueDispatch {
112125
store: Resource<key_value::Store>,
113126
key: String,
114127
) -> Result<Result<(), Error>> {
128+
if let Some(observe_context) = self.observe_context.as_ref() {
129+
observe_context.reparent_tracing_span()
130+
}
115131
let store = self.get_store(store)?;
116132
Ok(store.delete(&key).await)
117133
}
@@ -122,6 +138,9 @@ impl key_value::HostStore for KeyValueDispatch {
122138
store: Resource<key_value::Store>,
123139
key: String,
124140
) -> Result<Result<bool, Error>> {
141+
if let Some(observe_context) = self.observe_context.as_ref() {
142+
observe_context.reparent_tracing_span()
143+
}
125144
let store = self.get_store(store)?;
126145
Ok(store.exists(&key).await)
127146
}
@@ -131,6 +150,9 @@ impl key_value::HostStore for KeyValueDispatch {
131150
&mut self,
132151
store: Resource<key_value::Store>,
133152
) -> Result<Result<Vec<String>, Error>> {
153+
if let Some(observe_context) = self.observe_context.as_ref() {
154+
observe_context.reparent_tracing_span()
155+
}
134156
let store = self.get_store(store)?;
135157
Ok(store.get_keys().await)
136158
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::{
88
};
99

1010
use anyhow::ensure;
11+
use spin_factor_observe::ObserveContext;
1112
use spin_factors::{
1213
ConfigureAppContext, Factor, FactorInstanceBuilder, InitContext, PrepareContext, RuntimeFactors,
1314
};
@@ -81,17 +82,19 @@ impl Factor for KeyValueFactor {
8182

8283
fn prepare<T: RuntimeFactors>(
8384
&self,
84-
ctx: PrepareContext<T, Self>,
85+
mut ctx: PrepareContext<T, Self>,
8586
) -> anyhow::Result<InstanceBuilder> {
8687
let app_state = ctx.app_state();
8788
let allowed_stores = app_state
8889
.component_allowed_stores
8990
.get(ctx.app_component().id())
9091
.expect("component should be in component_stores")
9192
.clone();
93+
let observe_context = ObserveContext::from_prepare_context(&mut ctx)?;
9294
Ok(InstanceBuilder {
9395
store_manager: app_state.store_manager.clone(),
9496
allowed_stores,
97+
observe_context,
9598
})
9699
}
97100
}
@@ -140,6 +143,7 @@ pub struct InstanceBuilder {
140143
store_manager: Arc<AppStoreManager>,
141144
/// The allowed stores for this component instance.
142145
allowed_stores: HashSet<String>,
146+
observe_context: ObserveContext,
143147
}
144148

145149
impl FactorInstanceBuilder for InstanceBuilder {
@@ -149,11 +153,13 @@ impl FactorInstanceBuilder for InstanceBuilder {
149153
let Self {
150154
store_manager,
151155
allowed_stores,
156+
observe_context,
152157
} = self;
153158
Ok(KeyValueDispatch::new_with_capacity(
154159
allowed_stores,
155160
store_manager,
156161
u32::MAX,
162+
Some(observe_context),
157163
))
158164
}
159165
}

crates/factor-llm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ llm-cublas = ["llm", "spin-llm-local/cublas"]
1717
anyhow = { workspace = true }
1818
async-trait = { workspace = true }
1919
serde = { workspace = true }
20+
spin-factor-observe = { path = "../factor-observe" }
2021
spin-factors = { path = "../factors" }
2122
spin-llm-local = { path = "../llm-local", optional = true }
2223
spin-llm-remote-http = { path = "../llm-remote-http" }

crates/factor-llm/src/host.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ impl v2::Host for InstanceState {
1515
prompt: String,
1616
params: Option<v2::InferencingParams>,
1717
) -> Result<v2::InferencingResult, v2::Error> {
18+
self.observe_context.reparent_tracing_span();
19+
1820
if !self.allowed_models.contains(&model) {
1921
return Err(access_denied_error(&model));
2022
}
@@ -42,6 +44,8 @@ impl v2::Host for InstanceState {
4244
model: v1::EmbeddingModel,
4345
data: Vec<String>,
4446
) -> Result<v2::EmbeddingsResult, v2::Error> {
47+
self.observe_context.reparent_tracing_span();
48+
4549
if !self.allowed_models.contains(&model) {
4650
return Err(access_denied_error(&model));
4751
}

crates/factor-llm/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::collections::{HashMap, HashSet};
55
use std::sync::Arc;
66

77
use async_trait::async_trait;
8+
use spin_factor_observe::ObserveContext;
89
use spin_factors::{
910
ConfigureAppContext, Factor, PrepareContext, RuntimeFactors, SelfInstanceBuilder,
1011
};
@@ -76,7 +77,7 @@ impl Factor for LlmFactor {
7677

7778
fn prepare<T: RuntimeFactors>(
7879
&self,
79-
ctx: PrepareContext<T, Self>,
80+
mut ctx: PrepareContext<T, Self>,
8081
) -> anyhow::Result<Self::InstanceBuilder> {
8182
let allowed_models = ctx
8283
.app_state()
@@ -85,10 +86,12 @@ impl Factor for LlmFactor {
8586
.cloned()
8687
.unwrap_or_default();
8788
let engine = ctx.app_state().engine.clone();
89+
let observe_context = ObserveContext::from_prepare_context(&mut ctx)?;
8890

8991
Ok(InstanceState {
9092
engine,
9193
allowed_models,
94+
observe_context,
9295
})
9396
}
9497
}
@@ -103,6 +106,7 @@ pub struct AppState {
103106
pub struct InstanceState {
104107
engine: Arc<Mutex<dyn LlmEngine>>,
105108
pub allowed_models: Arc<HashSet<String>>,
109+
observe_context: ObserveContext,
106110
}
107111

108112
/// The runtime configuration for the LLM factor.

0 commit comments

Comments
 (0)