Full-depth rename per the approved plan; the 'claw' product vocabulary (claws, /claws routes, clawId, Claw Chat) stays — it is now the brand. - Display brand: Clawmates (manifest, titles, hero, login/rail logo 'clawmates'); default host app.clawmates.work; registry ghcr.io/clawmates - Crates tc-* -> cm-* (16 crates + all imports); binaries clawmates-server/broker/bundler; images clawmates/*; env prefix CLAWMATES_* (+ CM_TEST_DATABASE_URL / CM_LIVE_LLM); config clawmates.toml; helm chart deploy/helm/clawmates with clawmates-* resources; db names clawmates*; sockets /run/clawmates; cookie cm_session; kind cluster clawmates-test; seccomp node profile clawmates-agent-profile.json - All 9 Playwright brand assertions updated in lockstep; historical spec document left untouched as the only remaining 'TeamClaw' - Local env migrated: dev pg clawmates-dev-pg/clawmates_dev, shared test server clawmates-test-pg, kind cluster recreated with image + profile, compose images rebuilt under clawmates/* Verified end to end: 161 Rust + 68 frontend tests, 29 Playwright journeys, 4 live kind tests, helm/install/LOC/placeholder gates, and the clean-room install rehearsal serving the clawmates login page from a signed bundle of the rebuilt images. Co-Authored-By: Claude Fable 5 <[email protected]>
93 lines
3.3 KiB
Rust
93 lines
3.3 KiB
Rust
//! Tracing setup (§16 NFR: observability). Always installs a fmt
|
|
//! subscriber honoring `RUST_LOG`; with an OTLP endpoint configured,
|
|
//! spans also export over OTLP/HTTP — to a collector shipped in the
|
|
//! air-gapped bundle or any cloud backend. No endpoint, no export, no
|
|
//! network: telemetry never phones home uninvited.
|
|
|
|
use opentelemetry::trace::TracerProvider as _;
|
|
use opentelemetry::KeyValue;
|
|
use opentelemetry_otlp::WithExportConfig;
|
|
use opentelemetry_sdk::trace::SdkTracerProvider;
|
|
use opentelemetry_sdk::Resource;
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
use tracing_subscriber::util::SubscriberInitExt;
|
|
use tracing_subscriber::{EnvFilter, Layer};
|
|
|
|
/// Keeps the exporter alive; dropping it flushes pending spans.
|
|
pub struct TelemetryGuard {
|
|
provider: Option<SdkTracerProvider>,
|
|
}
|
|
|
|
impl TelemetryGuard {
|
|
/// Forces all batched spans out — call before process exit (tests
|
|
/// call it to assert delivery).
|
|
pub fn flush(&self) {
|
|
if let Some(provider) = &self.provider {
|
|
let _ = provider.force_flush();
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for TelemetryGuard {
|
|
fn drop(&mut self) {
|
|
if let Some(provider) = self.provider.take() {
|
|
let _ = provider.force_flush();
|
|
let _ = provider.shutdown();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum TelemetryError {
|
|
#[error("otlp exporter: {0}")]
|
|
Exporter(String),
|
|
#[error("subscriber already installed")]
|
|
AlreadyInstalled,
|
|
}
|
|
|
|
/// Installs the global subscriber. `otlp_endpoint` is the collector's
|
|
/// OTLP/HTTP base (e.g. `http://otel-collector:4318`).
|
|
pub fn init(
|
|
service_name: &str,
|
|
otlp_endpoint: Option<&str>,
|
|
) -> Result<TelemetryGuard, TelemetryError> {
|
|
let fmt = tracing_subscriber::fmt::layer().with_target(false);
|
|
let filter = EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| EnvFilter::new("info,sqlx=warn,hyper=warn"));
|
|
|
|
match otlp_endpoint {
|
|
Some(endpoint) => {
|
|
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
|
.with_http()
|
|
.with_endpoint(format!("{}/v1/traces", endpoint.trim_end_matches('/')))
|
|
.build()
|
|
.map_err(|e| TelemetryError::Exporter(e.to_string()))?;
|
|
let provider = SdkTracerProvider::builder()
|
|
.with_batch_exporter(exporter)
|
|
.with_resource(
|
|
Resource::builder()
|
|
.with_attributes([KeyValue::new("service.name", service_name.to_owned())])
|
|
.build(),
|
|
)
|
|
.build();
|
|
let tracer = provider.tracer(service_name.to_owned());
|
|
let otel = tracing_opentelemetry::layer().with_tracer(tracer);
|
|
tracing_subscriber::registry()
|
|
.with(fmt.with_filter(filter))
|
|
.with(otel)
|
|
.try_init()
|
|
.map_err(|_| TelemetryError::AlreadyInstalled)?;
|
|
Ok(TelemetryGuard {
|
|
provider: Some(provider),
|
|
})
|
|
}
|
|
None => {
|
|
tracing_subscriber::registry()
|
|
.with(fmt.with_filter(filter))
|
|
.try_init()
|
|
.map_err(|_| TelemetryError::AlreadyInstalled)?;
|
|
Ok(TelemetryGuard { provider: None })
|
|
}
|
|
}
|
|
}
|