chore: add loadtest observability setup
This commit is contained in:
75
server-rs/crates/spacetime-client/src/telemetry.rs
Normal file
75
server-rs/crates/spacetime-client/src/telemetry.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use opentelemetry::{KeyValue, global, metrics::Counter};
|
||||
|
||||
use crate::SpacetimeClientError;
|
||||
|
||||
// SpacetimeDB procedure 指标只使用 procedure / status_class 等低基数字段,避免把用户或作品 ID 写进指标标签。
|
||||
pub(crate) struct ProcedureMetricsGuard {
|
||||
procedure: &'static str,
|
||||
started_at: std::time::Instant,
|
||||
}
|
||||
|
||||
pub(crate) fn begin_procedure(procedure: &'static str) -> ProcedureMetricsGuard {
|
||||
ProcedureMetricsGuard {
|
||||
procedure,
|
||||
started_at: std::time::Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcedureMetricsGuard {
|
||||
pub(crate) fn finish<T>(&self, result: &Result<T, SpacetimeClientError>) {
|
||||
let duration = self.started_at.elapsed();
|
||||
record_procedure(self.procedure, duration, result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
struct SpacetimeMetrics {
|
||||
calls: Counter<u64>,
|
||||
errors: Counter<u64>,
|
||||
duration_ms: opentelemetry::metrics::Histogram<f64>,
|
||||
}
|
||||
|
||||
fn spacetime_metrics() -> &'static SpacetimeMetrics {
|
||||
static METRICS: std::sync::OnceLock<SpacetimeMetrics> = std::sync::OnceLock::new();
|
||||
METRICS.get_or_init(|| {
|
||||
let meter = global::meter("genarrative-spacetime-client");
|
||||
SpacetimeMetrics {
|
||||
calls: meter
|
||||
.u64_counter("genarrative.spacetime.procedure.calls")
|
||||
.with_description("SpacetimeDB procedure call count")
|
||||
.build(),
|
||||
errors: meter
|
||||
.u64_counter("genarrative.spacetime.procedure.errors")
|
||||
.with_description("SpacetimeDB procedure error count")
|
||||
.build(),
|
||||
duration_ms: meter
|
||||
.f64_histogram("genarrative.spacetime.procedure.duration_ms")
|
||||
.with_unit("ms")
|
||||
.with_description("SpacetimeDB procedure duration in milliseconds")
|
||||
.build(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn record_procedure(
|
||||
procedure: &'static str,
|
||||
duration: Duration,
|
||||
failed: bool,
|
||||
) {
|
||||
let labels = vec![
|
||||
KeyValue::new("procedure", procedure),
|
||||
KeyValue::new(
|
||||
"status_class",
|
||||
if failed { "error" } else { "ok" },
|
||||
),
|
||||
];
|
||||
let metrics = spacetime_metrics();
|
||||
metrics.calls.add(1, &labels);
|
||||
metrics
|
||||
.duration_ms
|
||||
.record(duration.as_secs_f64() * 1000.0, &labels);
|
||||
if failed {
|
||||
metrics.errors.add(1, &labels);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user