Tail Workers
Consume another Worker's execution traces from Go with a Tail Worker.
A Tail Worker receives a batch of trace events for every invocation of a “producer” Worker. The exp/cloudflare/tail package registers the worker’s tail(events, env, ctx) handler and decodes each TraceItem.
Point a producer at the tail worker
There is no trigger key in the tail worker’s own wrangler.toml. Instead, add a tail_consumers entry to the producer worker’s wrangler.toml, naming the tail worker’s service:
tail_consumers = [{ service = "tail-worker" }]
Handle trace events
tail.Handle registers a func([]tail.TraceItem) error and blocks. Each TraceItem describes one producer invocation — ScriptName, Outcome, ExecutionModel, CpuTime, WallTime, plus Logs ([]TraceLog) and Exceptions ([]TraceException).
func main() {
tail.Handle(func(items []tail.TraceItem) error {
for _, item := range items {
log.Printf("script=%s outcome=%s cpu=%.2fms wall=%.2fms",
item.ScriptName, item.Outcome, item.CpuTime, item.WallTime)
switch item.EventKind() {
case "fetch":
if fe, ok := item.FetchEvent(); ok {
log.Printf("fetch %s %s", fe.Request.Method(), fe.Request.URL())
}
case "scheduled":
if se, ok := item.ScheduledEvent(); ok {
log.Printf("cron=%q", se.Cron)
}
case "queue":
if qe, ok := item.QueueEvent(); ok {
log.Printf("queue=%s batchSize=%d", qe.Queue, int(qe.BatchSize))
}
}
}
return nil
})
}
item.Eventis a discriminated union left as ajs.Value.item.EventKind()infers the branch —"fetch","jsrpc","scheduled","alarm","queue","email","tail", or"hibernatableWebSocket"— and the matching typed accessor (FetchEvent(),ScheduledEvent(),AlarmEvent(),QueueEvent(),EmailEvent(),TailEvent(),JsRpcEvent(),HibernatableWebSocketEvent()) returns(*T, bool).connectandcustomevents carry no distinguishing properties, so they (and anything unrecognized) reportEventKind() == "".item.EventTime()decodesEventTimestamp(Unix ms) as atime.Time; a timestamp of0is reported as absent.- Returning an error logs the rejection but does not retry delivery.
Handleblocks; a worker that also serves other triggers should register those first and call a single blocking entry point such asworkers.Serveinstead.
Example project
_examples/tail-worker logs a summary of every trace event it receives.