-
Notifications
You must be signed in to change notification settings - Fork 107
Add support for summarize
#837
Changes from all commits
b9e8c71
273ca4d
433184c
11000bb
dd390ff
03fdc38
1897d08
50cbd2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package expr | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
"github.com/grafana/metrictank/api/models" | ||
"github.com/grafana/metrictank/batch" | ||
"github.com/grafana/metrictank/consolidation" | ||
"github.com/grafana/metrictank/util" | ||
"github.com/raintank/dur" | ||
"gopkg.in/raintank/schema.v1" | ||
) | ||
|
||
type FuncSummarize struct { | ||
in GraphiteFunc | ||
intervalString string | ||
fn string | ||
alignToFrom bool | ||
} | ||
|
||
func NewSummarize() GraphiteFunc { | ||
return &FuncSummarize{fn: "sum", alignToFrom: false} | ||
} | ||
|
||
func (s *FuncSummarize) Signature() ([]Arg, []Arg) { | ||
return []Arg{ | ||
ArgSeriesList{val: &s.in}, | ||
ArgString{val: &s.intervalString, validator: []Validator{IsIntervalString}}, | ||
ArgString{key: "func", opt: true, val: &s.fn, validator: []Validator{IsConsolFunc}}, | ||
ArgBool{key: "alignToFrom", opt: true, val: &s.alignToFrom}, | ||
}, []Arg{ArgSeriesList{}} | ||
} | ||
|
||
func (s *FuncSummarize) Context(context Context) Context { | ||
context.consol = 0 | ||
return context | ||
} | ||
|
||
func (s *FuncSummarize) Exec(cache map[Req][]models.Series) ([]models.Series, error) { | ||
series, err := s.in.Exec(cache) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
interval, _ := dur.ParseDuration(s.intervalString) | ||
aggFunc := consolidation.GetAggFunc(consolidation.FromConsolidateBy(s.fn)) | ||
|
||
var alignToFromTarget string | ||
if s.alignToFrom { | ||
alignToFromTarget = ", true" | ||
} | ||
newName := func(oldName string) string { | ||
return fmt.Sprintf("summarize(%s, \"%s\", \"%s\"%s)", oldName, s.intervalString, s.fn, alignToFromTarget) | ||
} | ||
|
||
var outputs []models.Series | ||
for _, serie := range series { | ||
var newStart, newEnd uint32 = serie.QueryFrom, serie.QueryTo | ||
if len(serie.Datapoints) > 0 { | ||
newStart = serie.Datapoints[0].Ts | ||
newEnd = serie.Datapoints[len(serie.Datapoints)-1].Ts + serie.Interval | ||
} | ||
if !s.alignToFrom { | ||
newStart = newStart - (newStart % interval) | ||
newEnd = newEnd - (newEnd % interval) + interval | ||
} | ||
|
||
out := summarizeValues(serie, aggFunc, interval, newStart, newEnd) | ||
|
||
output := models.Series{ | ||
Target: newName(serie.Target), | ||
QueryPatt: newName(serie.QueryPatt), | ||
Tags: serie.Tags, | ||
Datapoints: out, | ||
Interval: interval, | ||
} | ||
output.Tags["summarize"] = s.intervalString | ||
output.Tags["summarizeFunction"] = s.fn | ||
|
||
outputs = append(outputs, output) | ||
cache[Req{}] = append(cache[Req{}], output) | ||
} | ||
return outputs, nil | ||
} | ||
|
||
func summarizeValues(serie models.Series, aggFunc batch.AggFunc, interval, start, end uint32) []schema.Point { | ||
out := pointSlicePool.Get().([]schema.Point) | ||
|
||
numPoints := int(util.Min(uint32(len(serie.Datapoints)), (start-end)/interval)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm confused here. the only reason to get the util.Min of these two, is just in case the input series had a low number of points wrt to the requested interval right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If (serie.Datapoints[i].Ts < ts+interval) is violated, it doesn't increment i. So it would append NaN's for the inbetween. I'll push a test case that shows this. |
||
|
||
for ts, i := start, 0; i < numPoints && ts < end; ts += interval { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be thorough, this is different from the python code. To mirror the python code you would remove |
||
s := i | ||
for ; i < numPoints && serie.Datapoints[i].Ts < ts+interval; i++ { | ||
if serie.Datapoints[i].Ts <= ts { | ||
s = i | ||
} | ||
} | ||
|
||
aggPoint := schema.Point{Val: math.NaN(), Ts: ts} | ||
if s != i { | ||
aggPoint.Val = aggFunc(serie.Datapoints[s:i]) | ||
} | ||
|
||
out = append(out, aggPoint) | ||
} | ||
|
||
return out | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the python code also does:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does...which is odd IMO. Tags are something set at ingest and it seems odd to add more tags at query time (non-optionally). I get that this isn't the place to make these sorts of arguments, but it doesn't sit right with me to mess with the tags (especially in the case of name collision).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was to make the info about how the series was processed available to functions further down the chain, and the rationale for modifying the tags is that when you run series
x
through a functionf
you are creating a new seriesf(x)
, and its tags should identify it and describe how it's different fromx
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that, but it means a lot of "reserved" tag names that need to be kept track of and new ones for each function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Added in