Skip to content

feat(profiling): add continuous profiler timeline exploration - #877

Draft
AlexJF wants to merge 3 commits into
DataDog:mainfrom
AlexJF:feat/timeline-exploration
Draft

AlexJF wants to merge 3 commits into
DataDog:mainfrom
AlexJF:feat/timeline-exploration

Conversation

@AlexJF

@AlexJF AlexJF commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds pup profiling explore timeline, which calls the Continuous Profiler timeline exploration endpoint (POST /api/unstable/profiling/pup/explore/timeline). It returns an AI-friendly summary of a profile timeline: top lane groups (threads, GC, etc.) with thread-state and event breakdowns, utilization and insights, and optionally the critical path of a span.

  • src/commands/profiling.rs: explore_timeline, scoped by exactly one of:

    • --profile-id + --event-id: a single profile
    • --runtime-id + --query: recent profiles of one process
    • --trace-id + --span-id + --time-hint: the profiles behind a span

    Optional flags are --limit-lanes, --focus-from/--focus-to, --focus-event-type, --focus-lane-group and --critical-path (Go only, requires --trace-id). Unset fields are left out so server defaults apply.

  • src/main.rs: ProfilingExploreActions::Timeline plus dispatch and doc-comment updates.

  • Tests: each scope's request body, all validation rules, null optional response fields, a 400 error, and missing auth.

  • Docs: timeline examples in docs/EXAMPLES.md and the command listing in docs/COMMANDS.md.

Motivation

Follow-up to #819 (pup profiling operations), alongside call graph exploration (#876). Timeline exploration was the remaining exploration view only exposed through the profiling MCP server.

Additional Notes

Checklist

  • The code change follows the project conventions (see CONTRIBUTING.md)
  • Tests have been added/updated (if applicable)
  • Documentation has been updated (if applicable)
  • All CI checks pass
  • Code coverage is maintained or improved

Related Issues

Follow-up to #819. Depends on #876.

Plan
# PROF-16039: Add timeline exploration support to pup (pup leg)

Full cross-repo plan: /home/bits/.claude/plans/lets-work-on-https-datadoghq-atlassian-n-nested-dragon.md

## Context

Third of three repos for PROF-16039 (follow-up to PROF-15503; sibling of PROF-16038/callgraph).
- profiling-backend: ddoghq/profiling-backend#9128 adds `POST /api/pup/explore/timeline`.
- dd-source: ddoghq/dd-source#114431 proxies it at `/api/unstable/profiling/pup/explore/timeline`.
- This leg adds `pup profiling explore timeline`.

Follows pup's own conventions (branch `feat/timeline-exploration`, conventional commits, fork PR).
**Stacked on `feat/callgraph-exploration` (DataDog/pup#876)** since both touch the same regions of
`profiling.rs`/`main.rs`; retarget/rebase once #876 merges.

Signing: the DataDog-org SSH signing key isn't in the forwarded agent, so commits are signed with
the user's personal SSH key (repo-local `user.signingkey`; registered as a signing key on AlexJF).

## Backend contract (TimelineExplorationRequest)

Exactly one of `runtimeId` (requires non-empty filter query), `traceContext`
(`traceId`+`spanId`+`timeHint`, all `@NotEmpty`), `profileContext` (`profileId`+`eventId`).
Optional, server-defaulted: `limitLanes` (>0), `focusEventType`, `focusStartTime`/`focusEndTime`
(Instant), `focusLaneGroup` (exact `groupName` match), `useCriticalPath` (requires traceContext; Go).

## Bug found along the way

`timeHint` is `@NotEmpty` on the backend `TraceContext`, but pup sent `timeHint: null`, so
`--trace-id` scoping always 400'd. Fixed for callgraph in #876 (new commit fc8b744): shared
`trace_context_json` helper requiring `--trace-id`/`--span-id`/`--time-hint` together and
converting `--time-hint` (any pup time format) to epoch seconds. Timeline reuses it.
**Not fixed** (pre-existing, already merged in #819): `explore flamegraph` and
`profile-types list` trace-id modes have the same bug — flagged to the user as a separate fix.

## Changes

- `src/commands/profiling.rs`: `explore_timeline` (validation: exactly one scope, profile/event
  pairing, runtime-id requires query, critical-path requires trace-id, limit-lanes > 0; optional
  fields omitted when unset; focus times sent as RFC3339). 13 tests.
- `src/main.rs`: `ProfilingExploreActions::Timeline` + dispatch; doc comment capability/example;
  `Explore` doc string mentions call graphs/timelines.
- `docs/EXAMPLES.md`: "Explore a Timeline" (profile-id, runtime-id + focus lane group, trace-id +
  critical path). `docs/COMMANDS.md`: `timeline` in row/bullet.

## Status

- [x] Worktree `.claude/worktrees/feat-timeline-exploration`, branch stacked on callgraph
- [x] Implementation, docs, tests
- [x] `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`
- [x] `cargo test profiling::` — 52 pass
- [x] Commit 8f9ac32 + push to `origin`; draft PR into DataDog/pup:main
Prompts
# Prompts log — PROF-16039 (pup leg)

1. "Lets work on https://datadoghq.atlassian.net/browse/PROF-16039, following similar patterns to
   https://github.com/ddoghq/profiling-backend/pull/9070 and https://github.com/ddoghq/dd-source/pull/102914"
2. Plan approved as-is (via plan mode).
3. "Can't we sign with my personal SSH key, open a PR against my fork AlexJF/pup and open a draft PR
   from there to upstream?"
4. "try again" (after the forwarded SSH agent was restored)

🤖 Generated with Claude Code

AlexJF and others added 3 commits October 1, 2026 12:06
Add `pup profiling explore callgraph`, calling the new prof-gateway
/api/unstable/profiling/pup/explore/callgraph endpoint (PROF-16038).

- explore_callgraph in src/commands/profiling.rs, mirroring explore_flamegraph
  (query/trace/profile scoping, profile-id+event-id pairing validation)
- ProfilingExploreActions::Callgraph clap variant and dispatch in src/main.rs
- Tests for happy path, scoping/pairing validation, null optional fields,
  validation errors, and missing auth
- Call graph examples in docs/EXAMPLES.md and command listing in docs/COMMANDS.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The backend's traceContext requires traceId, spanId and timeHint (epoch
seconds) together and rejects requests with a null timeHint, so
`--trace-id` scoping could never succeed.

- Add a shared trace_context_json helper that validates the three flags
  together and converts --time-hint (any pup time format) to epoch seconds
- Add --time-hint to `pup profiling explore callgraph`
- Tests for the helper and for the callgraph traceContext request body

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `pup profiling explore timeline`, calling the new prof-gateway
/api/unstable/profiling/pup/explore/timeline endpoint (PROF-16039).

- explore_timeline in src/commands/profiling.rs: scoped by exactly one of
  --runtime-id (with --query), --trace-id (with --span-id/--time-hint) or
  --profile-id (with --event-id); optional focus window, focus event type,
  focus lane group, lane limit and Go critical-path analysis
- ProfilingExploreActions::Timeline clap variant and dispatch in src/main.rs
- Tests for each scope, request body shape, validation rules, null optional
  response fields, 400 errors and missing auth
- Timeline examples in docs/EXAMPLES.md and command listing in docs/COMMANDS.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant