mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 14:31:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			166 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			166 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
 | |
| }
 |