CLI for querying Cloudflare Workers Observability logs.
pip install cf-logsOr run directly without installing:
uvx cf-logs events -s 1hSet your Cloudflare credentials (or create a .env file):
export CF_ACCOUNT_ID="your-account-id"
export CF_API_TOKEN="your-api-token"The API token needs the Workers Observability Read permission (and Write for managing destinations).
cf-logs COMMAND [OPTIONS]
Run cf-logs COMMAND --help for detailed usage and examples.
| Command | Description |
|---|---|
events |
Fetch individual log events |
query |
Run aggregate queries (counts, percentiles, etc.) |
invocations |
Fetch logs grouped by request |
tail |
Live-tail logs (like tail -f) |
keys |
List available field keys |
values |
List unique values for a field |
destinations |
Manage OpenTelemetry export destinations |
The events command has built-in presets for common debugging scenarios via -p:
| Preset | What it filters |
|---|---|
errors |
Log level = error |
exceptions |
Unhandled exceptions (outcome = exception) |
5xx |
HTTP 5xx responses |
4xx |
HTTP 4xx responses |
slow |
Slow requests (wall time >= 1s) |
cold |
Cold start requests |
cpu |
Exceeded CPU or memory limits |
cf-logs events -p errors # all errors in last hour
cf-logs events -p 5xx -w my-api -s 24h # 5xx for a worker, last 24h
cf-logs events -p slow -j # slow requests as JSON
cf-logs events -p exceptions -n "db" # exceptions mentioning "db"Presets combine with other filters, so -p 5xx -w my-api -n "timeout" all work together.
# Quick look at errors
cf-logs events -p errors -w my-api
# Are there unhandled exceptions?
cf-logs events -p exceptions -w my-api -s 30m
# What's the error rate?
cf-logs query -c COUNT -g '$workers.outcome' -w my-api -s 1h# Find slow requests
cf-logs events -p slow -w my-api
# P99 and P50 latency
cf-logs query -c P99:'$workers.wallTimeMs' -c P50:'$workers.wallTimeMs' -w my-api -s 6h
# Latency by endpoint
cf-logs query -c P99:'$workers.wallTimeMs' -g '$workers.event.request.url' -w my-api# Tail logs in real time
cf-logs tail -w my-api
# Tail only errors
cf-logs tail -w my-api -f '$metadata.level=error'
# Watch for 5xx
cf-logs tail -w my-api -f '$workers.event.response.status>=500' -i 2# Requests per worker
cf-logs query -c COUNT -g '$workers.scriptName' -s 24h
# Status code distribution
cf-logs query -c COUNT -g '$workers.event.response.status' -w my-api
# Traffic over time (5-min buckets)
cf-logs query -c COUNT --granularity 300 -w my-api -s 6h -j# View all logs for recent invocations
cf-logs invocations -w my-api -s 15m
# Find failed invocations
cf-logs invocations -f '$workers.outcome=exception' -s 1h# Last hour of events (default)
cf-logs events
# Last 24 hours for a specific worker
cf-logs events -s 24h -w my-api
# Events with 5xx status codes
cf-logs events -f '$workers.event.response.status>=500'
# Search for "timeout" in log messages
cf-logs events -n "timeout"
# Exceptions or errors (OR filter)
cf-logs events -f '$workers.outcome=exception' -f '$metadata.level=error' --or
# Raw JSON output for piping to jq
cf-logs events -w my-api -j | jq '.events.events[].["$metadata"].message'# Total event count (default)
cf-logs query
# Count events per worker
cf-logs query -c COUNT -g '$workers.scriptName'
# P99 latency over the last 24 hours
cf-logs query -c P99:'$workers.wallTimeMs' -s 24h
# Average CPU time per worker, sorted descending
cf-logs query -c AVG:'$workers.cpuTimeMs' -g '$workers.scriptName' -o AVG:desc
# Error rate by status code
cf-logs query -c COUNT -g '$workers.event.response.status' -w my-api
# Multiple calculations at once
cf-logs query -c COUNT -c P50:'$workers.wallTimeMs' -c P99:'$workers.wallTimeMs'
# Time-series with 5-minute buckets
cf-logs query -c COUNT -g '$workers.outcome' --granularity 300 -j
# Only show groups with more than 100 events
cf-logs query -c COUNT -g '$workers.scriptName' -H 'COUNT>100'# Tail all logs
cf-logs tail
# Tail a specific worker
cf-logs tail -w my-api
# Tail errors only, poll every 2 seconds
cf-logs tail -f '$metadata.level=error' -i 2
# Tail as JSON for piping
cf-logs tail -w my-api -j | jq '.["$metadata"].message'# List all available field keys
cf-logs keys
# Search for keys related to "status"
cf-logs keys -S status
# List all worker names
cf-logs values '$workers.scriptName'
# List all outcomes for a worker
cf-logs values '$workers.outcome' -w my-api
# List HTTP status codes (numeric field)
cf-logs values '$workers.event.response.status' -t number# List configured destinations
cf-logs destinations list
# Create an OTLP destination
cf-logs destinations create \
--name my-collector \
--type otlp \
--endpoint https://otel.example.com/v1/traces \
-H 'Authorization=Bearer token123'
# Disable a destination
cf-logs destinations update my-collector-slug --disabled
# Delete a destination
cf-logs destinations delete my-collector-slug -yFilters are passed with -f and support these operators:
| Syntax | Operator |
|---|---|
key=value |
equals |
key!=value |
not equals |
key>value |
greater than |
key>=value |
greater than or equal |
key<value |
less than |
key<=value |
less than or equal |
key~=pattern |
regex match |
key::value |
contains substring |
key!:value |
does not contain |
key^=value |
starts with |
key@=a,b,c |
value in list |
key@!=a,b,c |
value not in list |
key? |
field exists |
key!? |
field is null |
Multiple -f flags are combined with AND by default. Use --or to combine with OR.
| Field | Description |
|---|---|
$workers.scriptName |
Worker script name |
$workers.outcome |
ok, exception, exceededCpu, exceededMemory, canceled |
$workers.wallTimeMs |
Wall clock time in ms |
$workers.cpuTimeMs |
CPU time in ms |
$workers.eventType |
fetch, scheduled, cron, queue, alarm, email, rpc |
$workers.executionModel |
stateless or durableObject |
$workers.event.response.status |
HTTP response status code |
$metadata.level |
log, debug, info, warn, error |
$metadata.message |
Log message text |
$metadata.requestId |
Request ID |
$metadata.traceId |
Trace ID |
Used with -c in the query command:
COUNT, UNIQ, AVG, SUM, MIN, MAX, MEDIAN, STDDEV, VARIANCE, P01, P05, P10, P25, P75, P90, P95, P99, P999
Format: OPERATOR (for count) or OPERATOR:field (for field aggregations).
The --since and --until options accept:
- Durations:
30s,5m,1h,7d,2w,1h30m - ISO datetimes:
2024-01-15T10:00:00