pub mod context;
pub mod metrics;
pub mod resource;
pub mod tracing;
pub use context::{
extract_context, extract_from_headers, inject_context, inject_into_headers,
context_with_span, get_baggage, propagate_context, with_baggage, with_context,
BaggageItem, HeaderCarrier,
};
pub use metrics::{
init_meter_provider, shutdown_meter_provider, metric_attributes, metric_names,
ExportConfig, MetricsConfig, MetricsRecorder, Temporality,
};
pub use resource::{create_processor_resource, ResourceBuilder};
pub use tracing::{
init_tracer_provider, record_exception, shutdown_tracer_provider, BatchConfiguration,
OtlpProtocol, SamplingStrategy, SpanBuilder, TraceConfig,
};
pub use opentelemetry::{
global,
trace::{Span, SpanKind, Status, Tracer},
Context, KeyValue,
};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TelemetryConfig {
pub tracing: TraceConfig,
pub metrics: MetricsConfig,
}
impl Default for TelemetryConfig {
fn default() -> Self {
Self {
tracing: TraceConfig::default(),
metrics: MetricsConfig::default(),
}
}
}
impl TelemetryConfig {
pub fn new(service_name: impl Into<String>) -> Self {
let service_name = service_name.into();
Self {
tracing: TraceConfig {
service_name: service_name.clone(),
..Default::default()
},
metrics: MetricsConfig {
service_name,
..Default::default()
},
}
}
pub fn with_otlp_endpoint(mut self, endpoint: impl Into<String>) -> Self {
let endpoint = endpoint.into();
self.tracing.otlp_endpoint = endpoint.clone();
self.metrics.otlp_endpoint = endpoint;
self
}
pub fn with_service_version(mut self, version: impl Into<String>) -> Self {
let version = version.into();
self.tracing.service_version = version.clone();
self.metrics.service_version = version;
self
}
pub fn with_environment(mut self, env: impl Into<String>) -> Self {
let env = Some(env.into());
self.tracing.environment = env.clone();
self.metrics.environment = env;
self
}
pub fn with_tracing_enabled(mut self, enabled: bool) -> Self {
self.tracing.enabled = enabled;
self
}
pub fn with_metrics_enabled(mut self, enabled: bool) -> Self {
self.metrics.enabled = enabled;
self
}
}
pub fn init_telemetry(
config: TelemetryConfig,
) -> Result<TelemetryProviders, Box<dyn std::error::Error>> {
let tracer_provider = if config.tracing.enabled {
Some(init_tracer_provider(config.tracing)?)
} else {
None
};
let meter_provider = if config.metrics.enabled {
Some(init_meter_provider(config.metrics)?)
} else {
None
};
Ok(TelemetryProviders {
tracer_provider,
meter_provider,
})
}
pub struct TelemetryProviders {
pub tracer_provider: Option<opentelemetry_sdk::trace::TracerProvider>,
pub meter_provider: Option<opentelemetry_sdk::metrics::SdkMeterProvider>,
}
impl TelemetryProviders {
pub async fn shutdown(self) -> Result<(), Box<dyn std::error::Error>> {
if let Some(_provider) = self.tracer_provider {
shutdown_tracer_provider().await;
}
if let Some(_provider) = self.meter_provider {
shutdown_meter_provider()?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_telemetry_config_default() {
let config = TelemetryConfig::default();
assert!(config.tracing.enabled);
assert!(config.metrics.enabled);
}
#[test]
fn test_telemetry_config_new() {
let config = TelemetryConfig::new("test-service");
assert_eq!(config.tracing.service_name, "test-service");
assert_eq!(config.metrics.service_name, "test-service");
}
#[test]
fn test_telemetry_config_builder() {
let config = TelemetryConfig::new("test-service")
.with_otlp_endpoint("http://collector:4317")
.with_service_version("1.0.0")
.with_environment("production")
.with_tracing_enabled(true)
.with_metrics_enabled(false);
assert_eq!(config.tracing.otlp_endpoint, "http://collector:4317");
assert_eq!(config.metrics.otlp_endpoint, "http://collector:4317");
assert_eq!(config.tracing.service_version, "1.0.0");
assert_eq!(config.metrics.service_version, "1.0.0");
assert_eq!(
config.tracing.environment,
Some("production".to_string())
);
assert_eq!(
config.metrics.environment,
Some("production".to_string())
);
assert!(config.tracing.enabled);
assert!(!config.metrics.enabled);
}
#[test]
fn test_telemetry_config_serialization() {
let config = TelemetryConfig::new("test");
let json = serde_json::to_string(&config).unwrap();
let deserialized: TelemetryConfig = serde_json::from_str(&json).unwrap();
assert_eq!(config.tracing.service_name, deserialized.tracing.service_name);
assert_eq!(config.metrics.service_name, deserialized.metrics.service_name);
}
}