use processor::telemetry::{
context_with_span, init_telemetry, metric_attributes, metric_names, record_exception,
MetricsRecorder, SpanBuilder, TelemetryConfig,
};
use processor::{otel_global, OtelContext, OtelKeyValue, SpanKind};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
println!("Starting telemetry demo...");
let config = TelemetryConfig::new("telemetry-demo")
.with_otlp_endpoint("http://localhost:4317")
.with_service_version("1.0.0")
.with_environment("development")
.with_tracing_enabled(true)
.with_metrics_enabled(true);
println!("Initializing OpenTelemetry providers...");
let providers = init_telemetry(config)?;
let metrics = MetricsRecorder::new()
.with_attribute("service", "telemetry-demo")
.with_attribute("environment", "development");
println!("\n=== Running Demo Scenarios ===\n");
println!("1. Creating basic spans...");
demo_basic_spans().await;
println!("2. Creating nested spans...");
demo_nested_spans().await;
println!("3. Recording metrics...");
demo_metrics(&metrics).await;
println!("4. Demonstrating error handling...");
demo_error_handling().await;
println!("5. Demonstrating async operations...");
demo_async_operations().await;
println!("6. Simulating event processing...");
demo_event_processing(&metrics).await;
println!("\n=== Demo Complete ===\n");
println!("View traces at: http://localhost:16686");
println!("View metrics at: http://localhost:9090");
println!("\nWaiting for final export...");
tokio::time::sleep(Duration::from_secs(3)).await;
println!("Shutting down telemetry providers...");
providers.shutdown().await?;
println!("Demo finished!");
Ok(())
}
async fn demo_basic_spans() {
let tracer = otel_global::tracer("demo");
for i in 0..3 {
let mut span = tracer
.span_builder(format!("basic_operation_{}", i))
.with_kind(SpanKind::Internal)
.with_attributes(vec![
OtelKeyValue::new("operation.id", i.to_string()),
OtelKeyValue::new("operation.type", "basic"),
])
.start(&tracer);
span.add_event("Operation started".to_string(), vec![]);
tokio::time::sleep(Duration::from_millis(50)).await;
span.add_event(
"Operation completed".to_string(),
vec![OtelKeyValue::new("status", "success")],
);
}
println!(" ✓ Created 3 basic spans");
}
async fn demo_nested_spans() {
let tracer = otel_global::tracer("demo");
let parent_span = tracer
.span_builder("parent_operation")
.with_kind(SpanKind::Server)
.with_attributes(vec![OtelKeyValue::new("level", "parent")])
.start(&tracer);
let parent_context = context_with_span(parent_span);
let _parent_guard = parent_context.attach();
for i in 0..2 {
let child_span = tracer
.span_builder(format!("child_operation_{}", i))
.with_kind(SpanKind::Internal)
.with_attributes(vec![
OtelKeyValue::new("level", "child"),
OtelKeyValue::new("child.id", i.to_string()),
])
.start(&tracer);
let child_context = context_with_span(child_span);
let _child_guard = child_context.attach();
tokio::time::sleep(Duration::from_millis(30)).await;
}
println!(" ✓ Created parent span with 2 children");
}
async fn demo_metrics(recorder: &MetricsRecorder) {
for i in 0..5 {
recorder.record_counter(
"demo",
metric_names::EVENTS_PROCESSED,
1,
vec![OtelKeyValue::new(metric_attributes::EVENT_TYPE, "demo")],
);
recorder.record_histogram(
"demo",
metric_names::PROCESSING_DURATION,
(i as f64) * 10.5,
vec![OtelKeyValue::new(
metric_attributes::OPERATION_TYPE,
"demo",
)],
);
tokio::time::sleep(Duration::from_millis(20)).await;
}
recorder.record_gauge(
"demo",
metric_names::WATERMARK_LAG,
100,
vec![OtelKeyValue::new(metric_attributes::PARTITION_ID, "0")],
);
println!(" ✓ Recorded 5 counters, 5 histograms, and 1 gauge");
}
async fn demo_error_handling() {
let tracer = otel_global::tracer("demo");
let mut span = tracer
.span_builder("operation_with_error")
.with_kind(SpanKind::Internal)
.start(&tracer);
let error = std::io::Error::new(std::io::ErrorKind::Other, "Simulated error for demo");
record_exception(&mut span, &error);
println!(" ✓ Recorded exception in span");
}
async fn demo_async_operations() {
use processor::telemetry::propagate_context;
let tracer = otel_global::tracer("demo");
let span = tracer
.span_builder("async_parent")
.with_kind(SpanKind::Internal)
.start(&tracer);
let context = context_with_span(span);
let _guard = context.attach();
let mut handles = vec![];
for i in 0..3 {
let handle = tokio::spawn(propagate_context(async move {
let tracer = otel_global::tracer("demo");
let _span = tracer
.span_builder(format!("async_task_{}", i))
.with_kind(SpanKind::Internal)
.start(&tracer);
tokio::time::sleep(Duration::from_millis(20)).await;
}));
handles.push(handle);
}
for handle in handles {
handle.await.ok();
}
println!(" ✓ Spawned 3 async tasks with context propagation");
}
async fn demo_event_processing(recorder: &MetricsRecorder) {
let tracer = otel_global::tracer("demo");
for event_id in 0..5 {
let mut process_span = tracer
.span_builder("process_event")
.with_kind(SpanKind::Internal)
.with_attributes(vec![
OtelKeyValue::new("event.id", event_id.to_string()),
OtelKeyValue::new("event.type", "metric"),
])
.start(&tracer);
let process_context = context_with_span(process_span.clone());
let _process_guard = process_context.attach();
process_span.add_event("Event received".to_string(), vec![]);
{
let mut validate_span = tracer
.span_builder("validate_event")
.with_kind(SpanKind::Internal)
.start(&tracer);
tokio::time::sleep(Duration::from_millis(10)).await;
validate_span.add_event("Validation passed".to_string(), vec![]);
}
{
let mut process_span = tracer
.span_builder("process_data")
.with_kind(SpanKind::Internal)
.start(&tracer);
tokio::time::sleep(Duration::from_millis(20)).await;
process_span.add_event("Processing complete".to_string(), vec![]);
}
{
let mut state_span = tracer
.span_builder("update_state")
.with_kind(SpanKind::Internal)
.with_attributes(vec![OtelKeyValue::new(
metric_attributes::STATE_BACKEND,
"memory",
)])
.start(&tracer);
tokio::time::sleep(Duration::from_millis(5)).await;
state_span.add_event("State updated".to_string(), vec![]);
recorder.record_histogram(
"demo",
metric_names::STATE_OPERATION_DURATION,
5.0,
vec![
OtelKeyValue::new(metric_attributes::STATE_BACKEND, "memory"),
OtelKeyValue::new(metric_attributes::OPERATION_TYPE, "update"),
],
);
}
process_span.add_event("Event processing complete".to_string(), vec![]);
recorder.record_counter(
"demo",
metric_names::EVENTS_PROCESSED,
1,
vec![OtelKeyValue::new(metric_attributes::EVENT_TYPE, "metric")],
);
recorder.record_histogram(
"demo",
metric_names::PROCESSING_DURATION,
35.0,
vec![OtelKeyValue::new(
metric_attributes::OPERATION_TYPE,
"process",
)],
);
}
println!(" ✓ Processed 5 events with full telemetry");
}