Skip to content

Commit

Permalink
Merge pull request #19 from libp2p/feat/metrics-redux
Browse files Browse the repository at this point in the history
Add OpenCensus metrics registration functionality to core
  • Loading branch information
bigs authored Jun 20, 2019
2 parents d962316 + 464d1e2 commit a237360
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
70 changes: 70 additions & 0 deletions core/metrics/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package metrics

import (
"fmt"
"sync"

"go.opencensus.io/stats/view"
)

var registeredViews = map[string][]*view.View{}
var mu = new(sync.Mutex)

type ErrNamespace struct {
Namespace string
}

// ErrUnregisteredNamespace is an error for lookup of requested unregistered Namespace
type ErrUnregisteredNamespace ErrNamespace

func (e ErrUnregisteredNamespace) Error() string {
return fmt.Sprintf("no views found registered under Namespace %s", e.Namespace)
}

// ErrDuplicateNamespaceRegistration is an error for a Namespace that has already
// registered views
type ErrDuplicateNamespaceRegistration ErrNamespace

func (e ErrDuplicateNamespaceRegistration) Error() string {
return fmt.Sprintf("duplicate registration of views by Namespace %s", e.Namespace)
}

// RegisterViews accepts a namespace and a slice of Views, which will be registered
// with opencensus and maintained in the global registered views map
func RegisterViews(namespace string, views ...*view.View) error {
mu.Lock()
defer mu.Unlock()
_, ok := registeredViews[namespace]
if ok {
return ErrDuplicateNamespaceRegistration{Namespace: namespace}
} else {
registeredViews[namespace] = views
}

return nil
}

// LookupViews returns all views for a Namespace name. Returns an error if the
// Namespace has not been registered.
func LookupViews(name string) ([]*view.View, error) {
mu.Lock()
defer mu.Unlock()
views, ok := registeredViews[name]
if !ok {
return nil, ErrUnregisteredNamespace{Namespace: name}
}
response := make([]*view.View, len(views))
copy(response, views)
return response, nil
}

// AllViews returns all registered views as a single slice
func AllViews() []*view.View {
var views []*view.View
mu.Lock()
defer mu.Unlock()
for _, vs := range registeredViews {
views = append(views, vs...)
}
return views
}
94 changes: 94 additions & 0 deletions core/metrics/register_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package metrics

import (
"fmt"
"go.opencensus.io/stats"
"testing"

"go.opencensus.io/stats/view"
)

func newTestMeasure(name string) stats.Measure {
return stats.Int64(fmt.Sprintf("test/measure/%s", name),
fmt.Sprintf("Test measurement %s", name),
stats.UnitDimensionless,
)
}

func newTestView(name string) *view.View {
return &view.View{
Name: fmt.Sprintf("test/%s", name),
Description: fmt.Sprintf("Test view %s", name),
Measure: newTestMeasure(name),
Aggregation: view.LastValue(),
}
}

func TestRegisteringViews(t *testing.T) {
registeredViews = make(map[string][]*view.View)

t.Run("test registering first views", func(t *testing.T) {
testView := newTestView("empty-map-0")

if err := RegisterViews("test", testView); err != nil {
t.Fatal("unable to register view in empty map", err)
}
})

t.Run("test registering with existing views", func(t *testing.T) {
testView := newTestView("empty-map-1")
testView2 := newTestView("existing-entity-0")

if err := RegisterViews("test2", testView); err != nil {
t.Fatal("unable to register view in empty map", err)
}
if err := RegisterViews("test3", testView2); err != nil {
t.Fatal("unable to register view in map", err)
}
})

t.Run("test registering duplicate views", func(t *testing.T) {
testView := newTestView("empty-map-2")
testView2 := newTestView("existing-entity-1")

if err := RegisterViews("test4", testView); err != nil {
t.Fatal("unable to register view in empty map", err)
}
if err := RegisterViews("test4", testView2); err == nil {
t.Fatal("allowed duplicate view registration")
}
})

t.Run("test looking up views", func(t *testing.T) {
testView := newTestView("empty-map-3")

if err := RegisterViews("test5", testView); err != nil {
t.Fatal("unable to register view in empty map", err)
}

views, err := LookupViews("test5")
if err != nil {
t.Fatal("error looking up views", err)
}

if views[0].Name != testView.Name {
t.Fatal("incorrect view lookup, received name:", views[0].Name)
}
})
}

func TestAllViews(t *testing.T) {
registeredViews = make(map[string][]*view.View)
t.Run("test retrieving all views", func(t *testing.T) {
views := []*view.View{newTestView("all-views-0"), newTestView("all-views-1"), newTestView("all-views-2")}

if err := RegisterViews("test6", views...); err != nil {
t.Fatal("unable to register multiple views at once", err)
}

allViews := AllViews()
if len(allViews) != len(views) {
t.Fatalf("didn't receive equal number of views: %d %d", len(views), len(allViews))
}
})
}

0 comments on commit a237360

Please sign in to comment.