Skip to content

Commit b4a97e6

Browse files
committed
Finish a v1 draft of the traces.wit
Signed-off-by: Caleb Schoepp <[email protected]>
1 parent 4aec925 commit b4a97e6

File tree

3 files changed

+150
-91
lines changed
  • crates/factor-observe/src
  • tests/test-components/components/wasi-observe-tracing/src
  • wit/deps/observe

3 files changed

+150
-91
lines changed

crates/factor-observe/src/host.rs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,17 @@ use crate::{GuestSpan, InstanceState};
1414
#[async_trait]
1515
impl traces::Host for InstanceState {}
1616

17+
// TODO: Figure out a standard import scheme for my wit types vs otel types
18+
1719
#[async_trait]
1820
impl traces::HostSpan for InstanceState {
1921
// TODO(Caleb): Make this implicit logic make more sense (the indexmap seems wrong)
20-
async fn start(&mut self, name: String) -> Result<Resource<WitSpan>> {
22+
async fn start(
23+
&mut self,
24+
name: String,
25+
_parent: traces::SpanParent,
26+
_options: Option<traces::StartOptions>,
27+
) -> Result<Resource<WitSpan>> {
2128
let mut state = self.state.write().unwrap();
2229

2330
if state.active_spans.is_empty() {
@@ -59,23 +66,12 @@ impl traces::HostSpan for InstanceState {
5966
Ok(Resource::new_own(resource_id))
6067
}
6168

62-
async fn set_attribute(
63-
&mut self,
64-
resource: Resource<WitSpan>,
65-
attribute: KeyValue,
66-
) -> Result<()> {
67-
if let Some(guest_span) = self
68-
.state
69-
.write()
70-
.unwrap()
71-
.guest_spans
72-
.get_mut(resource.rep())
73-
{
74-
guest_span.inner.set_attribute(attribute.into())
75-
} else {
76-
tracing::debug!("can't find guest span to set attribute on")
77-
}
78-
Ok(())
69+
async fn span_context(&mut self, _resource: Resource<WitSpan>) -> Result<traces::SpanContext> {
70+
todo!()
71+
}
72+
73+
async fn is_recording(&mut self, _resource: Resource<WitSpan>) -> Result<bool> {
74+
todo!()
7975
}
8076

8177
async fn set_attributes(
@@ -106,11 +102,30 @@ impl traces::HostSpan for InstanceState {
106102
_timestamp: Option<Datetime>,
107103
_attributes: Option<Vec<KeyValue>>,
108104
) -> Result<()> {
109-
// TODO: Implement
110-
Ok(())
105+
todo!()
106+
}
107+
108+
async fn add_link(&mut self, _resource: Resource<WitSpan>, _link: traces::Link) -> Result<()> {
109+
todo!()
111110
}
112111

113-
async fn end(&mut self, resource: Resource<WitSpan>) -> Result<()> {
112+
async fn set_status(
113+
&mut self,
114+
_resource: Resource<WitSpan>,
115+
_status: traces::Status,
116+
) -> Result<()> {
117+
todo!()
118+
}
119+
120+
async fn update_name(&mut self, _resource: Resource<WitSpan>, _name: String) -> Result<()> {
121+
todo!()
122+
}
123+
124+
async fn end(
125+
&mut self,
126+
resource: Resource<WitSpan>,
127+
_timestamp: Option<Datetime>,
128+
) -> Result<()> {
114129
if let Some(guest_span) = self
115130
.state
116131
.write()

tests/test-components/components/wasi-observe-tracing/src/lib.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use spin_sdk::{
88
http::{Method, Params, Request, Response, Router},
99
http_component,
1010
};
11-
use wasi::observe::traces::{KeyValue, Span, Value};
11+
use wasi::observe::traces::{KeyValue, Span, SpanParent, Value};
1212

1313
#[http_component]
1414
fn handle(req: http::Request<()>) -> Response {
@@ -21,29 +21,29 @@ fn handle(req: http::Request<()>) -> Response {
2121
}
2222

2323
fn nested_spans(_req: Request, _params: Params) -> Response {
24-
let span = Span::start("outer_func");
24+
let span = Span::start("outer_func", &SpanParent::Implicit, None);
2525
inner_func();
26-
span.end();
26+
span.end(None);
2727
Response::new(200, "")
2828
}
2929

3030
fn inner_func() {
31-
let span = Span::start("inner_func");
32-
span.end();
31+
let span = Span::start("inner_func", &SpanParent::Implicit, None);
32+
span.end(None);
3333
}
3434

3535
fn drop_semantics(_req: Request, _params: Params) -> Response {
36-
let _span = Span::start("drop_semantics");
36+
let _span = Span::start("drop_semantics", &SpanParent::Implicit, None);
3737
Response::new(200, "")
3838
// _span will drop here and should be ended
3939
}
4040

4141
fn setting_attributes(_req: Request, _params: Params) -> Response {
42-
let span = Span::start("setting_attributes");
43-
span.set_attribute(&KeyValue {
42+
let span = Span::start("setting_attributes", &SpanParent::Implicit, None);
43+
span.set_attributes(&[KeyValue {
4444
key: "foo".to_string(),
4545
value: Value::String("bar".to_string()),
46-
});
46+
}]);
4747
span.set_attributes(&[
4848
KeyValue {
4949
key: "foo".to_string(),
@@ -54,19 +54,19 @@ fn setting_attributes(_req: Request, _params: Params) -> Response {
5454
value: Value::StringArray(vec!["qaz".to_string(), "thud".to_string()]),
5555
},
5656
]);
57-
span.end();
57+
span.end(None);
5858
Response::new(200, "")
5959
}
6060

6161
async fn host_guest_host(_req: Request, _params: Params) -> Response {
62-
let span = Span::start("guest");
62+
let span = Span::start("guest", &SpanParent::Implicit, None);
6363

6464
let req = Request::builder()
6565
.method(Method::Get)
6666
.uri("https://asdf.com")
6767
.build();
6868
let _res: Response = spin_sdk::http::send(req).await.unwrap();
69-
span.end();
69+
span.end(None);
7070

7171
Response::new(200, "")
7272
}

wit/deps/observe/traces.wit

Lines changed: 102 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,92 @@ interface traces {
33

44
/// Represents a unit of work or operation.
55
resource span {
6-
/// Starts a new span with the given name.
7-
///
8-
/// By default the currently active `span` is set as the nex `span`'s parent.
9-
start: static func(name: string) -> span;
6+
/// Starts a new span with the given name, parent, and options.
7+
start: static func(name: string, parent: span-parent, options: option<start-options>) -> span;
108

11-
// TODO: Start with timestamp, attrs, links, newroot, spankind, stacktrace?, context? is this possible?
9+
/// Get the `span-context` for this `span`.
10+
span-context: func() -> span-context;
1211

13-
/// Set an attribute of this span.
14-
///
15-
/// If the key already exists for an attribute of the Span it will be overwritten with the new value.
16-
set-attribute: func(attribute: key-value);
12+
/// Returns true when the data provided to this `span` is captured in some form. If it returns false then any data provided is discarded.
13+
is-recording: func() -> bool;
1714

18-
/// Set multiple attributes of this span.
15+
/// Set attributes of this span.
1916
///
20-
/// If one of the keys already exists for an attribute of the Span it will be overwritten with the corresponding new value.
17+
/// If a key already exists for an attribute of the Span it will be overwritten with the corresponding new value.
2118
set-attributes: func(attributes: list<key-value>);
2219

23-
/// Get the `span-context` for this `span`.
24-
// span-context: func() -> span-context;
25-
26-
// TODO: Is recording?
27-
2820
/// Adds an event with the provided name at the curent timestamp.
2921
///
3022
/// Optionally an alternative timestamp may be provided. You may also provide attributes of this event.
3123
add-event: func(name: string, timestamp: option<datetime>, attributes: option<list<key-value>>);
3224

33-
/// Adds a link from the current span to another span, identified by its `span-context`.
34-
///
35-
/// Links can be used to connect spans from different traces or within the same trace. Attributes can be attached to the link to provide additional context or metadata.
36-
// add-link: func(span-context: span-context, attributes: option<list<key-value>>)
25+
/// Associates this `span` with another.
26+
add-link: func(link: link);
3727

38-
// TODO: Set status
28+
/// Override the default `span` status, which is unset.
29+
set-status: func(status: status);
3930

40-
// TODO: Set name, is this possible?
41-
// update-name: func(name: string)
31+
/// Updates the `span` name.
32+
update-name: func(name: string);
4233

4334
/// Signals that the operation described by this span has now ended.
44-
end: func();
35+
///
36+
/// If a timestamp is not provided then it is treated equivalent to passing the current time.
37+
end: func(timestamp: option<datetime>);
38+
}
39+
40+
/// Configuration for starting a `span`.
41+
record start-options {
42+
/// `span-kind` for the new `span`.
43+
span-kind: option<span-kind>,
44+
/// Attributes for the new `span`.
45+
attributes: option<list<key-value>>,
46+
/// `link`'s for the new `span`.
47+
links: option<list<link>>,
48+
/// When the `span` should begin. If this is not provided it defaults to the current time.
49+
timestamp: option<datetime>,
50+
}
4551

46-
// TODO: Is this possible?
47-
// end_with_timestamp
52+
/// Describes a relationship to another `span`.
53+
record link {
54+
/// Denotes which `span` to link to.
55+
span-context: span-context,
56+
/// Attributes describing the link.
57+
attributes: list<key-value>,
58+
}
59+
60+
/// Describes the relationship between the Span, its parents, and its children in a trace.
61+
enum span-kind {
62+
/// Indicates that the span describes a request to some remote service. This span is usually the parent of a remote server span and does not end until the response is received.
63+
client,
64+
/// Indicates that the span covers server-side handling of a synchronous RPC or other remote request. This span is often the child of a remote client span that was expected to wait for a response.
65+
server,
66+
/// Indicates that the span describes the initiators of an asynchronous request. This parent span will often end before the corresponding child consumer span, possibly even before the child span starts. In messaging scenarios with batching, tracing individual messages requires a new producer span per message to be created.
67+
producer,
68+
/// Indicates that the span describes a child of an asynchronous consumer request.
69+
consumer,
70+
/// Default value. Indicates that the span represents an internal operation within an application, as opposed to an operations with remote parents or children.
71+
internal
72+
}
73+
74+
/// The `status` of a `span`.
75+
variant status {
76+
/// The default status.
77+
unset,
78+
/// The operation has been validated by an Application developer or Operator to have completed successfully.
79+
ok,
80+
/// The operation contains an error with a description.
81+
error(string),
82+
}
83+
84+
/// Determines how the parent of a `span` should be set.
85+
variant span-parent {
86+
/// The `span`'s parent is the current active span. The current active span is the most recently created and non-closed span. If no spans have been started in the guest this may be a span in the host.
87+
implicit,
88+
/// The `span` is a root span and should have no parent.
89+
is-root,
90+
/// The `span`'s parent is identified by the given `span-context`.
91+
span-context(span-context),
4892
}
4993

5094
/// A key-value pair describing an attribute.
@@ -60,50 +104,50 @@ interface traces {
60104

61105
/// The value part of attribute `key-value` pairs.
62106
variant value {
107+
/// A string value.
63108
%string(string),
109+
/// A boolean value.
64110
%bool(bool),
111+
/// A double precision floating point value.
65112
%float64(float64),
113+
/// A signed 64 bit integer value.
66114
%s64(s64),
115+
/// A homogeneous array of string values.
67116
string-array(list<string>),
117+
/// A homogeneous array of boolean values.
68118
bool-array(list<bool>),
119+
/// A homogeneous array of double precision floating point values.
69120
float64-array(list<float64>),
121+
/// A homogeneous array of 64 bit integer values.
70122
s64-array(list<s64>),
71123
}
72124

73125
/// Identifying trace information about a span that can be serialized and propagated.
74-
// TODO: Make types for the trace-id's and such?
75126
record span-context {
76-
/// Hexidecimal representation of the trace id.
77-
trace-id: string,
78-
/// Hexidecimal representation of the span id.
79-
span-id: string,
80-
/// Hexidecimal representation of the trace flags
81-
trace-flags: string,
82-
/// Span remoteness
83-
is-remote: bool,
84-
/// Entirety of tracestate
85-
trace-state: string,
127+
/// The `trace-id` for this `span-context`.
128+
trace-id: trace-id,
129+
/// The `span-id` for this `span-context`.
130+
span-id: span-id,
131+
/// The `trace-flags` for this `span-context`.
132+
trace-flags: trace-flags,
133+
/// Whether this `span-context` was propagated from a remote parent.
134+
is-remote: bool,
135+
/// The `trace-state` for this `span-context`.
136+
trace-state: string,
86137
}
87138

88-
// ????????????????????
89-
// // TODO: Document this and children.
90-
// enum span-kind {
91-
// client,
92-
// server,
93-
// producer,
94-
// consumer,
95-
// internal
96-
// }
97-
98-
// ??????????????????????
99-
// // An immutable representation of the entity producing telemetry as attributes.
100-
// record otel-resource {
101-
// // Resource attributes.
102-
// attrs: list<tuple<string, string>>,
103-
104-
// // Resource schema url.
105-
// schema-url: option<string>,
106-
// }
107-
}
139+
/// The trace that this `span-context` belongs to.
140+
type trace-id = tuple<u64, u64>;
141+
142+
/// The id of this `span-context`.
143+
type span-id = u64;
108144

109-
// TODO: Do we want set-attribute in addition to set-attributes? I'm leaning towards no
145+
/// Flags that can be set on a `span-context`.
146+
flags trace-flags {
147+
/// Whether the `span` should be sampled or not.
148+
sampled,
149+
}
150+
151+
/// Carries system-specific configuration data, represented as a list of key-value pairs. `trace-state` allows multiple tracing systems to participate in the same trace.
152+
type trace-state = option<list<tuple<string, string>>>;
153+
}

0 commit comments

Comments
 (0)