mockforge_tracing/
lib.rs

1//! OpenTelemetry tracing integration for MockForge
2//!
3//! This crate provides distributed tracing capabilities across all MockForge protocols
4//! (HTTP, gRPC, WebSocket, GraphQL) using OpenTelemetry and Jaeger.
5
6pub mod context;
7pub mod exporter;
8pub mod tracer;
9
10pub use context::{
11    extract_from_axum_headers, extract_trace_context, inject_into_axum_headers,
12    inject_trace_context, TraceContext,
13};
14pub use exporter::{
15    ExporterError, ExporterType, JaegerExporter, OtlpCompression, OtlpExporter, OtlpProtocol,
16};
17pub use tracer::{init_tracer, shutdown_tracer, TracingConfig};
18
19use opentelemetry::global::BoxedSpan;
20use opentelemetry::trace::{Span, SpanKind, Status, Tracer};
21use opentelemetry::{global, KeyValue};
22use std::time::SystemTime;
23
24/// Protocol types for tracing
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Protocol {
27    Http,
28    Grpc,
29    WebSocket,
30    GraphQL,
31}
32
33impl Protocol {
34    pub fn as_str(&self) -> &'static str {
35        match self {
36            Protocol::Http => "http",
37            Protocol::Grpc => "grpc",
38            Protocol::WebSocket => "websocket",
39            Protocol::GraphQL => "graphql",
40        }
41    }
42}
43
44/// Create a span for an incoming request
45pub fn create_request_span(
46    protocol: Protocol,
47    operation_name: &str,
48    attributes: Vec<KeyValue>,
49) -> BoxedSpan {
50    let tracer = global::tracer("mockforge");
51
52    let mut span = tracer
53        .span_builder(operation_name.to_string())
54        .with_kind(SpanKind::Server)
55        .with_start_time(SystemTime::now())
56        .with_attributes(attributes)
57        .start(&tracer);
58
59    // Add protocol attribute
60    span.set_attribute(KeyValue::new("mockforge.protocol", protocol.as_str()));
61
62    span
63}
64
65/// Record span success with optional attributes
66pub fn record_success(span: &mut BoxedSpan, attributes: Vec<KeyValue>) {
67    for attr in attributes {
68        span.set_attribute(attr);
69    }
70    span.set_status(Status::Ok);
71}
72
73/// Record span error
74pub fn record_error(span: &mut BoxedSpan, error_message: &str) {
75    span.set_status(Status::error(error_message.to_string()));
76    span.set_attribute(KeyValue::new("error", true));
77    span.set_attribute(KeyValue::new("error.message", error_message.to_string()));
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_protocol_as_str() {
86        assert_eq!(Protocol::Http.as_str(), "http");
87        assert_eq!(Protocol::Grpc.as_str(), "grpc");
88        assert_eq!(Protocol::WebSocket.as_str(), "websocket");
89        assert_eq!(Protocol::GraphQL.as_str(), "graphql");
90    }
91}