mcpField
D
dt-obs-analytics

dt-obs-analytics

github.com/dynatrace数据与数据库1691.1k 次安装今天更新
代码仓库

关于 dt-obs-analytics

一组用于 Dynatrace 的技能脚本,可从 dashboard 和 notebook 提取 DQL 查询,再交给 Davis analyzer 分析。支持按标题筛选查询,并传入时间范围与变量。

主要功能

  1. 01从 dashboard 提取 DQL
  2. 02从 notebook 提取 DQL
  3. 03按标题或正则筛选
  4. 04调用 Davis analyzer 分析查询
  5. 05传入时间范围和变量

适用场景

  1. 01提取 dashboard 指定图表的查询
  2. 02分析 notebook 中的指标异常
  3. 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.js
extract-timeseries-notebook.js
run-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 个磁贴,返回所有查询会显著增加上下文占用。应改用以下两步流程:

  1. 使用 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"},...]}}
    
  2. 向用户展示磁贴名称,并询问他们指的是哪些磁贴。
  3. 使用 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":[...]}})。这三种形式都会自动规范化。

常用分析器
目标analyzerNameanalyzerParams
查找异常指标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 之前,会先去除开头的行注释和块注释)。

脚本参考

评论

支持 Markdown