Skip to content

Changelog

New updates and improvements at Cloudflare.

Back to all posts

Workers tracing — write custom spans with new startActiveSpan() and span.end() runtime APIs

The Workers runtime now provides built-in tracing.startActiveSpan() and span.end() APIs, allowing you to write custom spans for operations that last beyond a single callback — for example, instrumenting a stream pipeline where the span should stay open until the stream is fully consumed.

This augments the existing API for writing custom spans, tracing.enterSpan(), which automatically ends a span when its callback is returned. With startActiveSpan(), the span remains open after the callback returns, and you call span.end() when the work is complete:

src/index.jsjs
import { tracing } from "cloudflare:workers";

const encoder = new TextEncoder();

export default {
	fetch() {
		return tracing.startActiveSpan("stream-response", (span) => {
			let timer;

			const body = new ReadableStream({
				start(controller) {
					controller.enqueue(encoder.encode("Starting...\n"));

					timer = setTimeout(() => {
						controller.enqueue(encoder.encode("Complete.\n"));
						controller.close();

						span.setAttribute("stream.status", "complete");
						span.end();
					}, 1000);
				},

				cancel() {
					if (timer !== undefined) clearTimeout(timer);

					span.setAttribute("stream.status", "cancelled");
					span.end();
				},
			});

			return new Response(body, {
				headers: { "content-type": "text/plain" },
			});
		});
	},
};
src/index.tsts
import { tracing } from "cloudflare:workers";

const encoder = new TextEncoder();

export default {
	fetch(): Response {
		return tracing.startActiveSpan("stream-response", (span) => {
			let timer: ReturnType<typeof setTimeout> | undefined;

			const body = new ReadableStream<Uint8Array>({
				start(controller) {
					controller.enqueue(encoder.encode("Starting...\n"));

					timer = setTimeout(() => {
						controller.enqueue(encoder.encode("Complete.\n"));
						controller.close();

						span.setAttribute("stream.status", "complete");
						span.end();
					}, 1000);
				},

				cancel() {
					if (timer !== undefined) clearTimeout(timer);

					span.setAttribute("stream.status", "cancelled");
					span.end();
				},
			});

			return new Response(body, {
				headers: { "content-type": "text/plain" },
			});
		});
	},
};

For more details, refer to the custom spans documentation.