mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
ddc5197bce
* feat: add metric relabel debug (#3807) * fix: add link to relabeling cookbook * lib/promrelabel: merge, fix conflicts * lib/promrelabel: fix diff * docs/vmui: add metric relabel playground --------- Co-authored-by: dmitryk-dk <kozlovdmitriyy@gmail.com>
207 lines
7.8 KiB
Text
207 lines
7.8 KiB
Text
{% import (
|
|
"fmt"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/htmlcomponents"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
|
|
) %}
|
|
|
|
{% stripspace %}
|
|
|
|
{% func RelabelDebugSteps(targetURL, targetID, format string, dss []DebugStep, metric, relabelConfigs string, err error) %}
|
|
{% if format == "json" %}
|
|
{%= RelabelDebugStepsJSON(targetURL, targetID, dss, metric, relabelConfigs, err) %}
|
|
{% else %}
|
|
{%= RelabelDebugStepsHTML(targetURL, targetID, dss, metric, relabelConfigs, err) %}
|
|
{% endif %}
|
|
{% endfunc %}
|
|
|
|
{% func RelabelDebugStepsHTML(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) %}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
{%= htmlcomponents.CommonHeader() %}
|
|
<title>Metric relabel debug</title>
|
|
<script>
|
|
function submitRelabelDebugForm(e) {
|
|
var form = e.target;
|
|
var method = "GET";
|
|
if (form.elements["relabel_configs"].value.length + form.elements["metric"].value.length > 1000) {
|
|
method = "POST";
|
|
}
|
|
form.method = method;
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
{%= htmlcomponents.Navbar() %}
|
|
<div class="container-fluid">
|
|
<a href="https://docs.victoriametrics.com/relabeling.html" target="_blank">Relabeling docs</a>{% space %}
|
|
|
|
{% if targetURL != "" %}
|
|
<a href="metric-relabel-debug{% if targetID != "" %}?id={%s targetID %}{% endif %}">Metric relabel debug</a>
|
|
{% else %}
|
|
<a href="target-relabel-debug{% if targetID != "" %}?id={%s targetID %}{% endif %}">Target relabel debug</a>
|
|
{% endif %}
|
|
|
|
<br>
|
|
{% if err != nil %}
|
|
{%= htmlcomponents.ErrorNotification(err) %}
|
|
{% endif %}
|
|
|
|
<div class="m-3">
|
|
<form method="POST" onsubmit="submitRelabelDebugForm(event)">
|
|
{%= relabelDebugFormInputs(metric, relabelConfigs) %}
|
|
{% if targetID != "" %}
|
|
<input type="hidden" name="id" value="{%s targetID %}" />
|
|
{% endif %}
|
|
<input type="submit" value="Submit" class="btn btn-primary m-1" />
|
|
{% if targetID != "" %}
|
|
<button type="button" onclick="location.href='?id={%s targetID %}'" class="btn btn-secondary m-1">Reset</button>
|
|
{% endif %}
|
|
</form>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<main class="col-12">
|
|
{%= relabelDebugSteps(dss, targetURL, targetID) %}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
{% endfunc %}
|
|
|
|
{% func relabelDebugFormInputs(metric, relabelConfigs string) %}
|
|
<div>
|
|
Relabel configs:<br/>
|
|
<textarea name="relabel_configs" style="width: 100%; height: 15em" class="m-1">{%s relabelConfigs %}</textarea>
|
|
</div>
|
|
|
|
<div>
|
|
Labels:<br/>
|
|
<textarea name="metric" style="width: 100%; height: 5em" class="m-1">{%s metric %}</textarea>
|
|
</div>
|
|
{% endfunc %}
|
|
|
|
{% func relabelDebugSteps(dss []DebugStep, targetURL, targetID string) %}
|
|
{% if len(dss) > 0 %}
|
|
<div class="m-3">
|
|
<b>Original labels:</b> <samp>{%= mustFormatLabels(dss[0].In) %}</samp>
|
|
</div>
|
|
{% endif %}
|
|
<table class="table table-striped table-hover table-bordered table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" style="width: 5%">Step</th>
|
|
<th scope="col" style="width: 25%">Relabeling Rule</th>
|
|
<th scope="col" style="width: 35%">Input Labels</th>
|
|
<th scope="col" stile="width: 35%">Output labels</a>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for i, ds := range dss %}
|
|
{% code
|
|
inLabels := promutils.MustNewLabelsFromString(ds.In)
|
|
outLabels := promutils.MustNewLabelsFromString(ds.Out)
|
|
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
|
%}
|
|
<tr>
|
|
<td>{%d i %}</td>
|
|
<td><b><pre class="m-2">{%s ds.Rule %}</pre></b></td>
|
|
<td>
|
|
<div class="m-2" style="font-size: 0.9em" title="deleted and updated labels highlighted in red">
|
|
{%= labelsWithHighlight(inLabels, changedLabels, "red") %}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="m-2" style="font-size: 0.9em" title="added and updated labels highlighted in blue">
|
|
{%= labelsWithHighlight(outLabels, changedLabels, "blue") %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% if len(dss) > 0 %}
|
|
<div class="m-3">
|
|
<b>Resulting labels:</b> <samp>{%= mustFormatLabels(dss[len(dss)-1].Out) %}</samp>
|
|
{% if targetURL != "" %}
|
|
<div>
|
|
<b>Target URL:</b>{% space %}<a href="{%s targetURL %}" target="_blank">{%s targetURL %}</a>
|
|
{% if targetID != "" %}
|
|
{% space %}
|
|
(<a href="target_response?id={%s targetID %}" target="_blank" title="click to fetch target response on behalf of the scraper">response</a>)
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endfunc %}
|
|
|
|
{% func RelabelDebugStepsJSON(targetURL, targetID string, dss []DebugStep, metric, relabelConfigs string, err error) %}
|
|
{
|
|
{% if err != nil %}
|
|
"status": "error",
|
|
"error": {%q= fmt.Sprintf("Error: %s", err) %}
|
|
{% else %}
|
|
"status": "success",
|
|
{% if len(dss) > 0 %}
|
|
"originalLabels": {%q= string(mustFormatLabels(dss[0].In)) %},
|
|
"resultingLabels": {%q= string(mustFormatLabels(dss[len(dss)-1].Out)) %},
|
|
{% endif %}
|
|
"steps": [
|
|
{% for i, ds := range dss %}
|
|
{% code
|
|
inLabels := promutils.MustNewLabelsFromString(ds.In)
|
|
outLabels := promutils.MustNewLabelsFromString(ds.Out)
|
|
changedLabels := getChangedLabelNames(inLabels, outLabels)
|
|
%}
|
|
{
|
|
"inLabels": {%q= labelsWithHighlight(inLabels, changedLabels, "red") %},
|
|
"outLabels": {%q= labelsWithHighlight(outLabels, changedLabels, "blue") %},
|
|
"rule": {%q= ds.Rule %}
|
|
}
|
|
{% if i != len(dss)-1 %},{% endif %}
|
|
{% endfor %}
|
|
]
|
|
{% endif %}
|
|
}
|
|
{% endfunc %}
|
|
|
|
{% func labelsWithHighlight(labels *promutils.Labels, highlight map[string]struct{}, color string) %}
|
|
{% code
|
|
labelsList := labels.GetLabels()
|
|
metricName := ""
|
|
for i, label := range labelsList {
|
|
if label.Name == "__name__" {
|
|
metricName = label.Value
|
|
labelsList = append(labelsList[:i], labelsList[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
%}
|
|
{% if metricName != "" %}
|
|
{% if _, ok := highlight["__name__"]; ok %}
|
|
<span style="font-weight:bold;color:{%s color %}">{%s metricName %}</span>
|
|
{% else %}
|
|
{%s metricName %}
|
|
{% endif %}
|
|
{% if len(labelsList) == 0 %}{% return %}{% endif %}
|
|
{% endif %}
|
|
{
|
|
{% for i, label := range labelsList %}
|
|
{% if _, ok := highlight[label.Name]; ok %}
|
|
<span style="font-weight:bold;color:{%s color %}">{%s label.Name %}={%q label.Value %}</span>
|
|
{% else %}
|
|
{%s label.Name %}={%q label.Value %}
|
|
{% endif %}
|
|
{% if i < len(labelsList)-1 %},{% space %}{% endif %}
|
|
{% endfor %}
|
|
}
|
|
{% endfunc %}
|
|
|
|
{% func mustFormatLabels(s string) %}
|
|
{% code labels := promutils.MustNewLabelsFromString(s) %}
|
|
{%= labelsWithHighlight(labels, nil, "") %}
|
|
{% endfunc %}
|
|
|
|
{% endstripspace %}
|