Cloudflare Worker Logs
Query historical logs from Cloudflare Workers using the Workers Observability API.
Requirements
Requires environment variables (should be defined in env already; if not, available via uv run poe init-secrets):
CLOUDFLARE_ACCOUNT_IDCLOUDFLARE_API_TOKEN
Real-time Logs
For real-time log streaming (not historical queries), use wrangler tail instead:
cd terraform/cloudflare && wrangler tail llms --format pretty
This requires a terminal session that stays open.
Available Scripts
All scripts are in the scripts/ directory relative to this skill. Run them with:
uv run scripts/<script_name>.py [args]
cf_workers_list.py
List all Workers in the Cloudflare account. If you only need details of a single Worker, use cf_worker_get.py instead.
uv run scripts/cf_workers_list.py
No arguments required.
cf_worker_get.py
Get the details of a Cloudflare Worker.
uv run scripts/cf_worker_get.py <script_name>
Arguments:
script_name(required): The name of the worker script to retrieve
cf_observability_keys.py
Find keys in the Workers Observability data.
Best Practices:
- Set a high limit (1000+) to ensure you see all available keys
- Add the
$metadata.servicefilter to narrow results to a specific Worker
Troubleshooting:
- If expected fields are missing, verify the Worker is actively logging
- For empty results, try broadening your time range
uv run scripts/cf_observability_keys.py [options]
Options:
--minutes N: Time range in minutes (default: 60, max: 10080 for 7 days)--limit N: Max keys to return (default: 100, set high like 1000 for comprehensive list)--key-needle PATTERN: Pattern to match key names--key-needle-regex: Treat key-needle as regex--needle TEXT: General text search in log content--needle-regex: Treat needle as regex--filter KEY:OP:TYPE:VALUE: Filter (can be repeated)
Example:
uv run scripts/cf_observability_keys.py --limit 1000 --filter '$metadata.service:eq:string:llms'
cf_observability_values.py
Find values in the Workers Observability Data.
Troubleshooting:
- For no results, verify the field exists using
cf_observability_keys.pyfirst - If expected values are missing, try broadening your time range
uv run scripts/cf_observability_values.py <key> [options]
Arguments:
key(required): The key to get values for (e.g.,$metadata.service,$metadata.level)
Options:
--key-type {string,number,boolean}: Type of the key (default: string)--minutes N: Time range in minutes (default: 60, max: 10080 for 7 days)--limit N: Max values to return (default: 50)--needle PATTERN: Pattern to match values--needle-regex: Treat needle as regex--filter KEY:OP:TYPE:VALUE: Filter (can be repeated)
Example:
uv run scripts/cf_observability_values.py '$metadata.service' --limit 100
cf_observability_query.py
Query the Workers Observability API to analyze logs and metrics from Cloudflare Workers.
Core Capabilities:
This script provides three primary views of your Worker data:
- events (default): Browse individual request logs and errors
- calculations: Compute statistics across requests (avg, p99, etc.)
- invocations: Find specific request invocations matching criteria
Examples by View Type:
Events View:
- "Show all errors for worker llms in the last 30 minutes"
- "Show events where the path contains /api"
Calculation View:
- "What is the p99 wall time for worker llms?"
- "Count requests grouped by status code"
Invocation View:
- "Find a request that resulted in a 500 error"
- "List successful requests with status 200"
Filtering Best Practices:
- Before applying filters, use
cf_observability_keys.pyandcf_observability_values.pyto confirm available fields and values - Common filter fields:
$metadata.service,$metadata.origin,$metadata.trigger,$metadata.message,$metadata.level,$metadata.requestId
Calculation Best Practices:
- Before applying calculations, use
cf_observability_keys.pyto confirm the key exists
Troubleshooting:
- If no results returned, try broadening the time range or relaxing filters
- For errors about invalid fields, use
cf_observability_keys.pyto see available options
uv run scripts/cf_observability_query.py [options]
Options:
--view {events,calculations,invocations}: Query view type (default: events)--minutes N: Time range in minutes (default: 60, max: 10080 for 7 days)--limit N: Max results to return (default: 10)--offset ID: Pagination offset (use$metadata.idfrom previous results)--offset-by N: Numeric offset for pagination--offset-direction {next,prev}: Pagination direction--dry: Dry run - validate query without executing--granularity N: Time bucket granularity for calculations--filter KEY:OP:TYPE:VALUE: Filter (can be repeated)--filter-combination {and,or}: How to combine filters (default: and)--calculation OPERATOR[:KEY[:TYPE[:ALIAS]]]: Calculation (can be repeated, for calculations view)--group-by VALUE[:TYPE]: Field to group by (can be repeated)--order-by ALIAS: Calculation alias to sort by--order {asc,desc}: Sort order (default: desc)--needle TEXT: Full-text search in log content--needle-regex: Treat needle as regex
Filter Format:
Filters use format key:operation:type:value where:
key: Field name (e.g.,$metadata.service)operation: One ofincludes,not_includes,starts_with,regex,exists,is_null,in,not_in,eq,neq,gt,gte,lt,ltetype: One ofstring,number,booleanvalue: Comparison value
Calculation Format:
Calculations use format operator[:key[:key_type[:alias]]] where:
operator: One ofuniq,count,max,min,sum,avg,median,p001,p01,p05,p10,p25,p75,p90,p95,p99,p999,stddev,variancekey: Field to calculate on (optional forcount)key_type: Type of the key (default: number)alias: Name for this calculation in results
Examples:
Show recent errors for the llms worker:
uv run scripts/cf_observability_query.py --filter '$metadata.service:eq:string:llms' --filter '$metadata.level:eq:string:error' --limit 20
Get p99 wall time grouped by service:
uv run scripts/cf_observability_query.py --view calculations --calculation 'p99:wallTime:number:p99_wall' --group-by '$metadata.service'
Count requests by status code:
uv run scripts/cf_observability_query.py --view calculations --calculation 'count' --group-by 'response.status:number'
Search for specific text in logs:
uv run scripts/cf_observability_query.py --needle 'timeout' --minutes 120
cf_analytics_query.py
Query Workers Analytics Engine datasets using the SQL API. This is for custom metrics written via writeDataPoint(), not request logs (use cf_observability_query.py for logs).
Key Features:
- Automatic semantic aliases for known datasets (e.g.,
blob1→path,double1→latency_ms) - Built-in sampling-aware aggregation helpers
- Raw SQL mode for complex queries
Schema for llms_usage dataset:
| Raw Field | Semantic Name | Description |
| --------- | --------------- | ------------------------------------------------------------------------------------- |
| index1 | method | HTTP method or "unauthorized" |
| blob1 | path | Request path |
| blob2 | status | HTTP status code |
| blob3 | request_type | Category: provider, amp-tab, amp-telemetry, amp-admin, management, oauth, other |
| blob4 | provider | LLM provider: anthropic, google, openai, etc. (empty for non-provider requests) |
| blob5 | model | Model name from path (Gemini only; empty for Anthropic/OpenAI where model is in body) |
| blob6 | client | Client identifier: "VS Code CLI", "VS Code Insiders", "Bun", "node", etc. |
| double1 | latency_ms | Response time in milliseconds |
| double2 | input_tokens | Input/prompt tokens (non-streaming provider requests only; 0 for streaming) |
| double3 | output_tokens | Output/completion tokens (non-streaming provider requests only; 0 for streaming) |
uv run scripts/cf_analytics_query.py [options]
Options:
--dataset NAME: Analytics Engine dataset (default: llms_usage)--minutes N: Time range in minutes (default: 60)--limit N: Max results (default: 20)--field FIELD: Field to select (can be repeated). Omit for default fields with aliases.--agg EXPR: Aggregation expression (e.g.,SUM(_sample_interval) AS count). Can be repeated.--group-by FIELD: Field to group by (can be repeated). Use with --agg.--where CONDITION: WHERE clause condition (can be repeated). E.g.,"blob2 = '401'"--order-by FIELD: Field or alias to order by--order {asc,desc}: Sort order (default: desc)--raw QUERY: Execute raw SQL (ignores other query options)--format {json,jsonl,tsv}: Output format (default: json)--show-query: Print generated SQL--show-schema: Show schema mapping for dataset--list-datasets: List available datasets
Examples:
Show recent events with semantic field names:
uv run scripts/cf_analytics_query.py --limit 10
Request counts by path and status (last 24 hours):
uv run scripts/cf_analytics_query.py --agg 'SUM(_sample_interval) AS request_count' --group-by blob1 --group-by blob2 --minutes 1440
Average latency by method:
uv run scripts/cf_analytics_query.py --agg 'SUM(_sample_interval * double1) / SUM(_sample_interval) AS avg_latency_ms' --group-by index1
Filter by status code (show 401 errors):
uv run scripts/cf_analytics_query.py --where "blob2 = '401'" --minutes 1440
Raw SQL query:
uv run scripts/cf_analytics_query.py --raw "SELECT blob1, SUM(_sample_interval) AS count FROM llms_usage GROUP BY blob1 ORDER BY count DESC LIMIT 10"
Sampling Notes:
Analytics Engine may sample high-volume data. Always use _sample_interval for accurate counts:
- Count:
SUM(_sample_interval)instead ofCOUNT() - Sum:
SUM(_sample_interval * field)instead ofSUM(field) - Average:
SUM(_sample_interval * field) / SUM(_sample_interval)instead ofAVG(field)
Preferred Filter Keys
These keys are faster and always available:
$metadata.service: Worker name$metadata.origin: Trigger type (fetch, scheduled, queue, etc.)$metadata.trigger: Request method and path (e.g., GET /users)$metadata.message: Log message text$metadata.error: Error message (when applicable)$metadata.level: Log level (log, warn, error)$metadata.requestId: Unique request identifier
cf_ai_gateway_logs.py
Query AI Gateway logs with conversation-focused interface. Each log entry contains the full conversation history (Anthropic Messages API format), so viewing the latest entry for a conversation gives you everything.
Modes (mutually exclusive, one required):
--conversations: List conversations grouped by conversation-id metadata--conversation ID: Get messages from a specific conversation's latest log--raw: Dump raw logs to /tmp file (prints filename to avoid context overload)
uv run scripts/cf_ai_gateway_logs.py <mode> [options]
Common Options:
--gateway NAME: AI Gateway ID (default: llms)--minutes N: Time range in minutes (default: 60)--limit N: Max results (default: 20)
Options for --conversation mode:
--last-messages N: Only show the last N messages (default: 4, use 0 for all)--include-tools: Include the full tools array (omitted by default)--include-system: Include the full system prompt (omitted by default)--truncate CHARS: Truncate text content to N characters
Options for --raw mode:
--include-bodies: Include request bodies in dump (slow, fetches each individually)
Examples:
List recent conversations:
uv run scripts/cf_ai_gateway_logs.py --conversations --limit 10
Get last 10 messages from a conversation:
uv run scripts/cf_ai_gateway_logs.py --conversation T-xxx-xxx --last-messages 10
Dump 100 raw logs to file:
uv run scripts/cf_ai_gateway_logs.py --raw --limit 100
Include request bodies in raw dump:
uv run scripts/cf_ai_gateway_logs.py --raw --limit 10 --include-bodies
Workflow Example:
- List conversations:
uv run scripts/cf_ai_gateway_logs.py --conversations - Pick a conversation ID from the output
- View messages:
uv run scripts/cf_ai_gateway_logs.py --conversation T-xxx --last-messages 10
Regex Notes
For regex operations, Cloudflare uses ClickHouse RE2 syntax (not PCRE/JavaScript):
- No lookaheads/lookbehinds
- Escape backslashes with double backslash
微信扫一扫