cosmian_logger
Why
Velo platform services export three observability signals — logs, traces, and metrics — to Grafana Alloy over OTLP/gRPC. Without a shared, consistent initialisation path, each service would re-implement the same boilerplate and risk diverging from the platform's Alloy → Loki / Tempo / Prometheus pipeline.
What
cosmian_logger provides two initialisation paths and a set of logging macros:
| API | Use case |
|---|---|
[tracing_init] |
Full-featured init driven by a TracingConfig struct: stdout, syslog, rolling files, and OTLP. Used by long-running services with rich operator configuration. |
[init_tracing] |
Lightweight init driven by two environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME). Used by minimal daemons and jobs. |
info! / debug! / warn! / error! / trace! |
Drop-in replacements for the tracing macros that automatically add a fn_name structured field to each event. |
Signal pipeline
| Signal | SDK pipeline | Destination |
|---|---|---|
| Logs | opentelemetry-appender-tracing bridges tracing events → SdkLoggerProvider → OTLP/gRPC LogExporter |
Alloy → Loki |
| Traces | tracing-opentelemetry bridges tracing spans → SdkTracerProvider → OTLP/gRPC SpanExporter |
Alloy → Tempo |
| Metrics | SdkMeterProvider with a 30-second PeriodicReader → OTLP/gRPC MetricExporter |
Alloy → Prometheus |
When OTEL_EXPORTER_OTLP_ENDPOINT is not set all three pipelines are skipped and
output falls back to structured console logging with no network traffic.
How
tracing_init layer composition
TracingConfig
│
├─ stdout_layer (unless no_log_to_stdout)
├─ file_layer (when log_to_file is set — daily rolling)
├─ syslog_layer (when log_to_syslog, Unix only)
└─ otel_layer (when otlp is set)
├─ SdkTracerProvider → SpanExporter ──► Tempo
└─ SdkMeterProvider → MetricExporter ──► Prometheus (when enable_metering)
init_tracing layer composition
OTEL_EXPORTER_OTLP_ENDPOINT set?
│
├─ YES ──► stdout layer
│ tracing-opentelemetry layer → SdkTracerProvider → SpanExporter ──► Tempo
│ OpenTelemetryTracingBridge → SdkLoggerProvider → LogExporter ──► Loki
│ SdkMeterProvider (global) → MetricExporter (30 s) ──► Prometheus
│
└─ NO ──► stdout layer only
All OTLP exporters share the same gRPC endpoint and service.name resource attribute so
every signal from a service is correlated in Grafana.
Using
[]
= { = true }
Full-featured init (tracing_init)
use ;
LoggingGuards is dropped at the end of main — no explicit shutdown needed.
ANSI colours
Coloured output is controlled by with_ansi_colors in TracingConfig. It applies only to the
stdout layer — the file and syslog layers always disable ANSI codes.
tracing_init;
Tip: set with_ansi_colors: true in development and false in production / when stdout is
piped to a log collector that does not interpret ANSI sequences.
Syslog (Unix only)
Setting log_to_syslog: true adds a syslog layer alongside any other layers that are active.
Logs are forwarded to the system syslog daemon using Facility::User and the
service_name as the syslog identity. The layer is compiled out on Windows.
tracing_init;
You can verify syslog output on Linux with:
# or
|
On macOS:
Lightweight env-var init (init_tracing)
use init_tracing;
use ;
async
Logging macros
cosmian_logger exports info!, debug!, warn!, error!, and trace! macros that
wrap the standard tracing macros and automatically inject a fn_name structured field,
making it easy to locate the call site in structured log aggregators:
use info;
Recording metrics
use Counter;
use init_tracing;
async
Distributed tracing with #[instrument]
use instrument;
async
Environment variables
| Variable | Default | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
(absent — console only) | gRPC endpoint for all three OTLP signals, e.g. http://obs-stack-alloy.observability.svc.cluster.local:4317 |
OTEL_SERVICE_NAME |
value passed to init_tracing |
service.name resource attribute stamped on every signal |
RUST_LOG |
info |
tracing_subscriber log filter, e.g. debug,hyper=warn |
Kubernetes manifest
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://obs-stack-alloy.observability.svc.cluster.local:4317"
- name: OTEL_SERVICE_NAME
value: "my-service"
- name: RUST_LOG
value: "info"
Building
# From workspace root
Testing
# Unit tests (no network required)
# Smoke test against a live collector
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_SERVICE_NAME=test-service \
RUST_LOG=debug \
To port-forward the Velo platform's Alloy instance: