You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stats.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Package stats defines a lightweight interface for collecting statistics. It
  2. // doesn't provide an implementation, just the shared interface.
  3. package stats
  4. // Client provides methods to collection statistics.
  5. type Client interface {
  6. // BumpAvg bumps the average for the given key.
  7. BumpAvg(key string, val float64)
  8. // BumpSum bumps the sum for the given key.
  9. BumpSum(key string, val float64)
  10. // BumpHistogram bumps the histogram for the given key.
  11. BumpHistogram(key string, val float64)
  12. // BumpTime is a special version of BumpHistogram which is specialized for
  13. // timers. Calling it starts the timer, and it returns a value on which End()
  14. // can be called to indicate finishing the timer. A convenient way of
  15. // recording the duration of a function is calling it like such at the top of
  16. // the function:
  17. //
  18. // defer s.BumpTime("my.function").End()
  19. BumpTime(key string) interface {
  20. End()
  21. }
  22. }
  23. // PrefixClient adds multiple keys for the same value, with each prefix
  24. // added to the key and calls the underlying client.
  25. func PrefixClient(prefixes []string, client Client) Client {
  26. return &prefixClient{
  27. Prefixes: prefixes,
  28. Client: client,
  29. }
  30. }
  31. type prefixClient struct {
  32. Prefixes []string
  33. Client Client
  34. }
  35. func (p *prefixClient) BumpAvg(key string, val float64) {
  36. for _, prefix := range p.Prefixes {
  37. p.Client.BumpAvg(prefix+key, val)
  38. }
  39. }
  40. func (p *prefixClient) BumpSum(key string, val float64) {
  41. for _, prefix := range p.Prefixes {
  42. p.Client.BumpSum(prefix+key, val)
  43. }
  44. }
  45. func (p *prefixClient) BumpHistogram(key string, val float64) {
  46. for _, prefix := range p.Prefixes {
  47. p.Client.BumpHistogram(prefix+key, val)
  48. }
  49. }
  50. func (p *prefixClient) BumpTime(key string) interface {
  51. End()
  52. } {
  53. var m multiEnder
  54. for _, prefix := range p.Prefixes {
  55. m = append(m, p.Client.BumpTime(prefix+key))
  56. }
  57. return m
  58. }
  59. // multiEnder combines many enders together.
  60. type multiEnder []interface {
  61. End()
  62. }
  63. func (m multiEnder) End() {
  64. for _, e := range m {
  65. e.End()
  66. }
  67. }
  68. // HookClient is useful for testing. It provides optional hooks for each
  69. // expected method in the interface, which if provided will be called. If a
  70. // hook is not provided, it will be ignored.
  71. type HookClient struct {
  72. BumpAvgHook func(key string, val float64)
  73. BumpSumHook func(key string, val float64)
  74. BumpHistogramHook func(key string, val float64)
  75. BumpTimeHook func(key string) interface {
  76. End()
  77. }
  78. }
  79. // BumpAvg will call BumpAvgHook if defined.
  80. func (c *HookClient) BumpAvg(key string, val float64) {
  81. if c.BumpAvgHook != nil {
  82. c.BumpAvgHook(key, val)
  83. }
  84. }
  85. // BumpSum will call BumpSumHook if defined.
  86. func (c *HookClient) BumpSum(key string, val float64) {
  87. if c.BumpSumHook != nil {
  88. c.BumpSumHook(key, val)
  89. }
  90. }
  91. // BumpHistogram will call BumpHistogramHook if defined.
  92. func (c *HookClient) BumpHistogram(key string, val float64) {
  93. if c.BumpHistogramHook != nil {
  94. c.BumpHistogramHook(key, val)
  95. }
  96. }
  97. // BumpTime will call BumpTimeHook if defined.
  98. func (c *HookClient) BumpTime(key string) interface {
  99. End()
  100. } {
  101. if c.BumpTimeHook != nil {
  102. return c.BumpTimeHook(key)
  103. }
  104. return NoOpEnd
  105. }
  106. type noOpEnd struct{}
  107. func (n noOpEnd) End() {}
  108. // NoOpEnd provides a dummy value for use in tests as valid return value for
  109. // BumpTime().
  110. var NoOpEnd = noOpEnd{}
  111. // BumpAvg calls BumpAvg on the Client if it isn't nil. This is useful when a
  112. // component has an optional stats.Client.
  113. func BumpAvg(c Client, key string, val float64) {
  114. if c != nil {
  115. c.BumpAvg(key, val)
  116. }
  117. }
  118. // BumpSum calls BumpSum on the Client if it isn't nil. This is useful when a
  119. // component has an optional stats.Client.
  120. func BumpSum(c Client, key string, val float64) {
  121. if c != nil {
  122. c.BumpSum(key, val)
  123. }
  124. }
  125. // BumpHistogram calls BumpHistogram on the Client if it isn't nil. This is
  126. // useful when a component has an optional stats.Client.
  127. func BumpHistogram(c Client, key string, val float64) {
  128. if c != nil {
  129. c.BumpHistogram(key, val)
  130. }
  131. }
  132. // BumpTime calls BumpTime on the Client if it isn't nil. If the Client is nil
  133. // it still returns a valid return value which will be a no-op. This is useful
  134. // when a component has an optional stats.Client.
  135. func BumpTime(c Client, key string) interface {
  136. End()
  137. } {
  138. if c != nil {
  139. return c.BumpTime(key)
  140. }
  141. return NoOpEnd
  142. }