-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from hashicorp/metrics
Add metrics package with go-metrics shim
- Loading branch information
Showing
15 changed files
with
492 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package metrics | ||
|
||
import "sync/atomic" | ||
|
||
var ( | ||
_ Collector = &AtomicCollector{} | ||
) | ||
|
||
// AtomicCollector is a simple Collector that atomically stores | ||
// counters and gauges in memory. | ||
type AtomicCollector struct { | ||
counters []uint64 | ||
gauges []uint64 | ||
|
||
counterIndex, gaugeIndex map[string]int | ||
} | ||
|
||
// NewAtomicCollector creates a collector for the given set of Definitions. | ||
func NewAtomicCollector(defs Definitions) *AtomicCollector { | ||
c := &AtomicCollector{ | ||
counters: make([]uint64, len(defs.Counters)), | ||
gauges: make([]uint64, len(defs.Gauges)), | ||
counterIndex: make(map[string]int), | ||
gaugeIndex: make(map[string]int), | ||
} | ||
for i, d := range defs.Counters { | ||
if _, ok := c.counterIndex[d.Name]; ok { | ||
panic("duplicate metrics named " + d.Name) | ||
} | ||
c.counterIndex[d.Name] = i | ||
} | ||
for i, d := range defs.Gauges { | ||
if _, ok := c.counterIndex[d.Name]; ok { | ||
panic("duplicate metrics named " + d.Name) | ||
} | ||
if _, ok := c.gaugeIndex[d.Name]; ok { | ||
panic("duplicate metrics named " + d.Name) | ||
} | ||
c.gaugeIndex[d.Name] = i | ||
} | ||
return c | ||
} | ||
|
||
// IncrementCounter record val occurrences of the named event. Names will | ||
// follow prometheus conventions with lower_case_and_underscores. We don't | ||
// need any additional labels currently. | ||
func (c *AtomicCollector) IncrementCounter(name string, delta uint64) { | ||
id, ok := c.counterIndex[name] | ||
if !ok { | ||
panic("invalid metric name: " + name) | ||
} | ||
atomic.AddUint64(&c.counters[id], delta) | ||
} | ||
|
||
// SetGauge sets the value of the named gauge overriding any previous value. | ||
func (c *AtomicCollector) SetGauge(name string, val uint64) { | ||
id, ok := c.gaugeIndex[name] | ||
if !ok { | ||
panic("invalid metric name: " + name) | ||
} | ||
atomic.StoreUint64(&c.gauges[id], val) | ||
} | ||
|
||
// Summary returns a summary of the metrics since startup. Each value is | ||
// atomically loaded but the set is not atomic overall and may represent an | ||
// inconsistent snapshot e.g. with some metrics reflecting the most recent | ||
// operation while others don't. | ||
func (c *AtomicCollector) Summary() Summary { | ||
s := Summary{ | ||
Counters: make(map[string]uint64, len(c.counters)), | ||
Gauges: make(map[string]uint64, len(c.gauges)), | ||
} | ||
for name, id := range c.counterIndex { | ||
s.Counters[name] = atomic.LoadUint64(&c.counters[id]) | ||
} | ||
for name, id := range c.gaugeIndex { | ||
s.Gauges[name] = atomic.LoadUint64(&c.gauges[id]) | ||
} | ||
return s | ||
} | ||
|
||
// Summary is a copy of the values recorded so far for each metric. | ||
type Summary struct { | ||
Counters map[string]uint64 | ||
Gauges map[string]uint64 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package metrics | ||
|
||
import ( | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestAtomicCollector(t *testing.T) { | ||
defs := Definitions{ | ||
Counters: []Descriptor{ | ||
{ | ||
Name: "c1", | ||
Desc: "counter one.", | ||
}, | ||
{ | ||
Name: "c2", | ||
Desc: "counter two.", | ||
}, | ||
}, | ||
Gauges: []Descriptor{ | ||
{ | ||
Name: "g1", | ||
Desc: "gauge one.", | ||
}, | ||
{ | ||
Name: "g2", | ||
Desc: "gauge two.", | ||
}, | ||
}, | ||
} | ||
|
||
c := NewAtomicCollector(defs) | ||
|
||
var wg sync.WaitGroup | ||
|
||
for i := 0; i < 10; i++ { | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
for j := 0; j < 10; j++ { | ||
c.IncrementCounter("c1", 1) | ||
c.IncrementCounter("c2", 2) | ||
c.SetGauge("g1", uint64(j)) | ||
c.SetGauge("g2", uint64(j*2)) | ||
} | ||
}() | ||
} | ||
|
||
wg.Wait() | ||
|
||
s := c.Summary() | ||
require.Equal(t, 100, int(s.Counters["c1"])) | ||
require.Equal(t, 200, int(s.Counters["c2"])) | ||
require.Equal(t, 9, int(s.Gauges["g1"])) | ||
require.Equal(t, 18, int(s.Gauges["g2"])) | ||
} |
Oops, something went wrong.