فهرست منبع

Allow lazy instantiation of metric in GetOrRegister.

Fix also memleaks in GetOrRegister* due to this
non-lazy instantiation.
Laurent 11 سال پیش
والد
کامیت
b29332614c
7فایلهای تغییر یافته به همراه43 افزوده شده و 7 حذف شده
  1. 1 1
      counter.go
  2. 1 1
      gauge.go
  3. 1 1
      histogram.go
  4. 1 1
      meter.go
  5. 13 2
      registry.go
  6. 25 0
      registry_test.go
  7. 1 1
      timer.go

+ 1 - 1
counter.go

@@ -17,7 +17,7 @@ func GetOrRegisterCounter(name string, r Registry) Counter {
 	if nil == r {
 		r = DefaultRegistry
 	}
-	return r.GetOrRegister(name, NewCounter()).(Counter)
+	return r.GetOrRegister(name, NewCounter).(Counter)
 }
 
 // NewCounter constructs a new StandardCounter.

+ 1 - 1
gauge.go

@@ -15,7 +15,7 @@ func GetOrRegisterGauge(name string, r Registry) Gauge {
 	if nil == r {
 		r = DefaultRegistry
 	}
-	return r.GetOrRegister(name, NewGauge()).(Gauge)
+	return r.GetOrRegister(name, NewGauge).(Gauge)
 }
 
 // NewGauge constructs a new StandardGauge.

+ 1 - 1
histogram.go

@@ -22,7 +22,7 @@ func GetOrRegisterHistogram(name string, r Registry, s Sample) Histogram {
 	if nil == r {
 		r = DefaultRegistry
 	}
-	return r.GetOrRegister(name, NewHistogram(s)).(Histogram)
+	return r.GetOrRegister(name, func() Histogram { return NewHistogram(s) }).(Histogram)
 }
 
 // NewHistogram constructs a new StandardHistogram from a Sample.

+ 1 - 1
meter.go

@@ -20,7 +20,7 @@ func GetOrRegisterMeter(name string, r Registry) Meter {
 	if nil == r {
 		r = DefaultRegistry
 	}
-	return r.GetOrRegister(name, NewMeter()).(Meter)
+	return r.GetOrRegister(name, NewMeter).(Meter)
 }
 
 // NewMeter constructs a new StandardMeter and launches a goroutine.

+ 13 - 2
registry.go

@@ -1,6 +1,9 @@
 package metrics
 
-import "sync"
+import (
+	"reflect"
+	"sync"
+)
 
 // A Registry holds references to a set of metrics by name and can iterate
 // over them, calling callback functions provided by the user.
@@ -15,7 +18,9 @@ type Registry interface {
 	// Get the metric by the given name or nil if none is registered.
 	Get(string) interface{}
 
-	// Gets an existing metric or creates and registers a new one.
+	// Gets an existing metric or registers the given one.
+	// The interface can be the metric to register if not found in registry,
+	// or a function returning the metric for lazy instantiation.
 	GetOrRegister(string, interface{}) interface{}
 
 	// Register the given metric under the given name.
@@ -56,12 +61,18 @@ func (r *StandardRegistry) Get(name string) interface{} {
 
 // Gets an existing metric or creates and registers a new one. Threadsafe
 // alternative to calling Get and Register on failure.
+// The interface can be the metric to register if not found in registry,
+// or a function returning the metric for lazy instantiation.
 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
 	r.mutex.Lock()
 	defer r.mutex.Unlock()
 	if metric, ok := r.metrics[name]; ok {
 		return metric
 	}
+	if refVal := reflect.ValueOf(i); refVal.Kind() == reflect.Func {
+		i = refVal.Call(nil)[0].Interface()
+	}
+
 	r.register(name, i)
 	return i
 }

+ 25 - 0
registry_test.go

@@ -71,3 +71,28 @@ func TestRegistryGetOrRegister(t *testing.T) {
 		t.Fatal(i)
 	}
 }
+
+func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) {
+	r := NewRegistry()
+
+	// First metric wins with GetOrRegister
+	_ = r.GetOrRegister("foo", NewCounter)
+	m := r.GetOrRegister("foo", NewGauge)
+	if _, ok := m.(Counter); !ok {
+		t.Fatal(m)
+	}
+
+	i := 0
+	r.Each(func(name string, iface interface{}) {
+		i++
+		if name != "foo" {
+			t.Fatal(name)
+		}
+		if _, ok := iface.(Counter); !ok {
+			t.Fatal(iface)
+		}
+	})
+	if i != 1 {
+		t.Fatal(i)
+	}
+}

+ 1 - 1
timer.go

@@ -31,7 +31,7 @@ func GetOrRegisterTimer(name string, r Registry) Timer {
 	if nil == r {
 		r = DefaultRegistry
 	}
-	return r.GetOrRegister(name, NewTimer()).(Timer)
+	return r.GetOrRegister(name, NewTimer).(Timer)
 }
 
 // NewCustomTimer constructs a new StandardTimer from a Histogram and a Meter.