# OpenTelemetry on Workers セットアップ手順

監査 P1 (A2 / 2026-04-26): Workers BFF の分散トレース基盤を OpenTelemetry で構築する。
Sentry on Workers (A3) と相補的に、「何が壊れた (Sentry)」と「どこが遅い (OTel)」を
別軸で観測する。

> **状態:** lib/otel.ts は no-op skeleton のみ。実 install と collector 接続は Stage 3。
> 本書は配線時の段取りを残すための準備ドキュメント。

## 採用ライブラリ

[@microlabs/otel-cf-workers](https://github.com/evanderkoogh/otel-cf-workers) を予定。

理由:
- Workers API (fetch / scheduled / queue) を auto-instrument
- OTLP/HTTP exporter (Workers の Node API 制約を回避済み)
- Cloudflare 公式が紹介、数千 stars でメンテ活発
- entrypoint を `instrument(handler, config)` で wrap するだけで span / metric が流れる

## Collector backend 候補

| backend | 月次無料枠 | 強み | 弱み |
|---|---|---|---|
| **Honeycomb** | 200M events | OTel native、UI 軽快 | 統合的なログ管理は別系統 |
| **Grafana Cloud Tempo** | 50GB metrics | Loki / Sentry と併用しやすい | UI 学習コスト |
| **Datadog APM** | trial | エコ全部 (logs / metrics / synthetics) | コスト |
| **Axiom** | 0.5TB | 安価、OTel native、LogQL ライク | 知名度低い |

Parky 規模では **Honeycomb 無料枠** が現実解。

## 環境変数 (env/bindings.ts に既定義)

```
OTEL_EXPORTER_OTLP_ENDPOINT  例: https://api.honeycomb.io/v1/traces
OTEL_EXPORTER_OTLP_HEADERS   例: x-honeycomb-team=<token>
OTEL_SERVICE_NAME            例: parky-api-prod / parky-api-stg / parky-api-dev
```

## 配線手順 (Stage 3)

### 1. install

```bash
npm install @microlabs/otel-cf-workers --workspace=api
```

### 2. lib/otel.ts を実装に差し替え

現在 no-op の `withOtelInstrumentation` / `withSpan` を実 OTel API に。

### 3. entrypoint を wrap

`api/src/index.ts` (および split worker entry) で:

```ts
import { instrument } from "@microlabs/otel-cf-workers";
import handler from "./app";

export default instrument(handler, {
  service: { name: "parky-api" },
  exporter: {
    url: env.OTEL_EXPORTER_OTLP_ENDPOINT,
    headers: parseOtelHeaders(env.OTEL_EXPORTER_OTLP_HEADERS),
  },
  sampling: {
    headSampler: { ratio: env.ENVIRONMENT === "production" ? 0.2 : 1.0 },
  },
});
```

### 4. secret 投入

```bash
wrangler secret put OTEL_EXPORTER_OTLP_ENDPOINT --env dev
wrangler secret put OTEL_EXPORTER_OTLP_HEADERS --env dev
wrangler secret put OTEL_SERVICE_NAME --env dev  # parky-api-dev
```

production / staging も同様。1Password vault `HF｜開発` に
`Honeycomb｜APIトークン｜Parky` を保管して `set-secrets.sh` で一括投入。

### 5. 動作確認

dev で `/healthz` を 1 リクエスト叩く → Honeycomb で span が表示される。
複数 endpoint で span が階層になっていることを確認。

## トレード重視ポイント

- **production sampling**: 全件取ると Honeycomb 無料枠を超える。0.2 程度で開始、
  4xx/5xx は forced-sample で常時記録。
- **PII**: span の attribute に email / phone / token を載せない。`lib/otel.ts` の
  span 開始時に attribute 名を whitelist する。
- **Hyperdrive query**: postgres.js の各 query を span 化すると slow query が見える。
  ただし trace が肥大するので sample の上で。
- **Sentry / Logger との突合**: span に `request_id` を attribute として付ければ
  Sentry / Workers log と突合できる (request-id middleware と同じ ID)。

## 関連

- [parky/api/src/lib/otel.ts](../../api/src/lib/otel.ts) — 現状 skeleton
- [parky/docs/ops/sentry-setup.md](./sentry-setup.md) — 例外側の観測
- [parky/docs/ops/logpush-setup.md](./logpush-setup.md) — log 側の観測
- 公式: https://github.com/evanderkoogh/otel-cf-workers
