dogfetch

command module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 2 Imported by: 0

README

Cartoon dog chomping on a log.

dogfetch

Getting Datadog logs to your machine is ruff. If you're a lazy mutt like me, use dogfetch. Woof!

Quick start

export DD_API_KEY=your_api_key
export DD_APP_KEY=your_app_key

dogfetch --query 'service:web status:error' \
  --from '2024-01-01T00:00:00Z' \
  --to '2024-01-02T00:00:00Z' --format ndjson | jq -r '.attributes.message'

[!IMPORTANT] Breaking change: when writing to stdout, the default output format is now TOON (a compact, agent-friendly tabular format) with a minimal field projection (timestamp,status,service,message). Pipelines that expect JSON lines on stdout should pass --format ndjson or set DOGFETCH_FORMAT=ndjson. File export with --output still defaults to lossless NDJSON — nothing changes there.

Features

  • Simple query interface - Fetch logs using Datadog's query syntax
  • Agent-friendly by default - Compact TOON output with field projection on stdout (~70% smaller than raw JSON)
  • Pre-computed aggregates - dogfetch summary for counts by status/service and a timeline, without fetching raw logs
  • Pattern clustering - dogfetch patterns collapses thousands of repetitive logs into a handful of templates
  • Flexible output formats - TOON, JSON, or NDJSON (newline-delimited JSON)
  • Memory efficient streaming - NDJSON mode streams results to disk with minimal memory usage
  • Pagination checkpoint/resume - Save progress and resume from where you left off if interrupted
  • Configurable time ranges - Query logs from specific time windows
  • Cross-platform - Works on Linux, macOS, and Windows

Installation

/plugin marketplace add jtzemp/dogfetch
/plugin install dogfetch@dogfetch

This installs a skill that teaches Claude the agent-optimal call order (summary → patterns → fetch --limit) and a wrapper script that auto-downloads a sha256-verified binary from GitHub Releases on first use (cached in ~/.cache/dogfetch/). No manual binary install needed — only the one-time Datadog key setup (run dogfetch auth or see Prerequisites).

Pre-built binaries

Download the latest release for your platform from the releases page.

Go install
go install github.com/jtzemp/dogfetch@latest
Build from source
git clone https://github.com/jtzemp/dogfetch
cd dogfetch

make build

make build injects version info from git (tag, commit, build date) via -ldflags, so ./dogfetch --version reports something meaningful. A plain go build -o dogfetch also works but skips that.

Makefile targets
Target What it does
make build Build ./dogfetch with version info
make install Build and install to $GOPATH/bin
make test Run the test suite
make test-cover Run tests with coverage
make lint Run golangci-lint (matches CI)
make build-all Cross-compile for linux/darwin/windows
make version Print the version/commit/date that would be built
make dev Quick build with no version info injected
make clean Remove build artifacts
make release-tag Update the version and create a tag for releasing
# Check version
./dogfetch --version

# Build for all platforms
make build-all

Prerequisites

You need a Datadog API key and Application key. Set them as environment variables:

export DD_API_KEY=your_api_key
export DD_APP_KEY=your_app_key

Optionally, set your Datadog site if not using the default (datadoghq.com):

export DD_SITE=datadoghq.eu

Usage

Commands
Command What it does
dogfetch fetch Fetch raw log lines (the default — dogfetch --query … is shorthand)
dogfetch summary Counts by status/service + a timeline, via the Aggregate API (no raw logs)
dogfetch patterns Cluster messages into templates so repetitive logs collapse to a few rows
dogfetch auth Show credential status and setup help
dogfetch version Print version information
dogfetch (no args) Live home view: tool path, auth status, example commands

For agents the cheap-to-expensive order is summary → patterns → fetch --limit.

Basic Usage
# Fetch logs matching a query (compact TOON on stdout)
dogfetch --query 'service:web status:error'

# Pipe full JSON lines to a file
dogfetch --query 'service:web status:error' --format ndjson > logs.ndjson

# Or save directly to a file (defaults to lossless ndjson)
dogfetch --query 'service:web status:error' --output logs.ndjson

# Specify a custom time range
dogfetch --query 'service:api' --from '2024-01-01T00:00:00Z' --to '2024-01-02T00:00:00Z'

# Use JSON format and save to file
dogfetch --query 'service:database' --format json --output db-logs.json
Summaries (no raw logs)

dogfetch summary answers "how many, what kind, when" with one fast call to Datadog's Aggregate API — no pagination, no raw log payloads:

dogfetch summary --query 'service:web' --from 2h
total: 4523
by_status[3]{status,count}:
  error,3200
  warn,1000
  info,323
by_service[2]{service,count}:
  web,4000
  api,523
timeline[24]{time,count}:
  2026-06-11T10:00:00Z,2100
  ...

Group-bys show the top 25 by count (a help hint reports the full distinct count when truncated). --format json emits the same data as a JSON object.

Patterns (collapse repetitive logs)

dogfetch patterns clusters messages drain-style: volatile tokens (numbers, hex ids, UUIDs, IPs, quoted values) become <*>, so a flood of similar logs reads as a few templates with counts:

dogfetch patterns --query 'service:web status:error' --from 2h
scanned: 9421
patterns[3]{count,first_seen,last_seen,pattern}:
  8804,2026-06-11T08:01:12Z,2026-06-11T10:00:41Z,failed to process payment <*> for user <*> card_declined
  601,2026-06-11T08:00:03Z,2026-06-11T09:58:59Z,connection to <*> timed out after <*>
  16,2026-06-11T08:12:44Z,2026-06-11T09:40:02Z,schema migration completed successfully

Scans up to 10,000 logs by default (--limit to change), shows the top 50 patterns (--top), and --samples adds one raw example per pattern.

Command Line Options (fetch)
--query string
    The filter query (search term). Single quote the entire query for best results.
    Example: --query 'service:web status:error'

--index string
    Which index to read from (default "main")

--limit int
    Stop after this many logs (0 = unlimited). Pairs with TOON output to
    keep agent context small; prints a resume cursor when more remain.

--from string
    Start date/time (default: 24 hours ago)
    Formats: RFC3339 (2024-01-01T00:00:00Z), Unix timestamp (1704067200)

--to string
    End date/time (default: current time)
    Formats: RFC3339 (2024-01-01T00:00:00Z), Unix timestamp (1704067200)

--pageSize int
    How many results to download at a time (default: 1000, max: 5000)

--output string
    Path of file to write results to (default: stdout)
    When not specified, logs are written to stdout and progress to stderr

--format string
    Output format: "toon", "json", or "ndjson"
    (default: "toon" on stdout, "ndjson" with --output)

    toon   - Compact tabular format with field projection, built for agents
    json   - Single JSON array, all data loaded into memory
    ndjson - Newline-delimited JSON, streams as it fetches (low memory)

--fields string
    Comma-separated fields to include in output
    (toon default: timestamp,status,service,message; any Datadog
    attribute path works, e.g. http.status_code)

--cursor string
    Page cursor position for resuming from a specific point
    Works with ndjson and toon (not json)

--append
    Append to output file instead of overwriting
    Only works with streamable formats (ndjson)

--errors-out string
    Write progress and error messages to file (default: stderr)
Advanced Usage
Streaming Large Datasets

NDJSON (the default when writing to a file with --output) streams results as they're fetched, minimizing memory usage:

dogfetch --query 'service:api' \
  --output large-export.ndjson \
  --pageSize 5000

# Or pipe directly to another tool (force ndjson — stdout defaults to TOON)
dogfetch --query 'service:api' --format ndjson | jq -r '.attributes.message'
Resume After Interruption

If a large fetch is interrupted, you can resume from where it left off. The cursor value is printed to stderr when the fetch stops:

# First attempt (gets interrupted)
dogfetch --query 'service:web' --output logs.ndjson
# stderr: Fetched 50000 logs... cursor: eyJhZnRlciI6eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0aW1lc3RhbXAiOjE3MDQwNjcyMDB9fQ==
# (interrupted)

# Resume from cursor
dogfetch --query 'service:web' \
  --output logs.ndjson \
  --cursor 'eyJhZnRlciI6eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0aW1lc3RhbXAiOjE3MDQwNjcyMDB9fQ==' \
  --append

Why manual checkpointing? The Datadog SDK provides automatic pagination helpers, but they don't expose the cursor or allow resuming from a specific point. By managing pagination manually, we can print the cursor after each page and allow you to resume long-running fetches if they're interrupted by network issues, rate limits, or system shutdowns. This is particularly useful for large exports that may take hours.

Query Multiple Indexes
dogfetch --query 'status:error' --index 'retention-30' --output errors.ndjson
Redirect Errors to File
# Keep progress messages separate from output
dogfetch --query 'service:web' --errors-out progress.log > logs.ndjson

Output Formats

TOON (default on stdout)

A compact tabular format (TOON) with a default field projection (timestamp,status,service,message). Built for agents — roughly 70% smaller than the equivalent raw JSON. Read it directly; no parsing needed:

count: 2
logs[2]{timestamp,status,service,message}:
  2026-06-11T10:00:00Z,error,web,connection refused
  2026-06-11T10:00:01Z,warn,api,"timeout after 5s, retrying"
help[1]:
  Add fields with --fields timestamp,status,service,message,host (any Datadog attribute path works, e.g. http.status_code)

Widen columns with --fields. For lossless full objects, use --format ndjson or --format json (or --output, which defaults to ndjson).

NDJSON (default with --output)

Each log is a separate JSON object on its own line:

{"id":"...","attributes":{"message":"...","timestamp":"..."}}
{"id":"...","attributes":{"message":"...","timestamp":"..."}}

This format:

  • Uses minimal memory (logs are streamed as they're fetched)
  • Can be processed line-by-line with standard tools
  • Supports checkpoint/resume with --cursor and --append
  • Works well with pipes and streaming tools

Process with standard tools:

# Count logs
wc -l logs.ndjson

# Filter with jq
jq 'select(.attributes.status == "error")' logs.ndjson

# Extract specific field
jq -r '.attributes.message' logs.ndjson

# Stream and process in real-time (force ndjson — stdout defaults to TOON)
dogfetch --query 'service:web' --format ndjson | jq -r '.attributes.message'
JSON

Outputs a single JSON object with all logs in an array:

{
  "logs": [
    {
      "id": "...",
      "attributes": {
        "message": "...",
        "timestamp": "...",
        ...
      }
    },
    ...
  ],
  "meta": {
    "total_fetched": 1523,
    "pages": 2
  }
}

This format buffers all logs in memory before writing. Use for smaller datasets or when you need the metadata wrapper.

Architecture

Design Goals
  1. Low memory footprint - Stream data when possible instead of buffering everything
  2. Resilient - Handle network failures, rate limits, and interruptions gracefully
  3. Fast - Maximize page size and minimize unnecessary processing
  4. Simple - Single binary, minimal configuration
How It Works
┌─────────────────┐
│   CLI Parser    │  Parse args, validate config
└────────┬────────┘
         │
┌────────▼────────┐
│  Fetcher Loop   │  Paginate through results with cursor
│                 │  - Retry on transient errors
│                 │  - Print cursor for checkpointing
│                 │  - Handle rate limits
└────────┬────────┘
         │
┌────────▼────────┐
│ Writer Strategy │  JSON: buffer all, write once
│                 │  NDJSON: stream each page
└────────┬────────┘
         │
┌────────▼────────┐
│   Output File   │
└─────────────────┘
Error Handling
  • Transient errors (network timeouts, 5xx): Exponential backoff retry (3 attempts)
  • Rate limits (429): Extended backoff based on Retry-After header
  • Permanent errors (400, 401, 403): Fail immediately with clear message
  • Context cancellation (Ctrl+C): Graceful shutdown, print current cursor (works on Windows, macOS, and Linux)

Using with Claude Code

Install the plugin — it ships the skill and handles the binary automatically:

/plugin marketplace add jtzemp/dogfetch
/plugin install dogfetch@dogfetch

The bundled skill (skills/dogfetch/SKILL.md) teaches Claude Datadog query syntax and the token-cheap call order: summary (counts, no raw logs) → patterns (collapse repetitive logs) → fetch --limit (raw lines, projected fields). The wrapper script downloads a sha256-verified release binary on first use and caches it.

The only manual step is Datadog credentials: put DD_API_KEY and DD_APP_KEY in ~/.config/dogfetch/env (chmod 600) or export them; run dogfetch auth to check. Other agents can copy the same SKILL.md — it's plain markdown over a plain CLI.

Contributing

Contributions welcome! Please open an issue or PR.

Releases

Releases are automated using GitHub Actions and GoReleaser. To create a new release:

  1. Bump the plugin version, commit, and tag — all in one step:

    make release-tag V=0.2.0
    

    This updates .claude-plugin/plugin.json version to 0.2.0, commits that change, and creates tag v0.2.0 on top of it, so the version bump and the tag point at the same commit. Requires a clean working tree.

  2. Review, then push both:

    git show
    git push origin HEAD
    git push origin v0.2.0
    
  3. GitHub Actions will automatically:

    • Check the plugin version matches the tag and the wrapper script parses
    • Run all tests
    • Build binaries for Linux, macOS, and Windows (amd64 and arm64)
    • Create a GitHub release with:
      • Release notes from commits since last tag
      • Pre-built binaries
      • Checksums for verification (used by the plugin wrapper's sha256 check)

    The release workflow only validates the tagged commit. You tag it. Goreleaser builds it if it matches.

  4. Manual release (optional):

    # Install goreleaser
    go install github.com/goreleaser/goreleaser@latest
    
    # Create a release locally
    goreleaser release --snapshot --clean
    

License

MIT

Acknowledgments

Built with the Datadog Go API Client.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
axierr
Package axierr defines structured, agent-readable errors.
Package axierr defines structured, agent-readable errors.
cli
Package cli holds shared helpers for command-line handling.
Package cli holds shared helpers for command-line handling.
cluster
Package cluster groups log messages into drain-style templates: volatile tokens (numbers, hex ids, UUIDs, IPs, quoted values) are masked to <*>, and messages whose remaining shape matches an existing template merge into it.
Package cluster groups log messages into drain-style templates: volatile tokens (numbers, hex ids, UUIDs, IPs, quoted values) are masked to <*>, and messages whose remaining shape matches an existing template merge into it.
project
Package project selects a small set of fields from Datadog log objects so agent-facing output carries only what the agent asked for.
Package project selects a small set of fields from Datadog log objects so agent-facing output carries only what the agent asked for.
toon
Package toon implements the subset of TOON (Token-Oriented Object Notation) that dogfetch emits: scalar key/value lines, tabular array blocks, and AXI-style help lists.
Package toon implements the subset of TOON (Token-Oriented Object Notation) that dogfetch emits: scalar key/value lines, tabular array blocks, and AXI-style help lists.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL