Skip to content

Commit 9c87129

Browse files
igoramfclaude
andauthored
feat(observability): wire three-channel o11y model into template (#13)
* feat(observability): wire three-channel o11y model into template Add tail worker, version metadata, OTEL endpoints, and full CF Destinations config (1% sampled logs + traces → deco-otel-ingest) mirroring the production setup in casaevideo-tanstack. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(observability): set DECO_SITE_NAME to storefront Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5bc5fc6 commit 9c87129

1 file changed

Lines changed: 92 additions & 1 deletion

File tree

wrangler.jsonc

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,101 @@
99
// "kv_namespaces": [
1010
// { "binding": "SITES_KV", "id": "YOUR_KV_NAMESPACE_ID" }
1111
// ],
12+
// Strategy B tail worker — 100% capture of producer errors that the
13+
// framework's direct-POST channel can't see (uncaught throws, exceededCpu,
14+
// exceededMemory, raw console.error). Invoked by CF on every request to
15+
// this worker; filters and forwards to deco-otel-ingest via in-account
16+
// service binding. See the observability block below for the full
17+
// three-channel model.
18+
"tail_consumers": [
19+
{ "service": "deco-otel-tail" }
20+
],
21+
// Worker version (build SHA / deployment id) — surfaced as
22+
// `service.version` on every span / log line by `instrumentWorker`.
23+
"version_metadata": {
24+
"binding": "CF_VERSION_METADATA"
25+
},
26+
// Cloudflare Analytics Engine dataset for high-cardinality counters
27+
// (per-route request counts, cache hit/miss, request duration).
28+
// Queryable via SQL from the CF dashboard. Replace YOUR_SITE_NAME with
29+
// the actual site slug (must match DECO_SITE_NAME below).
30+
// "analytics_engine_datasets": [
31+
// {
32+
// "binding": "DECO_METRICS",
33+
// "dataset": "deco_metrics_YOUR_SITE_NAME"
34+
// }
35+
// ],
36+
// Observability — three-channel model (Strategy B, see decocms/deco-start D-8).
37+
//
38+
// Identity:
39+
// `DECO_SITE_NAME` drives `service.name` on every span and log line.
40+
// `DECO_ENV_NAME` drives `deployment.environment`.
41+
//
42+
// Three channels, each owning a different slice of the observability cube:
43+
//
44+
// 1. CF Destinations (`observability.{logs,traces}.destinations` below)
45+
// Sampled 1% logs + 1% traces. Bulk volume.
46+
// 2. Direct-POST in-worker (`DECO_OTEL_*_ENDPOINT`, resolved at
47+
// `instrumentWorker` boot)
48+
// - METRICS_ENDPOINT → direct POST `/v1/metrics` (CF Destinations
49+
// doesn't support OTLP metrics). Buffered per-isolate, flushed
50+
// via `ctx.waitUntil` after every request.
51+
// - LOGS_ENDPOINT → direct POST `/v1/logs` for framework
52+
// `logger.error(...)` only (100% capture, rate-limited).
53+
// 3. Tail Worker (`tail_consumers` above → deco-otel-tail)
54+
// Catches uncaught throws, exceededCpu/Memory, raw console.error —
55+
// what direct-POST can't see and CF Destinations would sample away.
56+
//
57+
// Coverage matrix:
58+
// framework logger.error → direct-POST (100%, rate-limited)
59+
// framework span errors → CF Destinations + tail (1% sampled + 100%)
60+
// uncaught throws → tail worker (100%)
61+
// exceededCpu / exceededMemory → tail worker (100%)
62+
// raw console.error → tail worker (100%)
63+
// console.log / console.warn → CF Destinations (1% sampled)
64+
// OTel spans → CF Destinations (1% sampled)
65+
// OTel metrics → direct-POST (100%, buffered)
66+
"vars": {
67+
"DECO_SITE_NAME": "storefront",
68+
"DECO_ENV_NAME": "production",
69+
"DECO_OTEL_METRICS_ENDPOINT": "https://deco-otel-ingest.deco-cx.workers.dev/v1/metrics",
70+
"DECO_OTEL_LOGS_ENDPOINT": "https://deco-otel-ingest.deco-cx.workers.dev/v1/logs"
71+
},
72+
// CF-native observability: structured console.* output and auto-
73+
// instrumented traces (fetch/KV/R2/DO subrequests + @opentelemetry/api
74+
// global-tracer spans the framework's withTracing() emits) are
75+
// captured by the Cloudflare runtime, retained in the CF dashboard
76+
// via persist:true, AND forwarded to deco-otel-ingest →
77+
// stats-lake ClickHouse via the named destinations below.
78+
//
79+
// The named destinations are registered out-of-band in the CF
80+
// dashboard (Workers & Pages → Observability → Destinations) against
81+
// the deco-cx account. Wrangler resolves these names to the URLs +
82+
// any auth headers configured there.
1283
"observability": {
84+
// Master switch — without enabled:true at the top level CF
85+
// captures nothing, regardless of the sub-block flags.
86+
"enabled": true,
1387
"logs": {
1488
"enabled": true,
15-
"invocation_logs": true
89+
"invocation_logs": true,
90+
// 1% of info/warn logs forward to deco-otel-ingest. Errors are
91+
// NOT subject to this rate — they're covered by both the
92+
// direct-POST channel (framework logger.error) and the tail
93+
// worker (uncaught throws, exceededCpu, raw console.error).
94+
"head_sampling_rate": 0.01,
95+
"persist": true,
96+
"destinations": ["deco-otel-ingest-logs"]
97+
},
98+
"traces": {
99+
"enabled": true,
100+
// Fleet-scale cost discipline — see `@decocms/start`
101+
// docs/observability.md "Sampling" section. 1% gives 2.5x
102+
// headroom against the 5B-events/day CF cap at projected
103+
// fleet traffic.
104+
"head_sampling_rate": 0.01,
105+
"persist": true,
106+
"destinations": ["deco-otel-ingest-traces"]
16107
}
17108
}
18109
}

0 commit comments

Comments
 (0)