feat(metrics-sidecar): OTLP-logs exporter for webrtc.* events (FU #28) #2

Merged
triform-admin merged 1 commit from feat/otlp-logs into main 2026-05-07 02:44:40 +00:00

Summary

Wave 2 A4 closeout follow-up. The chromeless-metrics-sidecar now
forwards every chromeless.webrtc.* dot-named event to OTLP-logs in
parallel to the existing Prometheus counter increments — closing the
gap flagged at the end of A4 (Triform's event bus / activity feed
needs the dot-named stream verbatim, not a Prometheus rollup).

This PR is based on feat/wave-1-emitters (the open PR #1 head) so
A4's /webrtc-event endpoint exists in the diff base. After PR #1
merges, the base branch will rebase to main automatically.

What changed

  • New otlp_logs.goOTLPLogger struct with the same env-gated,
    no-op-stub shape as tracing.go. Reads OTEL_EXPORTER_OTLP_ENDPOINT
    (or the signal-specific OTEL_EXPORTER_OTLP_LOGS_ENDPOINT override),
    plus OTEL_EXPORTER_OTLP_HEADERS, TLS, compression, timeout via the
    OTel SDK's standard env-var contract. Endpoint unset → no-op stub
    that drops Emit + Shutdown cleanly. Uses HTTP transport (/v1/logs)
    since SigNoz / OTel collectors ship both gRPC and HTTP on the same
    listener and HTTP is the more portable default.
  • webrtc_handler.goapplyWebRTCEvent and webrtcEventHandler
    take an *OTLPLogger and call otlp.Emit(event, attrs) alongside
    the existing Prometheus counter increment for every envelope.
    element_id is stamped on the OTLP attrs so consumers don't have to
    re-derive it.
  • main.go — wires newOTLPLogger next to initTracing, deferred
    Shutdown on graceful exit, passes the logger into the handler factory.
  • go.mod / go.sum — adds otlplog/otlploghttp v0.8.0, log v0.8.0,
    sdk/log v0.8.0. The v0.8.0 minor pairs cleanly with the existing
    otel v1.32.0 core; same Go 1.22 baseline.

Test plan

  • go build ./... clean
  • go vet ./... clean
  • go test ./... — 27/27 passing (22 existing + 5 new)
  • No-op-on-unset-env: sidecar starts with OTEL_EXPORTER_OTLP_ENDPOINT
    unset, /metrics serves pre-registered series, /webrtc-event
    accepts events (HTTP 204), counters increment correctly, no
    goroutine leaks, clean shutdown.
  • Production: when deployed to dev with the SigNoz collector
    endpoint set, confirm chromeless.webrtc.* records appear in SigNoz
    (Logs view filtered by service.name = chromeless-metrics-sidecar).

New tests added

  • TestOTLPLogger_NoOpWhenEnvUnset — env unset path produces a stub
    whose Emit / Shutdown are safe no-ops.
  • TestOTLPLogger_NilReceiverIsSafe — typed-nil receivers don't panic.
  • TestOTLPLogger_EmitsRecordWithBodyAndAttrs — body + severity +
    attribute round-trip via in-memory exporter.
  • TestOTLPLogger_DropsEmptyEvent — empty event string is dropped at
    the exporter (mirrors handler-side guard).
  • TestWebRTCEventHandler_ForwardsToOTLP — cross-cutting wiring check
    that an applyWebRTCEvent call drives both Prometheus and OTLP.

Deploy-side env config

Production deploys (chromeless pod, dev or wtf) should set:

OTEL_EXPORTER_OTLP_ENDPOINT=<signoz-collector-url-or-otel-collector>

— typically the in-cluster collector that already terminates traces
(tracing.go's OTLP-gRPC path). The logs path uses HTTP and will hit
<endpoint>/v1/logs automatically per the OTel SDK contract. Auth /
TLS via the standard OTEL_EXPORTER_OTLP_HEADERS and
OTEL_EXPORTER_OTLP_LOGS_INSECURE envs.

Constraint compliance

  • Diff stays small (5 modified + 2 new files). No restructure of
    webrtc_handler.go — the OTLP Emit is one extra line per event,
    plus a small attr-merge block at the top of applyWebRTCEvent.
  • Existing 21 sidecar tests untouched in behavior; only the
    webrtcEventHandler(...) factory call sites updated to pass
    nil for the OTLP logger argument.
  • Env-gating mirrors tracing.go exactly so deploy configs use the
    same shape.
## Summary Wave 2 A4 closeout follow-up. The `chromeless-metrics-sidecar` now forwards every `chromeless.webrtc.*` dot-named event to OTLP-logs in parallel to the existing Prometheus counter increments — closing the gap flagged at the end of A4 (Triform's event bus / activity feed needs the dot-named stream verbatim, not a Prometheus rollup). This PR is **based on `feat/wave-1-emitters`** (the open PR #1 head) so A4's `/webrtc-event` endpoint exists in the diff base. After PR #1 merges, the base branch will rebase to `main` automatically. ## What changed - **New `otlp_logs.go`** — `OTLPLogger` struct with the same env-gated, no-op-stub shape as `tracing.go`. Reads `OTEL_EXPORTER_OTLP_ENDPOINT` (or the signal-specific `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` override), plus `OTEL_EXPORTER_OTLP_HEADERS`, TLS, compression, timeout via the OTel SDK's standard env-var contract. Endpoint unset → no-op stub that drops `Emit` + `Shutdown` cleanly. Uses HTTP transport (`/v1/logs`) since SigNoz / OTel collectors ship both gRPC and HTTP on the same listener and HTTP is the more portable default. - **`webrtc_handler.go`** — `applyWebRTCEvent` and `webrtcEventHandler` take an `*OTLPLogger` and call `otlp.Emit(event, attrs)` alongside the existing Prometheus counter increment for every envelope. `element_id` is stamped on the OTLP attrs so consumers don't have to re-derive it. - **`main.go`** — wires `newOTLPLogger` next to `initTracing`, deferred `Shutdown` on graceful exit, passes the logger into the handler factory. - **`go.mod` / `go.sum`** — adds `otlplog/otlploghttp v0.8.0`, `log v0.8.0`, `sdk/log v0.8.0`. The v0.8.0 minor pairs cleanly with the existing `otel v1.32.0` core; same Go 1.22 baseline. ## Test plan - [x] `go build ./...` clean - [x] `go vet ./...` clean - [x] `go test ./...` — 27/27 passing (22 existing + 5 new) - [x] No-op-on-unset-env: sidecar starts with `OTEL_EXPORTER_OTLP_ENDPOINT` unset, `/metrics` serves pre-registered series, `/webrtc-event` accepts events (HTTP 204), counters increment correctly, no goroutine leaks, clean shutdown. - [ ] Production: when deployed to dev with the SigNoz collector endpoint set, confirm `chromeless.webrtc.*` records appear in SigNoz (Logs view filtered by `service.name = chromeless-metrics-sidecar`). ## New tests added - `TestOTLPLogger_NoOpWhenEnvUnset` — env unset path produces a stub whose `Emit` / `Shutdown` are safe no-ops. - `TestOTLPLogger_NilReceiverIsSafe` — typed-nil receivers don't panic. - `TestOTLPLogger_EmitsRecordWithBodyAndAttrs` — body + severity + attribute round-trip via in-memory exporter. - `TestOTLPLogger_DropsEmptyEvent` — empty event string is dropped at the exporter (mirrors handler-side guard). - `TestWebRTCEventHandler_ForwardsToOTLP` — cross-cutting wiring check that an `applyWebRTCEvent` call drives both Prometheus and OTLP. ## Deploy-side env config Production deploys (chromeless pod, dev or wtf) should set: ``` OTEL_EXPORTER_OTLP_ENDPOINT=<signoz-collector-url-or-otel-collector> ``` — typically the in-cluster collector that already terminates traces (`tracing.go`'s OTLP-gRPC path). The logs path uses HTTP and will hit `<endpoint>/v1/logs` automatically per the OTel SDK contract. Auth / TLS via the standard `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_EXPORTER_OTLP_LOGS_INSECURE` envs. ## Constraint compliance - Diff stays small (5 modified + 2 new files). No restructure of `webrtc_handler.go` — the OTLP `Emit` is one extra line per event, plus a small attr-merge block at the top of `applyWebRTCEvent`. - Existing 21 sidecar tests untouched in behavior; only the `webrtcEventHandler(...)` factory call sites updated to pass `nil` for the OTLP logger argument. - Env-gating mirrors `tracing.go` exactly so deploy configs use the same shape.
feat(metrics-sidecar): OTLP-logs exporter for chromeless.webrtc.* events (FU #28)
Some checks failed
CI / Lint (pull_request) Failing after 2s
CI / Docs link check (pull_request) Failing after 1s
CodeQL / Analyze javascript-typescript (pull_request) Failing after 2s
CodeQL / Analyze go (pull_request) Failing after 5s
CI / Build container image (pull_request) Failing after 9s
CI / Container smoke test (pull_request) Has been skipped
E2E / docker-compose + Playwright (pull_request) Failing after 14s
b2a63684e1
Closes the gap flagged at the end of Wave 2 A4: the dot-named WebRTC
events POSTed to /webrtc-event were incrementing Prometheus counters
but never reaching Triform's event bus / activity feed because the
sidecar had only an OTLP-trace exporter (tracing.go) and Prometheus
scrape — no OTLP-logs path.

Adds:
  - otlp_logs.go — OTLPLogger struct with the same env-gated, no-op-stub
    shape as tracing.go. Reads OTEL_EXPORTER_OTLP_ENDPOINT (and the
    signal-specific OTEL_EXPORTER_OTLP_LOGS_ENDPOINT override) plus
    OTEL_EXPORTER_OTLP_HEADERS / TLS / compression / timeout via the
    OTel SDK's standard env-var contract. When endpoint is unset,
    construction returns a non-nil stub that drops Emit + Shutdown
    cleanly — dev compose without a collector pays no wire cost.
  - otlp_logs_test.go — 5 tests (no-op-on-unset-env path, nil-receiver
    safety, body+attribute round-trip via in-memory exporter, empty-event
    drop, and the cross-cutting wiring check that /webrtc-event drives
    both Prometheus + OTLP).

Modifies:
  - webrtc_handler.go — applyWebRTCEvent + webrtcEventHandler take an
    *OTLPLogger and Emit(event, attrs) for every envelope, in parallel
    to the existing Prometheus counter increments. element_id is
    stamped onto the OTLP attrs so consumers can filter without
    re-deriving it.
  - main.go — wires newOTLPLogger alongside initTracing, deferred
    Shutdown on graceful exit, passes the logger into webrtcEventHandler.
  - go.mod / go.sum — adds otlplog/otlploghttp v0.8.0, log v0.8.0,
    sdk/log v0.8.0 (the v0.8.0 versions pair cleanly with the existing
    otel v1.32.0; same go 1.22 baseline as signaling/go.mod).

Verification:
  go build ./...   passes
  go vet ./...     clean
  go test ./...    27/27 pass (22 existing + 5 new)
  Smoke run with OTEL_EXPORTER_OTLP_ENDPOINT unset: sidecar starts,
  /metrics serves pre-registered series, /webrtc-event accepts events
  with HTTP 204, counters increment correctly, no goroutine leaks,
  process shuts down cleanly.

Deploy-side env config: production should set
  OTEL_EXPORTER_OTLP_ENDPOINT=<signoz-collector-url>
on the chromeless pod (typically the in-cluster SigNoz / OTel
collector that already terminates traces). The sidecar uses HTTP for
logs (vs gRPC for traces) because /v1/logs is the OTel default and
SigNoz collectors ship both protocols on the same listener.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
triform-admin force-pushed feat/otlp-logs from b2a63684e1
Some checks failed
CI / Lint (pull_request) Failing after 2s
CI / Docs link check (pull_request) Failing after 1s
CodeQL / Analyze javascript-typescript (pull_request) Failing after 2s
CodeQL / Analyze go (pull_request) Failing after 5s
CI / Build container image (pull_request) Failing after 9s
CI / Container smoke test (pull_request) Has been skipped
E2E / docker-compose + Playwright (pull_request) Failing after 14s
to ec82d79694
Some checks failed
CI / Lint (pull_request) Failing after 2s
CI / Docs link check (pull_request) Failing after 2s
CodeQL / Analyze javascript-typescript (pull_request) Failing after 2s
CodeQL / Analyze go (pull_request) Failing after 4s
CI / Build container image (pull_request) Failing after 9s
CI / Container smoke test (pull_request) Has been skipped
E2E / docker-compose + Playwright (pull_request) Failing after 13s
2026-05-07 02:44:02 +00:00
Compare
triform-admin changed target branch from feat/wave-1-emitters to main 2026-05-07 02:44:10 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
triform/chromeless!2
No description provided.