Merge pull request #1283 from letsencrypt/metrics_scope

add metrics.Scope
This commit is contained in:
Jeff Hodges 2015-12-16 17:25:28 -08:00
commit 26b51e7a90
3 changed files with 316 additions and 0 deletions

138
metrics/mock_statsd_test.go Normal file
View File

@ -0,0 +1,138 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: github.com/cactus/go-statsd-client/statsd (interfaces: Statter)
package metrics
import (
gomock "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/golang/mock/gomock"
time "time"
)
// Mock of Statter interface
type MockStatter struct {
ctrl *gomock.Controller
recorder *_MockStatterRecorder
}
// Recorder for MockStatter (not exported)
type _MockStatterRecorder struct {
mock *MockStatter
}
func NewMockStatter(ctrl *gomock.Controller) *MockStatter {
mock := &MockStatter{ctrl: ctrl}
mock.recorder = &_MockStatterRecorder{mock}
return mock
}
func (_m *MockStatter) EXPECT() *_MockStatterRecorder {
return _m.recorder
}
func (_m *MockStatter) Close() error {
ret := _m.ctrl.Call(_m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Close() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Close")
}
func (_m *MockStatter) Dec(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Dec", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Dec(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Dec", arg0, arg1, arg2)
}
func (_m *MockStatter) Gauge(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Gauge", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Gauge(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Gauge", arg0, arg1, arg2)
}
func (_m *MockStatter) GaugeDelta(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "GaugeDelta", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) GaugeDelta(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GaugeDelta", arg0, arg1, arg2)
}
func (_m *MockStatter) Inc(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Inc", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Inc(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Inc", arg0, arg1, arg2)
}
func (_m *MockStatter) Raw(_param0 string, _param1 string, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Raw", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Raw(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Raw", arg0, arg1, arg2)
}
func (_m *MockStatter) Set(_param0 string, _param1 string, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Set", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Set(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Set", arg0, arg1, arg2)
}
func (_m *MockStatter) SetInt(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "SetInt", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) SetInt(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SetInt", arg0, arg1, arg2)
}
func (_m *MockStatter) SetPrefix(_param0 string) {
_m.ctrl.Call(_m, "SetPrefix", _param0)
}
func (_mr *_MockStatterRecorder) SetPrefix(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SetPrefix", arg0)
}
func (_m *MockStatter) Timing(_param0 string, _param1 int64, _param2 float32) error {
ret := _m.ctrl.Call(_m, "Timing", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) Timing(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Timing", arg0, arg1, arg2)
}
func (_m *MockStatter) TimingDuration(_param0 string, _param1 time.Duration, _param2 float32) error {
ret := _m.ctrl.Call(_m, "TimingDuration", _param0, _param1, _param2)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockStatterRecorder) TimingDuration(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "TimingDuration", arg0, arg1, arg2)
}

116
metrics/scope.go Normal file
View File

@ -0,0 +1,116 @@
// Copyright 2015 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//go:generate sh -c "mockgen -package metrics github.com/cactus/go-statsd-client/statsd Statter > ./mock_statsd_test.go && sed -i '' -e 's:github.com/golang/mock/gomock:github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/golang/mock/gomock:' ./mock_statsd_test.go"
package metrics
import (
"strings"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
)
// Scope is a stats collector that will prefix the name the stats it
// collects.
type Scope interface {
NewScope(scopes ...string) Scope
Scope() string
Inc(stat string, value int64) error
Dec(stat string, value int64) error
Gauge(stat string, value int64) error
GaugeDelta(stat string, value int64) error
Timing(stat string, delta int64) error
TimingDuration(stat string, delta time.Duration) error
Set(stat string, value string) error
SetInt(stat string, value int64) error
Raw(stat string, value string) error
}
// StatsdScope is a Scope that sends data to statsd with a prefix added to the
// stat names.
type StatsdScope struct {
prefix string
statter statsd.Statter
}
var _ Scope = &StatsdScope{}
// NewStatsdScope returns a StatsdScope that prefixes stats it collections with
// the scopes given joined together by periods
func NewStatsdScope(statter statsd.Statter, scopes ...string) *StatsdScope {
return &StatsdScope{
prefix: strings.Join(scopes, ".") + ".",
statter: statter,
}
}
// NewNoopScope returns a Scope that won't collect anything
func NewNoopScope() Scope {
c, _ := statsd.NewNoopClient()
return NewStatsdScope(c, "noop")
}
// NewScope generates a new Scope prefixed by this Scope's prefix plus the
// prefixes given joined by periods
func (s *StatsdScope) NewScope(scopes ...string) Scope {
scope := strings.Join(scopes, ".")
return NewStatsdScope(s.statter, s.prefix+scope)
}
// Scope returns the current string prefix (except for the final period) that
// stats will receive
func (s *StatsdScope) Scope() string {
return s.prefix[:len(s.prefix)-1]
}
// Inc increments the given stat and adds the Scope's prefix to the name
func (s *StatsdScope) Inc(stat string, value int64) error {
return s.statter.Inc(s.prefix+stat, value, 1.0)
}
// Dec decrements the given stat and adds the Scope's prefix to the name
func (s *StatsdScope) Dec(stat string, value int64) error {
return s.statter.Dec(s.prefix+stat, value, 1.0)
}
// Gauge sends a gauge stat and adds the Scope's prefix to the name
func (s *StatsdScope) Gauge(stat string, value int64) error {
return s.statter.Gauge(s.prefix+stat, value, 1.0)
}
// GaugeDelta sends the change in a gauge stat and adds the Scope's prefix to the name
func (s *StatsdScope) GaugeDelta(stat string, value int64) error {
return s.statter.GaugeDelta(s.prefix+stat, value, 1.0)
}
// Timing sends a latency stat and adds the Scope's prefix to the name
func (s *StatsdScope) Timing(stat string, delta int64) error {
return s.statter.Timing(s.prefix+stat, delta, 1.0)
}
// TimingDuration sends a latency stat as a time.Duration and adds the Scope's
// prefix to the name
func (s *StatsdScope) TimingDuration(stat string, delta time.Duration) error {
return s.statter.TimingDuration(s.prefix+stat, delta, 1.0)
}
// Set sets a stat's new value and adds the Scope's prefix to the name
func (s *StatsdScope) Set(stat string, value string) error {
return s.statter.Set(s.prefix+stat, value, 1.0)
}
// SetInt sets a stat's integer value and adds the Scope's prefix to the name
func (s *StatsdScope) SetInt(stat string, value int64) error {
return s.statter.SetInt(s.prefix+stat, value, 1.0)
}
// Raw sends a stat value without interpretation and adds the Scope's prefix to
// the name
func (s *StatsdScope) Raw(stat string, value string) error {
return s.statter.Raw(s.prefix+stat, value, 1.0)
}

62
metrics/scope_test.go Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2015 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package metrics
import (
"testing"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/golang/mock/gomock"
)
func TestScopedStatsStatsd(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
statter := NewMockStatter(ctrl)
stats := NewStatsdScope(statter, "fake")
statter.EXPECT().Inc("fake.counter", int64(2), float32(1.0)).Return(nil)
stats.Inc("counter", 2)
statter.EXPECT().Dec("fake.counter", int64(2), float32(1.0)).Return(nil)
stats.Dec("counter", 2)
statter.EXPECT().Gauge("fake.gauge", int64(2), float32(1.0)).Return(nil)
stats.Gauge("gauge", 2)
statter.EXPECT().GaugeDelta("fake.delta", int64(2), float32(1.0)).Return(nil)
stats.GaugeDelta("delta", 2)
statter.EXPECT().Timing("fake.latency", int64(2), float32(1.0)).Return(nil)
stats.Timing("latency", 2)
statter.EXPECT().TimingDuration("fake.latency", 2*time.Second, float32(1.0)).Return(nil)
stats.TimingDuration("latency", 2*time.Second)
statter.EXPECT().Set("fake.something", "value", float32(1.0)).Return(nil)
stats.Set("something", "value")
statter.EXPECT().SetInt("fake.someint", int64(10), float32(1.0)).Return(nil)
stats.SetInt("someint", 10)
statter.EXPECT().Raw("fake.raw", "raw value", float32(1.0)).Return(nil)
stats.Raw("raw", "raw value")
s := stats.NewScope("foobar")
statter.EXPECT().Inc("fake.foobar.counter", int64(3), float32(1.0)).Return(nil)
s.Inc("counter", 3)
ss := stats.NewScope("another", "level")
statter.EXPECT().Inc("fake.foobar.counter", int64(4), float32(1.0)).Return(nil)
s.Inc("counter", 4)
if stats.Scope() != "fake" {
t.Errorf(`expected "fake", got %#v`, stats.Scope())
}
if s.Scope() != "fake.foobar" {
t.Errorf(`expected "fake.foobar", got %#v`, s.Scope())
}
if ss.Scope() != "fake.another.level" {
t.Errorf(`expected "fake.foobar", got %#v`, s.Scope())
}
twoScope := NewStatsdScope(statter, "fake", "bang")
statter.EXPECT().Inc("fake.bang.counter", int64(7), float32(1.0)).Return(nil)
twoScope.Inc("counter", 7)
}