Browse Source

Merge pull request #641 from prometheus/stddev

Add stddev and stdvar aggregation functions.
pull/642/head
Julius Volz 10 years ago
parent
commit
e681a57d73
  1. 14
      rules/ast/ast.go
  2. 2
      rules/ast/printer.go
  3. 2
      rules/helpers.go
  4. 4
      rules/lexer.l
  5. 542
      rules/lexer.l.go
  6. 26
      rules/rules_test.go
  7. 2
      templates/templates.go

14
rules/ast/ast.go

@ -68,6 +68,7 @@ type Matrix []SampleStream
type groupedAggregation struct {
labels clientmodel.COWMetric
value clientmodel.SampleValue
valuesSquaredSum clientmodel.SampleValue
groupCount int
}
@ -128,6 +129,8 @@ const (
Min
Max
Count
Stdvar
Stddev
)
// ----------------------------------------------------------------------------
@ -468,6 +471,12 @@ func (node *VectorAggregation) groupedAggregationsToVector(aggregations map[uint
aggregation.value = aggregation.value / clientmodel.SampleValue(aggregation.groupCount)
case Count:
aggregation.value = clientmodel.SampleValue(aggregation.groupCount)
case Stdvar:
avg := float64(aggregation.value) / float64(aggregation.groupCount)
aggregation.value = clientmodel.SampleValue(float64(aggregation.valuesSquaredSum)/float64(aggregation.groupCount) - avg*avg)
case Stddev:
avg := float64(aggregation.value) / float64(aggregation.groupCount)
aggregation.value = clientmodel.SampleValue(math.Sqrt(float64(aggregation.valuesSquaredSum)/float64(aggregation.groupCount) - avg*avg))
default:
// For other aggregations, we already have the right value.
}
@ -509,6 +518,10 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
}
case Count:
groupedResult.groupCount++
case Stdvar, Stddev:
groupedResult.value += sample.Value
groupedResult.valuesSquaredSum += sample.Value * sample.Value
groupedResult.groupCount++
default:
panic("Unknown aggregation type")
}
@ -531,6 +544,7 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
result[groupingKey] = &groupedAggregation{
labels: m,
value: sample.Value,
valuesSquaredSum: sample.Value * sample.Value,
groupCount: 1,
}
}

2
rules/ast/printer.go

@ -65,6 +65,8 @@ func (aggrType AggrType) String() string {
Min: "MIN",
Max: "MAX",
Count: "COUNT",
Stdvar: "STDVAR",
Stddev: "STDDEV",
}
return aggrTypeMap[aggrType]
}

2
rules/helpers.go

@ -83,6 +83,8 @@ func NewVectorAggregation(aggrTypeStr string, vector ast.Node, groupBy clientmod
"MIN": ast.Min,
"AVG": ast.Avg,
"COUNT": ast.Count,
"STDVAR": ast.Stdvar,
"STDDEV": ast.Stddev,
}
aggrType, ok := aggrTypes[aggrTypeStr]
if !ok {

4
rules/lexer.l

@ -89,8 +89,8 @@ GROUP_LEFT|GROUP_RIGHT lval.str = lexer.token(); return MATCH_MOD
group_left|group_right lval.str = strings.ToUpper(lexer.token()); return MATCH_MOD
KEEPING_EXTRA|keeping_extra return KEEPING_EXTRA
OFFSET|offset return OFFSET
AVG|SUM|MAX|MIN|COUNT lval.str = lexer.token(); return AGGR_OP
avg|sum|max|min|count lval.str = strings.ToUpper(lexer.token()); return AGGR_OP
AVG|SUM|MAX|MIN|COUNT|STDVAR|STDDEV lval.str = lexer.token(); return AGGR_OP
avg|sum|max|min|count|stdvar|stddev lval.str = strings.ToUpper(lexer.token()); return AGGR_OP
\<|>|AND|OR|and|or lval.str = strings.ToUpper(lexer.token()); return CMP_OP
==|!=|>=|<=|=~|!~ lval.str = lexer.token(); return CMP_OP
[+\-] lval.str = lexer.token(); return ADDITIVE_OP

542
rules/lexer.l.go

File diff suppressed because it is too large Load Diff

26
rules/rules_test.go

@ -1295,6 +1295,32 @@ func TestExpressions(t *testing.T) {
`{l="y"} => -Inf @[%v]`,
},
},
{
expr: `stddev(http_requests)`,
output: []string{
`{} => 229.12878474779 @[%v]`,
},
},
{
expr: `stddev by (instance)(http_requests)`,
output: []string{
`{instance="0"} => 223.60679774998 @[%v]`,
`{instance="1"} => 223.60679774998 @[%v]`,
},
},
{
expr: `stdvar(http_requests)`,
output: []string{
`{} => 52500 @[%v]`,
},
},
{
expr: `stdvar by (instance)(http_requests)`,
output: []string{
`{instance="0"} => 50000 @[%v]`,
`{instance="1"} => 50000 @[%v]`,
},
},
}
storage, closer := newTestStorage(t)

2
templates/templates.go

@ -219,7 +219,7 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
return fmt.Sprintf("%.4g%ss", v, prefix)
},
"pathPrefix": func() string {
return pathPrefix;
return pathPrefix
},
},
}

Loading…
Cancel
Save