关于 dt-obs-analytics
一组用于 Dynatrace 的技能脚本,可从 dashboard 和 notebook 提取 DQL 查询,再交给 Davis analyzer 分析。支持按标题筛选查询,并传入时间范围与变量。
主要功能
- 01从 dashboard 提取 DQL
- 02从 notebook 提取 DQL
- 03按标题或正则筛选
- 04调用 Davis analyzer 分析查询
- 05传入时间范围和变量
适用场景
- 01提取 dashboard 指定图表的查询
- 02分析 notebook 中的指标异常
- 03将多个查询与主指标进行相关性分析
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dynatrace/ dynatrace-for-ai --skill dt-obs-analytics安装后在 Claude Code 中输入/dt-obs-analytics确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
scripts/extract-timeseries-dashboard.jsextract-timeseries-notebook.jsrun-analyzer.js详细介绍
分析 — 仪表板与 Notebook 查询提取
scripts/ 下由三个平台 JavaScript 脚本组成的管道——两个提取器为一个共享的分析器运行器提供数据:
scripts/extract-timeseries-dashboard.js ──┐
scripts/extract-timeseries-notebook.js ──┴──► queryset.json ──► scripts/run-analyzer.js (any Davis analyzer)
每个脚本的调用方式如下:
dtctl exec function -f scripts/<script>.js --payload '<json>' -o json
-o json 会将函数返回值封装在 .result 下。需要检查结果时,直接从输出中读取即可——无需 jq。将完整的原始输出作为 queries 传给 run-analyzer.js,它会自动解包。
解析仪表板 URL
当入口是 Dynatrace 仪表板 URL 时,提取脚本所需的三个组成部分:
https://<tenant>/ui/apps/dynatrace.dashboards/dashboard/<ID>#from=<from>&to=<to>&vfilter_<name>=<val>...
| URL 部分 | 脚本中的目标位置 |
|---|---|
/dashboard/ 之后、# 之前的路径段 | extract-timeseries-dashboard.js 载荷中的 id |
#from= 的值(URL 解码 %3A → :) | run-analyzer.js 中的 timeframe.startTime(仅在运行分析时需要) |
#to= 的值(URL 解码) | run-analyzer.js 中的 timeframe.endTime(仅在运行分析时需要) |
vfilter_<name>=<value> 参数 | run-analyzer.js 中的 variables 映射(去掉 vfilter_ 前缀) |
URL 片段中的时间范围是仪表板的显示窗口。它不会注入提取出的 DQL——提取器会原样返回 DQL,保留原有的 $variable 标记和任何内嵌的 | timeframe 子句。仅在调用 run-analyzer.js 设置分析窗口时使用解析出的 from/to 值。如果用户只想列出查询,时间范围仅供参考。
注意:向 run-analyzer.js 传入绝对值 timeframe.startTime(而不是 now... 表达式)时,它会在分析前从 DQL 中移除任何内嵌的 | timeframe ... 阶段,以便分析器遵循你指定的窗口,而不是查询中固有的窗口。对于相对(now...)窗口,内嵌的 | timeframe 会保持不变。这意味着实际分析的查询可能与提取出的文本不同——这是预期行为,在此说明是为了确保结果与指定的窗口一致。
快速 bash 解析(仅使用纯 bash + sed/awk,无需 python):
DASHBOARD_URL="https://abc123.apps.dynatrace.com/ui/apps/dynatrace.dashboards/dashboard/5bea16c7-029b-43b6-9735-459db2d25bbf#from=2026-05-28T04%3A00Z&to=2026-05-28T05%3A00Z&vfilter_host_group=prod&vfilter_workload=my-svc"
# Minimal URL-decoder: turn %XX into \xXX and let printf interpret it.
urldecode() { local s="${1//+/ }"; printf '%b' "${s//%/\\x}"; }
DOC_ID=$(echo "$DASHBOARD_URL" | sed 's/#.*//' | awk -F/ '{print $NF}')
FROM=$(urldecode "$(echo "$DASHBOARD_URL" | sed -n 's/.*[#&]from=\([^&]*\).*/\1/p')")
TO=$(urldecode "$(echo "$DASHBOARD_URL" | sed -n 's/.*[#&]to=\([^&]*\).*/\1/p')")
HOST_GROUP=$(echo "$DASHBOARD_URL" | sed -n 's/.*[#&]vfilter_host_group=\([^&]*\).*/\1/p')
WORKLOAD=$(echo "$DASHBOARD_URL" | sed -n 's/.*[#&]vfilter_workload=\([^&]*\).*/\1/p')
对于 Notebook:使用 /notebook/ 之后的路径段,或 /document/v0/#share=<ID> 链接中的 #share= 值。
第 1 步 — 提取查询
从仪表板提取
# All tiles
dtctl exec function -f scripts/extract-timeseries-dashboard.js \
--payload '{"id":"<dashboard-id-or-name>"}' -o json
# Only tiles whose title matches a name the user mentioned (e.g. "CPU usage", "Kafka lag")
dtctl exec function -f scripts/extract-timeseries-dashboard.js \
--payload '{"id":"<dashboard-id>","titleFilter":"CPU usage"}' -o json
用户指定了某个磁贴、图表或区块时,将其名称作为 titleFilter 传入,而不是提取整个仪表板。titleFilter 支持不区分大小写的子字符串或 /regex/flags 模式。这样可以让查询集保持精简且聚焦。
不清楚用户想要哪些磁贴时,不要提取所有 DQL——仪表板可能有 20–50 个磁贴,返回所有查询会显著增加上下文占用。应改用以下两步流程:
- 使用
listOnly: true列出磁贴名称(不含 DQL,仅返回标题):dtctl exec function -f scripts/extract-timeseries-dashboard.js \ --payload '{"id":"<dashboard-id>","listOnly":true}' -o json # Returns: {"result":{"ok":true,"tiles":[{"id":"...","title":"CPU Usage","visualization":"lineChart"},...]}} - 向用户展示磁贴名称,并询问他们指的是哪些磁贴。
- 使用
titleFilter重新运行,只提取感兴趣的磁贴。
这样可以避免在只有 1–2 个查询相关时,将 20–50 条 DQL 查询拉入上下文。
载荷参数:
id(必填)——仪表板 ID(UUID)或确切名称。像my.dynatrace.infraops.preview.*这样的预设 ID 也可使用。titleFilter——不区分大小写的子字符串("CPU usage")或/regex/flags("/^kafka/i")。listOnly——为true时,返回tiles: [{id, title, visualization}],不含 DQL。用于消除歧义。compact——为true时,每个磁贴仅返回{id, title, dqlQuery}(省略 description、visualization、isTimeseries)。每个磁贴可节省约 40% 的 token。在listOnly模式下,也会省略 visualization。includeSkipped——为true时,返回完整的skipped[]数组。默认情况下仅返回skippedCount。
响应封装:
{
"ok": true,
"documentId": "...", "documentName": "...", "documentVersion": 7,
"queries": [
{ "id": "<tile-key>", "title": "...", "description": "...",
"dqlQuery": "timeseries avg(dt.host.cpu.usage)",
"visualization": "lineChart", "isTimeseries": true }
],
"skipped": [{ "id": "...", "reason": "non-data tile (markdown)" }]
}
失败时:{ "ok": false, "error": { "code": "...", "message": "..." } }。
从 Notebook 提取
封装格式相同,架构遍历方式不同:
# All cells
dtctl exec function -f scripts/extract-timeseries-notebook.js \
--payload '{"id":"<notebook-id-or-name>"}' -o json
# A specific section (if cell titles are set)
dtctl exec function -f scripts/extract-timeseries-notebook.js \
--payload '{"id":"<notebook-id>","titleFilter":"JVM memory"}' -o json
Notebook 单元格的标题通常为空——若要指定某个单元格,优先使用封装中的 id。
第 2 步 — 运行分析器
将提取器的输出保存到文件,然后通过 shell 替换传入 — shell 会读取文件,因此 JSON 不会进入模型的上下文:
# Run extractor, save output
dtctl exec function -f scripts/extract-timeseries-dashboard.js \
--payload '{"id":"<id>","titleFilter":"CPU usage","compact":true}' -o json > queryset.json
# Shell substitution: $(cat queryset.json) is expanded by the shell, not the model
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.NoveltyScoreAnalyzer",
"queries": '"$(cat queryset.json)"',
"timeframe": { "startTime": "...", "endTime": "..." },
"analyzerParams": { ... }
}' -o json
run-analyzer.js 会自动解包 {"result":{...}} dtctl 信封 — 按原样传入保存的原始输出即可。无需使用 jq 或执行解析步骤:脚本内部会规范化数组、信封和 dtctl 输出等不同形状的数据。
对于大型查询集(包含大量图块),内联的 $(cat ...) 形式可能会触及 shell 参数长度限制。请构建载荷文件并使用 dtctl 的 --data 标志 — 同样无需使用 jq,且数据仍不会进入模型上下文:
{ printf '{"analyzerName":"dt.statistics.NoveltyScoreAnalyzer","timeframe":{"startTime":"now-1h","endTime":"now"},"queries":'
cat queryset.json
printf '}'; } > payload.json
dtctl exec function -f scripts/run-analyzer.js --data payload.json -o json
run-analyzer.js 的关键载荷参数:
minScore— 丢弃低于此阈值的结果(例如0.5)。自动检测分数字段,支持noveltyScore、anomalyScore、correlationCoefficient、correlation、coefficient。传入scoreField可覆盖自动检测结果。scoreField— 要读取分数的显式字段名称(例如"noveltyScore")。
queries 字段接受以下任一形式:原始数组、提取器信封({queries:[...]})或完整 dtctl 输出({"result":{"queries":[...]}})。这三种形式都会自动规范化。
常用分析器
| 目标 | analyzerName | analyzerParams |
|---|---|---|
| 查找异常指标 | dt.statistics.anomaly_detection.SeasonalBaselineAnomalyDetectionAnalyzer | { "trainingTimeframe": { "startTime": "now-8d", "endTime": "now-1d" } }(可选) |
| 评估每个指标的新颖程度 | dt.statistics.NoveltyScoreAnalyzer | { "detectionMode": "ALL", "minNoveltyScore": 0 }(可选) |
| 针对主要指标进行相关性分析 | dt.statistics.SimplePearsonCorrelationAnalyzer | 改为设置 metricQuery(调用形式会变化) |
相关性模式
传入 metricQuery,即可将集合中的每个查询与单个主要 DQL 字符串进行相关性分析:
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.SimplePearsonCorrelationAnalyzer",
"queries": '"$(cat queryset.json)"',
"metricQuery": "<dqlQuery of the primary tile, copied from extractor output>",
"timeframe": { "startTime": "...", "endTime": "..." }
}' -o json
从上一次分析器运行结果继续串联(例如,异常检测 → 相关性分析)时,请改用 metricQueryFrom。脚本会自动选取得分最高结果中的 dqlQuery:
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.SimplePearsonCorrelationAnalyzer",
"queries": '"$(cat queryset.json)"',
"metricQueryFrom": '"$(cat findings.json)"',
"timeframe": { "startTime": "...", "endTime": "..." }
}' -o json
如果两者都已设置,metricQuery 优先。
变量替换
仪表板查询通常包含 $variable 令牌(来自 URL 的 vfilter_* 参数)。通过 variables 传入这些变量,即可在执行前进行替换:
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.anomaly_detection.SeasonalBaselineAnomalyDetectionAnalyzer",
"queries": [...],
"timeframe": { "startTime": "2026-05-28T04:00Z", "endTime": "2026-05-28T05:00Z" },
"variables": { "host_group": "prod", "workload": "my-svc" }
}' -o json
从 vfilter_* URL 参数构建 variables 时,请去掉 vfilter_ 前缀。末尾的 * 通配符会自动去掉。未解析的令牌会从 DQL 筛选子句中清理,而不是保留并导致错误。
响应结构
{
"ok": true,
"checkedAt": "...",
"analyzerName": "...",
"summary": { "checked": 12, "completed": 11, "errors": 1 },
"results": [
{
"id": "tile-key", "title": "CPU usage", "dqlQuery": "...",
"output": <raw analyzer output>,
"executionStatus": "COMPLETED"
}
],
"errors": [ { "id": "...", "error": "..." } ]
}
output 字段是原始分析器结果。请根据分析器类型进行解读:
- 异常检测:在每个输出条目中查找
anomalyScore、anomalies[]或raisedAlerts[]。分数 ≥ 0.7 → 异常,≥ 0.4 → 临界。 - 新颖性:查找
noveltyScore(或最接近的类似分数的数值字段)。分数 ≥ 0.7 → 新颖。 - 相关性:查找
correlationCoefficient。按|correlationCoefficient|降序排序;丢弃|correlationCoefficient| < 0.5的条目。
端到端示例:“此仪表板上有哪些异常?”
# 1. Extract queries — shell reads file, JSON stays out of model context
dtctl exec function -f scripts/extract-timeseries-dashboard.js \
--payload '{"id":"5bea16c7-029b-43b6-9735-459db2d25bbf","compact":true}' \
-o json > queryset.json
# 2. Run anomaly detection — $(cat queryset.json) expanded by shell, not model
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.anomaly_detection.SeasonalBaselineAnomalyDetectionAnalyzer",
"queries": '"$(cat queryset.json)"',
"timeframe": { "startTime": "2026-05-28T04:00Z", "endTime": "2026-05-28T05:00Z" },
"variables": { "host_group": "prod", "workload": "my-svc" }
}' -o json > findings.json
# 3. Correlate — metricQueryFrom picks the top finding automatically
dtctl exec function -f scripts/run-analyzer.js \
--payload '{
"analyzerName": "dt.statistics.SimplePearsonCorrelationAnalyzer",
"queries": '"$(cat queryset.json)"',
"metricQueryFrom": '"$(cat findings.json)"',
"timeframe": { "startTime": "2026-05-28T04:00Z", "endTime": "2026-05-28T05:00Z" }
}' -o json
验证单个提取的查询
从提取器输出中读取 dqlQuery 字段,并直接传入:
dtctl query --query "<dqlQuery copied from extractor output>" -o json | head -40
注意事项
- 切勿自行读取原始仪表板 JSON。
dtctl get dashboard <id> -o json通常有 50–200 KB。提取器会在平台上读取它,并返回精简的封装数据(约 5–15 KB)。 - 只需要一个图表时,切勿提取所有图表。 一个包含 50 个图表的仪表板会向上下文中返回 50 条 DQL 查询。如果用户指定了某个图表,请使用
titleFilter。如果指定不明确,请先使用listOnly: true询问用户要哪个图表,然后只提取该图表。 - 经过筛选的仪表板必须提供变量。 未替换
$variable标记的查询会静默丢弃实体筛选条件(例如,in(field, $undefined)的计算结果为true)。如果 URL 包含vfilter_*参数,请务必传入variables。 - 架构变更。 如果某个图表因
no DQL query found而被列入skipped,说明仪表板架构中的查询位置不在提取器的已知范围内——请将其添加到脚本的pickQuery候选列表中。 - 分析器可用性。 并非每个租户都提供所有 Davis 分析器。如果调用返回
Could not find an analyzer with name '...'或is not a function,请列出当前实际注册的分析器:dtctl get analyzers -o json。 - 已移除统计回退功能。
run-analyzer.js只会调用 Davis 分析器。对于历史异常检测,请通过analyzerParams传入较长的trainingTimeframe(例如{ "trainingTimeframe": { "startTime": "now-30d", "endTime": "now-1d" } }),或者直接查询 DQL。 - 查询中的注释。 以
// comment行开头的查询会被提取器正确分类(在检查timeseries之前,会先去除开头的行注释和块注释)。
脚本参考
- scripts/extract-timeseries-dashboard.js — 从仪表板中提取 timeseries DQL
- scripts/extract-timeseries-notebook.js — 对笔记本执行相同操作
- scripts/run-analyzer.js — 通用 Davis 分析器运行器