Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Taco_Lin authored and Taco_Lin committed Aug 4, 2015
0 parents commit d362ca8
Show file tree
Hide file tree
Showing 18 changed files with 1,873 additions and 0 deletions.
161 changes: 161 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package metric

import (
"sort"
"strings"
"sync"
"time"

"github.com/facebookgo/stats"
)

var (
// pkgClis stores pkgClients
pkgClis = map[string]*pkgClient{}
// pkgClis protects pkgClis
pkgClisLock = sync.RWMutex{}
// default counter paramters
counterParams = struct {
window, bucket time.Duration
}{window: 15 * time.Minute, bucket: time.Minute}
// default histogram parameters
histogramParams = struct {
window, bucket time.Duration
}{window: 5 * time.Minute, bucket: time.Minute}
)

// Counter defines interface for counter
type Counter interface {
// Incr increments value to the counter
Incr(value float64)
// Snapshot return the snapshot of the counter
Snapshot() CounterSnapshot
}

// Histogram defines interface for counter
type Histogram interface {
// Update add value to the histogram
Update(value float64)
// Snapshot returns the snapshot of the histogrom
Snapshot() HistSnapshot
}

// Snapshot includes CounterSnapshot, HistogramSnapshot and name
type Snapshot interface {
CounterSnapshot
HistSnapshot
// HasHistogram returns whether this snapshot contains histogram
HasHistogram() bool
// Pkg returns the package of Histogram
Pkg() string
// Name returns the package of Histogram Name
Name() string
}

// CounterSnapshot defines interface for accessing counter with following methods
type CounterSnapshot interface {
// SliceIn returns statistics of each bucket in the given duration
SliceIn(dur time.Duration) []Bucket
// AggrIn returns aggregration statistics in the given duration
AggrIn(dur time.Duration) Bucket
}

// HistSnapshot represents a snapshot of a histogram
type HistSnapshot interface {
// List histogram bins
Bins() []Bin
// Return export percentail values of the histogram
Percentiles([]float64) ([]float64, int64)
}

// Bucket represents the snapshot of a counter bucket, including
// statistics values like count, sum, average, min, max and bucket start/end
// time.
type Bucket struct {
Count float64
Sum float64
Min float64
Max float64
Avg float64
Start time.Time
End time.Time
}

// Bin represents the snapshot of a histogram bin, including bin couner and
// its lower and upper bound
type Bin struct {
Count int64
Lower float64
Upper float64
}

// NewClient creates an instance of facebookgo/stats implementation with
// the given pkg name and preifx.
func NewClient(pkg, prefix string) stats.Client {
pkgClisLock.Lock()
defer pkgClisLock.Unlock()

pc, ok := pkgClis[pkg]
if !ok {
pc = newClient(pkg)
pkgClis[pkg] = pc
}
if prefix == "" {
return pc
}
if !strings.HasSuffix(prefix, ".") {
prefix += "."
}
return stats.PrefixClient([]string{prefix}, pc)
}

// GetSnapshot returns shapshot of counters and histograms matched the
// given pkg and name
func GetSnapshot(qpkg string, qname string) []Snapshot {
pkgClisLock.RLock()
defer pkgClisLock.RUnlock()

snapshots := []Snapshot{}
for _, pc := range pkgClis {
if qpkg != "*" && !strings.Contains(pc.pkg, qpkg) {
continue
}
snapshots = append(snapshots, pc.get(qname)...)
}
return snapshots
}

// GetPkgs lista all package names
func GetPkgs(showEmpty bool) []string {
pkgClisLock.RLock()
result := make([]string, 0, len(pkgClis))
for pkg, cli := range pkgClis {
if showEmpty || cli.size() > 0 {
result = append(result, pkg)
}
}
pkgClisLock.RUnlock()

sort.Strings(result)
return result
}

// SetCounterParam sets the parameters of counter and histogram
func SetCounterParam(window, bucket time.Duration) error {
if err := check(window, bucket); err != nil {
return err
}
counterParams.window = window
counterParams.bucket = bucket
return nil
}

// SetHistogramParam sets the parameters of counter and histogram
func SetHistogramParam(window, bucket time.Duration) error {
if err := check(window, bucket); err != nil {
return err
}
histogramParams.window = window
histogramParams.bucket = bucket
return nil
}
92 changes: 92 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package metric

import (
"testing"

"github.com/stretchr/testify/suite"
)

// TestCase counter
type SuiteAPI struct {
suite.Suite
factory *mockFactory
}

func (s *SuiteAPI) SetupTest() {
pkgClis = map[string]*pkgClient{}
s.factory = &mockFactory{}

newCounter = s.factory.NewCounter
newHistogram = s.factory.NewHist
}

func (s *SuiteAPI) TestNewClient() {
defer s.add("aaa", "ccc.ddd", 10, 2, 1)()

c := NewClient("aaa", "")
c.BumpAvg("ccc.ddd", 10)
c.BumpHistogram("ccc.ddd", 10)

ss := GetSnapshot("aaa", "ccc.ddd")
s.Equal(len(ss), 1)
s.Equal(ss[0].Pkg(), "aaa")
s.Equal(ss[0].Name(), "ccc.ddd")
s.True(ss[0].HasHistogram())

ss = GetSnapshot("*", "*")
s.Equal(len(ss), 1)
s.True(ss[0].HasHistogram())
}

func (s *SuiteAPI) TestNewClientWithPrefix() {
defer s.add("aaa", "ccc.ddd", 10, 6, 0)()

c1 := NewClient("aaa", "ccc")
c1.BumpAvg("ddd", 10)
c1.BumpSum("ddd", 10)

c2 := NewClient("aaa", "ccc.")
c2.BumpAvg("ddd", 10)
c2.BumpSum("ddd", 10)

c3 := NewClient("aaa", "")
c3.BumpAvg("ccc.ddd", 10)
c3.BumpSum("ccc.ddd", 10)

ss := GetSnapshot("aaa", "ccc.ddd")
s.Equal(len(ss), 1)
s.Equal(ss[0].Pkg(), "aaa")
s.Equal(ss[0].Name(), "ccc.ddd")
s.False(ss[0].HasHistogram())
}

func (s *SuiteAPI) TestGetPkgs() {
s.add("aaa", "aaa.bbb", 10, 1, 0)
s.add("bbb", "ccc.ddd", 20, 1, 0)

c1 := NewClient("aaa", "")
c2 := NewClient("bbb", "")
_ = NewClient("ccc", "")

c1.BumpSum("aaa.bbb", 10)
c2.BumpSum("ccc.ddd", 20)

s.Equal(GetPkgs(false), []string{
"aaa",
"bbb",
})

s.Equal(GetPkgs(true), []string{
"aaa",
"bbb",
"ccc",
})
}

func (s *SuiteAPI) add(pkg, name string, v float64, ct, ht int) func() {
return addTestData(s.T(), s.factory, pkg, name, v, ct, ht)
}

func TestRunSuiteAPI(t *testing.T) {
suite.Run(t, new(SuiteAPI))
}
Loading

0 comments on commit d362ca8

Please sign in to comment.