mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-14 20:56:49 +00:00
feat(metrics): Record metrics with OpenTelemetry and export over OTLP
This commit is contained in:
1 parent
e96b6e6665
commit
5185045cb6
33 files changed
+1118
-455
No files matched your search
+2
-4
@@ -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
|
||||
|
||||
@@ -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) = ®istry {
|
||||
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))
|
||||
}
|
||||
@@ -9,6 +9,7 @@ conduwuit_macros::introspect_crate! {}
|
||||
mod clap;
|
||||
mod deadlock;
|
||||
mod logging;
|
||||
mod metrics;
|
||||
mod mods;
|
||||
mod panic;
|
||||
mod restart;
|
||||
|
||||
+12
-4
@@ -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,
|
||||
|
||||
|
||||
Reference in new issue
Block a user