Workers tracing の startSpan() は子 span を持たない、例外記録 API も追加
Workers のカスタム span API 4種の挙動を解説。tracing を有効にしたうえで startSpan() の非 active 性、root span への属性付け、例外記録と end() の呼び出し順を確認する。
Workers のカスタム span API 4種の挙動を解説。tracing を有効にしたうえで startSpan() の非 active 性、root span への属性付け、例外記録と end() の呼び出し順を確認する。
Cloudflare Workers のカスタム span で使える OpenTelemetry の span API が増えた。2026年9月25日の changelog に載ったのは tracing.startSpan()、tracing.getActiveSpan()、span.recordException()、span.setAttributes() の4つで、どれも cloudflare:workers から import する tracing を起点に使う。自前の span を仕込むなら、書き始める前に押さえておきたい挙動が二つある。startSpan() で作った span は active span にならないこと、そして getActiveSpan() はカスタム span の外で invocation の root span を返すことだ。
changelog によると、tracing.startSpan(name) は span を作って返すが、その span を active span にはしない。他の span はその下にネストしない。OpenTelemetry の他の環境の感覚で「親 span を開いておけば、その間に作った span は子になる」と考えて書くと、この前提は外れる。
終了は呼び出し側の責任で、処理が終わったら span.end() を呼ぶ。changelog の例では try/finally の finally で end() を呼んでおり、成功しても例外で抜けても必ず閉じる形になっている。end() を呼び忘れた span がトレース上でどう扱われるかは changelog には書かれていない。
使いどころは、例の "load-profile" のように、一つの処理の区間を独立した span として切り出す場面だ。区間の中にさらに階層を作る用途には、この API 単体では向かない。
tracing.getActiveSpan() は現在 active な span を返す。changelog が挙げる用途は、span オブジェクトを引数で持ち回らずに、ヘルパー関数やライブラリから今の span に注釈を付けることだ。カスタム span の外で呼ぶと、invocation の root span が返る。例のコメントが「Annotate the invocation’s root span」となっているのはこのためで、fetch ハンドラの冒頭で呼べばリクエスト全体に user.id や user.plan を載せられる。
前の節と組み合わせると注意点が一つ出る。startSpan() の span は active にならないので、その区間の中でヘルパーが getActiveSpan() を呼んでも、返るのは startSpan() で作った span ではない。他にカスタム span が開いていなければ root span が返ると読めるが、これは changelog の二つの記述を組み合わせた推測だ。ヘルパーで付けた属性を startSpan() の span に載せたいなら、span オブジェクトを引数で渡すほうが確実である。
例では tracing.getActiveSpan()?.setAttributes(...) とオプショナルチェーンを使っている。getActiveSpan() が undefined などを返す条件があるのかは、changelog の本文からは分からない。
span.recordException(exception) は span に例外イベントを記録する。受け付けるのは Error、文字列、または code・name・message のいずれかを持つオブジェクトだ。TypeScript 版の例では catch 節の err を err as Error とキャストして渡している。
例の catch 節は recordException() の後に throw err で例外を投げ直している。記録するだけでは処理の流れは変わらないので、エラーレスポンスをどう返すかは従来どおり自分で決める。記録によって span のステータスがエラー扱いになるかどうかは changelog に書かれていない。
カスタム span を記録するには、先に Worker の tracing を有効にする。Cloudflare の Custom spans 文書 に従い、Wrangler 設定の observability.traces.enabled が true か確認する。以下は changelog の TypeScript 版の例だ。
import { tracing } from "cloudflare:workers";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const user = await authenticate(request, env);
// Annotate the invocation's root span
tracing.getActiveSpan()?.setAttributes({
"user.id": user.id,
"user.plan": user.plan,
});
const span = tracing.startSpan("load-profile");
try {
return Response.json(await loadProfile(env, user.id));
} catch (err) {
span.recordException(err as Error);
throw err;
} finally {
span.end();
}
},
};
流れは次のとおりだ。
getActiveSpan() を呼び、root span に setAttributes() でまとめて属性を付けるstartSpan("load-profile") で区間を開くrecordException() で span に記録し、投げ直すend() を呼んで区間を閉じるauthenticate と loadProfile は例の中で定義されていないアプリ側の関数である。
span.setAttributes(attributes) は複数の属性を一度に設定する。あわせて setAttribute() と setAttributes() が span 自身を返すようになったので、呼び出しをチェーンできる。たとえば tracing.startSpan("load-profile").setAttributes({ ... }) と書けば、作成と属性付けを一つの式で済ませて span を変数に受けられる。
changelog には、これらの API を使うのに必要な compatibility date や wrangler のバージョン、対象プランは書かれていない。導入前に自分の Worker の設定で動くかを確かめたうえで、まずは root span への属性付けと、重い処理一つを startSpan() で囲むところから始めるのが手堅い。