registry.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package mock
  2. import (
  3. "sync"
  4. "github.com/ydb-platform/ydb/library/go/core/metrics"
  5. "github.com/ydb-platform/ydb/library/go/core/metrics/internal/pkg/metricsutil"
  6. "github.com/ydb-platform/ydb/library/go/core/metrics/internal/pkg/registryutil"
  7. "go.uber.org/atomic"
  8. )
  9. var _ metrics.Registry = (*Registry)(nil)
  10. type Registry struct {
  11. separator string
  12. prefix string
  13. tags map[string]string
  14. allowLoadRegisteredMetrics bool
  15. subregistries map[string]*Registry
  16. m *sync.Mutex
  17. metrics *sync.Map
  18. }
  19. func NewRegistry(opts *RegistryOpts) *Registry {
  20. r := &Registry{
  21. separator: ".",
  22. subregistries: make(map[string]*Registry),
  23. m: new(sync.Mutex),
  24. metrics: new(sync.Map),
  25. }
  26. if opts != nil {
  27. r.separator = string(opts.Separator)
  28. r.prefix = opts.Prefix
  29. r.tags = opts.Tags
  30. r.allowLoadRegisteredMetrics = opts.AllowLoadRegisteredMetrics
  31. }
  32. return r
  33. }
  34. // WithTags creates new sub-scope, where each metric has tags attached to it.
  35. func (r Registry) WithTags(tags map[string]string) metrics.Registry {
  36. return r.newSubregistry(r.prefix, registryutil.MergeTags(r.tags, tags))
  37. }
  38. // WithPrefix creates new sub-scope, where each metric has prefix added to it name.
  39. func (r Registry) WithPrefix(prefix string) metrics.Registry {
  40. return r.newSubregistry(registryutil.BuildFQName(r.separator, r.prefix, prefix), r.tags)
  41. }
  42. func (r Registry) ComposeName(parts ...string) string {
  43. return registryutil.BuildFQName(r.separator, parts...)
  44. }
  45. func (r Registry) Counter(name string) metrics.Counter {
  46. s := &Counter{
  47. Name: r.newMetricName(name),
  48. Tags: r.tags,
  49. Value: new(atomic.Int64),
  50. }
  51. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  52. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  53. if r.allowLoadRegisteredMetrics {
  54. return val.(*Counter)
  55. }
  56. panic("metric with key " + key + " already registered")
  57. }
  58. return s
  59. }
  60. func (r Registry) FuncCounter(name string, function func() int64) metrics.FuncCounter {
  61. metricName := r.newMetricName(name)
  62. key := registryutil.BuildRegistryKey(metricName, r.tags)
  63. s := FuncCounter{function: function}
  64. if _, loaded := r.metrics.LoadOrStore(key, s); loaded {
  65. panic("metric with key " + key + " already registered")
  66. }
  67. return s
  68. }
  69. func (r Registry) Gauge(name string) metrics.Gauge {
  70. s := &Gauge{
  71. Name: r.newMetricName(name),
  72. Tags: r.tags,
  73. Value: new(atomic.Float64),
  74. }
  75. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  76. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  77. if r.allowLoadRegisteredMetrics {
  78. return val.(*Gauge)
  79. }
  80. panic("metric with key " + key + " already registered")
  81. }
  82. return s
  83. }
  84. func (r Registry) FuncGauge(name string, function func() float64) metrics.FuncGauge {
  85. metricName := r.newMetricName(name)
  86. key := registryutil.BuildRegistryKey(metricName, r.tags)
  87. s := FuncGauge{function: function}
  88. if _, loaded := r.metrics.LoadOrStore(key, s); loaded {
  89. panic("metric with key " + key + " already registered")
  90. }
  91. return s
  92. }
  93. func (r *Registry) IntGauge(name string) metrics.IntGauge {
  94. s := &IntGauge{
  95. Name: r.newMetricName(name),
  96. Tags: r.tags,
  97. Value: new(atomic.Int64),
  98. }
  99. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  100. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  101. if r.allowLoadRegisteredMetrics {
  102. return val.(*IntGauge)
  103. }
  104. panic("metric with key " + key + " already registered")
  105. }
  106. return s
  107. }
  108. func (r *Registry) FuncIntGauge(name string, function func() int64) metrics.FuncIntGauge {
  109. metricName := r.newMetricName(name)
  110. key := registryutil.BuildRegistryKey(metricName, r.tags)
  111. s := FuncIntGauge{function: function}
  112. if _, loaded := r.metrics.LoadOrStore(key, s); loaded {
  113. panic("metric with key " + key + " already registered")
  114. }
  115. return s
  116. }
  117. func (r Registry) Timer(name string) metrics.Timer {
  118. s := &Timer{
  119. Name: r.newMetricName(name),
  120. Tags: r.tags,
  121. Value: new(atomic.Duration),
  122. }
  123. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  124. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  125. if r.allowLoadRegisteredMetrics {
  126. return val.(*Timer)
  127. }
  128. panic("metric with key " + key + " already registered")
  129. }
  130. return s
  131. }
  132. func (r Registry) Histogram(name string, buckets metrics.Buckets) metrics.Histogram {
  133. s := &Histogram{
  134. Name: r.newMetricName(name),
  135. Tags: r.tags,
  136. BucketBounds: metricsutil.BucketsBounds(buckets),
  137. BucketValues: make([]int64, buckets.Size()),
  138. InfValue: new(atomic.Int64),
  139. }
  140. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  141. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  142. if r.allowLoadRegisteredMetrics {
  143. return val.(*Histogram)
  144. }
  145. panic("metric with key " + key + " already registered")
  146. }
  147. return s
  148. }
  149. func (r Registry) DurationHistogram(name string, buckets metrics.DurationBuckets) metrics.Timer {
  150. s := &Histogram{
  151. Name: r.newMetricName(name),
  152. Tags: r.tags,
  153. BucketBounds: metricsutil.DurationBucketsBounds(buckets),
  154. BucketValues: make([]int64, buckets.Size()),
  155. InfValue: new(atomic.Int64),
  156. }
  157. key := registryutil.BuildRegistryKey(s.Name, r.tags)
  158. if val, loaded := r.metrics.LoadOrStore(key, s); loaded {
  159. if r.allowLoadRegisteredMetrics {
  160. return val.(*Histogram)
  161. }
  162. panic("metric with key " + key + " already registered")
  163. }
  164. return s
  165. }
  166. func (r *Registry) newSubregistry(prefix string, tags map[string]string) *Registry {
  167. registryKey := registryutil.BuildRegistryKey(prefix, tags)
  168. r.m.Lock()
  169. defer r.m.Unlock()
  170. if existing, ok := r.subregistries[registryKey]; ok {
  171. return existing
  172. }
  173. subregistry := &Registry{
  174. separator: r.separator,
  175. prefix: prefix,
  176. tags: tags,
  177. allowLoadRegisteredMetrics: r.allowLoadRegisteredMetrics,
  178. subregistries: r.subregistries,
  179. m: r.m,
  180. metrics: r.metrics,
  181. }
  182. r.subregistries[registryKey] = subregistry
  183. return subregistry
  184. }
  185. func (r *Registry) newMetricName(name string) string {
  186. return registryutil.BuildFQName(r.separator, r.prefix, name)
  187. }