wingfoil 4.0.1

graph based stream processing framework
Documentation
# OTLP Adapter

Wingfoil adapter that pushes stream values as OpenTelemetry gauge metrics to any
OTLP-compatible backend (Grafana Alloy, Datadog, Honeycomb, New Relic, etc.).

## Module Structure

```
otlp/
  mod.rs               # Public API re-exports, module-level docs
  push.rs              # OtlpPush trait + push_consumer async fn
  integration_tests.rs # Integration tests (testcontainers — no external setup needed)
  CLAUDE.md            # This file
```

## Key Design Decisions

- Uses the OpenTelemetry Rust SDK (`opentelemetry`, `opentelemetry_sdk`, `opentelemetry-otlp`).
  Metrics are exported via HTTP/protobuf (`http-proto` feature) to the OTLP `/v1/metrics` endpoint.
- A `SdkMeterProvider` with a 500 ms `PeriodicReader` is created per consumer invocation so that
  the final batch of metrics is flushed on `shutdown()` before the function returns.
- The metric name is leaked to a `&'static str` (`Box::leak`) because the OTel SDK's
  `f64_gauge` builder requires `Cow<'static, str>`. This is a one-time allocation per run.
- **Historical / backtesting mode**: the consumer checks `ctx.run_mode` via `RunParams` and
  drains the source stream without connecting to any external service. No OTel provider is
  built and no network calls are made.
- The adapter is push-based (contrast with `prometheus` which is pull-based).
- `OtlpPush` is implemented for `dyn Stream<T>` where `T: Display` so any numeric or string
  stream can be pushed without wrapping.

## Feature Flags

- `otlp` — enables the adapter (pulls in `opentelemetry`, `opentelemetry_sdk`, `opentelemetry-otlp`,
  `reqwest`).
- `otlp-integration-test` — enables `otlp` + `testcontainers` for self-contained integration tests.

## Pre-Commit Requirements

```bash
# 1. Standard checks
cargo fmt --all
cargo clippy --workspace --all-targets --all-features

# 2. Unit / doc tests (no external dependencies)
cargo test --features otlp -p wingfoil -- adapters::otlp

# 3. Integration tests (testcontainers pulls the collector image automatically)
RUST_LOG=INFO cargo test --features otlp-integration-test -p wingfoil \
  -- --test-threads=1 --nocapture adapters::otlp::integration_tests
```

## Integration Tests

Tests use `testcontainers` with `SyncRunner` to start an `otel/opentelemetry-collector` container
automatically — no manual Docker setup required. The container is stopped when dropped.

## Gotchas

- The OTel SDK logs its own startup/shutdown messages to stderr even with `RUST_LOG` unset.
  This is expected and harmless in tests.
- `PeriodicReader` interval is set to 500 ms to ensure at least one export happens during
  short-running tests. Decrease if tests become flaky; increase if the backend is slow.
- Non-numeric stream values are parsed as f64 via `.to_string().parse()`. Values that fail
  parsing are recorded as `0.0` and a warning is logged.
- The collector image version is pinned (`0.116.0`) to avoid unexpected API changes.
  Update the pin deliberately and re-run integration tests.