use std::{
sync::{Arc, Mutex},
time::Duration,
};
use opentelemetry::{KeyValue, Value, global};
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::{
Resource,
metrics::{PeriodicReader, SdkMeterProvider},
};
use sysinfo::RefreshKind;
#[derive(Clone)]
pub struct MetricsConfig {
pub endpoint: String,
pub interval: Duration,
}
impl Default for MetricsConfig {
fn default() -> Self {
Self {
endpoint: String::from("https://limonen.click:5130/v1/metrics"),
interval: Duration::from_secs(30),
}
}
}
pub(crate) struct MetricsSdk;
impl MetricsSdk {
pub fn init(config: MetricsConfig) {
let exporter = opentelemetry_otlp::MetricExporter::builder()
.with_http()
.with_endpoint(config.endpoint)
.build()
.expect("opentelemetry exporter failed");
let reader = PeriodicReader::builder(exporter)
.with_interval(config.interval)
.build();
let provider = SdkMeterProvider::builder()
.with_resource(
Resource::builder()
.with_service_name(env!("CARGO_PKG_NAME"))
.build(),
)
.with_reader(reader)
.build();
global::set_meter_provider(provider);
#[cfg(feature = "sysinfo")]
Self::setup_system_metrics()
}
#[cfg(feature = "sysinfo")]
fn setup_system_metrics() {
let meter = global::meter("system.runtime");
let system = Arc::new(Mutex::new(sysinfo::System::new_with_specifics(
RefreshKind::everything().without_processes(),
)));
meter
.u64_observable_gauge("system.memory.usage")
.with_description("Amount of used RAM in KB")
.with_callback({
let system = Arc::clone(&system);
move |observer| {
let mut s = system.lock().unwrap();
s.refresh_memory();
observer.observe(s.used_memory(), &[]);
}
})
.build();
meter
.u64_observable_gauge("system.memory.total")
.with_description("Amount of total RAM in KB")
.with_callback({
let system = Arc::clone(&system);
move |observer| {
let mut s = system.lock().unwrap();
s.refresh_memory();
observer.observe(s.total_memory(), &[]);
}
})
.build();
meter
.f64_observable_gauge("system.cpu.usage")
.with_description("CPU load in percentage across all cores")
.with_callback({
let system = Arc::clone(&system);
move |observer| {
let mut s = system.lock().unwrap();
s.refresh_cpu_usage();
for (i, cpu) in s.cpus().iter().enumerate() {
observer.observe(
cpu.cpu_usage() as f64,
&[KeyValue::new("core", Value::I64(i as i64))],
);
}
}
})
.build();
}
}