telemetry-init 0.1.0

One-call observability bootstrap for Rust services — tracing + metrics + OTLP wired with estate defaults
Documentation
# telemetry-init

One-call observability bootstrap for Rust — the shared init pattern of the
WyattAu estate, wiring **logs** (`tracing_subscriber`), **metrics**
(`metrics-kit`), and **traces** (`opentelemetry-otlp`) in a single fallible
call instead of six hand-rolled dialects of the same 40–80 lines.

- **One init, typed failure**: `Telemetry::init` returns `TelemetryError`;
  double initialization is `AlreadyInitialized`, never a panic.
- **Logs**: `EnvFilter` from the configured directive with `RUST_LOG`
  override, JSON by default (`json` feature), human format for local dev.
- **Metrics**: a lock-free `metrics-kit::Registry` with a cardinality
  budget, handed to you as an `Arc` — no hidden globals.
- **Traces** (`otlp` feature): OTLP/HTTP exporter wired as a
  `tracing-opentelemetry` layer with `service.name` / `service.version`
  resource attributes and parent-based ratio sampling.
- **Explicit shutdown, best-effort drop**: `shutdown()` is the guaranteed,
  idempotent flush path; `Drop` is a documented safety net.
- **No silent fallbacks**: `LogFormat::Json` without the `json` feature is a
  configuration error.
- **`#![forbid(unsafe_code)]`, `#![deny(missing_docs)]`**, clippy
  `unwrap_used`/`expect_used`/`panic`/`indexing_slicing` denied.

## Install

```toml
[dependencies]
telemetry-init = "0.1"
```

## Example

```rust
use telemetry_init::{Telemetry, TelemetryConfig};

let telemetry = Telemetry::init(
    TelemetryConfig::new("payments-api")
        .version(env!("CARGO_PKG_VERSION"))
        .log_level("info"),          // RUST_LOG wins when set
)?;

// Hot-path handles register through the handed-out Arc.
let requests = telemetry
    .metrics()
    .counter("http_requests_total", "Total HTTP requests.", &[])?;
requests.inc();

assert!(telemetry.metrics().render().contains("http_requests_total 1"));
telemetry.shutdown()?;
# Ok::<(), telemetry_init::TelemetryError>(())
```

With traces enabled:

```toml
[dependencies]
telemetry-init = { version = "0.1", features = ["otlp"] }
```

```rust,ignore
let telemetry = Telemetry::init(
    TelemetryConfig::new("payments-api")
        .otlp_endpoint("http://localhost:4317")
        .sample_rate(0.1),
)?;
```

Spans export over OTLP/HTTP (protobuf, batched); the endpoint is trusted
infrastructure — point it at your collector, not the public internet.

## The config surface

| Builder call | Default | Notes |
|---|---|---|
| `new("service-name")` | — | required; becomes `service.name` |
| `.version("1.2.3")` | `"0.0.0"` | becomes `service.version` |
| `.log_level("info")` | `"info"` | any `env-filter` directive; `RUST_LOG` wins |
| `.log_format(LogFormat::Json)` | `Json` | `Json` needs the `json` feature |
| `.metrics_budget(8192)` | `8192` | series cardinality guard |
| `.otlp_endpoint("…")` | none | `otlp` feature; none = no traces |
| `.sample_rate(1.0)` | `1.0` | clamped to `0.0..=1.0` |

## Feature flags

| Feature | Default | Description |
|---|---|---|
| `metrics` | yes | metrics-kit registry via `Telemetry::metrics()` |
| `json` | yes | JSON log format via `tracing-subscriber/json` |
| `otlp` | no | OTLP trace export (`opentelemetry-otlp` + `tracing-opentelemetry`) |

`--no-default-features` builds a logs-only bootstrap (choose
`LogFormat::Pretty` explicitly; `Json` errors without the feature).

## Why not `otelkit::init`?

`otelkit` v2 exposes a whole-subscriber init: it installs its own global
subscriber and returns a flush guard, so it cannot compose as a layer inside
this crate's single subscriber — and its OTLP path ignores the log format and
`RUST_LOG`. telemetry-init wires `opentelemetry-otlp` +
`tracing-opentelemetry` directly to keep one code path for every feature
combination.

## Testing note

The global subscriber is a once-per-process resource. All tests that call
`Telemetry::init` live in a single deterministic function
(`tests/global_init.rs`), so the default multi-threaded harness cannot race
double-init assertions.

## Performance

Init is a startup cost, measured as a smoke benchmark
(`benches/init_bench.rs`, `cargo bench`): subscriber construction is
filter-parse + layer assembly, microseconds-class; the metrics hot path is
metrics-kit's lock-free recording (see its README for the measured numbers).

## License

Licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT)
at your option.