一键导入
dashboard
Generate, repair, or review Guance Dashboard JSON from real metrics CSV files, tag metadata, and resource-catalog or custom-object CSV/JSON data.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Generate, repair, or review Guance Dashboard JSON from real metrics CSV files, tag metadata, and resource-catalog or custom-object CSV/JSON data.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generate Guance monitor JSON from CSV metric files for any component.
Convert Grafana dashboard JSON into Guance dashboard JSON with a fully self-contained skill package. Use when the user wants to analyze Grafana dashboards before conversion, run conversion, audit conversion gaps, improve units or PromQL compatibility with LLM-assisted review, repair panel or variable mappings, preserve settings, groups, and vars as much as possible, validate generated Guance dashboard JSON against the bundled schemas, or debug why a Grafana dashboard does not convert cleanly.
Use the owl CLI for Guance queries, diagnostics, root-cause analysis, and structured Markdown reports.
Convert Prometheus alerting rules into Guance monitor JSON and validate all generated DQL.
Generate, fix, explain, and review DQL; final executable DQL must pass dqlcheck item by item.
Convert, validate, and explain Alibaba Cloud SLS queries as GuanceDB DQL.
| name | dashboard |
| author | liurui |
| description | Generate, repair, or review Guance Dashboard JSON from real metrics CSV files, tag metadata, and resource-catalog or custom-object CSV/JSON data. |
Generate Guance Dashboard JSON from real metrics CSV files. Standard resource dashboards also use resource-catalog or custom-object data for instance-property tables. When the user provides a manually edited Dashboard JSON, treat it as feedback and carry its verified corrections into unfinished charts.
This skill must produce an operations-usable dashboard, not a thin demo. The final output must be based only on the user-provided CSV metrics and every final DQL must pass dqlcheck.
Input: csv/{{type}}*.csv plus tag metadata
resource-object CSV/JSON for a standard resource dashboard
optional manually edited Dashboard JSON
->
[Check real inputs] <- refuse generation when metrics CSV is missing
-> <- request object export when a standard resource table is required
[Parse metrics, tags, and object top-level fields]
->
[Research official units and enum semantics]
->
[Apply operations baseline]
->
[Generate JSON]
->
[Autofix style] <- required before DQL validation
->
[Validate DQL] <- validate one query at a time
->
Output: output/dashboard/{{type}}/{{type}}.json
Before generation, the skill must verify that at least one matching CSV file exists:
csv/{{type}}*.csvcsv/{{type}}.csvcsv/{{type}}/*.csvIf no CSV file exists, refuse generation.
Do not:
A standard resource dashboard must build its instance-property table from resource-catalog or custom-object CSV/JSON data. The object input must provide:
When object input is missing:
A review-only task that does not modify an existing object table may proceed without object input. Any new object field, unit, or enum mapping still requires a real object sample.
Read these fields from the CSV with either Chinese or English column names:
指标名 or metric_name字段类型 or data_type单位 or unit操作 or tag_key or TagThe parsed tag field is the source of truth for variable naming.
Also classify:
_average, _max, and _min metric familiesFor object data, capture the class, top-level fields, sample values, field types, unit metadata, and low-cardinality enum candidates. Nested message payloads are evidence sources only; do not assume their fields are queryable top-level CO:: fields.
The variable code must come from the actual CSV tag keys. Do not rename tags by datasource convention.
Prefer readable filters and stable identity when the actual fields exist:
account_nameinstance_nameinstance_idinstanceId, host, or first parsed tag without renaming ithost only when no tag existsExample logic:
def get_variable_codes(csv_row):
tag_text = csv_row.get("操作") or csv_row.get("tag_key") or csv_row.get("Tag") or ""
tags = [t.strip() for t in tag_text.split(",") if t.strip()]
preferred = [
key for key in ["account_name", "instance_name", "instance_id", "instanceId", "host"]
if key in tags
]
return preferred or tags[:1] or ["host"]
Consistency is mandatory:
main.vars rather than assuming main.vars[0] is the only variablename and value must match its actual variable and #{code}groupBy must match the DQL BY display dimensionsBY; readable names belong in legends while stable IDs may remain filters or object grouping keysThe dashboard must be useful for troubleshooting, not just overview display.
Minimum requirements for every dashboard:
table chart; for a standard resource dashboard this must query real object datasinglestat KPI cards, usually 4 to 8 cardssequence trend chartsIf CSV coverage exists, do not silently skip important dimensions unless they are explicitly low-value and you say so.
MySQL-specific minimums when matching CSV files exist:
mysql: include connection, query, transaction, and network trendsmysql_user_status: include at least 1 user-dimension table with BY host, usermysql_schema: include at least 1 schema-dimension table with BY host, schema_namemysql_table_schema: include at least 1 table-dimension table with BY host, table_schema, table_namemysql_replication: include at least 1 replication-related chartDo not:
Autofix is required after JSON generation and before DQL validation.
dashboardExtend.groupUnfoldStatus entry to true.dashboardExtend.groupColor.main.groups[].extend.bgColor from a restrained but distinguishable operations palette.main.groups[].extend.colorKey.singlestat charts, force extend.settings.valueColor from a varied palette.singlestat charts, force extend.settings.bgColor to a transparent background derived from valueColor.singlestat charts, force extend.settings.borderColor = "#E5E7EB".sequence query that returns multiple series, clear the query color and settings.colors so the UI palette can distinguish those series.Reference pseudocode:
def to_alpha_bg(hex_color, alpha=0.12):
h = hex_color.lstrip("#")
r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)
return f"rgba({r}, {g}, {b}, {alpha})"
def autofix_dashboard_style(dashboard):
groups = [g["name"] for g in dashboard["main"]["groups"]]
dashboard["dashboardExtend"]["groupUnfoldStatus"] = {name: True for name in groups}
list_groups = [g for g in groups if "list" in g.lower() and g.lower() != "overview"]
other_groups = [g for g in groups if g not in (["overview"] + list_groups)]
ordered = (["overview"] if "overview" in groups else []) + list_groups + other_groups
group_palette = ["#3B82F6", "#94A3B8", "#22C55E", "#F59E0B", "#06B6D4", "#EF4444", "#8B5CF6"]
multi = ["#06B6D4", "#10B981", "#EAB308", "#F97316", "#EF4444", "#8B5CF6", "#EC4899"]
dashboard["dashboardExtend"].pop("groupColor", None)
order_index = {name: idx for idx, name in enumerate(ordered)}
dashboard["main"]["groups"].sort(key=lambda group: order_index[group["name"]])
dashboard["main"]["charts"].sort(
key=lambda chart: order_index.get(
chart.get("group", {}).get("name", ""), len(order_index)
)
)
for idx, group in enumerate(dashboard["main"]["groups"]):
ext = group.setdefault("extend", {})
ext["bgColor"] = to_alpha_bg(group_palette[idx % len(group_palette)], 0.10)
ext.pop("colorKey", None)
card_idx = 0
for chart in dashboard["main"]["charts"]:
settings = chart.setdefault("extend", {}).setdefault("settings", {})
group_name = chart.get("group", {}).get("name", "")
if chart.get("type") == "singlestat" and group_name.lower() == "overview":
settings["valueColor"] = multi[card_idx % len(multi)]
settings["bgColor"] = to_alpha_bg(settings["valueColor"], 0.14)
settings["borderColor"] = "#E5E7EB"
card_idx += 1
if chart.get("type") == "sequence":
for item in chart.get("queries", []):
if item.get("query", {}).get("groupBy"):
item["color"] = ""
settings["colors"] = []
return dashboard
The generated JSON must follow this shape:
{
"title": "MySQL Monitoring",
"dashboardType": "CUSTOM",
"dashboardExtend": {
"groupUnfoldStatus": {}
},
"dashboardMapping": [],
"dashboardOwnerType": "node",
"dashboardBindSet": [],
"thumbnail": "",
"summary": "Description",
"main": {
"vars": [],
"charts": [],
"groups": []
}
}
Do not put chartGroupPos inside main.
Use the real tag key in the variable definition and downstream queries.
Example:
{
"name": "Host",
"code": "host",
"type": "QUERY",
"definition": {
"value": "SHOW_TAG_VALUE(from=['mysql'],keyin=['host'])[10m]"
},
"multiple": true,
"includeStar": true
}
Groups are required under main.groups.
Rules:
extend.bgColorEvery chart must configure units.
If the CSV or object schema does not provide a unit, research the current service's first-party API, metric, or SDK documentation. Use ["custom", ""] and mark the result UNVERIFIED only when the unit still cannot be confirmed. Otherwise map it to a standard pair.
Recommended mappings:
| CSV unit | units |
|---|---|
- | ["custom", ""] |
percent | ["percent", "percent"] |
% | ["percent", "percent"] |
B | ["digital", "B"] |
KB | ["digital", "KB"] |
MB | ["digital", "MB"] |
GB | ["digital", "GB"] |
B/S | ["traffic", "B/S"] |
KB/S | ["traffic", "KB/S"] |
MB/S | ["traffic", "MB/S"] |
ms | ["time", "ms"] |
s | ["time", "s"] |
iops | ["throughput", "iops"] |
ops | ["throughput", "ops"] |
reqps | ["throughput", "reqps"] |
Only use custom when the unit is actually empty or remains unrecognized after research. Distinguish bytes from bits, ratios from percentages, cumulative values from rates, and instance totals from node or shard values.
Use singlestat for overview KPIs.
Required behavior:
series_sum(...)fill = nullfuncList = []fieldFunc = "last"AVG() or SUM() directly inside the core KPI field expression when a direct field is enoughname, type, unit, color, and qtypeExample validation commands:
./dql/bin/dqlcheck -q 'M::`mysql`:(`Threads_connected` AS `Connections`) { `host` = "#{host}" } BY `host`'
Use sequence for trends.
Required behavior:
fill(last(...), linear) style queryAVG(field)fill = "linear"currentChartType = "area"chartType = "areaLine"funcList = []queryFuncs = []groupByTime = ""fieldFunc = "last" for rate-like countersfieldFunc = "avg" for average-value metrics= in filters, not regex operatorsDo not add extra Grafana-style rendering flags that Guance does not need.
Choose the query from the metric's aggregation semantics:
| Metric kind | Preferred trend DQL | fieldFunc |
|---|---|---|
| Raw counter | rate(field) or compatible rollup logic | last |
| Raw gauge | AVG(field) | avg |
Cloud-side *_average | fill(last(field), linear) | last |
Cloud-side *_max / *_min | Use fill(last(...), linear) only when peak or floor analysis is explicitly needed | last |
Do not apply a second AVG() to already aggregated *_average fields. Default to the _average member of an _average/_max/_min family, keep one metric field per queries[] item, prefer readable instance names in ordinary multi-instance legends, and leave grouped-query colors empty so the UI can distinguish the returned series.
Use table charts for instance lists and high-cardinality operational views.
At least one instance-level table is mandatory.
When the CSV supports richer dimensions, prefer:
For a standard resource dashboard, use a real custom-object query for the instance table:
CO::service_object:(last(`account_name`), last(`instance_name`), last(`region_id`), last(`status`)) { `account_name` = '#{account_name}' and `instance_id` = '#{instance_id}' } BY `instance_id`
Use namespace: "custom_object", the real object measurement/class as dataSource, and a stable resource ID in groupBy. Query only top-level fields found in the object sample. Use verified alias/fieldMapping and valMappings for readable columns; preserve unknown values rather than guessing.
Preferred dimensions:
h = 6Recommended widths:
| cards per row | width |
|---|---|
| 8 | 3 |
| 6 | 4 |
| 4 | 6 |
| 3 | 8 |
If there are 6 cards in a row, use width 4 so the row spans the full dashboard width.
Prefer stable layouts:
w = 8, h = 10w = 6, h = 10w = 12, h = 10w = 24, h = 10Default to 3 charts per row unless the group divides cleanly into 4.
Tables should usually be full-width:
w = 24h = 10Every final chart DQL must pass dqlcheck one by one.
Validation steps:
Commands:
./dql/bin/dqlcheck -q '<DQL>'
./dql/bin/dqlcheck --file /tmp/query.dql
Pass criteria:
sequence DQL passessinglestat DQL passestable DQL passesIf a query still fails after repair attempts, say so explicitly and do not present it as a valid final result.
main.groups exists.main does not contain chartGroupPos.dashboardExtend.groupUnfoldStatus.main.vars entries.filters.name and filters.value matches an actual variable, and groupBy matches the DQL BY display dimensions.singlestat uses series_sum(...).singlestat uses fill = null.sequence uses valid fill and chart-type settings.CO::, custom_object, the real object class, and a stable resource ID.dqlcheck.dql/SKILL.mdunit/SKILL.md