feat(metrics): Record metrics with OpenTelemetry and export over OTLP

This commit is contained in:
Erwan Leboucher authored and Jade Ellis committed 2026-10-12 10:03:14 +01:00
1 parent e96b6e6665
commit 5185045cb6
33 files changed
+1118 -455

No files matched your search

+2 -4
View File
@@ -131,9 +131,7 @@ media_thumbnail = [
"conduwuit-service/media_thumbnail",
]
otlp_telemetry = [
"dep:opentelemetry",
"dep:tracing-opentelemetry",
"dep:opentelemetry_sdk",
"dep:opentelemetry-otlp",
]
perf_measurements = [
@@ -221,12 +219,12 @@ console-subscriber.optional = true
console-subscriber.workspace = true
const-str.workspace = true
log.workspace = true
opentelemetry.optional = true
opentelemetry.workspace = true
opentelemetry-otlp.optional = true
opentelemetry-otlp.workspace = true
opentelemetry_sdk.optional = true
opentelemetry-prometheus.workspace = true
opentelemetry_sdk.workspace = true
prometheus.workspace = true
sentry-tower.optional = true
sentry-tower.workspace = true
sentry-tracing.optional = true
+76
View File
@@ -0,0 +1,76 @@
use conduwuit_core::{Result, config::Config, err, metrics::Metrics};
use opentelemetry::{KeyValue, metrics::MeterProvider};
use opentelemetry_sdk::{
Resource,
metrics::SdkMeterProvider,
resource::{EnvResourceDetector, TelemetryResourceDetector},
};
use tokio::runtime;
/// The returned provider must outlive the server so pending OTLP exports are
/// flushed on drop.
pub(crate) fn init(
config: &Config,
runtime: Option<&runtime::Handle>,
) -> Result<(Metrics, SdkMeterProvider)> {
// Defaults first so OTEL_RESOURCE_ATTRIBUTES and OTEL_SERVICE_NAME win.
let mut resource = Resource::builder_empty()
.with_detector(Box::new(TelemetryResourceDetector))
.with_service_name(conduwuit_core::BRANDING)
.with_attributes([
KeyValue::new("service.version", conduwuit_core::version()),
KeyValue::new("service.instance.id", config.server_name.to_string()),
])
.with_detector(Box::new(EnvResourceDetector::new()));
if let Some(name) = std::env::var("OTEL_SERVICE_NAME")
.ok()
.filter(|name| !name.is_empty())
{
resource = resource.with_service_name(name);
}
let resource = resource.build();
let mut builder = SdkMeterProvider::builder().with_resource(resource);
let registry = config
.allow_prometheus_metrics
.then(prometheus::Registry::new);
if let Some(registry) = &registry {
let exporter = opentelemetry_prometheus::exporter()
.with_registry(registry.clone())
.scope_info_enabled(false)
.build()
.map_err(|e| err!(Config("allow_prometheus_metrics", "{e}")))?;
builder = builder.with_reader(exporter);
}
#[cfg(feature = "otlp_telemetry")]
if config.allow_otlp_metrics {
use opentelemetry_otlp::{MetricExporter, Protocol, WithExportConfig};
let exporter = match config.otlp_protocol.as_str() {
| "grpc" => MetricExporter::builder()
.with_tonic()
.with_protocol(Protocol::Grpc)
.build(),
| _ => MetricExporter::builder().with_http().build(),
}
.map_err(|e| err!(Config("allow_otlp_metrics", "{e}")))?;
builder = builder.with_periodic_exporter(exporter);
}
#[cfg(not(feature = "otlp_telemetry"))]
if config.allow_otlp_metrics {
conduwuit_core::warn!(
"allow_otlp_metrics is set but this build does not include the otlp_telemetry \
feature"
);
}
let provider = builder.build();
let meter = provider.meter(conduwuit_core::BRANDING);
Ok((Metrics::new(runtime.cloned(), meter, registry), provider))
}
+1
View File
@@ -9,6 +9,7 @@ conduwuit_macros::introspect_crate! {}
mod clap;
mod deadlock;
mod logging;
mod metrics;
mod mods;
mod panic;
mod restart;
+12 -4
View File
@@ -23,6 +23,8 @@ pub(crate) struct Server {
_tracing_flame_guard: TracingFlameGuard,
_meter_provider: opentelemetry_sdk::metrics::SdkMeterProvider,
#[cfg(feature = "sentry_telemetry")]
_sentry_guard: Option<::sentry::ClientInitGuard>,
@@ -56,6 +58,8 @@ impl Server {
sys::maximize_fd_limit()
.expect("Unable to increase maximum soft and hard file descriptor limit");
let (metrics, meter_provider) = crate::metrics::init(&config, runtime)?;
let (_old_width, _new_width) = stream::set_width(config.stream_width_default);
let (_old_amp, _new_amp) = stream::set_amplification(config.stream_amplification);
@@ -68,15 +72,19 @@ impl Server {
);
Ok(Arc::new(Self {
server: Arc::new(conduwuit_core::Server::new(config, runtime.cloned(), Log {
reload: tracing_reload_handle,
capture,
})),
server: Arc::new(conduwuit_core::Server::new(
config,
runtime.cloned(),
Log { reload: tracing_reload_handle, capture },
metrics,
)),
services: None.into(),
_tracing_flame_guard: tracing_flame_guard,
_meter_provider: meter_provider,
#[cfg(feature = "sentry_telemetry")]
_sentry_guard: sentry_guard,