new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Cloudflare Workers · all subjects

observability

243 notes in this subject, read out of this brain and free to use. This is page 4 of 5.

Enable tracing in Wrangler configuration

Custom spans require tracing to be enabled on the Worker. Set observability.traces.enabled to true in the Wrangler configuration file under the [observability.traces] section.

tracing.enterSpan() API reference

tracing.enterSpan(name, callback, ...args) creates a new span and runs the callback inside it. The span automatically ends when the callback returns (synchronously or asynchronously) or throws. Parameters: name (string, appears in trace visualizations), callback ((span: Span, ...args: A) => T, the function to execute within the span receiving the Span object as first argument), ...args (optional additional arguments forwarded to callback after the span parameter). Returns the return value of callback. Behavior: the new span becomes a child of the currently active span in async context, or the request's root span if none is active. Nested enterSpan calls and runtime-created spans (fetch, KV operations) inside the callback automatically become children of this span. The span ends when the callback returns synchronously, throws synchronously, or when its returned promise fulfills or rejects.

tracing.startActiveSpan() API reference

tracing.startActiveSpan(name, callback, ...args) creates a new span, makes it active while callback runs, and returns the callback result without automatically ending the span. You must call span.end() explicitly. Parameters: name (string, appears in trace visualizations), callback ((span: Span, ...args: A) => T, function to execute while span is active, receiving Span object as first argument), ...args (optional additional arguments forwarded after span parameter). Returns the return value of callback. Behavior: unlike enterSpan, the span is NOT automatically ended when the callback returns or throws. The span is active context parent only during the callback; after the callback returns, the span is no longer the active parent even though it remains open. If you forget to call span.end(), the span is still submitted when the request-owned span object is destroyed as a backstop, but do not rely on this behavior. You cannot create child spans of a startActiveSpan span from outside the callback.

span.setAttribute() sets span metadata

span.setAttribute(key, value) sets an attribute on the span. Parameter key is a string (the attribute name), value is string | number | boolean | undefined (passing undefined is a no-op). Attributes appear alongside the span in traces and OpenTelemetry exports.

span.isTraced indicates if invocation is being traced

span.isTraced is a readonly boolean indicating whether the invocation is being traced. When the request is not sampled based on head_sampling_rate, isTraced is false and enterSpan still runs the callback but does not record any telemetry. Use this to skip expensive attribute computation when the request is not being traced.

span.end() submits the span

span.end() ends the span and submits its attributes to the tracing system. This method is idempotent—calling it multiple times has no effect after the first call. After end() is called, span.isTraced returns false and any further setAttribute calls are silently ignored, including calls from in-flight async work. For spans created with enterSpan, you do not need to call end() as the runtime calls it automatically. For spans created with startActiveSpan, you must call end() to submit the span.

Spans nest automatically based on async context

Spans nest automatically based on the JavaScript async context. Any enterSpan call or platform operation such as fetch and env.MY_KV.get() that runs inside a callback becomes a child of the enclosing span.

Console logs are attributed to active span

console.log() and other console methods emit log events that are automatically attributed to the currently active span. This means log output from inside an enterSpan or startActiveSpan callback is associated with that span in traces and OpenTelemetry exports.

TypeScript type declarations for custom spans

The full type declarations for the custom spans API are: declare module 'cloudflare:workers' { namespace tracing { function enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; function startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T; } class Span { readonly isTraced: boolean; setAttribute(key: string, value: string | number | boolean | undefined): void; end(): void; } }. The same API is available on the handler context as ctx.tracing with the same types.

enterSpan vs startActiveSpan comparison

enterSpan: span ends automatically when callback returns/throws or promise settles, active context scope during callback, used for most instrumentation (sync and async work in single callback), span auto-ends on throw. startActiveSpan: span ends manually when you call span.end(), active context scope during callback, used for operations outliving callback like stream pipelines, span stays open on throw. Both methods set span as active context parent only during callback. After callback returns, span is no longer active parent. With enterSpan this does not matter because span also ends. With startActiveSpan, span remains open but is no longer context parent—new spans after callback return are not children of this span.

Custom spans limitations

Current limitations of custom spans: (1) No manual parent-child wiring—parent-child relationships are determined by JavaScript async context automatically. (2) No setAttributes (bulk set) yet—use individual setAttribute calls, bulk setting is planned for future release. (3) No spanContext() (trace/span IDs) yet—access to trace and span identifiers for manual propagation across boundaries is planned for future release. (4) No setOutcome yet—setting span outcome status is planned for future release.

Example: enterSpan with synchronous and asynchronous callbacks

Example showing enterSpan usage: const result = tracing.enterSpan('parse', (span) => { span.setAttribute('format', 'json'); return JSON.parse(body); }); const data = await tracing.enterSpan('fetchData', async (span) => { const res = await fetch('https://api.example.com/data'); span.setAttribute('http.response.status_code', res.status); return res.json(); }); const doubled = tracing.enterSpan('compute', (span, x) => x * 2, 21); The first example shows synchronous callback—span ends when function returns. The second shows async callback—span ends when promise settles. The third shows forwarding arguments to the callback.

Example: startActiveSpan with stream pipeline

Example of startActiveSpan instrumenting a stream pipeline: import { tracing } from 'cloudflare:workers'; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { const body = request.body; if (!body) return new Response('No body', { status: 400 }); const stream = tracing.startActiveSpan('process-stream', (span) => { span.setAttribute( 'request.content_type', request.headers.get('content-type') ?? 'unknown', ); return body.pipeThrough( new TransformStream({ transform(chunk, controller) { controller.enqueue(chunk); }, flush() { span.setAttribute('stream.status', 'complete'); span.end(); }, cancel() { span.setAttribute('stream.status', 'cancelled'); span.end(); }, }), ); }); return new Response(stream); }, }; The span is active during the callback so the pipeThrough operation is correctly nested. The span stays open after callback returns until flush() or cancel() calls span.end().

Example: startActiveSpan capturing span reference for later use

Example of capturing span reference without streams: let capturedSpan; const value = tracing.startActiveSpan('manual-operation', (span) => { capturedSpan = span; span.setAttribute('phase', 'started'); return computeResult(); }); capturedSpan.setAttribute('phase', 'complete'); capturedSpan.end(); The span is still open after the callback returns, allowing you to set more attributes before ending it.

Example: Using both import and ctx.tracing access methods

Example showing both custom spans access methods are interchangeable: import { tracing } from 'cloudflare:workers'; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { return tracing.enterSpan('handleRequest', async (span) => { span.setAttribute('url.path', new URL(request.url).pathname); const user = await ctx.tracing.enterSpan('auth', async () => { return authenticate(request, env); }); return buildResponse(user); }); }, }; The example demonstrates that tracing.enterSpan from the cloudflare:workers import and ctx.tracing.enterSpan are interchangeable.

Example: Using span.isTraced to skip expensive computation

Example of using span.isTraced to conditionally skip expensive attribute computation: tracing.enterSpan('process', (span) => { if (span.isTraced) { span.setAttribute( 'request.body.preview', JSON.stringify(body).slice(0, 200), ); } return processBody(body); }); When the request is not sampled, isTraced is false and you can skip expensive operations like stringifying and slicing the body.

Example: Logging within spans

Example of console logging within spans: tracing.enterSpan('processPayment', async (span) => { console.log('Starting payment processing'); const result = await chargeCard(token, amount); console.log('Payment complete', result.id); }); Log output from inside an enterSpan or startActiveSpan callback is automatically associated with that span in traces and OpenTelemetry exports.

Queue handler span attributes

Queue handler spans capture: cloudflare.queue.name (queue name), cloudflare.queue.batch_size (batch size).

Universal span attributes

All spans include these attributes: cloud.provider (cloudflare), cloud.platform (cloudflare.workers), faas.name (Worker name), faas.invocation_id (unique invocation identifier), faas.version (deployed version tag), faas.invoked_region (invocation region), service.name (Worker name), cloudflare.colo (three-letter IATA code), cloudflare.script_name (Worker name), cloudflare.script_tags (deployment tags), cloudflare.script_version.id (version identifier), cloudflare.invocation.sequence.number (counter for span ordering), telemetry.sdk.language (javascript), telemetry.sdk.name (cloudflare).

Root span attributes

Root spans include these additional attributes: faas.trigger (invocation trigger type: http, cron, queue, email), cloudflare.ray_id (unique request identifier), cloudflare.handler_type (handler type: fetch, scheduled, queue, email, alarm), cloudflare.entrypoint (invoked entrypoint name), cloudflare.execution_model (execution model: stateless or stateful for Durable Objects), cloudflare.outcome (invocation outcome: ok, exception, exceededCpu, exceededMemory), cloudflare.cpu_time_ms (CPU time in milliseconds), cloudflare.wall_time_ms (wall time in milliseconds).

Fetch span attributes

Fetch spans capture: network.protocol.name, network.protocol.version, url.full, url.scheme, url.path, url.query, server.port, server.address, user_agent.original, http.request.method, http.request.header.content-type, http.request.header.content-length, http.request.header.accept, http.request.header.accept-encoding, http.request.body.size, http.response.status_code, http.response.body.size.

Cache put span attributes

Cache put spans capture: cache.request.url, cache.request.method, cache.request.payload.status_code, cache.request.payload.header.cache_control, cache.request.payload.header.cache_tag, cache.request.payload.header.etag, cache.request.payload.header.expires, cache.request.payload.header.last_modified, cache.request.payload.size, cache.response.success.

Cache match span attributes

Cache match spans capture: cache.request.ignore_method, cache.request.url, cache.request.method, cache.request.header.range, cache.request.header.if_modified_since, cache.request.header.if_none_match, cache.response.status_code, cache.response.body.size, cache.response.cache_status, cache.response.success.

Cache delete span attributes

Cache delete spans capture: cache.request.ignore_method, cache.request.url, cache.request.method, cache.response.status_code, cache.response.success.

Durable Object Storage KV delete span attributes

Durable Object Storage KV delete operation spans capture: cloudflare.durable_object.kv.query.keys, cloudflare.durable_object.kv.query.keys.count, cloudflare.durable_object.kv.response.deleted_count.

Fetch handler span attributes

Fetch handler spans capture: cloudflare.verified_bot_category, cloudflare.asn, cloudflare.response.time_to_first_byte_ms, geo.timezone, geo.continent.code, geo.country.code, geo.locality.name, geo.locality.region, user_agent.original, user_agent.os.name, user_agent.os.version, user_agent.browser.name, user_agent.browser.major_version, user_agent.browser.version, user_agent.engine.name, user_agent.engine.version, user_agent.device.type, user_agent.device.vendor, user_agent.device.model, http.request.method, http.request.header.accept, http.request.header.accept-encoding, http.request.header.accept-language, url.full, url.path, network.protocol.name.

Scheduled handler span attributes

Scheduled handler spans capture: faas.cron (cron expression), cloudflare.scheduled_time (scheduled execution time).

Automatic tracing instrumentation

Cloudflare Workers provides automatic tracing instrumentation out of the box. No code changes or SDK are required to capture spans and attributes.

RPC handler span attributes

RPC handler spans capture: cloudflare.jsrpc.method (RPC method name).

Email handler span attributes

Email handler spans capture: cloudflare.email.from (sender address), cloudflare.email.to (recipient address), cloudflare.email.size (email size).

Tail handler span attributes

Tail handler spans capture: cloudflare.trace.count (number of traces).

Alarm handler span attributes

Alarm handler spans capture: cloudflare.scheduled_time (scheduled alarm time).

D1 universal span attributes

All D1 spans capture: db.system.name, db.operation.name, db.query.text, cloudflare.binding.type, cloudflare.d1.response.size_after, cloudflare.d1.response.rows_read, cloudflare.d1.response.rows_written, cloudflare.d1.response.last_row_id, cloudflare.d1.response.changed_db, cloudflare.d1.response.changes, cloudflare.d1.response.served_by_region, cloudflare.d1.response.served_by_primary, cloudflare.d1.response.sql_duration_ms, cloudflare.d1.response.total_attempts.

D1 batch span attributes

D1 batch operation spans additionally capture: db.operation.batch.size, cloudflare.d1.query.bookmark, cloudflare.d1.response.bookmark.

D1 prepared statement span attributes

D1 prepared statement operations (first, run, all, raw) capture: cloudflare.d1.query.bookmark, cloudflare.d1.response.bookmark.

KV universal span attributes

All KV spans capture: db.system.name, db.operation.name, cloudflare.binding.name, cloudflare.binding.type.

KV getWithMetadata span attributes

KV getWithMetadata operation spans capture: cloudflare.kv.query.keys, cloudflare.kv.query.keys.count, cloudflare.kv.query.type, cloudflare.kv.query.cache_ttl, cloudflare.kv.response.size, cloudflare.kv.response.returned_rows, cloudflare.kv.response.metadata, cloudflare.kv.response.cache_status.

KV put span attributes

KV put operation spans capture: cloudflare.kv.query.keys, cloudflare.kv.query.keys.count, cloudflare.kv.query.value_type, cloudflare.kv.query.expiration, cloudflare.kv.query.expiration_ttl, cloudflare.kv.query.metadata, cloudflare.kv.query.payload.size.

KV delete span attributes

KV delete operation spans capture: cloudflare.kv.query.keys, cloudflare.kv.query.keys.colunt.

KV list span attributes

KV list operation spans capture: cloudflare.kv.query.prefix, cloudflare.kv.query.limit, cloudflare.kv.query.cursor, cloudflare.kv.response.size, cloudflare.kv.response.returned_rows, cloudflare.kv.response.list_complete, cloudflare.kv.response.cursor, cloudflare.kv.response.cache_status, cloudflare.kv.response.expiration.

R2 universal span attributes

All R2 spans capture: cloudflare.binding.type, cloudflare.binding.name, cloudflare.r2.bucket, cloudflare.r2.operation, cloudflare.r2.response.success, cloudflare.r2.error.message, cloudflare.r2.error.code.

R2 head operation span attributes

R2 head operation spans capture: cloudflare.r2.request.key, cloudflare.r2.response.etag, cloudflare.r2.response.size, cloudflare.r2.response.uploaded, cloudflare.r2.response.checksum.value, cloudflare.r2.response.checksum.type, cloudflare.r2.response.storage_class, cloudflare.r2.response.ssec_key, cloudflare.r2.response.content_type, cloudflare.r2.response.content_encoding, cloudflare.r2.response.content_disposition, cloudflare.r2.response.content_language, cloudflare.r2.response.cache_control, cloudflare.r2.response.cache_expiry, cloudflare.r2.response.custom_metadata.

R2 put operation span attributes

R2 put operation spans capture: cloudflare.r2.request.key, cloudflare.r2.request.size, cloudflare.r2.request.checksum.type, cloudflare.r2.request.checksum.value, cloudflare.r2.request.custom_metadata, cloudflare.r2.request.http_metadata.content_type, cloudflare.r2.request.http_metadata.content_encoding, cloudflare.r2.request.http_metadata.content_disposition, cloudflare.r2.request.http_metadata.content_language, cloudflare.r2.request.http_metadata.cache_control, cloudflare.r2.request.http_metadata.cache_expiry, cloudflare.r2.request.storage_class, cloudflare.r2.request.ssec_key, cloudflare.r2.request.only_if.etag_matches, cloudflare.r2.request.only_if.etag_does_not_match, cloudflare.r2.request.only_if.uploaded_before, cloudflare.r2.request.only_if.uploaded_after, cloudflare.r2.response.etag, cloudflare.r2.response.size, cloudflare.r2.response.uploaded, cloudflare.r2.response.checksum.value, cloudflare.r2.response.checksum.type, cloudflare.r2.response.storage_class, cloudflare.r2.response.ssec_key, cloudflare.r2.response.content_type, cloudflare.r2.response.content_encoding, cloudflare.r2.response.content_disposition, cloudflare.r2.response.content_language, cloudflare.r2.response.cache_control, cloudflare.r2.response.cache_expiry, cloudflare.r2.response.custom_metadata.

R2 list operation span attributes

R2 list operation spans capture: cloudflare.r2.request.limit, cloudflare.r2.request.prefix, cloudflare.r2.request.cursor, cloudflare.r2.request.delimiter, cloudflare.r2.request.start_after, cloudflare.r2.request.include.http_metadata, cloudflare.r2.request.include.custom_metadata, cloudflare.r2.response.returned_objects, cloudflare.r2.response.delimited_prefixes, cloudflare.r2.response.truncated, cloudflare.r2.response.cursor.

R2 delete operation span attributes

R2 delete operation spans capture: cloudflare.r2.request.keys.

R2 createMultipartUpload operation span attributes

R2 createMultipartUpload operation spans capture: cloudflare.r2.request.key, cloudflare.r2.request.custom_metadata, cloudflare.r2.request.http_metadata.content_type, cloudflare.r2.request.http_metadata.content_encoding, cloudflare.r2.request.http_metadata.content_disposition, cloudflare.r2.request.http_metadata.content_language, cloudflare.r2.request.http_metadata.cache_control, cloudflare.r2.request.http_metadata.cache_expiry, cloudflare.r2.request.storage_class, cloudflare.r2.request.ssec_key, cloudflare.r2.response.upload_id.

R2 uploadPart operation span attributes

R2 uploadPart operation spans capture: cloudflare.r2.request.key, cloudflare.r2.request.upload_id, cloudflare.r2.request.part_number, cloudflare.r2.request.ssec_key, cloudflare.r2.request.size, cloudflare.r2.response.etag.

R2 abortMultipartUpload operation span attributes

R2 abortMultipartUpload operation spans capture: cloudflare.r2.request.key, cloudflare.r2.request.upload_id.

R2 completeMultipartUpload operation span attributes

R2 completeMultipartUpload operation spans capture: cloudflare.r2.request.key, cloudflare.r2.request.upload_id, cloudflare.r2.request.uploaded_parts, cloudflare.r2.response.etag, cloudflare.r2.response.size, cloudflare.r2.response.uploaded, cloudflare.r2.response.checksum.value, cloudflare.r2.response.checksum.type, cloudflare.r2.response.storage_class, cloudflare.r2.response.ssec_key, cloudflare.r2.response.content_type, cloudflare.r2.response.content_encoding, cloudflare.r2.response.content_disposition, cloudflare.r2.response.content_language, cloudflare.r2.response.cache_control, cloudflare.r2.response.cache_expiry, cloudflare.r2.response.custom_metadata.

Durable Object Storage SQL API exec span attributes

Durable Object Storage SQL exec operation spans capture: db.system.name, db.operation.name, db.query.text, cloudflare.durable_object.query.bindings, cloudflare.durable_object.response.rows_read, cloudflare.durable_object.response.rows_written.

Durable Object Storage SQL API getDatabaseSize span attributes

Durable Object Storage getDatabaseSize operation spans capture: db.operation.name, cloudflare.durable_object.response.db_size.

Durable Object Storage KV list span attributes

Durable Object Storage KV list operation spans capture: cloudflare.durable_object.kv.query.start, cloudflare.durable_object.kv.query.startAfter, cloudflare.durable_object.kv.query.end, cloudflare.durable_object.kv.query.prefix, cloudflare.durable_object.kv.query.reverse, cloudflare.durable_object.kv.query.limit.

Images output binding span attributes

Images output binding operation spans capture: cloudflare.binding.type, cloudflare.images.options.format, cloudflare.images.options.quality, cloudflare.images.options.background, cloudflare.images.options.anim, cloudflare.images.options.transforms, cloudflare.images.error.code.

Images info binding span attributes

Images info binding operation spans capture: cloudflare.binding.type, cloudflare.images.options.encoding, cloudflare.images.result.format, cloudflare.images.result.file_size, cloudflare.images.result.width, cloudflare.images.result.height, cloudflare.images.error.code.

Cache API error message improvements

As of 2020-03-26, certain internal errors thrown when using the Cache API are now reported with human-friendly error messages instead of generic internal errors.

Monitoring CPU usage

CPU time and wall time appear in Workers Logs in the invocation log. CPU time and wall time appear at the top level of the Workers Trace Events object for Tail Workers and Logpush. Use CPU profiling with DevTools locally to identify CPU-intensive sections of your code.

Workers Trace Events Logpush pricing

Workers Logpush is only available on the Workers Paid plan. Pricing is 10 million requests per month included, plus $0.05 per additional million requests. Workers Logpush charges for request logs that reach your end destination after applying filtering or sampling.

Playground log viewer capabilities

The Playground includes a lightweight log viewer at the bottom of the preview panel that displays output from console.log calls during preview runs. It supports logging primitive values, objects, and arrays, and supports clearing log output between runs. It does not support logging class instances or their properties such as request.url.

CF-Cache-Status header indicates caching attempt

When a response fills the cache, the response header contains CF-Cache-Status: HIT. You can tell an object is attempting to cache if you see the CF-Cache-Status header at all.

Logpush API call with ScriptVersion example

Example Logpush API call to add ScriptVersion field for gradual deployment observability: curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/logpush/jobs' \ -H 'Authorization: Bearer <TOKEN>' \ -H 'Content-Type: application/json' \ -d '{ "name": "workers-logpush", "output_options": { "field_names": ["Event", "EventTimestampMs", "Outcome", "Logs", "ScriptName", "ScriptVersion"] }, "destination_conf": "<DESTINATION_URL>", "dataset": "workers_trace_events", "enabled": true }'| jq .

Give your agent this brain