Dynatrace Control with dtctl
Operate dtctl, the kubectl-style CLI for Dynatrace. Pattern: dtctl <verb> <resource> [flags].
Initialization
Run once to establish context, permissions, and the command catalog:
Safety levels: readonly, readwrite-mine, readwrite-all, dangerously-unrestricted.
dtctl commands answers "what can I run?"; dtctl inventory answers "what is there to query?" — run it before exploratory DQL. It partitions catalog objects into fetchable vs query-only (never fetch metrics or fetch smartscape.*), and reports capabilities as present, absent (with the evidence checked — cite it instead of re-probing), or unknown (no verdict; not evidence of absence). Org-specific capability definitions: --definitions file.yaml.
Don't use dtctl auth whoami to test connectivity — it needs an OAuth token with app-engine:apps:run and returns a spurious 403 for plain API or read-scoped tokens even when reads work. Confirm with a real get/query.
DQL (required reading)
Before writing, modifying, or running any DQL (dtctl query, dtctl wait query, query files), consult references/DQL-reference.md and follow it over any assumption or memory.
Billable fetch (logs, events, bizevents, spans) bills by bytes scanned and dashboard tiles re-bill on every refresh — read "Scan Cost" in references/DQL-reference.md before emitting DQL, and treat a PARTIAL or sampled result as incomplete.
dtctl not installed/working? See references/troubleshooting.md [blocked].
Resources & verbs
Resources and aliases are discoverable via dtctl commands (run at init). They include: analyzer, anomaly-detector, app, aws/azure/gcp connection & monitoring, bucket, copilot-skill, dashboard, document, edgeconnect, environment, extension, extension-config, function, group, intent, license, license-settings, lookup, notebook, notification, sdk-version, segment, settings, settings-schema, slo, slo-template, trash, user, workflow, workflow-execution. Use IDs, not names — names may be ambiguous and fail.
Davis analyzers: before running one, dtctl describe analyzer <id> shows its required/optional inputs and result schema (add --doc for full docs, -o json for the raw schemas); dtctl verify analyzer <id> -f in.json validates an input without executing (exit 0 valid / 1 invalid).
Output for agents
--agent/-A is auto-detected in AI environments (implies --plain; opt out with --no-agent). It wraps output in {ok, result, context} (errors: {ok:false, error:{code,message}}, where context carries total, has_more, suggestions).
Prefer --agent plus -o toon and --jq to cut tokens. Agent-mode query trims metadata to cost/sampling fields by default; -M=all for the full block.
Query results: branch on result.kind
In agent mode dtctl query defaults to --spill=auto: large results spill to a local file and return a summary instead of dumping rows into context. Never assume result is an array — branch on result.kind:
Treat an unknown kind as opaque and fall back to context (decided, total, warnings, suggestions). Sampled results put stats in a sample_stats block (basis: "sample") — not population truth.
Inline results are bounded too. String values are clipped to 500 chars by default and end in …(+N chars) (--max-field-chars 0 gives full values; add | fields <col> to fetch only that column). --max-output-tokens N / --max-output-bytes SIZE returns only the rows that fit. When context.truncated is true the result is incomplete: truncated_fields lists the clipped fields, and returned < total means rows were dropped. In that case run context.next (a dtctl inspect command) to continue at next_offset without re-querying.
Inspect a spilled file (no Grail re-query)
dtctl inspect <file> reads the rows the summary left out — bounded, streaming, agent-context-friendly — so you never re-run the Grail scan. Pick exactly one primitive per call:
It is not a query engine — no filter/SQL/GROUP BY. For aggregates, push the work back into DQL (… | summarize …); for complex local analysis, hand the file to your preferred local analytics tooling. An oversized inspect window re-spills to a new file rather than flooding context, and refuses files from another context/tenant.
Log pattern analysis (token-frugal)
For free-text log triage, don't dump raw content — extract the taxonomy server-side, then drill:
dtctl exec analyzer dt.statistics.clustering.LogPatternExtractor --input '{"logQuery":"<DQL>","numberOfExamples":2}'→ DPL templates + match counts.logQueryis a plain DQL string (not an object) yieldingtimestamp+content. Projects well with--jqto{patternExpression, numberOfMatches}.- Lift a
patternExpressionverbatim intoparse content, "..."(rename capturesf_1→meaningful), thensummarize … by:{field}to extract/count at row scale. Unmatched lines yield null captures. - Need raw rows? Drill with
fetch … --agentand let it spill (above), then read them withdtctl inspect <path> --head/--page(above).
Apply & templates
dtctl apply is idempotent: POST when new, PUT when the file has an id. YAML/DQL files support Go templates filled via --set:
dtctl apply -f file.yaml --set environment=prod --set schedule="0 6 * * *"
Dashboards
Create/update: dtctl apply -f dashboard.yaml. Export for reference: dtctl get dashboard <id> -o yaml --plain. Full schema + visualizationSettings: references/resources/dashboards.md [blocked].
Gotchas: set davis.enabled: false on data tiles; makeTimeseries for log/span series, timeseries for metrics; id present → update, absent → create; the version warning on create is benign.
Permissions & safety
- Verify before mutating:
dtctl auth can-i <verb> <resource>. Scopes: TOKEN_SCOPES.md. - Destructive ops may be blocked by safety level — switch with
dtctl config use-context <name>, or raise the level when creating the context. - Prefer
get/describefirst;--minescopes to resources you own;--plainfor all machine consumption.
Credentials & teardown
Credentials are dtctl's business: read and remove them only through dtctl.
Never invoke OS keychain tooling — security (macOS), secret-tool
(Linux), cmdkey (Windows) — for any purpose, cleanup included. Their delete
verbs miss most of what a credential occupies; their read verbs print secrets,
and security dump-keychain covers every keychain on the machine, not just
dtctl's. Never verify a deletion by reading the secret back — a teardown
step that prints a token has leaked exactly what it was told to destroy.
More
troubleshooting [blocked] · multi-tenant config [blocked] · DQL [blocked] · notebooks [blocked] · extensions [blocked] · dtctl --help, dtctl <command> --help


