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

Commit 5a05d30

Browse files
committed
add resetcounter methods
1 parent cfc6ea5 commit 5a05d30

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ This package is intended as a way to publish metrics for applications that are _
1414

1515
## 🚨 Upgrading
1616

17-
Between v0.5.0 and v0.6.0, the behavior of the `IncrCounter` method changed: previously it would create a `GAUGE` [metric kind](https://cloud.google.com/monitoring/api/v3/kinds-and-types), but from v0.6.0 forward it will create a `CUMULATIVE` metric kind. (See https://github.com/google/go-metrics-stackdriver/issues/18 for a discussion.)
17+
Between v0.5.0 and v0.6.0, the behavior of the `IncrCounter()` method changed: previously it would create a `GAUGE` [metric kind](https://cloud.google.com/monitoring/api/v3/kinds-and-types), but from v0.6.0 forward it will create a `CUMULATIVE` metric kind. (See https://github.com/google/go-metrics-stackdriver/issues/18 for a discussion.)
1818

19-
However, once a [MetricDescriptor](https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics#MetricDescriptor) has been created in Google Cloud Monitoring, its `metricKind` field cannot be changed. So if you have any _existing_ `GAUGE` metrics that were created by `IncrCounter`, you will see errors in your logs when the v0.6.0 client attempts to update them and fails. Your options for handling this are:
19+
However, once a [MetricDescriptor](https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics#MetricDescriptor) has been created in Google Cloud Monitoring, its `metricKind` field cannot be changed. So if you have any _existing_ `GAUGE` metrics that were created by `IncrCounter()`, you will see errors in your logs when the v0.6.0 client attempts to update them and fails. Your options for handling this are:
2020

2121
1. Change the name of the metric you are passing to `IncrCounter` (creating a new metricDescriptor with a different name), or:
2222
2. Delete the existing metricDescriptor using the [delete API](https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.metricDescriptors/delete) and let go-metrics re-create it as a `CUMULATIVE` metric
2323

24+
Additionally, v0.6.0 adds `ResetCounter()` and `ResetCounterWithLabels()` methods: calling these methods resets the counter value to zero.
25+
2426
## Details
2527

2628
[stackdriver.NewSink](https://godoc.org/github.com/google/go-metrics-stackdriver#NewSink)'s return value satisfies the go-metrics library's [MetricSink](https://godoc.org/github.com/armon/go-metrics#MetricSink) interface. When providing a `stackdriver.Sink` to libraries and applications instrumented against `MetricSink`, the metrics will be aggregated within this library and written to stackdriver as [Generic Task](https://cloud.google.com/monitoring/api/resources#tag_generic_task) timeseries metrics.

stackdriver.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,34 @@ func (s *Sink) IncrCounterWithLabels(key []string, val float32, labels []metrics
562562
}
563563
}
564564

565+
// ResetCounter resets a counter to zero
566+
func (s *Sink) ResetCounter(key []string) {
567+
s.ResetCounterWithLabels(key, nil)
568+
}
569+
570+
// ResetCounterWithLabels resets a counter to zero
571+
func (s *Sink) ResetCounterWithLabels(key []string, labels []metrics.Label) {
572+
n := newSeries(key, labels)
573+
s.mu.Lock()
574+
defer s.mu.Unlock()
575+
576+
initVal := float64(0)
577+
startTime := time.Now().Add(time.Millisecond * -1)
578+
c, ok := s.counters[n.hash]
579+
if ok {
580+
// counter exists, reset to 0 and reset startTime
581+
c.value = initVal
582+
c.startTime = startTime
583+
} else {
584+
// counter did not exist, init at 0 value
585+
s.counters[n.hash] = &counter{
586+
name: n,
587+
value: initVal,
588+
startTime: startTime,
589+
}
590+
}
591+
}
592+
565593
// AddSample adds a sample to a histogram metric.
566594
func (s *Sink) AddSample(key []string, val float32) {
567595
s.AddSampleWithLabels(key, val, nil)

stackdriver_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,81 @@ func TestSample(t *testing.T) {
458458
}
459459
},
460460
},
461+
{
462+
name: "reset counter",
463+
collect: func() {
464+
ss.IncrCounter([]string{"foo", "bar"}, 1.0)
465+
ss.IncrCounter([]string{"foo", "bar"}, 1.0)
466+
ss.ResetCounter([]string{"foo", "bar"})
467+
},
468+
createFn: func(t *testing.T) func(context.Context, *monitoringpb.CreateTimeSeriesRequest) (*emptypb.Empty, error) {
469+
return func(_ context.Context, req *monitoringpb.CreateTimeSeriesRequest) (*emptypb.Empty, error) {
470+
want := &monitoringpb.CreateTimeSeriesRequest{
471+
Name: "projects/foo",
472+
TimeSeries: []*monitoringpb.TimeSeries{
473+
{
474+
Metric: &metricpb.Metric{
475+
Type: "custom.googleapis.com/go-metrics/foo_bar_counter",
476+
},
477+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
478+
Points: []*monitoringpb.Point{
479+
{
480+
Value: &monitoringpb.TypedValue{
481+
Value: &monitoringpb.TypedValue_DoubleValue{
482+
DoubleValue: 0.0,
483+
},
484+
},
485+
},
486+
},
487+
},
488+
},
489+
}
490+
if diff := diffCreateMsg(want, req); diff != "" {
491+
t.Errorf("unexpected CreateTimeSeriesRequest (-want +got):\n%s", diff)
492+
}
493+
return &emptypb.Empty{}, nil
494+
}
495+
},
496+
},
497+
{
498+
name: "reset counter with label",
499+
collect: func() {
500+
ss.IncrCounterWithLabels([]string{"foo", "bar"}, 1.0, []metrics.Label{{Name: "env", Value: "dev"}})
501+
ss.IncrCounterWithLabels([]string{"foo", "bar"}, 1.0, []metrics.Label{{Name: "env", Value: "dev"}})
502+
ss.ResetCounterWithLabels([]string{"foo", "bar"}, []metrics.Label{{Name: "env", Value: "dev"}})
503+
},
504+
createFn: func(t *testing.T) func(context.Context, *monitoringpb.CreateTimeSeriesRequest) (*emptypb.Empty, error) {
505+
return func(_ context.Context, req *monitoringpb.CreateTimeSeriesRequest) (*emptypb.Empty, error) {
506+
want := &monitoringpb.CreateTimeSeriesRequest{
507+
Name: "projects/foo",
508+
TimeSeries: []*monitoringpb.TimeSeries{
509+
{
510+
Metric: &metricpb.Metric{
511+
Type: "custom.googleapis.com/go-metrics/foo_bar_counter",
512+
Labels: map[string]string{
513+
"env": "dev",
514+
},
515+
},
516+
MetricKind: metricpb.MetricDescriptor_CUMULATIVE,
517+
Points: []*monitoringpb.Point{
518+
{
519+
Value: &monitoringpb.TypedValue{
520+
Value: &monitoringpb.TypedValue_DoubleValue{
521+
DoubleValue: 0.0,
522+
},
523+
},
524+
},
525+
},
526+
},
527+
},
528+
}
529+
if diff := diffCreateMsg(want, req); diff != "" {
530+
t.Errorf("unexpected CreateTimeSeriesRequest (-want +got):\n%s", diff)
531+
}
532+
return &emptypb.Empty{}, nil
533+
}
534+
},
535+
},
461536
{
462537
name: "gauge",
463538
collect: func() {

0 commit comments

Comments
 (0)