Skip to content
This repository was archived by the owner on Dec 3, 2024. It is now read-only.

Commit 15b6334

Browse files
committed
Record counters as CUMULATIVE metrics
This addresses #18 While using `|align delta_gauge()` in MQL is potentially a workaround, it suffers from the drawback of producing huge negative deltas when the counter resets, and the current behavior is unhappily surprising to first-time users who would reasonably assume that `IncrCounter()` would produce a CUMULATIVE metric. Signed-off-by: Nathan J. Mehl <n@oden.io>
1 parent da14b6e commit 15b6334

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

stackdriver.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,9 @@ func (s *Sink) deep() (time.Time, map[string]*gauge, map[string]*counter, map[st
325325
}
326326
for k, v := range s.counters {
327327
rCounters[k] = &counter{
328-
name: v.name,
329-
value: v.value,
328+
name: v.name,
329+
value: v.value,
330+
startTime: v.startTime,
330331
}
331332
}
332333
for k, v := range s.histograms {
@@ -365,11 +366,14 @@ func (s *Sink) report(ctx context.Context) {
365366
Type: fmt.Sprintf("custom.googleapis.com/%s%s", s.prefix, name),
366367
Labels: labels,
367368
},
368-
MetricKind: metricpb.MetricDescriptor_GAUGE,
369+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
369370
Resource: resource,
370371
Points: []*monitoringpb.Point{
371372
{
372373
Interval: &monitoringpb.TimeInterval{
374+
StartTime: &googlepb.Timestamp{
375+
Seconds: v.startTime.Unix(),
376+
},
373377
EndTime: &googlepb.Timestamp{
374378
Seconds: end.Unix(),
375379
},
@@ -537,11 +541,23 @@ func (s *Sink) IncrCounterWithLabels(key []string, val float32, labels []metrics
537541

538542
c, ok := s.counters[n.hash]
539543
if ok {
544+
// counter exists; increment value
540545
c.value += float64(val)
546+
// start times cannot be over 25 hours old; reset after 24h
547+
age := time.Now().Unix() - c.startTime.Unix()
548+
if age > 86400 {
549+
// Start times _must_ be before the end time (which is set in Report()),
550+
// so backdate our new start time to 1ms before the observed time.
551+
c.startTime = time.Now().Add(time.Millisecond * -1)
552+
}
541553
} else {
554+
// init new counter
542555
s.counters[n.hash] = &counter{
543556
name: n,
544557
value: float64(val),
558+
// startTime must predate what GCM believes is "now" when we create the interval;
559+
// so backdate by 1ms
560+
startTime: time.Now().Add(time.Millisecond * -1),
545561
}
546562
}
547563
}
@@ -645,8 +661,9 @@ type gauge struct {
645661

646662
// https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TimeSeries#point
647663
type counter struct {
648-
name *series
649-
value float64
664+
name *series
665+
value float64
666+
startTime time.Time
650667
}
651668

652669
// https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TimeSeries#distribution

stackdriver_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// you may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at
66
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
7+
// http://www.apache.org/licenses/LICENSE-2.0
88
//
99
// Unless required by applicable law or agreed to in writing, software
1010
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -365,7 +365,7 @@ func TestSample(t *testing.T) {
365365
Metric: &metricpb.Metric{
366366
Type: "custom.googleapis.com/go-metrics/foo_bar_counter",
367367
},
368-
MetricKind: metricpb.MetricDescriptor_GAUGE,
368+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
369369
Points: []*monitoringpb.Point{
370370
{
371371
Value: &monitoringpb.TypedValue{
@@ -402,7 +402,7 @@ func TestSample(t *testing.T) {
402402
"env": "dev",
403403
},
404404
},
405-
MetricKind: metricpb.MetricDescriptor_GAUGE,
405+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
406406
Points: []*monitoringpb.Point{
407407
{
408408
Value: &monitoringpb.TypedValue{
@@ -438,7 +438,7 @@ func TestSample(t *testing.T) {
438438
Metric: &metricpb.Metric{
439439
Type: "custom.googleapis.com/go-metrics/foo_bar_counter",
440440
},
441-
MetricKind: metricpb.MetricDescriptor_GAUGE,
441+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
442442
Points: []*monitoringpb.Point{
443443
{
444444
Value: &monitoringpb.TypedValue{
@@ -773,7 +773,7 @@ func TestExtract(t *testing.T) {
773773
"method": "bar",
774774
},
775775
},
776-
MetricKind: metricpb.MetricDescriptor_GAUGE,
776+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
777777
Points: []*monitoringpb.Point{
778778
{
779779
Value: &monitoringpb.TypedValue{
@@ -914,7 +914,7 @@ func TestExtract(t *testing.T) {
914914
"method": "baz",
915915
},
916916
},
917-
MetricKind: metricpb.MetricDescriptor_GAUGE,
917+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
918918
Points: []*monitoringpb.Point{
919919
{
920920
Value: &monitoringpb.TypedValue{

0 commit comments

Comments
 (0)