Skip to content

Commit

Permalink
Finish a v1 draft of the traces.wit
Browse files Browse the repository at this point in the history
Signed-off-by: Caleb Schoepp <[email protected]>
  • Loading branch information
calebschoepp committed Sep 5, 2024
1 parent 4aec925 commit b4a97e6
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 91 deletions.
57 changes: 36 additions & 21 deletions crates/factor-observe/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ use crate::{GuestSpan, InstanceState};
#[async_trait]
impl traces::Host for InstanceState {}

// TODO: Figure out a standard import scheme for my wit types vs otel types

#[async_trait]
impl traces::HostSpan for InstanceState {
// TODO(Caleb): Make this implicit logic make more sense (the indexmap seems wrong)
async fn start(&mut self, name: String) -> Result<Resource<WitSpan>> {
async fn start(
&mut self,
name: String,
_parent: traces::SpanParent,
_options: Option<traces::StartOptions>,
) -> Result<Resource<WitSpan>> {
let mut state = self.state.write().unwrap();

if state.active_spans.is_empty() {
Expand Down Expand Up @@ -59,23 +66,12 @@ impl traces::HostSpan for InstanceState {
Ok(Resource::new_own(resource_id))
}

async fn set_attribute(
&mut self,
resource: Resource<WitSpan>,
attribute: KeyValue,
) -> Result<()> {
if let Some(guest_span) = self
.state
.write()
.unwrap()
.guest_spans
.get_mut(resource.rep())
{
guest_span.inner.set_attribute(attribute.into())
} else {
tracing::debug!("can't find guest span to set attribute on")
}
Ok(())
async fn span_context(&mut self, _resource: Resource<WitSpan>) -> Result<traces::SpanContext> {
todo!()
}

async fn is_recording(&mut self, _resource: Resource<WitSpan>) -> Result<bool> {
todo!()
}

async fn set_attributes(
Expand Down Expand Up @@ -106,11 +102,30 @@ impl traces::HostSpan for InstanceState {
_timestamp: Option<Datetime>,
_attributes: Option<Vec<KeyValue>>,
) -> Result<()> {
// TODO: Implement
Ok(())
todo!()
}

async fn add_link(&mut self, _resource: Resource<WitSpan>, _link: traces::Link) -> Result<()> {
todo!()
}

async fn end(&mut self, resource: Resource<WitSpan>) -> Result<()> {
async fn set_status(
&mut self,
_resource: Resource<WitSpan>,
_status: traces::Status,
) -> Result<()> {
todo!()
}

async fn update_name(&mut self, _resource: Resource<WitSpan>, _name: String) -> Result<()> {
todo!()
}

async fn end(
&mut self,
resource: Resource<WitSpan>,
_timestamp: Option<Datetime>,
) -> Result<()> {
if let Some(guest_span) = self
.state
.write()
Expand Down
24 changes: 12 additions & 12 deletions tests/test-components/components/wasi-observe-tracing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use spin_sdk::{
http::{Method, Params, Request, Response, Router},
http_component,
};
use wasi::observe::traces::{KeyValue, Span, Value};
use wasi::observe::traces::{KeyValue, Span, SpanParent, Value};

#[http_component]
fn handle(req: http::Request<()>) -> Response {
Expand All @@ -21,29 +21,29 @@ fn handle(req: http::Request<()>) -> Response {
}

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

fn inner_func() {
let span = Span::start("inner_func");
span.end();
let span = Span::start("inner_func", &SpanParent::Implicit, None);
span.end(None);
}

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

fn setting_attributes(_req: Request, _params: Params) -> Response {
let span = Span::start("setting_attributes");
span.set_attribute(&KeyValue {
let span = Span::start("setting_attributes", &SpanParent::Implicit, None);
span.set_attributes(&[KeyValue {
key: "foo".to_string(),
value: Value::String("bar".to_string()),
});
}]);
span.set_attributes(&[
KeyValue {
key: "foo".to_string(),
Expand All @@ -54,19 +54,19 @@ fn setting_attributes(_req: Request, _params: Params) -> Response {
value: Value::StringArray(vec!["qaz".to_string(), "thud".to_string()]),
},
]);
span.end();
span.end(None);
Response::new(200, "")
}

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

let req = Request::builder()
.method(Method::Get)
.uri("https://asdf.com")
.build();
let _res: Response = spin_sdk::http::send(req).await.unwrap();
span.end();
span.end(None);

Response::new(200, "")
}
160 changes: 102 additions & 58 deletions wit/deps/observe/traces.wit
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,92 @@ interface traces {

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

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

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

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

/// Get the `span-context` for this `span`.
// span-context: func() -> span-context;

// TODO: Is recording?

/// Adds an event with the provided name at the curent timestamp.
///
/// Optionally an alternative timestamp may be provided. You may also provide attributes of this event.
add-event: func(name: string, timestamp: option<datetime>, attributes: option<list<key-value>>);

/// Adds a link from the current span to another span, identified by its `span-context`.
///
/// 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.
// add-link: func(span-context: span-context, attributes: option<list<key-value>>)
/// Associates this `span` with another.
add-link: func(link: link);

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

// TODO: Set name, is this possible?
// update-name: func(name: string)
/// Updates the `span` name.
update-name: func(name: string);

/// Signals that the operation described by this span has now ended.
end: func();
///
/// If a timestamp is not provided then it is treated equivalent to passing the current time.
end: func(timestamp: option<datetime>);
}

/// Configuration for starting a `span`.
record start-options {
/// `span-kind` for the new `span`.
span-kind: option<span-kind>,
/// Attributes for the new `span`.
attributes: option<list<key-value>>,
/// `link`'s for the new `span`.
links: option<list<link>>,
/// When the `span` should begin. If this is not provided it defaults to the current time.
timestamp: option<datetime>,
}

// TODO: Is this possible?
// end_with_timestamp
/// Describes a relationship to another `span`.
record link {
/// Denotes which `span` to link to.
span-context: span-context,
/// Attributes describing the link.
attributes: list<key-value>,
}

/// Describes the relationship between the Span, its parents, and its children in a trace.
enum span-kind {
/// 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.
client,
/// 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.
server,
/// 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.
producer,
/// Indicates that the span describes a child of an asynchronous consumer request.
consumer,
/// Default value. Indicates that the span represents an internal operation within an application, as opposed to an operations with remote parents or children.
internal
}

/// The `status` of a `span`.
variant status {
/// The default status.
unset,
/// The operation has been validated by an Application developer or Operator to have completed successfully.
ok,
/// The operation contains an error with a description.
error(string),
}

/// Determines how the parent of a `span` should be set.
variant span-parent {
/// 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.
implicit,
/// The `span` is a root span and should have no parent.
is-root,
/// The `span`'s parent is identified by the given `span-context`.
span-context(span-context),
}

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

/// The value part of attribute `key-value` pairs.
variant value {
/// A string value.
%string(string),
/// A boolean value.
%bool(bool),
/// A double precision floating point value.
%float64(float64),
/// A signed 64 bit integer value.
%s64(s64),
/// A homogeneous array of string values.
string-array(list<string>),
/// A homogeneous array of boolean values.
bool-array(list<bool>),
/// A homogeneous array of double precision floating point values.
float64-array(list<float64>),
/// A homogeneous array of 64 bit integer values.
s64-array(list<s64>),
}

/// Identifying trace information about a span that can be serialized and propagated.
// TODO: Make types for the trace-id's and such?
record span-context {
/// Hexidecimal representation of the trace id.
trace-id: string,
/// Hexidecimal representation of the span id.
span-id: string,
/// Hexidecimal representation of the trace flags
trace-flags: string,
/// Span remoteness
is-remote: bool,
/// Entirety of tracestate
trace-state: string,
/// The `trace-id` for this `span-context`.
trace-id: trace-id,
/// The `span-id` for this `span-context`.
span-id: span-id,
/// The `trace-flags` for this `span-context`.
trace-flags: trace-flags,
/// Whether this `span-context` was propagated from a remote parent.
is-remote: bool,
/// The `trace-state` for this `span-context`.
trace-state: string,
}

// ????????????????????
// // TODO: Document this and children.
// enum span-kind {
// client,
// server,
// producer,
// consumer,
// internal
// }

// ??????????????????????
// // An immutable representation of the entity producing telemetry as attributes.
// record otel-resource {
// // Resource attributes.
// attrs: list<tuple<string, string>>,

// // Resource schema url.
// schema-url: option<string>,
// }
}
/// The trace that this `span-context` belongs to.
type trace-id = tuple<u64, u64>;

/// The id of this `span-context`.
type span-id = u64;

// TODO: Do we want set-attribute in addition to set-attributes? I'm leaning towards no
/// Flags that can be set on a `span-context`.
flags trace-flags {
/// Whether the `span` should be sampled or not.
sampled,
}

/// 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.
type trace-state = option<list<tuple<string, string>>>;
}

0 comments on commit b4a97e6

Please sign in to comment.