feat(telemetry): report process memory and process and host uptime

This commit is contained in:
lda committed 2026-10-12 16:28:21 +07:00 Verified
1 parent b98b8717d1
commit 4a4acedbc3
16 files changed
+311 -8

No files matched your search

+17
View File
@@ -43,9 +43,23 @@ pub struct TelemetryGuard {
traces: Option<SdkTracerProvider>,
logs: Option<SdkLoggerProvider>,
metrics: Option<SdkMeterProvider>,
process: Option<process::ProcessMetrics>,
}
impl TelemetryGuard {
/// Attach platform measurements only when OTLP metrics are enabled. Core
/// owns instruments; the supplied reader owns all OS-specific collection.
pub fn with_process_metrics(mut self, source: impl ProcessMetricsSource) -> Self {
if let Some(metrics) = &self.metrics {
use opentelemetry::metrics::MeterProvider as _;
self.process = Some(process::ProcessMetrics::new(
&metrics.meter("wakey"),
source,
));
}
self
}
pub fn shutdown(self) {
// Export failures must not turn an otherwise successful daemon exit into a failure.
if let Some(provider) = self.metrics {
@@ -198,6 +212,7 @@ pub fn init(
traces: Some(traces),
logs: Some(logs),
metrics: Some(metrics),
process: None,
};
} else if config.json_logs {
tracing_subscriber::registry()
@@ -292,7 +307,9 @@ fn local_timer() -> fmt::time::OffsetTime<time::format_description::well_known::
// therefore does no per-PTY-read allocations or instrument registration.
static METRICS: OnceLock<Instruments> = OnceLock::new();
mod fleet;
mod process;
pub use fleet::{AgentDeviceCounts, FleetCounts, FleetMetrics};
pub use process::ProcessMetricsSource;
struct Instruments {
operations: opentelemetry::metrics::Counter<u64>,
duration: opentelemetry::metrics::Histogram<f64>,
+66
View File
@@ -0,0 +1,66 @@
//! OS-independent process/host instruments. Callers supply a platform reader.
//! Failed reads omit a sample: zero must not masquerade as a restart or freed RAM.
use opentelemetry::metrics::{Meter, ObservableGauge};
use std::sync::Arc;
/// Values are seconds/bytes, or None when unsupported/unavailable. Readers run
/// on the metric collection thread: keep work small and local, never perform
/// network requests or emit exporter-directed logs from these callbacks.
pub trait ProcessMetricsSource: Send + Sync + 'static {
fn process_uptime_seconds(&self) -> Option<f64>;
fn resident_memory_bytes(&self) -> Option<u64>;
fn host_uptime_seconds(&self) -> Option<f64>;
}
pub(super) struct ProcessMetrics {
_uptime: ObservableGauge<f64>,
_resident: ObservableGauge<u64>,
_host_uptime: ObservableGauge<f64>,
}
impl ProcessMetrics {
pub(super) fn new(meter: &Meter, source: impl ProcessMetricsSource) -> Self {
let source = Arc::new(source);
let uptime = source.clone();
let resident = source.clone();
Self {
_uptime: meter
.f64_observable_gauge("wakey.process.uptime")
.with_unit("s")
.with_description("Process age reported by the platform reader")
.with_callback(move |observer| {
if let Some(seconds) = uptime.process_uptime_seconds()
&& seconds.is_finite()
&& seconds >= 0.0
{
observer.observe(seconds, &[]);
}
})
.build(),
_resident: meter
.u64_observable_gauge("wakey.process.memory.resident")
.with_unit("By")
.with_description("Resident process memory reported by the platform reader")
.with_callback(move |observer| {
if let Some(bytes) = resident.resident_memory_bytes() {
observer.observe(bytes, &[]);
}
})
.build(),
_host_uptime: meter
.f64_observable_gauge("wakey.host.uptime")
.with_unit("s")
.with_description("Host uptime reported by the platform reader")
.with_callback(move |observer| {
if let Some(seconds) = source.host_uptime_seconds()
&& seconds.is_finite()
&& seconds >= 0.0
{
observer.observe(seconds, &[]);
}
})
.build(),
}
}
}