spectra (uf-spectra)
Typed metrics, structured event logs, and pluggable storage for Rust services. Depend on this as the primary crate; enable backend features explicitly on your dependency. At boot wire Spectra::builder() and use the prelude re-exports.
Role
- Re-exports
spectra-core,spectra-runtime, and feature-gated backends default = ["mem"]; optionalsqlite,tensorbase,clickhouse,telemetry-console- CI demo schemas (
platform_smoke_*) register via inventory; macros emit typed helpers and topics in linked modules
Configuration
Spectra has no global config file loader. Settings merge in this order (highest wins):
- Explicit builder calls —
.config(SpectraConfig { ... }),.sink(...),.persist_disabled(), backend constructors SpectraConfig— programmatic overrides passed to.config()- Environment variables — read by
SpectraConfig::from_env()when.config()is omitted - Schema defaults — per-metric/event levels and sample rates from the DSL
- Library defaults — documented below
Cargo features
Enable backends at compile time on your spectra dependency. See the root README.
Builder composition
| Wiring | Calls | Role |
|---|---|---|
| Direct persist (default) | .metrics_backend(..).events_backend(..).build() |
Emit process writes storage |
| Dual-path | .sink(transport).build() |
Bus mirror + local persist |
| Publish only (publish-consume) | .sink(transport).persist_disabled().build() |
Publisher — consumers write storage |
Publisher/consumer setup: cargo doc -p uf-spectra --open → Getting started → Publish-consume, then
SpectraSink, topics, and examples quickstart_publish_only /
quickstart_consume_forward.
Emit gate and sampling
Loaded by SpectraConfig::from_env() unless .config(...) overrides.
| Variable | Default | Effect |
|---|---|---|
SPECTRA_GATE |
on | Request disable with 0/false/no (ignored unless force-off is set) |
SPECTRA_GATE_FORCE_OFF |
unset | Set 1/true/yes with SPECTRA_GATE=0 to actually disable the emit gate |
SPECTRA_LEVEL |
info |
Global minimum verbosity (error … trace) |
SPECTRA_SAMPLE_RATE |
1.0 |
Global sample floor after level check |
SPECTRA_SAMPLE_<NAME> |
— | Per metric/event name override (0.0–1.0) |
SPECTRA_CONFIG |
— | Path to TOML file with a [spectra] table |
SPECTRA_ALLOW_INSECURE_REMOTE |
unset | Opt-in for plaintext http:// / tcp:// remote URLs (dev/CI only). Prefer https:// / tcp+tls://. |
Event query paging is clamped in-library (MAX_EVENT_QUERY_LIMIT = 1000). Metric/table/field identifiers must match validate_spectra_ident. See repository SECURITY.md.
Emit buffer (embedded profile)
| Variable | Default | Effect |
|---|---|---|
SPECTRA_REQUEST_BUFFER |
on | Buffer emits for web request scopes |
SPECTRA_JOB_BUFFER |
on | Buffer emits for worker scopes |
SPECTRA_COUNTER_AGGREGATE |
on | Coalesce counter deltas while buffering |
Set any of these to 0/false/no to disable.
Web note: prefer try_record_*_now / generated helpers (L2 enqueue) over request_scope.
request_scope drops undrained emits on panic or early exit — avoid if you need failure telemetry.
Async storage persist (builder)
Configure L2 queue/batch on Spectra::builder() — not environment variables:
use Duration;
use ;
builder
// …backends…
.persist
.build?;
| Field | Default | Role |
|---|---|---|
queue_max |
8192 | Bound L2 mpsc; see overflow |
overflow |
Drop |
Drop (lossy, default) or Block (backpressure) |
batch_max |
32 | Max jobs per batch insert |
batch_wait |
5ms | Coalesce delay when batch still size 1 |
batch_enabled |
true | Use record_*_batch APIs |
After fire-and-forget *_now emits, scripts that need durability before exit call
spectra.flush_persist().await.
Telemetry console (telemetry-console feature)
| Variable | Default | Effect |
|---|---|---|
SPECTRA_CONSOLE |
off | Mirror safe fields to stderr |
SPECTRA_SYNC_HOT_PATH |
off | Invoke transport sink on emit thread |
Use .telemetry_ndjson(dir) on the builder to write {dir}/metrics.ndjson and {dir}/events.ndjson.
Remote backends
| Variable | Used by |
|---|---|
SPECTRA_TENSORBASE_URL |
tensorbase feature — integration tests and adapters |
SPECTRA_CLICKHOUSE_URL |
clickhouse feature — integration tests and adapters |
SPECTRA_ALLOW_INSECURE_REMOTE |
Opt-in for plaintext http:// / tcp:// (dev/CI only; prefer https:// / tcp+tls://) |
Debug
| Variable | Effect |
|---|---|
COUNTER_ROOTCAUSE |
Enable internal persist-path counters (debugging) |
Backend wiring
In-memory (default)
use ;
let _spectra = builder
.metrics_backend
.events_backend
.embedded
.build?;
SQLite (durable embedded)
use ;
let metrics = new?;
let events = new?;
let _spectra = builder
.metrics_backend
.events_backend
.embedded
.build?;
Requires features = ["sqlite"].
Remote (ClickHouse / TensorBase)
See spectra-backend-clickhouse/README.md and spectra-backend-tensorbase/README.md.
Schema collection
Your application owns telemetry DSL modules and links them with an explicit mod list.
This repository demonstrates the contract with CI demo schemas under schemas/ and re-exports
smoke helpers and topics from those expansions.
How to run examples
Navigational index: examples/README.md (when-to-use ladder + links to each .rs file).
Canonical teaching path (start here). Topology docs: Direct persist / Publish-consume / Dual-path.
1. Embedded + schema emit — quickstart_schema_emit (standalone)
One process, in-memory store, typed helpers + query. No external services.
Success: stderr prints schema emit OK: … metric point(s) persisted.
2. Publish-consume (two binaries)
Publisher and consumer are separate binaries in production. Spectra does not ship a
message bus; your host owns that piece. The bus_* examples use a TCP JSON-lines adapter so
you can run a real process boundary without Photon. Replace TcpJsonSink / the listener with
your bus (Photon, NATS, …) in production.
| Rule | Detail |
|---|---|
| Shared schemas | Same spectra_*! modules (mod-linked) on publisher and consumer |
| Start order | Consumer first, then publisher |
| Publishers | .sink(...).persist_disabled() |
| Consumers | Own storage (persist on); decode → try_record_*_at / try_log_event_at |
# Terminal 1 — consumer
# Terminal 2 — publisher
Success: bus-consume OK: … metric point(s) in storage.
In-process sketches (no TCP): quickstart_publish_only, quickstart_consume_forward.
ClickHouse dual-path (sink + remote persist in one process):
3. Remote storage — quickstart_clickhouse_emit (standalone)
Direct persist into ClickHouse. Requires a live ClickHouse (Docker Compose below).
# local plaintext only
Success: stderr prints clickhouse emit OK: … metric point(s), … event row(s).
Other examples
| Example | Topology | Features | Notes |
|---|---|---|---|
quickstart |
Direct persist | mem |
Minimal boot + tracing_subscriber |
quickstart_sqlite |
Direct persist | sqlite |
Durable embedded wiring |
quickstart_transport |
Dual-path | mem |
Sink + persist in one process |
clickhouse_dual_path |
Dual-path (remote) | clickhouse |
RecordingSink + ClickHouse |
query_and_pii_console |
Direct persist | mem |
Query + mask_field_value |
custom_backend_stub |
Direct persist | mem |
Custom storage trait stub |
quickstart_telemetry |
Direct persist | mem,telemetry-console |
NDJSON under a temp dir |
quickstart_tensorbase_emit |
Direct persist (remote) | tensorbase |
Needs SPECTRA_TENSORBASE_URL |
quickstart_publish_only / quickstart_consume_forward |
Publish-consume sketches | mem |
No process boundary |
Status
Shipped in tag v0.1.0.