greentic-telemetry
Tenant-aware telemetry utilities for Greentic services built on top of tracing and opentelemetry.
Highlights
TelemetryCtx: lightweight context carrying{tenant, session, flow, node, provider}.layer_from_task_local: grab the context from a Tokio task-local without wiring closures.CtxLayer(layer_with): legacy closure-based path kept for backwards compatibility.init_telemetry_auto: env/preset-driven setup (OTLP gRPC/HTTP with headers/compression/sampling) or stdout fallback.- Utilities for integration testing (
testutil::span_recorder) and task-local helpers.
Quickstart (auto-config)
use ;
async
OTLP wiring
init_telemetry_auto installs a tracing subscriber composed of:
tracing_opentelemetry::layerconnected to an OTLP exporter (gRPC or HTTP, based on env)- Optional gzip compression, headers, and sampling wired from env/preset config
service.namepopulated fromTelemetryConfig
The subscriber becomes the global default; use opentelemetry::global::shutdown_tracer_provider() during graceful shutdown to flush spans. The legacy init_otlp path has been removed; use init_telemetry_auto.
Config-first init (authoritative)
If you resolve telemetry settings via greentic-config (or any other loader), pass them directly to the config-based initializer. No env/preset merging occurs inside greentic-telemetry.
use ;
use HashMap;
let export = ExportConfig ;
init_telemetry_from_config?;
When you call init_telemetry_from_config, the crate does not read environment variables for telemetry; the provided config is authoritative. Keep init_telemetry_auto around only for legacy env-driven flows.
Secrets attribute contract (telemetry)
- Attribute keys (never store secret values):
secrets.op,secrets.key,secrets.scope.env,secrets.scope.tenant,secrets.scope.team(optional),secrets.result,secrets.error_kind(optional, structured likehost_error,io,policy,serde). - Allowed values:
secrets.op:get | put | delete | listsecrets.result:ok | not_found | denied | invalid | errorsecrets.key: the logical secret key (string), never bytes.
- Redaction is global for logs and OTLP export: any fields named like
secret,token,api_key,authorization,password,client_secret,access_token,refresh_token,bearer,x-api-key(case-insensitive) are masked. Bearer tokens under auth-ish keys are replaced withBearer [REDACTED]. No sizes/hashes/previews are emitted. - Helper to avoid stringly-typed attrs:
use ;
let span = secret_span;
let _enter = span.enter;
record_secret_attrs;
WASM guest/host bridge
- Guest side (
wasm32): usegreentic_telemetry::wasm_guest::{log, span_start, span_end}to emit logs/spans; falls back to stdout when not on wasm. - Host side: use
greentic_telemetry::wasm_host::{log, span_start, span_end}to forward guest events into the native tracing pipeline; spans/events are tagged withruntime=wasm. - Minimal host integration example:
use ;
See src/wasm_guest.rs, src/wasm_host.rs, and wit/greentic-telemetry.wit for details.
Upgrading from legacy init_otlp
- Replace calls to
init_otlpwithinit_telemetry_auto(TelemetryConfig { service_name }). - Set export behaviour via env:
TELEMETRY_EXPORT,OTLP_ENDPOINT,OTLP_HEADERS,TELEMETRY_SAMPLING,OTLP_COMPRESSION. - If you previously layered
layer_from_task_local, continue to do so when building your subscriber or pass it ininit_telemetryas an extra layer. - Remove any direct dependencies on
OtlpConfig/TelemetryError; these types are no longer exported.
Testing utilities
testutil::span_recorder() returns a (CaptureLayer, Arc<Mutex<Vec<RecordedSpan>>>) pair for asserting that spans carry TelemetryCtx. See tests/context_propagation.rs for an end-to-end example exercising propagation across nested spans.
Dev Elastic bundle
A ready-to-run Elastic/Kibana/OpenTelemetry Collector stack lives in dev/elastic-compose/.
Then open Kibana at http://localhost:5601/. The default collector config writes spans/metrics to stdout for quick inspection—customise otel-config.yaml if you want to forward to Elastic APM.
The existing dev/docker-compose.elastic.yml + Filebeat setup remains available if you need the legacy log ingestion pipeline.
Verification
This crate must pass:
Local CI checks
Run ci/local_check.sh before pushing to mirror the GitHub Actions matrix locally. The script is offline by default; opt in to extra checks via:
LOCAL_CHECK_ONLINE=1— run networked steps (cargo publish dry-run, cloud telemetry loops, schema curls).LOCAL_CHECK_STRICT=1— treat skipped steps as failures and require every optional tool/env to be present.LOCAL_CHECK_VERBOSE=1— echo each command for easier debugging.
The generated .git/hooks/pre-push hook invokes the script automatically; remove or edit it if you prefer to run the checks manually.
Dependabot auto-merge
- Dependabot is configured for daily Cargo updates. A workflow auto-approves and enables GitHub auto-merge only for Dependabot PRs once checks pass.
- Repo settings required: enable “Allow auto-merge” and configure required status checks as desired in branch protection.