167 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
// Package stats defines a lightweight interface for collecting statistics. It
 | 
						|
// doesn't provide an implementation, just the shared interface.
 | 
						|
package stats
 | 
						|
 | 
						|
// Client provides methods to collection statistics.
 | 
						|
type Client interface {
 | 
						|
	// BumpAvg bumps the average for the given key.
 | 
						|
	BumpAvg(key string, val float64)
 | 
						|
 | 
						|
	// BumpSum bumps the sum for the given key.
 | 
						|
	BumpSum(key string, val float64)
 | 
						|
 | 
						|
	// BumpHistogram bumps the histogram for the given key.
 | 
						|
	BumpHistogram(key string, val float64)
 | 
						|
 | 
						|
	// BumpTime is a special version of BumpHistogram which is specialized for
 | 
						|
	// timers. Calling it starts the timer, and it returns a value on which End()
 | 
						|
	// can be called to indicate finishing the timer. A convenient way of
 | 
						|
	// recording the duration of a function is calling it like such at the top of
 | 
						|
	// the function:
 | 
						|
	//
 | 
						|
	//     defer s.BumpTime("my.function").End()
 | 
						|
	BumpTime(key string) interface {
 | 
						|
		End()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// PrefixClient adds multiple keys for the same value, with each prefix
 | 
						|
// added to the key and calls the underlying client.
 | 
						|
func PrefixClient(prefixes []string, client Client) Client {
 | 
						|
	return &prefixClient{
 | 
						|
		Prefixes: prefixes,
 | 
						|
		Client:   client,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type prefixClient struct {
 | 
						|
	Prefixes []string
 | 
						|
	Client   Client
 | 
						|
}
 | 
						|
 | 
						|
func (p *prefixClient) BumpAvg(key string, val float64) {
 | 
						|
	for _, prefix := range p.Prefixes {
 | 
						|
		p.Client.BumpAvg(prefix+key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *prefixClient) BumpSum(key string, val float64) {
 | 
						|
	for _, prefix := range p.Prefixes {
 | 
						|
		p.Client.BumpSum(prefix+key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *prefixClient) BumpHistogram(key string, val float64) {
 | 
						|
	for _, prefix := range p.Prefixes {
 | 
						|
		p.Client.BumpHistogram(prefix+key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *prefixClient) BumpTime(key string) interface {
 | 
						|
	End()
 | 
						|
} {
 | 
						|
	var m multiEnder
 | 
						|
	for _, prefix := range p.Prefixes {
 | 
						|
		m = append(m, p.Client.BumpTime(prefix+key))
 | 
						|
	}
 | 
						|
	return m
 | 
						|
}
 | 
						|
 | 
						|
// multiEnder combines many enders together.
 | 
						|
type multiEnder []interface {
 | 
						|
	End()
 | 
						|
}
 | 
						|
 | 
						|
func (m multiEnder) End() {
 | 
						|
	for _, e := range m {
 | 
						|
		e.End()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// HookClient is useful for testing. It provides optional hooks for each
 | 
						|
// expected method in the interface, which if provided will be called. If a
 | 
						|
// hook is not provided, it will be ignored.
 | 
						|
type HookClient struct {
 | 
						|
	BumpAvgHook       func(key string, val float64)
 | 
						|
	BumpSumHook       func(key string, val float64)
 | 
						|
	BumpHistogramHook func(key string, val float64)
 | 
						|
	BumpTimeHook      func(key string) interface {
 | 
						|
		End()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpAvg will call BumpAvgHook if defined.
 | 
						|
func (c *HookClient) BumpAvg(key string, val float64) {
 | 
						|
	if c.BumpAvgHook != nil {
 | 
						|
		c.BumpAvgHook(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpSum will call BumpSumHook if defined.
 | 
						|
func (c *HookClient) BumpSum(key string, val float64) {
 | 
						|
	if c.BumpSumHook != nil {
 | 
						|
		c.BumpSumHook(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpHistogram will call BumpHistogramHook if defined.
 | 
						|
func (c *HookClient) BumpHistogram(key string, val float64) {
 | 
						|
	if c.BumpHistogramHook != nil {
 | 
						|
		c.BumpHistogramHook(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpTime will call BumpTimeHook if defined.
 | 
						|
func (c *HookClient) BumpTime(key string) interface {
 | 
						|
	End()
 | 
						|
} {
 | 
						|
	if c.BumpTimeHook != nil {
 | 
						|
		return c.BumpTimeHook(key)
 | 
						|
	}
 | 
						|
	return NoOpEnd
 | 
						|
}
 | 
						|
 | 
						|
type noOpEnd struct{}
 | 
						|
 | 
						|
func (n noOpEnd) End() {}
 | 
						|
 | 
						|
// NoOpEnd provides a dummy value for use in tests as valid return value for
 | 
						|
// BumpTime().
 | 
						|
var NoOpEnd = noOpEnd{}
 | 
						|
 | 
						|
// BumpAvg calls BumpAvg on the Client if it isn't nil. This is useful when a
 | 
						|
// component has an optional stats.Client.
 | 
						|
func BumpAvg(c Client, key string, val float64) {
 | 
						|
	if c != nil {
 | 
						|
		c.BumpAvg(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpSum calls BumpSum on the Client if it isn't nil. This is useful when a
 | 
						|
// component has an optional stats.Client.
 | 
						|
func BumpSum(c Client, key string, val float64) {
 | 
						|
	if c != nil {
 | 
						|
		c.BumpSum(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpHistogram calls BumpHistogram on the Client if it isn't nil. This is
 | 
						|
// useful when a component has an optional stats.Client.
 | 
						|
func BumpHistogram(c Client, key string, val float64) {
 | 
						|
	if c != nil {
 | 
						|
		c.BumpHistogram(key, val)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// BumpTime calls BumpTime on the Client if it isn't nil. If the Client is nil
 | 
						|
// it still returns a valid return value which will be a no-op. This is useful
 | 
						|
// when a component has an optional stats.Client.
 | 
						|
func BumpTime(c Client, key string) interface {
 | 
						|
	End()
 | 
						|
} {
 | 
						|
	if c != nil {
 | 
						|
		return c.BumpTime(key)
 | 
						|
	}
 | 
						|
	return NoOpEnd
 | 
						|
}
 |