# camel-otel

> OpenTelemetry integration for rust-camel

OpenTelemetry integration for rust-camel.

## Overview

Implements `Lifecycle` and `MetricsCollector` traits to export **traces, metrics, and logs** to any OTLP-compatible backend (e.g., Grafana LGTM, Jaeger, Tempo, Prometheus via OTLP).

`OtelService` initializes the global `TracerProvider`, `MeterProvider`, and `LoggerProvider` on start and shuts them down gracefully on stop. W3C `traceparent` / `tracestate` headers are propagated automatically in HTTP and Kafka components via optional feature flags.

**Features:**
- **Traces**: Distributed tracing via OTLP span exporter
- **Metrics**: Route-level metrics (duration, exchanges, errors) automatically recorded
- **Logs**: Log bridge exports `tracing` logs via OTLP
- **Auto-registration**: `OtelService.as_metrics_collector()` enables automatic metrics collection

## Quick Start

```rust
use camel_otel::{OtelConfig, OtelService};
use camel_core::context::CamelContext;

// OTel providers start/stop automatically with context
let ctx = CamelContext::new()
    .with_lifecycle(OtelService::new(
        OtelConfig::new("http://localhost:4317", "my-service"),
    ));

ctx.start().await?;
// Traces, metrics, and logs exported to OTLP backend

ctx.stop().await?;
// All providers flushed and shut down
```

### Default Configuration

```rust
use camel_otel::OtelService;

// Connects to http://localhost:4317, service name "rust-camel"
let ctx = CamelContext::new()
    .with_lifecycle(OtelService::with_defaults());
```

### Custom Sampling and Resource Attributes

```rust
use camel_otel::{OtelConfig, OtelProtocol, OtelSampler, OtelService};

let config = OtelConfig::new("http://otel-collector:4317", "payments-service")
    .with_protocol(OtelProtocol::Grpc)
    .with_sampler(OtelSampler::TraceIdRatioBased(0.1))
    .with_resource_attr("deployment.environment", "production")
    .with_resource_attr("service.version", "2.3.1");

let ctx = CamelContext::new().with_lifecycle(OtelService::new(config));
 ```

### Configuration via Camel.toml

All OTel parameters can be configured in `Camel.toml`:

```toml
[observability.otel]
enabled = true
endpoint = "http://localhost:4317"
service_name = "my-app"
log_level = "info"
protocol = "grpc"               # "grpc" or "http"
sampler = "ratio"               # "always_on", "always_off", or "ratio"
sampler_ratio = 0.1             # Only used when sampler = "ratio"
metrics_interval_ms = 15000     # Metrics export interval (default: 60000)
logs_enabled = true             # Export logs via OTLP (default: true)

[observability.otel.resource_attrs]
env = "production"
region = "us-east-1"
```

| Field | Default | Description |
|-------|---------|-------------|
| `enabled` | `false` | Enable OTel export |
| `endpoint` | `http://localhost:4317` | OTLP endpoint |
| `service_name` | `rust-camel` | Service name reported to backend |
| `log_level` | `info` | Log level filter |
| `protocol` | `grpc` | Export protocol (`grpc` or `http`) |
| `sampler` | `always_on` | Sampling strategy |
| `sampler_ratio` | - | Ratio (0.0-1.0) when sampler = "ratio" |
| `metrics_interval_ms` | `60000` | Metrics export interval in ms |
| `logs_enabled` | `true` | Export logs via OTLP |
| `resource_attrs` | `{}` | Custom resource attributes |

## OtelService

`OtelService` implements the `Lifecycle` trait, which follows Apache Camel's Service pattern:

- Initializes global `TracerProvider`, `MeterProvider`, and `LoggerProvider` when `CamelContext.start()` is called
- Installs `OpenTelemetryTracingBridge` to export logs via OTLP
- Exposes `as_metrics_collector()` for automatic metrics registration
- Flushes and shuts down all providers when `CamelContext.stop()` is called
- Exposes `status()` reflecting `Stopped` / `Started` / `Failed` states

## Metrics Exported

Route-level metrics are recorded automatically by `TracingProcessor`:

| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `camel.exchanges.total` | Counter | `route.id` | Total exchanges processed |
| `camel.errors.total` | Counter | `route.id`, `error.type` | Total errors |
| `camel.exchange.duration.seconds` | Histogram | `route.id` | Exchange processing duration |
| `camel.queue.depth` | UpDownCounter | `route.id` | Current queue depth |
| `camel.circuit.breaker.state` | UpDownCounter | `route.id` | Circuit breaker state (0=closed, 1=open, 2=half_open) |

## Log Bridge

The `OpenTelemetryTracingBridge` is installed automatically when `OtelService` starts. All `tracing` logs are exported via OTLP to your backend.

```rust
// These logs are automatically exported via OTLP
tracing::info!("Processing exchange");
tracing::warn!(route_id = "my-route", "Something unusual happened");
```

## W3C Propagation

W3C `traceparent` and `tracestate` headers are propagated automatically when the `otel` feature is enabled on the HTTP or Kafka components.

```toml
[dependencies]
camel-component-http = { workspace = true, features = ["otel"] }
camel-component-kafka = { workspace = true, features = ["otel"] }
```

- **HTTP**: `traceparent` is injected into outgoing request headers and extracted from incoming requests
- **Kafka**: `traceparent` is injected into message headers and extracted on consume

## Architecture

```
OtelService (Lifecycle trait)
    ↓
    ├── TracerProvider (OTLP span exporter, batch)
    ├── MeterProvider (OTLP metric exporter, 60s periodic reader)
    ├── LoggerProvider (OTLP log exporter, batch)
    │       ↓
    │   OpenTelemetryTracingBridge (log → OTLP)
    ├── OtelMetrics (implements MetricsCollector)
    │       ↓
    │   as_metrics_collector() → auto-registered with CamelContext
    └── propagation.rs (W3C inject/extract used by camel-http and camel-kafka)
```

**Note:** Uses `Lifecycle` trait (not `Service`) to avoid confusion with `tower::Service`.

## Hot-reload Compatibility

**OTel configuration is NOT hot-reloadable.** Changes to endpoint, service name, or sampler require process restart. This is standard practice in OpenTelemetry implementations.

Route hot-reload via `ArcSwap` continues to work independently.

## Local Dev Backend

```bash
docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 grafana/otel-lgtm
```

Then open `http://localhost:3000` to view traces, metrics, and logs in Grafana.

Run the bundled demo:

```bash
cargo run -p otel-demo
```

## Documentation

- [API docs (docs.rs)](https://docs.rs/camel-otel)
- [OpenTelemetry Rust](https://github.com/open-telemetry/opentelemetry-rust)

## License

MIT — see [LICENSE](../../LICENSE) for details.

## Contributing

Contributions welcome. Please open an issue or pull request on [GitHub](https://github.com/rust-camel/rust-camel).

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
camel-otel = "*"
```
