// TracerOptions holds configuration for Tracer ID generation
///|
pub struct TracerOptions {
trace_id_generator : () -> TraceID
span_id_generator : () -> SpanID
get_current_time_nanos : () -> Int64
span_on_start : (Span) -> Unit
span_on_end : (Span) -> Unit
}
// Create default TracerOptions using built-in generators
///|
pub fn TracerOptions::default(
rand? : @random.Rand = rand_by_current_time(),
) -> TracerOptions {
{
trace_id_generator: () => generate_trace_id(rand),
span_id_generator: () => generate_span_id(rand),
get_current_time_nanos: current_time_nanos,
span_on_start: fn(_) { println("[Tracer] Span started.") },
span_on_end: fn(_) { println("[Tracer] Span ended.") },
}
}
// Set custom trace ID generator
///|
pub fn TracerOptions::with_trace_id_generator(
self : TracerOptions,
generator : () -> TraceID,
) -> TracerOptions {
{ ..self, trace_id_generator: generator }
}
// Set custom span ID generator
///|
pub fn TracerOptions::with_span_id_generator(
self : TracerOptions,
generator : () -> SpanID,
) -> TracerOptions {
{ ..self, span_id_generator: generator }
}
///|
pub fn TracerOptions::with_current_time_fn(
self : TracerOptions,
time_fn : () -> Int64,
) -> TracerOptions {
{ ..self, get_current_time_nanos: time_fn }
}
///|
pub fn TracerOptions::with_span_on_start(
self : TracerOptions,
on_start_fn : (Span) -> Unit,
) -> TracerOptions {
{ ..self, span_on_start: on_start_fn }
}
///|
pub fn TracerOptions::with_span_on_end(
self : TracerOptions,
on_end_fn : (Span) -> Unit,
) -> TracerOptions {
{ ..self, span_on_end: on_end_fn }
}
// Tracer is responsible for creating Spans
///|
pub struct Tracer {
identifier : TracerIdentifier // Identifier for this tracer
resource : Resource // Resource associated with this tracer
options : TracerOptions // Options for this tracer
}
///|
pub fn Tracer::name(self : Tracer) -> String {
self.identifier.name
}
///|
pub fn Tracer::version(self : Tracer) -> String {
self.identifier.version
}
///|
pub struct TracerIdentifier {
name : String // Tracer name (usually the instrumentation library name)
version : String // Tracer version
} derive(Hash, Eq)
///|
pub fn TracerIdentifier::new(
name : String,
version : String,
) -> TracerIdentifier {
{ name, version }
}
// Create a new Tracer with default configuration
///|
pub fn Tracer::new(
name : String,
version : String,
resource : Resource,
) -> Tracer {
let options = TracerOptions::default()
{ identifier: { name, version }, resource, options }
}
// Create a new Tracer with custom configuration
///|
pub fn Tracer::with_options(
name : String,
version : String,
resource : Resource,
options : TracerOptions,
) -> Tracer {
{ identifier: { name, version }, resource, options }
}
// Tracer methods for creating spans
///|
fn Tracer::span_builder(self : Tracer, name : String) -> SpanBuilder {
SpanBuilder::new(name, self.resource, self.identifier, self.options)
}
// Convenience method to start a span directly
///|
pub fn Tracer::start_span(
self : Tracer,
name : String,
kind? : SpanKind,
parent? : &SpanContextExtractable,
attributes? : Attributes = Default::default(),
) -> Span {
let builder = self
.span_builder(name)
.kind(kind.unwrap_or_else(() => SpanKind::Unspecified))
.attributes(attributes)
let builder_with_parent = match parent {
Some(p) => builder.parent(p)
None => builder
}
let span = builder_with_parent.start()
(self.options.span_on_start)(span)
span
}
///|
/// `run_async` spawn a new coroutine and execute an async function in it
fn run_async(f : async () -> Unit noraise) -> Unit = "%async.run"
///|
pub fn Tracer::span_event(
self : Tracer,
name : String,
attributes? : Attributes = Default::default(),
event_time? : Int64? = None,
) -> SpanEvent {
SpanEvent::new(
name,
attributes,
timestamp=event_time.unwrap_or_else(self.options.get_current_time_nanos),
)
}
///|
/// |
pub struct TracerProvider {
tracer_factory : (TracerOptions) -> Tracer
span_processors : Array[&SpanProcessor]
options : TracerOptions
}
///|
/// get Tracer from TracerProvider
pub fn TracerProvider::tracer(self : TracerProvider) -> Tracer {
let options = self.options
.with_span_on_start(fn(span) {
(self.options.span_on_start)(span)
for processor in self.span_processors {
processor.on_span_start(span)
}
})
.with_span_on_end(fn(span) {
(self.options.span_on_end)(span)
for processor in self.span_processors {
processor.on_span_end(span)
}
})
let tracer = (self.tracer_factory)(options)
tracer
}
///|
pub fn TracerProvider::new(
name : String,
version : String,
resource : Resource,
options? : TracerOptions = TracerOptions::default(),
processors? : Array[&SpanProcessor] = [],
) -> TracerProvider {
TracerProvider::{
tracer_factory: (opts : TracerOptions) => {
Tracer::with_options(name, version, resource, opts)
},
span_processors: processors,
options,
}
}
///|
pub fn TracerProvider::with_span_processors(
self : TracerProvider,
processors : Array[&SpanProcessor],
) -> TracerProvider {
{ ..self, span_processors: processors }
}
///|
pub async fn TracerProvider::shutdown(self : TracerProvider) -> Unit {
for processor in self.span_processors {
processor.shutdown()
}
}
///|
pub async fn TracerProvider::force_flush(self : TracerProvider) -> Unit {
for processor in self.span_processors {
processor.force_flush()
}
}
///|
let global_tracer_provider : Ref[TracerProvider] = Ref::new(TracerProvider::{
tracer_factory: (_ : TracerOptions) => {
abort("Global TracerProvider is not set.")
},
span_processors: [],
options: TracerOptions::default(),
})
///|
/// set global TracerProvider
pub fn TracerProvider::set_global(provider : TracerProvider) -> Unit {
global_tracer_provider.swap(Ref::new(provider))
}
///|
/// get global TracerProvider
pub fn TracerProvider::global() -> TracerProvider {
global_tracer_provider.val
}