| name | datadog-logs |
| description | Search and export Datadog logs and RUM errors from the command line. Use when the user wants to query logs, query RUM (Real User Monitoring) errors, export data, or search Datadog from the terminal. |
Datadog Logs CLI
The datadog logs subcommand searches Datadog logs and outputs each row as a JSON object. It paginates automatically and handles rate limits with retries. It uses the flex storage tier by default, which covers both recent and older logs (beyond the ~3 day online/standard tier window).
CLI availability
Run command -v datadog before use. If it is unavailable, install the local source with cargo install --path ~/code/datadog-cli/datadog.
Authentication
Set these environment variables (or pass as flags):
export DD_API_KEY="your-api-key"
export DD_APPLICATION_KEY="your-app-key"
Keys can be managed at:
Usage
Query with time range and query string
datadog logs --time-range "last 1 hour" --query "service:web env:production"
Query from a Datadog URL
Copy a log search URL from the Datadog UI and pass it directly — the CLI extracts the query and time range automatically:
datadog logs --datadog-url "https://app.datadoghq.com/logs?query=service%3Aweb&from_ts=1605055459837&to_ts=1605228259837"
If the URL has no time range, it defaults to the last 15 minutes.
Generate a Logs Explorer link
Use --generate-link to query normally and also print a Logs Explorer link. Use --only-link to print the link without calling the API or requiring --limit:
datadog logs --time-range "last 1 hour" --query "service:web env:production" \
--limit 20 --generate-link
datadog logs --time-range "last 1 hour" --query "service:web env:production" \
--only-link
When returning a Logs Explorer link to the user, always rerun the exact query arguments with --only-link (omitting --generate-link) and use the emitted URL verbatim. Never manually construct, retype, or edit the URL.
Limit output rows
datadog logs --time-range "last 4 hours" --query "status:error" --limit 100
Choose columns
By default, output includes timestamp, service, and message. Override with --columns:
datadog logs --time-range "last 1 hour" --query "env:production" \
--columns "timestamp,service,@version,@file.key"
Or append extra columns to the defaults with --add-columns:
datadog logs --time-range "last 1 hour" --query "env:production" \
--add-columns "@version,@file.key"
Deep-link to a specific log
Use --deep-links to get a clickable Datadog URL per row that opens with that
exact log highlighted (the UI's event=<id> deep-link). Each row also gets
a short id handle so you can pick one log to share without quoting the long
opaque Datadog event id:
datadog logs --time-range "last 30 minutes" --query "service:ugit @repo:*sessions*" \
--limit 5 --deep-links --columns "timestamp,service,@repo"
Each output row gains two fields:
id — a short, unique handle (default 6 hex chars; grows only if two
rows would otherwise collide). Use it to refer to a log, e.g. "share 2c327b".
url — the full deep-link that opens that specific log, highlighted, in a
flex-tier stream view bounded to the query's time window.
Notes:
- There is no shorter canonical Datadog log id — the only identifier is the long
opaque
event= string. The id handle is synthesized (a stable hash prefix);
the full id stays embedded in url.
- The
url's cols reflect --columns (minus timestamp/message), falling
back to host,service.
- Tune the handle length with
--id-min-len <N> (default 6).
Resume pagination
If a search is cut off by rate limiting, the CLI prints the last cursor. Resume with --cursor:
datadog logs --time-range "last 1 day" --query "service:web" \
--cursor "eyJhZnRlciI6..."
Flags reference
| Flag | Required | Description |
|---|
--dd-api-key | Yes (or DD_API_KEY env) | Datadog API key |
--dd-application-key | Yes (or DD_APPLICATION_KEY env) | Datadog application key |
--datadog-url | No* | Datadog log search URL (extracts query and time range) |
--time-range | No* | Time range string, e.g. "last 5 days", "last 30 minutes" |
--query | No* | Datadog log query string |
--cursor | No | Pagination cursor to resume a previous search |
--limit | Yes* | Maximum number of log rows to output (must be <= 100, or use --force) |
--force | No | Bypass the --limit <= 100 guard |
--generate-link | No | Query normally and also print a Logs Explorer link to stderr |
--only-link | No | Print only the Logs Explorer link, skip the API request, and do not require --limit |
--columns | No | Comma-separated columns to include (default: timestamp,service,message) |
--add-columns | No | Comma-separated columns to append to --columns |
--all-columns | No | Output all attributes for each log entry instead of selected columns |
--sort-by | No | Sort order: newest (default) or oldest |
--deep-links | No | Add a short unique id handle and a url that deep-links to each log (highlighted) |
--id-min-len | No | Minimum length of the --deep-links id handle (default: 6; grows to stay unique) |
*Either --datadog-url or both --time-range and --query must be provided. --limit must be <= 100 unless --force is used.
Column syntax
- Plain names resolve under
attributes: service -> attributes.service
@ prefix is shorthand for attributes.: @version -> attributes.version
- Nested paths work:
@file.key -> attributes.file.key
- Tag fallback: if a column isn't found in
attributes, it's looked up in the tags array (e.g. pod_name, kube_namespace, env)
Output format
Each log row is printed as a single-line JSON object with only the selected columns:
{"timestamp":"2026-02-24T12:00:00Z","service":"web","message":"request completed"}
{"timestamp":"2026-02-24T12:00:01Z","service":"web","message":"timeout error"}
Pipe to jq for further processing:
datadog logs --time-range "last 1 hour" --query "status:error" | jq '.message'
Time range formats
"last 15 minutes", "last 30 mins", "last 30m"
"last 1 hour", "last 4 hours", "last 1h"
"last 1 day", "last 7 days", "last 1d"
"last 1 week", "last 2 weeks", "last 1w"
"last 1 month", "last 6 months"
"last 1 year", "last 1y"
- Absolute ISO 8601 range:
"2026-02-19T17:35:00Z to 2026-02-19T23:00:00Z"
- Datadog URLs with
from_ts / to_ts query params (epoch milliseconds)
Query syntax tips
The CLI validates query syntax before calling the API. Common pitfall:
- Facet values containing colons must be quoted. For example,
@job_name:figma::highprifilethumbnailjob will be rejected — use @job_name:"figma::highprifilethumbnailjob" instead.
If validation fails, the CLI prints actionable tips and exits without making an API call.
Sort order
The CLI defaults to --sort-by newest (descending). Use --sort-by oldest when you need to find when something first appeared:
datadog logs --query 'service:multiplayer "skipping checkpoint request"' \
--time-range "last 7 days" --sort-by oldest --limit 5
Wildcard attribute search
Use *:VALUE to search across all attributes for a value. Useful for finding logs where @file.key isn't set but the file key appears in other fields:
datadog logs --query 'service:multiplayer *:s8ue67bYv1SwA7BBEZQ5XP' --time-range "last 1 hour"
Examples
datadog logs --time-range "last 1 hour" --query "status:error"
datadog logs --time-range "last 30 minutes" \
--query "env:production service:auth" \
--columns "timestamp,service,message,@duration,@status_code"
datadog logs --datadog-url "https://app.datadoghq.com/logs?..." --limit 50
datadog logs --time-range "last 4 hours" --query "service:api" \
--add-columns "@endpoint,@duration" \
| jq 'select(.["@duration"] > 1000)'
Datadog RUM errors (datadog rum)
The datadog rum subcommand queries browser/mobile RUM (Real User Monitoring) error events. It mirrors the Datadog RUM explorer's output toggle via --output:
--output timeseries (default) — aggregate errors into count-over-time buckets and draw a chart plus a summary line. No --limit (the buckets bound the output).
--output list — emit individual error events as JSON rows, capped by --limit (<= 100 unless --force).
Every query is automatically scoped to @type:error (override with --all-types).
Authentication is the same DD_API_KEY / DD_APPLICATION_KEY as logs.
Discover applications first
Every query is scoped to a single RUM application via --application-id, which is required. List the org's applications to find the id:
datadog rum --list-apps
Each row is a JSON object, active apps first:
{"application_id":"91eb025c-e89b-4645-bda6-ca0e442e0b64","name":"Web","type":"browser","is_active":true}
You do not need to embed @application.id:... in --query — pass --application-id <id> and it's added for you.
Occurrences over time (default)
datadog rum --application-id 91eb025c-e89b-4645-bda6-ca0e442e0b64 --time-range "last 1 hour"
Prints a summary (Occurrences, Peak) and a terminal chart of error count over time, using a bucket interval chosen to fit the range (override with --interval "5m").
Break down by error (top errors)
Use --group-by to split the count by a facet and draw one series per group, highest occurrence count first:
datadog rum --application-id 91eb025c-e89b-4645-bda6-ca0e442e0b64 \
--time-range "last 1 hour" --group-by "@error.message" --top 10
Common facets: @error.message, @error.source, service, @view.url. --top N limits the number of groups (default 10).
Add query filters
--query ANDs extra terms onto the application + error scope:
datadog rum --application-id 91eb025c-e89b-4645-bda6-ca0e442e0b64 \
--time-range "last 1 hour" --query "@error.source:source service:figma-web"
List individual errors (rows)
Use --output list to get one JSON row per error event — for pulling specific view.urls, timestamps, or attributes. This mode behaves like logs (columns, --limit <= 100 guard, --cursor pagination, --sort-by):
datadog rum --application-id 91eb025c-e89b-4645-bda6-ca0e442e0b64 \
--time-range "last 15 minutes" --output list --limit 20 \
--columns "timestamp,error.source,error.message,view.url"
Column syntax matches logs: dot-paths index the event attributes (error.message, view.url), @ is an accepted shorthand prefix, and unmatched columns fall back to the tags array (e.g. env).
Flags reference (rum)
| Flag | Required | Description |
|---|
--list-apps | No | List the org's RUM applications (id, name, type, active) and exit |
--application-id | Yes (for queries) | RUM application to scope the query to (discover via --list-apps) |
--time-range | Yes (for queries) | Time range string, e.g. "last 1 hour", or ISO 8601 range |
--query | No | Extra query terms ANDed onto the application + error scope |
--all-types | No | Search all RUM event types instead of only @type:error |
--group-by | No | Facet to split the occurrence count by (e.g. @error.message) |
--top | No | Number of groups to show with --group-by (default 10) |
--interval | No | Timeseries bucket size (e.g. "5m"); defaults to fit the range |
--output | No | timeseries (default, chart) or list (individual rows) |
--limit | Yes (with --output list) | Max rows in list mode (must be <= 100, or use --force) |
--columns / --add-columns / --all-columns | No | Column selection in list mode (same semantics as logs) |
--cursor | No | Pagination cursor to resume a list-mode search |
--sort-by | No | List-mode sort order: newest (default) or oldest |
--force | No | Bypass the list-mode --limit <= 100 guard |