Skip to main content

turbomcp_telemetry/
lib.rs

1//! OpenTelemetry integration and observability for TurboMCP SDK
2//!
3//! This crate provides comprehensive telemetry capabilities for MCP servers and clients:
4//!
5//! - **Distributed Tracing**: OpenTelemetry traces with MCP-specific span attributes
6//! - **Metrics Collection**: Request counts, latencies, error rates with Prometheus export
7//! - **Structured Logging**: JSON-formatted logs correlated with traces
8//! - **Tower Middleware**: Automatic instrumentation for MCP request handling
9//!
10//! # Quick Start
11//!
12//! ```rust,ignore
13//! use turbomcp_telemetry::{TelemetryConfig, TelemetryGuard};
14//!
15//! #[tokio::main]
16//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
17//!     // Initialize telemetry with OTLP export
18//!     let config = TelemetryConfig::builder()
19//!         .service_name("my-mcp-server")
20//!         .otlp_endpoint("http://localhost:4317")
21//!         .build();
22//!
23//!     let _guard = config.init()?;
24//!
25//!     // Your MCP server code here...
26//!     Ok(())
27//! }
28//! ```
29//!
30//! # Feature Flags
31//!
32//! - `opentelemetry` - Full OpenTelemetry integration with OTLP export
33//! - `prometheus` - Standalone Prometheus metrics (without OpenTelemetry)
34//! - `tower` - Tower middleware for automatic request instrumentation
35//! - `full` - All features enabled
36//!
37//! # Architecture
38//!
39//! ```text
40//! ┌─────────────────────────────────────────────────────────────┐
41//! │                    TurboMCP Application                      │
42//! ├─────────────────────────────────────────────────────────────┤
43//! │  TelemetryLayer (Tower Middleware)                          │
44//! │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
45//! │  │   Tracing   │  │   Metrics   │  │  Context Propagation │ │
46//! │  └─────────────┘  └─────────────┘  └─────────────────────┘ │
47//! ├─────────────────────────────────────────────────────────────┤
48//! │                    Export Layer                              │
49//! │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
50//! │  │    OTLP     │  │ Prometheus  │  │       Stdout        │ │
51//! │  └─────────────┘  └─────────────┘  └─────────────────────┘ │
52//! └─────────────────────────────────────────────────────────────┘
53//! ```
54
55#![cfg_attr(docsrs, feature(doc_cfg))]
56// Allow missing error/panic docs - telemetry errors are self-documenting through TelemetryError type
57#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
58
59mod config;
60mod error;
61mod init;
62
63pub mod attributes;
64
65#[cfg(feature = "tower")]
66#[cfg_attr(docsrs, doc(cfg(feature = "tower")))]
67pub mod tower;
68
69#[cfg(feature = "prometheus")]
70#[cfg_attr(docsrs, doc(cfg(feature = "prometheus")))]
71pub mod metrics;
72
73// Re-exports
74pub use config::{TelemetryConfig, TelemetryConfigBuilder};
75pub use error::{TelemetryError, TelemetryResult};
76pub use init::TelemetryGuard;
77
78// Re-export tracing macros for convenience
79pub use tracing::{Instrument, instrument};
80pub use tracing::{debug, error, info, trace, warn};
81pub use tracing::{debug_span, error_span, info_span, trace_span, warn_span};
82
83/// MCP span attribute keys following OpenTelemetry semantic conventions
84pub mod span_attributes {
85    /// MCP method name (e.g., "tools/call", "resources/read")
86    pub const MCP_METHOD: &str = "mcp.method";
87    /// Tool name for tools/call requests
88    pub const MCP_TOOL_NAME: &str = "mcp.tool.name";
89    /// Resource URI for resources/read requests
90    pub const MCP_RESOURCE_URI: &str = "mcp.resource.uri";
91    /// Prompt name for prompts/get requests
92    pub const MCP_PROMPT_NAME: &str = "mcp.prompt.name";
93    /// JSON-RPC request ID
94    pub const MCP_REQUEST_ID: &str = "mcp.request.id";
95    /// MCP session ID
96    pub const MCP_SESSION_ID: &str = "mcp.session.id";
97    /// Client implementation name
98    pub const MCP_CLIENT_NAME: &str = "mcp.client.name";
99    /// Client implementation version
100    pub const MCP_CLIENT_VERSION: &str = "mcp.client.version";
101    /// Server implementation name
102    pub const MCP_SERVER_NAME: &str = "mcp.server.name";
103    /// Server implementation version
104    pub const MCP_SERVER_VERSION: &str = "mcp.server.version";
105    /// Transport type (stdio, http, websocket, tcp, unix)
106    pub const MCP_TRANSPORT: &str = "mcp.transport";
107    /// Protocol version
108    pub const MCP_PROTOCOL_VERSION: &str = "mcp.protocol.version";
109    /// Tenant ID for multi-tenant deployments
110    pub const MCP_TENANT_ID: &str = "mcp.tenant.id";
111    /// User ID from authentication
112    pub const MCP_USER_ID: &str = "mcp.user.id";
113    /// Request duration in milliseconds
114    pub const MCP_DURATION_MS: &str = "mcp.duration_ms";
115    /// Response status (success, error)
116    pub const MCP_STATUS: &str = "mcp.status";
117    /// Error code if request failed
118    pub const MCP_ERROR_CODE: &str = "mcp.error.code";
119    /// Error message if request failed
120    pub const MCP_ERROR_MESSAGE: &str = "mcp.error.message";
121}
122
123/// Prelude module for convenient imports
124pub mod prelude {
125    pub use super::config::{TelemetryConfig, TelemetryConfigBuilder};
126    pub use super::error::{TelemetryError, TelemetryResult};
127    pub use super::init::TelemetryGuard;
128    pub use super::span_attributes;
129    pub use tracing::{Instrument, debug, error, info, instrument, trace, warn};
130
131    #[cfg(feature = "tower")]
132    pub use super::tower::{TelemetryLayer, TelemetryLayerConfig};
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_span_attributes_defined() {
141        // Verify all span attributes are properly defined
142        assert_eq!(span_attributes::MCP_METHOD, "mcp.method");
143        assert_eq!(span_attributes::MCP_TOOL_NAME, "mcp.tool.name");
144        assert_eq!(span_attributes::MCP_RESOURCE_URI, "mcp.resource.uri");
145        assert_eq!(span_attributes::MCP_SESSION_ID, "mcp.session.id");
146        assert_eq!(span_attributes::MCP_TRANSPORT, "mcp.transport");
147    }
148}