From 51cdd17d31f720ef5bebf40173f956e2688d96c6 Mon Sep 17 00:00:00 2001 From: Guide Fari Date: Sat, 4 Jul 2026 15:48:10 +0100 Subject: [PATCH] feat(cloudflare): expose Worker observability as first-class arg Add an `observability` prop to `cloudflare.Worker` so users can enable Cloudflare's logs and traces without reaching for `transform.worker`. The same prop is exposed on the components that create Workers internally: `SsrSite` (Astro, ReactRouter, TanStackStart, SolidStart), `StaticSiteV2`, and `Workflow`. `Cron`, `Queue.subscribe`, and `Auth` already spread `WorkerArgs` and pick it up automatically. Normalization sets top-level `enabled: true` and defaults `logs.invocationLogs: true` whenever `logs` is provided, while still letting the user override any field. `destinations` and `persist` are deferred; the upstream `WorkersScriptObservability` shape lets us add them later without breaking changes. Implements docs/design/cloudflare-worker-observability.md. --- .../src/components/cloudflare/ssr-site.ts | 6 ++ .../components/cloudflare/static-site-v2.ts | 6 ++ platform/src/components/cloudflare/worker.ts | 59 +++++++++++++++++++ .../src/components/cloudflare/workflow.ts | 6 ++ 4 files changed, 77 insertions(+) diff --git a/platform/src/components/cloudflare/ssr-site.ts b/platform/src/components/cloudflare/ssr-site.ts index 67a7412b23..3e39b32c4f 100644 --- a/platform/src/components/cloudflare/ssr-site.ts +++ b/platform/src/components/cloudflare/ssr-site.ts @@ -22,6 +22,11 @@ export type Plan = { export interface SsrSiteArgs extends BaseSsrSiteArgs { domain?: WorkerArgs["domain"]; + /** + * Configure [Cloudflare Workers observability](https://developers.cloudflare.com/workers/observability/) + * for the underlying Worker. See `WorkerArgs.observability` for details. + */ + observability?: WorkerArgs["observability"]; /** * The Cloudflare account ID to use for this SsrSite. * Overrides the default account ID set via `CLOUDFLARE_DEFAULT_ACCOUNT_ID`. @@ -244,6 +249,7 @@ export abstract class SsrSite extends Component implements Link.Linkable { url: true, dev: false, domain: args.domain, + observability: args.observability, handler: all([outputPath, plan.server]).apply( ([outputPath, server]) => path.join(outputPath, server), ), diff --git a/platform/src/components/cloudflare/static-site-v2.ts b/platform/src/components/cloudflare/static-site-v2.ts index f64e54a48e..35fa6be3b5 100644 --- a/platform/src/components/cloudflare/static-site-v2.ts +++ b/platform/src/components/cloudflare/static-site-v2.ts @@ -148,6 +148,11 @@ export interface StaticSiteV2Args extends Omit { * @default `"single-page-application"` */ notFound?: Input<"single-page-application" | "404">; + /** + * Configure [Cloudflare Workers observability](https://developers.cloudflare.com/workers/observability/) + * for the underlying Worker. See `WorkerArgs.observability` for details. + */ + observability?: WorkerArgs["observability"]; /** @deprecated */ indexPage?: string; /** @deprecated */ @@ -367,6 +372,7 @@ export class StaticSiteV2 extends Component implements Link.Linkable { url: true, dev: false, domain: args.domain, + observability: args.observability, assets: { directory: outputPath, htmlHandling, diff --git a/platform/src/components/cloudflare/worker.ts b/platform/src/components/cloudflare/worker.ts index 91becd003a..be5401b5a0 100644 --- a/platform/src/components/cloudflare/worker.ts +++ b/platform/src/components/cloudflare/worker.ts @@ -7,6 +7,7 @@ import { all, jsonStringify, interpolate, + Output, } from "@pulumi/pulumi"; import * as cf from "@pulumi/cloudflare"; import type { Loader } from "esbuild"; @@ -384,6 +385,49 @@ export interface WorkerArgs { host?: Input; hostname?: Input; }>; + /** + * Configure [Cloudflare Workers observability](https://developers.cloudflare.com/workers/observability/) + * for your Worker. Lets you enable logs and traces with optional sampling rates. + * + * @example + * + * #### Traces only + * ```js + * { + * observability: { + * traces: { enabled: true, headSamplingRate: 0.1 } + * } + * } + * ``` + * + * #### Logs and traces + * ```js + * { + * observability: { + * logs: { enabled: true, headSamplingRate: 0.5 }, + * traces: { enabled: true, headSamplingRate: 0.1 } + * } + * } + * ``` + */ + observability?: Input<{ + /** + * Capture `console.*` output and invocation metadata for the Worker. + */ + logs?: Input<{ + enabled?: Input; + headSamplingRate?: Input; + invocationLogs?: Input; + }>; + /** + * Capture platform operations (fetch, KV, R2, Durable Object, Queue) and any + * custom spans added in Worker code via `ctx.tracing`. + */ + traces?: Input<{ + enabled?: Input; + headSamplingRate?: Input; + }>; + }>; /** * [Transform](/docs/components/#transform) how this component creates its underlying * resources. @@ -483,6 +527,7 @@ export class Worker extends Component implements Link.Linkable { const urlEnabled = normalizeUrl(); const compatibility = normalizeCompatibility(args); const domain = normalizeDomain(); + const observability = normalizeObservability(); const bindings = buildBindings(); const iamCredentials = createAwsCredentials(); @@ -582,6 +627,17 @@ export class Worker extends Component implements Link.Linkable { }; } + function normalizeObservability() { + if (!args.observability) return undefined; + return output(args.observability).apply((v) => ({ + enabled: true, + logs: v.logs + ? { enabled: true, invocationLogs: true, ...v.logs } + : undefined, + traces: v.traces ? { enabled: true, ...v.traces } : undefined, + })); + } + function buildBindings() { const result = [ { @@ -882,6 +938,9 @@ export class Worker extends Component implements Link.Linkable { })), ], ), + observability: observability as + | Output + | undefined, }, { parent, ignoreChanges: ["scriptName"] }, ), diff --git a/platform/src/components/cloudflare/workflow.ts b/platform/src/components/cloudflare/workflow.ts index 83868691d1..7aa4e885ad 100644 --- a/platform/src/components/cloudflare/workflow.ts +++ b/platform/src/components/cloudflare/workflow.ts @@ -89,6 +89,11 @@ export interface WorkflowArgs { * ``` */ environment?: Input>>; + /** + * Configure [Cloudflare Workers observability](https://developers.cloudflare.com/workers/observability/) + * for the underlying Worker. See `WorkerArgs.observability` for details. + */ + observability?: WorkerArgs["observability"]; /** * The Cloudflare account ID to use for this Workflow. * Overrides the default account ID set via `CLOUDFLARE_DEFAULT_ACCOUNT_ID`. @@ -218,6 +223,7 @@ export class Workflow extends Component implements Link.Linkable { handler: args.handler, link: args.link, environment: args.environment, + observability: args.observability, }, { parent }, ),