dt-obs-ext-monitors — Claude Code skill: what it does, how to install
Sends third-party test outcomes and CI monitor results to Dynatrace Grail through the events ingest API. Replaces the deprecated synthetic v1 endpoint.
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a claude-codeWhat dt-obs-ext-monitors does
The skill guides ingestion of external synthetic and CI monitor results into Dynatrace Grail via /platform/ingest/custom/events/{endpoint}. This serves as the direct replacement for the deprecated POST /api/v1/synthetic/ext/tests route. OpenPipeline registers each test.id as an EXT_TEST Smartscape node, letting Davis Problems attach alerts directly to named topological entities.
It provides the event schema for external_test_run and external_test_step, curl and Java DTO examples, plus DQL queries for verification in Grail. Ingestion fails immediately if the payload is wrapped in a JSON object instead of a flat array, or if an invalid scope like events.ingest is used. You must use openpipeline.events.custom for Classic Api-Tokens or openpipeline:events.custom:ingest for Platform Tokens. Before sending data, configure the ingestion endpoint in OpenPipeline.
What it helps with
- ingest third-party monitor outcomes into Dynatrace Grail
- map external synthetic tests to Smartscape
EXT_TESTentities - format
external_test_runandexternal_test_stepevent payloads - verify ingested monitoring data using DQL queries
Example prompts for the agent
- Show me the external_test_run event schema for sending CI test results to Dynatrace
- How do I send external synthetic test results to Dynatrace Grail using curl?
- Write a DQL query to verify external monitor events received in the last hour
How to install dt-obs-ext-monitors
1Skills CLI (Vercel)
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a claude-code2Manually: put the files in place
~/.claude/skills/dt-obs-ext-monitors/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/dt-obs-ext-monitors/
1Skills CLI (Vercel)
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a codex2Manually: put the files in place
.agents/skills/dt-obs-ext-monitors/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a cursor2Manually: put the files in place
.cursor/skills/dt-obs-ext-monitors/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install Dynatrace/dynatrace-for-ai dt-obs-ext-monitors2Manually: put the files in place
.github/skills/dt-obs-ext-monitors/SKILL.md1Skills CLI (Vercel)
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a gemini-cli2Platform CLI
gemini skills install https://github.com/Dynatrace/dynatrace-for-ai --path skills/dt-obs-ext-monitorsManually: put the files in place
.devin/skills/dt-obs-ext-monitors/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about dt-obs-ext-monitors
How to install dt-obs-ext-monitors in Claude Code?
Run npx skills add Dynatrace/dynatrace-for-ai --skill dt-obs-ext-monitors -a claude-code to install the skill.
What does dt-obs-ext-monitors do?
It provides event schemas and instructions for streaming external monitor or synthetic test results to Dynatrace Grail. The skill covers OpenPipeline processing, Smartscape entity mapping, and verification with DQL.
Which token scopes are required for external test ingestion?
Classic Api-Tokens require the openpipeline.events.custom scope, while Platform Tokens require openpipeline:events.custom:ingest. The generic events.ingest scope will be rejected.
Source text
SKILL.md · Apache-2.0
---
name: dt-obs-ext-monitors
description: >-
3rd-party test and monitor result ingestion into Dynatrace Grail via the platform events
ingest API (platform/ingest/custom/events/). Use when sending external synthetic test outcomes,
CI monitor data, or third-party check results to Dynatrace. Covers token scope, full event
schema for external_test_run and external_test_step (including dt.security_context, ci.*,
trace correlation, and pipeline-added fields), curl and Java DTO examples, and DQL verification.
Triggers: "ingest test results", "send monitor results", "third party monitor",
"external test ingestion", "send synthetic results to Grail", "external test run event schema".
Not for Dynatrace-native Synthetic Monitoring browser/HTTP checks, or RUM (use dt-obs-frontends).
For migrating from the deprecated POST /api/v1/synthetic/ext/tests API, load dt-upgrade instead.
license: Apache-2.0
---
# External Monitor Ingestion
Send 3rd-party test and monitor results to Dynatrace Grail using the events ingest API.
This is the canonical replacement for the deprecated `POST /api/v1/synthetic/ext/tests` endpoint.
## Overview
Events posted to `/platform/ingest/custom/events/{endpoint}` land in Grail and are processed
by OpenPipeline, which:
- Extracts metrics (`external.test.availability`, `external.test.duration`) for alerting and SLOs
- Registers each unique `test.id` as an `EXT_TEST` Smartscape node — enabling Davis Problems to
attach to a named entity ("External test X went down") rather than floating without topology context
- Adds `result.status.category` to step events (`SUCCESS` / `SKIPPED` / `FAIL`) for dashboard filtering
Two event types form a test result:
| Type | Purpose |
|------|---------|
| `external_test_run` | Overall pass/fail result for one test execution |
| `external_test_step` | One step within that run (optional; enables step-level metrics) |
## Authentication
Two token types are accepted:
| Token type | Scope |
|------------|-------|
| Classic Api-Token | `openpipeline.events.custom` |
| Platform Token / OAuth | `openpipeline:events.custom:ingest` |
Common wrong guess that does NOT work: `events.ingest`.
## Quick Start
> **Prerequisite:** The ingest endpoint must be created in OpenPipeline before sending events.
> The `external.tests` endpoint is provisioned automatically by the
> default Dynatrace 3rd-party monitors Monaco bundle.
> See `references/event-ingestion.md` for setup details and custom endpoint creation.
Send one minimal test result (replace `external.tests` with your configured endpoint name):
```text
curl -X POST "https://{env-id}.live.dynatrace.com/platform/ingest/custom/events/external.tests" \
-H "Authorization: Api-Token {token}" \
-H "Content-Type: application/json" \
-d '[{
"event.kind": "EXTERNAL_TEST_EVENT",
"event.type": "external_test_run",
"test.id": "my-api-health-check",
"test.run.id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"test.name": "My API Health Check",
"test.type": "api",
"test.run.status": "passed",
"test.run.availability": 1,
"test.run.duration_ms": 245,
"test.run.location": "us-east-1",
"dt.security_context": "team-checkout",
"timestamp": "2024-01-15T10:30:00Z"
}]'
```
**Expected response:** HTTP 200 (empty body).
> Full event schema, step events, extended examples with error fields and CI metadata,
> Java DTO shapes, and DQL queries: `references/event-ingestion.md`
## Verify in Grail
After sending, confirm the event appears:
```dql
fetch events, from:now()-1h
| filter event.type == "external_test_run"
| fields timestamp, test.id, test.name, test.run.status, test.run.duration_ms, test.run.location
| sort timestamp desc
| limit 20
```
## Key Constraints
- Body **must** be a JSON array (`[{...}]`), not an object wrapper (`{"events":[...]}`).
- A single request can mix run events and step events in the same array.
- `timestamp` must be ISO 8601 UTC (e.g. `"2024-01-15T10:30:00Z"`).
- `test.run.availability` must be integer `1` or `0`, not a string.
- All step events in a run must share the same `test.run.id` and `test.id` as the parent run event.
- Step events must include `test.step.id` (unique within the run) in addition to `test.run.id`.
- `event.kind: "EXTERNAL_TEST_EVENT"` must be present — used by Grail for event classification.
Routing to the correct pipeline is driven by `event.type`, not `event.kind`.
- Do **not** send `dt.smartscape.ext_test` or `result.status.category` — these are written by
the pipeline after ingestion and will be overwritten if included.
- `dt.security_context` controls data access policies; it’s recommended to set it on every event to enable
per-team access control and cost attribution in multi-team tenants.
## Multi-Location Tests
Send the same `test.id` from multiple locations — each with a different `test.run.location`
value — to build a multi-location test. OpenPipeline creates one `EXT_TEST` node per `test.id`
and one availability metric timeseries per `(test.id, location)` pair.
This enables two alerting tiers out of the box:
| Alert type | Fires when |
|------------|-----------|
| Local outage | A single location's availability drops (per-location timeseries) |
| Global outage | Average across all locations drops below threshold (e.g. majority failing) |
Threshold maths for a 3-location test: 1 location failing → avg 0.67 (no alert at 0.5 threshold);
2 failing → avg 0.33 (fires); all 3 failing → avg ≈ 0 (fires immediately).
Keep `test.id` stable across all locations — changing it creates a new Smartscape node and
breaks metric history.
## Related Skills
- **dt-dql-essentials** — DQL syntax for querying ingested events and building analysis queries
- **dt-obs-frontends** — Link test runs to frontend entities via `dt.smartscape.frontend` to
draw EXT_TEST → FRONTEND dependency edges in Smartscape
© Dynatrace · Apache-2.0 · Dynatrace/dynatrace-for-ai