///|
pub(all) struct Span {
name : String
fields : Array[Field]
links : Array[SpanLink]
trace_id : String
span_id : String
parent_span_id : String
mut trace_flags : Int
mut trace_state : TraceState
mut kind : SpanKind
mut start_time : UInt64
mut end_time : UInt64
mut active : Bool
mut status : SpanStatus
mut status_message : String
} derive(Debug)
///|
pub fn span(
name : String,
fields? : Array[Field] = [],
kind? : SpanKind = Internal,
) -> Span {
let s = {
name,
fields,
links: [],
trace_id: next_trace_id(),
span_id: next_span_id(),
parent_span_id: "",
trace_flags: 0,
trace_state: TraceState::empty(),
kind,
start_time: @env.now(),
end_time: (0 : UInt64),
active: false,
status: Unset,
status_message: "",
}
notify_span_created(s)
s
}
///|
pub fn span_with_trace(
name : String,
trace_id : String,
fields? : Array[Field] = [],
kind? : SpanKind = Internal,
) -> Span {
let s = {
name,
fields,
links: [],
trace_id,
span_id: next_span_id(),
parent_span_id: "",
trace_flags: 0,
trace_state: TraceState::empty(),
kind,
start_time: @env.now(),
end_time: (0 : UInt64),
active: false,
status: Unset,
status_message: "",
}
notify_span_created(s)
s
}
///|
pub fn child_span(
parent : Span,
name : String,
fields? : Array[Field] = [],
kind? : SpanKind = Internal,
) -> Span {
let s = span_with_ids(
name,
fields,
parent.trace_id,
parent.span_id,
kind,
trace_flags=parent.trace_flags,
trace_state=parent.trace_state,
)
notify_span_linked(s, span_link(parent, kind=SpanChildOf))
s
}
///|
fn span_with_ids(
name : String,
fields : Array[Field],
trace_id : String,
parent_span_id : String,
kind : SpanKind,
trace_flags? : Int = 0,
trace_state? : TraceState = TraceState::empty(),
) -> Span {
let s = span_with_ids_unnotified(
name,
fields,
trace_id,
parent_span_id,
kind,
trace_flags~,
trace_state~,
)
notify_span_created(s)
s
}
///|
fn span_with_ids_unnotified(
name : String,
fields : Array[Field],
trace_id : String,
parent_span_id : String,
kind : SpanKind,
trace_flags? : Int = 0,
trace_state? : TraceState = TraceState::empty(),
) -> Span {
{
name,
fields,
links: [],
trace_id,
span_id: next_span_id(),
parent_span_id,
trace_flags,
trace_state: copy_trace_state(trace_state),
kind,
start_time: @env.now(),
end_time: (0 : UInt64),
active: false,
status: Unset,
status_message: "",
}
}
///|
fn Span::is_closed(self : Span) -> Bool {
!self.active && self.end_time != (0 : UInt64)
}
///|
pub fn Span::enter(self : Span) -> Unit {
if self.active || self.is_closed() {
return
}
self.start_time = @env.now()
self.end_time = (0 : UInt64)
self.active = true
notify_span_entered(self)
let enter_fields = self.fields.copy()
emit(Trace, "span.enter \{self.name}", enter_fields)
}
///|
pub fn Span::exit(self : Span) -> Unit {
if !self.active {
return
}
self.end_time = @env.now()
self.active = false
notify_span_exited(self)
let duration = self.end_time - self.start_time
let exit_fields = self.fields.copy()
exit_fields.push({ key: "duration_ns", value: duration.to_json() })
if self.status != Unset {
exit_fields.push({ key: "status", value: self.status.to_json() })
if !self.status_message.is_empty() {
exit_fields.push({
key: "status_message",
value: self.status_message.to_json(),
})
}
}
emit(Trace, "span.exit \{self.name}", exit_fields)
notify_span_closed(self)
}
///|
pub fn Span::set_status(
self : Span,
status : SpanStatus,
message? : String? = None,
) -> Unit {
self.status = status
match message {
Some(m) => self.status_message = m
None => if status != SpanError { self.status_message = "" }
}
}
///|
pub fn Span::record_error(self : Span, msg : String) -> Unit {
self.status = SpanError
self.status_message = msg
let field : Field = { key: "error", value: msg.to_json() }
self.fields.push(field)
notify_span_recorded(self, field)
}
///|
pub fn Span::is_active(self : Span) -> Bool {
self.active
}
///|
pub fn Span::duration(self : Span) -> UInt64 {
if self.end_time > self.start_time {
self.end_time - self.start_time
} else {
(0 : UInt64)
}
}