mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-10 07:34:04 -08:00
Drop metric names after transformations.
After many transformations, it doesn't make sense to keep the metric names, since the result of the transformation is no longer that metric. This drops the metric name after such transformations and makes the web UI deal well with missing metric names. This depends on the current branch on the following things: - prometheus/client_golang needs to be ate237cf15c6
in branch "julius/int-fingerprints" (to be merged with new storage) - prometheus/promdash needs to be atdd7691c9c2
Change-Id: Ib3c8cad8d647d9854e8c653c424b8c235ccc231d
This commit is contained in:
parent
53c0a43754
commit
3d47f94149
|
@ -83,6 +83,17 @@ const (
|
||||||
OR
|
OR
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// shouldDropMetric indicates whether the metric name should be dropped after
|
||||||
|
// applying this operator to a vector.
|
||||||
|
func (opType BinOpType) shouldDropMetric() bool {
|
||||||
|
switch opType {
|
||||||
|
case ADD, SUB, MUL, DIV, MOD:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AggrType is an enum for aggregation types.
|
// AggrType is an enum for aggregation types.
|
||||||
type AggrType int
|
type AggrType int
|
||||||
|
|
||||||
|
@ -487,8 +498,8 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
|
||||||
m := clientmodel.Metric{}
|
m := clientmodel.Metric{}
|
||||||
if node.keepExtraLabels {
|
if node.keepExtraLabels {
|
||||||
m = sample.Metric
|
m = sample.Metric
|
||||||
|
delete(m, clientmodel.MetricNameLabel)
|
||||||
} else {
|
} else {
|
||||||
m[clientmodel.MetricNameLabel] = sample.Metric[clientmodel.MetricNameLabel]
|
|
||||||
for _, l := range node.groupBy {
|
for _, l := range node.groupBy {
|
||||||
if v, ok := sample.Metric[l]; ok {
|
if v, ok := sample.Metric[l]; ok {
|
||||||
m[l] = v
|
m[l] = v
|
||||||
|
@ -708,9 +719,6 @@ func evalVectorBinop(opType BinOpType,
|
||||||
}
|
}
|
||||||
|
|
||||||
func labelsEqual(labels1, labels2 clientmodel.Metric) bool {
|
func labelsEqual(labels1, labels2 clientmodel.Metric) bool {
|
||||||
if len(labels1) != len(labels2) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for label, value := range labels1 {
|
for label, value := range labels1 {
|
||||||
if labels2[label] != value && label != clientmodel.MetricNameLabel {
|
if labels2[label] != value && label != clientmodel.MetricNameLabel {
|
||||||
return false
|
return false
|
||||||
|
@ -730,6 +738,9 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp) Vector {
|
||||||
value, keep := evalVectorBinop(node.opType, lhs, rhsSample.Value)
|
value, keep := evalVectorBinop(node.opType, lhs, rhsSample.Value)
|
||||||
if keep {
|
if keep {
|
||||||
rhsSample.Value = value
|
rhsSample.Value = value
|
||||||
|
if node.opType.shouldDropMetric() {
|
||||||
|
delete(rhsSample.Metric, clientmodel.MetricNameLabel)
|
||||||
|
}
|
||||||
result = append(result, rhsSample)
|
result = append(result, rhsSample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -741,6 +752,9 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp) Vector {
|
||||||
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhs)
|
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhs)
|
||||||
if keep {
|
if keep {
|
||||||
lhsSample.Value = value
|
lhsSample.Value = value
|
||||||
|
if node.opType.shouldDropMetric() {
|
||||||
|
delete(lhsSample.Metric, clientmodel.MetricNameLabel)
|
||||||
|
}
|
||||||
result = append(result, lhsSample)
|
result = append(result, lhsSample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -754,6 +768,9 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp) Vector {
|
||||||
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhsSample.Value)
|
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhsSample.Value)
|
||||||
if keep {
|
if keep {
|
||||||
lhsSample.Value = value
|
lhsSample.Value = value
|
||||||
|
if node.opType.shouldDropMetric() {
|
||||||
|
delete(lhsSample.Metric, clientmodel.MetricNameLabel)
|
||||||
|
}
|
||||||
result = append(result, lhsSample)
|
result = append(result, lhsSample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ func deltaImpl(timestamp clientmodel.Timestamp, args []Node) interface{} {
|
||||||
Value: resultValue,
|
Value: resultValue,
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
}
|
}
|
||||||
|
delete(resultSample.Metric, clientmodel.MetricNameLabel)
|
||||||
resultVector = append(resultVector, resultSample)
|
resultVector = append(resultVector, resultSample)
|
||||||
}
|
}
|
||||||
return resultVector
|
return resultVector
|
||||||
|
@ -381,6 +382,7 @@ func aggrOverTime(timestamp clientmodel.Timestamp, args []Node, aggrFn func(metr
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(el.Metric, clientmodel.MetricNameLabel)
|
||||||
resultVector = append(resultVector, &clientmodel.Sample{
|
resultVector = append(resultVector, &clientmodel.Sample{
|
||||||
Metric: el.Metric,
|
Metric: el.Metric,
|
||||||
Value: aggrFn(el.Values),
|
Value: aggrFn(el.Values),
|
||||||
|
@ -446,6 +448,7 @@ func absImpl(timestamp clientmodel.Timestamp, args []Node) interface{} {
|
||||||
n := args[0].(VectorNode)
|
n := args[0].(VectorNode)
|
||||||
vector := n.Eval(timestamp)
|
vector := n.Eval(timestamp)
|
||||||
for _, el := range vector {
|
for _, el := range vector {
|
||||||
|
delete(el.Metric, clientmodel.MetricNameLabel)
|
||||||
el.Value = clientmodel.SampleValue(math.Abs(float64(el.Value)))
|
el.Value = clientmodel.SampleValue(math.Abs(float64(el.Value)))
|
||||||
}
|
}
|
||||||
return vector
|
return vector
|
||||||
|
|
|
@ -70,30 +70,30 @@ func TestExpressions(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expr: `SUM(http_requests)`,
|
expr: `SUM(http_requests)`,
|
||||||
output: []string{`http_requests => 3600 @[%v]`},
|
output: []string{`{} => 3600 @[%v]`},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests{instance="0"}) BY(job)`,
|
expr: `SUM(http_requests{instance="0"}) BY(job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 400 @[%v]`,
|
`{job="api-server"} => 400 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 1200 @[%v]`,
|
`{job="app-server"} => 1200 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 4,
|
intervalRanges: 4,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests{instance="0"}) BY(job) KEEPING_EXTRA`,
|
expr: `SUM(http_requests{instance="0"}) BY(job) KEEPING_EXTRA`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{instance="0", job="api-server"} => 400 @[%v]`,
|
`{instance="0", job="api-server"} => 400 @[%v]`,
|
||||||
`http_requests{instance="0", job="app-server"} => 1200 @[%v]`,
|
`{instance="0", job="app-server"} => 1200 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 4,
|
intervalRanges: 4,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job)`,
|
expr: `SUM(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1000 @[%v]`,
|
`{job="api-server"} => 1000 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2600 @[%v]`,
|
`{job="app-server"} => 2600 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
|
@ -101,8 +101,8 @@ func TestExpressions(t *testing.T) {
|
||||||
// Non-existent labels mentioned in BY-clauses shouldn't propagate to output.
|
// Non-existent labels mentioned in BY-clauses shouldn't propagate to output.
|
||||||
expr: `SUM(http_requests) BY (job, nonexistent)`,
|
expr: `SUM(http_requests) BY (job, nonexistent)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1000 @[%v]`,
|
`{job="api-server"} => 1000 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2600 @[%v]`,
|
`{job="app-server"} => 2600 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
|
@ -112,141 +112,141 @@ func TestExpressions(t *testing.T) {
|
||||||
SUM(http_requests) BY /* comments shouldn't
|
SUM(http_requests) BY /* comments shouldn't
|
||||||
have any effect */ (job) // another comment`,
|
have any effect */ (job) // another comment`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1000 @[%v]`,
|
`{job="api-server"} => 1000 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2600 @[%v]`,
|
`{job="app-server"} => 2600 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `COUNT(http_requests) BY (job)`,
|
expr: `COUNT(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 4 @[%v]`,
|
`{job="api-server"} => 4 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 4 @[%v]`,
|
`{job="app-server"} => 4 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job, group)`,
|
expr: `SUM(http_requests) BY (job, group)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="canary", job="api-server"} => 700 @[%v]`,
|
`{group="canary", job="api-server"} => 700 @[%v]`,
|
||||||
`http_requests{group="canary", job="app-server"} => 1500 @[%v]`,
|
`{group="canary", job="app-server"} => 1500 @[%v]`,
|
||||||
`http_requests{group="production", job="api-server"} => 300 @[%v]`,
|
`{group="production", job="api-server"} => 300 @[%v]`,
|
||||||
`http_requests{group="production", job="app-server"} => 1100 @[%v]`,
|
`{group="production", job="app-server"} => 1100 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `AVG(http_requests) BY (job)`,
|
expr: `AVG(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 250 @[%v]`,
|
`{job="api-server"} => 250 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 650 @[%v]`,
|
`{job="app-server"} => 650 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `MIN(http_requests) BY (job)`,
|
expr: `MIN(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 100 @[%v]`,
|
`{job="api-server"} => 100 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 500 @[%v]`,
|
`{job="app-server"} => 500 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `MAX(http_requests) BY (job)`,
|
expr: `MAX(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 400 @[%v]`,
|
`{job="api-server"} => 400 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 800 @[%v]`,
|
`{job="app-server"} => 800 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) - COUNT(http_requests) BY (job)`,
|
expr: `SUM(http_requests) BY (job) - COUNT(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 996 @[%v]`,
|
`{job="api-server"} => 996 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2596 @[%v]`,
|
`{job="app-server"} => 2596 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `2 - SUM(http_requests) BY (job)`,
|
expr: `2 - SUM(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => -998 @[%v]`,
|
`{job="api-server"} => -998 @[%v]`,
|
||||||
`http_requests{job="app-server"} => -2598 @[%v]`,
|
`{job="app-server"} => -2598 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `1000 / SUM(http_requests) BY (job)`,
|
expr: `1000 / SUM(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1 @[%v]`,
|
`{job="api-server"} => 1 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 0.38461538461538464 @[%v]`,
|
`{job="app-server"} => 0.38461538461538464 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) - 2`,
|
expr: `SUM(http_requests) BY (job) - 2`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 998 @[%v]`,
|
`{job="api-server"} => 998 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2598 @[%v]`,
|
`{job="app-server"} => 2598 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) % 3`,
|
expr: `SUM(http_requests) BY (job) % 3`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1 @[%v]`,
|
`{job="api-server"} => 1 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 2 @[%v]`,
|
`{job="app-server"} => 2 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) / 0`,
|
expr: `SUM(http_requests) BY (job) / 0`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => +Inf @[%v]`,
|
`{job="api-server"} => +Inf @[%v]`,
|
||||||
`http_requests{job="app-server"} => +Inf @[%v]`,
|
`{job="app-server"} => +Inf @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) > 1000`,
|
expr: `SUM(http_requests) BY (job) > 1000`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="app-server"} => 2600 @[%v]`,
|
`{job="app-server"} => 2600 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `1000 < SUM(http_requests) BY (job)`,
|
expr: `1000 < SUM(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="app-server"} => 1000 @[%v]`,
|
`{job="app-server"} => 1000 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) <= 1000`,
|
expr: `SUM(http_requests) BY (job) <= 1000`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1000 @[%v]`,
|
`{job="api-server"} => 1000 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) != 1000`,
|
expr: `SUM(http_requests) BY (job) != 1000`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="app-server"} => 2600 @[%v]`,
|
`{job="app-server"} => 2600 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) == 1000`,
|
expr: `SUM(http_requests) BY (job) == 1000`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 1000 @[%v]`,
|
`{job="api-server"} => 1000 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) + SUM(http_requests) BY (job)`,
|
expr: `SUM(http_requests) BY (job) + SUM(http_requests) BY (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="api-server"} => 2000 @[%v]`,
|
`{job="api-server"} => 2000 @[%v]`,
|
||||||
`http_requests{job="app-server"} => 5200 @[%v]`,
|
`{job="app-server"} => 5200 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
|
@ -261,22 +261,22 @@ func TestExpressions(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
expr: `http_requests{job="api-server", group="canary"} + delta(http_requests{job="api-server"}[5m], 1)`,
|
expr: `http_requests{job="api-server", group="canary"} + delta(http_requests{job="api-server"}[5m], 1)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="canary", instance="0", job="api-server"} => 330 @[%v]`,
|
`{group="canary", instance="0", job="api-server"} => 330 @[%v]`,
|
||||||
`http_requests{group="canary", instance="1", job="api-server"} => 440 @[%v]`,
|
`{group="canary", instance="1", job="api-server"} => 440 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 4,
|
fullRanges: 4,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
expr: `delta(http_requests[25m], 1)`,
|
expr: `delta(http_requests[25m], 1)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="canary", instance="0", job="api-server"} => 150 @[%v]`,
|
`{group="canary", instance="0", job="api-server"} => 150 @[%v]`,
|
||||||
`http_requests{group="canary", instance="0", job="app-server"} => 350 @[%v]`,
|
`{group="canary", instance="0", job="app-server"} => 350 @[%v]`,
|
||||||
`http_requests{group="canary", instance="1", job="api-server"} => 200 @[%v]`,
|
`{group="canary", instance="1", job="api-server"} => 200 @[%v]`,
|
||||||
`http_requests{group="canary", instance="1", job="app-server"} => 400 @[%v]`,
|
`{group="canary", instance="1", job="app-server"} => 400 @[%v]`,
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 50 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 50 @[%v]`,
|
||||||
`http_requests{group="production", instance="0", job="app-server"} => 250 @[%v]`,
|
`{group="production", instance="0", job="app-server"} => 250 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 100 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 100 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="app-server"} => 300 @[%v]`,
|
`{group="production", instance="1", job="app-server"} => 300 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 8,
|
fullRanges: 8,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
@ -360,45 +360,45 @@ func TestExpressions(t *testing.T) {
|
||||||
// Lower-cased aggregation operators should work too.
|
// Lower-cased aggregation operators should work too.
|
||||||
expr: `sum(http_requests) by (job) + min(http_requests) by (job) + max(http_requests) by (job) + avg(http_requests) by (job)`,
|
expr: `sum(http_requests) by (job) + min(http_requests) by (job) + max(http_requests) by (job) + avg(http_requests) by (job)`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{job="app-server"} => 4550 @[%v]`,
|
`{job="app-server"} => 4550 @[%v]`,
|
||||||
`http_requests{job="api-server"} => 1750 @[%v]`,
|
`{job="api-server"} => 1750 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
// Deltas should be adjusted for target interval vs. samples under target interval.
|
// Deltas should be adjusted for target interval vs. samples under target interval.
|
||||||
expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m], 1)`,
|
expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m], 1)`,
|
||||||
output: []string{`http_requests{group="canary", instance="1", job="app-server"} => 288 @[%v]`},
|
output: []string{`{group="canary", instance="1", job="app-server"} => 288 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
// Rates should transform per-interval deltas to per-second rates.
|
// Rates should transform per-interval deltas to per-second rates.
|
||||||
expr: `rate(http_requests{group="canary", instance="1", job="app-server"}[10m])`,
|
expr: `rate(http_requests{group="canary", instance="1", job="app-server"}[10m])`,
|
||||||
output: []string{`http_requests{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`},
|
output: []string{`{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
// Counter resets in middle of range are ignored by delta() if counter == 1.
|
// Counter resets in middle of range are ignored by delta() if counter == 1.
|
||||||
expr: `delta(testcounter_reset_middle[50m], 1)`,
|
expr: `delta(testcounter_reset_middle[50m], 1)`,
|
||||||
output: []string{`testcounter_reset_middle => 90 @[%v]`},
|
output: []string{`{} => 90 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
// Counter resets in middle of range are not ignored by delta() if counter == 0.
|
// Counter resets in middle of range are not ignored by delta() if counter == 0.
|
||||||
expr: `delta(testcounter_reset_middle[50m], 0)`,
|
expr: `delta(testcounter_reset_middle[50m], 0)`,
|
||||||
output: []string{`testcounter_reset_middle => 50 @[%v]`},
|
output: []string{`{} => 50 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
// Counter resets at end of range are ignored by delta() if counter == 1.
|
// Counter resets at end of range are ignored by delta() if counter == 1.
|
||||||
expr: `delta(testcounter_reset_end[5m], 1)`,
|
expr: `delta(testcounter_reset_end[5m], 1)`,
|
||||||
output: []string{`testcounter_reset_end => 0 @[%v]`},
|
output: []string{`{} => 0 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
// Counter resets at end of range are not ignored by delta() if counter == 0.
|
// Counter resets at end of range are not ignored by delta() if counter == 0.
|
||||||
expr: `delta(testcounter_reset_end[5m], 0)`,
|
expr: `delta(testcounter_reset_end[5m], 0)`,
|
||||||
output: []string{`testcounter_reset_end => -90 @[%v]`},
|
output: []string{`{} => -90 @[%v]`},
|
||||||
fullRanges: 1,
|
fullRanges: 1,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
}, {
|
}, {
|
||||||
|
@ -470,8 +470,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `abs(-1 * http_requests{group="production",job="api-server"})`,
|
expr: `abs(-1 * http_requests{group="production",job="api-server"})`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 100 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 200 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 2,
|
intervalRanges: 2,
|
||||||
|
@ -479,8 +479,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `avg_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
expr: `avg_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 50 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 50 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 100 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 100 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 2,
|
fullRanges: 2,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
@ -488,8 +488,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `count_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
expr: `count_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 11 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 11 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 11 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 11 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 2,
|
fullRanges: 2,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
@ -497,8 +497,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `max_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
expr: `max_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 100 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 200 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 2,
|
fullRanges: 2,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
@ -506,8 +506,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `min_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
expr: `min_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 0 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 0 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 0 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 0 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 2,
|
fullRanges: 2,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
@ -515,8 +515,8 @@ func TestExpressions(t *testing.T) {
|
||||||
{
|
{
|
||||||
expr: `sum_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
expr: `sum_over_time(http_requests{group="production",job="api-server"}[1h])`,
|
||||||
output: []string{
|
output: []string{
|
||||||
`http_requests{group="production", instance="0", job="api-server"} => 550 @[%v]`,
|
`{group="production", instance="0", job="api-server"} => 550 @[%v]`,
|
||||||
`http_requests{group="production", instance="1", job="api-server"} => 1100 @[%v]`,
|
`{group="production", instance="1", job="api-server"} => 1100 @[%v]`,
|
||||||
},
|
},
|
||||||
fullRanges: 2,
|
fullRanges: 2,
|
||||||
intervalRanges: 0,
|
intervalRanges: 0,
|
||||||
|
|
|
@ -350,7 +350,7 @@ Prometheus.Graph.prototype.renderLabels = function(labels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Prometheus.Graph.prototype.metricToTsName = function(labels) {
|
Prometheus.Graph.prototype.metricToTsName = function(labels) {
|
||||||
var tsName = labels["__name__"] + "{";
|
var tsName = (labels["__name__"] || '') + "{";
|
||||||
var labelStrings = [];
|
var labelStrings = [];
|
||||||
for (label in labels) {
|
for (label in labels) {
|
||||||
if (label != "__name__") {
|
if (label != "__name__") {
|
||||||
|
@ -378,7 +378,7 @@ Prometheus.Graph.prototype.transformData = function(json) {
|
||||||
}
|
}
|
||||||
var data = json.Value.map(function(ts) {
|
var data = json.Value.map(function(ts) {
|
||||||
return {
|
return {
|
||||||
name: self.metricToTsName(ts.Metric),
|
name: escapeHTML(self.metricToTsName(ts.Metric)),
|
||||||
labels: ts.Metric,
|
labels: ts.Metric,
|
||||||
data: ts.Values.map(function(value) {
|
data: ts.Values.map(function(value) {
|
||||||
return {
|
return {
|
||||||
|
@ -438,7 +438,7 @@ Prometheus.Graph.prototype.updateGraph = function(reloadGraph) {
|
||||||
graph: self.rickshawGraph,
|
graph: self.rickshawGraph,
|
||||||
formatter: function(series, x, y) {
|
formatter: function(series, x, y) {
|
||||||
var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
|
var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
|
||||||
var content = swatch + series.labels["__name__"] + ": <strong>" + y + '</strong><br>';
|
var content = swatch + (series.labels["__name__"] || 'value') + ": <strong>" + y + '</strong><br>';
|
||||||
return content + self.renderLabels(series.labels);
|
return content + self.renderLabels(series.labels);
|
||||||
},
|
},
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
|
@ -518,7 +518,7 @@ Prometheus.Graph.prototype.handleConsoleResponse = function(data, textStatus) {
|
||||||
for (var i = 0; i < data.Value.length; i++) {
|
for (var i = 0; i < data.Value.length; i++) {
|
||||||
var v = data.Value[i];
|
var v = data.Value[i];
|
||||||
var tsName = self.metricToTsName(v.Metric);
|
var tsName = self.metricToTsName(v.Metric);
|
||||||
tBody.append("<tr><td>" + tsName + "</td><td>" + v.Value + "</td></tr>")
|
tBody.append("<tr><td>" + escapeHTML(tsName) + "</td><td>" + v.Value + "</td></tr>")
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "matrix":
|
case "matrix":
|
||||||
|
@ -529,7 +529,7 @@ Prometheus.Graph.prototype.handleConsoleResponse = function(data, textStatus) {
|
||||||
for (var j = 0; j < v.Values.length; j++) {
|
for (var j = 0; j < v.Values.length; j++) {
|
||||||
valueText += v.Values[j].Value + " @" + v.Values[j].Timestamp + "<br/>";
|
valueText += v.Values[j].Value + " @" + v.Values[j].Timestamp + "<br/>";
|
||||||
}
|
}
|
||||||
tBody.append("<tr><td>" + tsName + "</td><td>" + valueText + "</td></tr>")
|
tBody.append("<tr><td>" + escapeHTML(tsName) + "</td><td>" + valueText + "</td></tr>")
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "scalar":
|
case "scalar":
|
||||||
|
@ -575,6 +575,21 @@ function addGraph(options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeHTML(string) {
|
||||||
|
var entityMap = {
|
||||||
|
"&": "&",
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
"/": '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
||||||
|
return entityMap[s];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
cache: false
|
cache: false
|
||||||
|
|
Loading…
Reference in a new issue