選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

281 行
8.0 KiB

  1. // Copyright 2018, OpenCensus Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package metric
  15. import (
  16. "math"
  17. "sync"
  18. "sync/atomic"
  19. "time"
  20. "go.opencensus.io/internal/tagencoding"
  21. "go.opencensus.io/metric/metricdata"
  22. )
  23. // gauge represents a quantity that can go up an down, for example queue depth
  24. // or number of outstanding requests.
  25. //
  26. // gauge maintains a value for each combination of of label values passed to
  27. // the Set or Add methods.
  28. //
  29. // gauge should not be used directly, use Float64Gauge or Int64Gauge.
  30. type gauge struct {
  31. vals sync.Map
  32. desc metricdata.Descriptor
  33. start time.Time
  34. keys []string
  35. gType gaugeType
  36. }
  37. type gaugeEntry interface {
  38. read(t time.Time) metricdata.Point
  39. }
  40. // Read returns the current values of the gauge as a metric for export.
  41. func (g *gauge) read() *metricdata.Metric {
  42. now := time.Now()
  43. m := &metricdata.Metric{
  44. Descriptor: g.desc,
  45. }
  46. g.vals.Range(func(k, v interface{}) bool {
  47. entry := v.(gaugeEntry)
  48. key := k.(string)
  49. labelVals := g.labelValues(key)
  50. m.TimeSeries = append(m.TimeSeries, &metricdata.TimeSeries{
  51. StartTime: now, // Gauge value is instantaneous.
  52. LabelValues: labelVals,
  53. Points: []metricdata.Point{
  54. entry.read(now),
  55. },
  56. })
  57. return true
  58. })
  59. return m
  60. }
  61. func (g *gauge) mapKey(labelVals []metricdata.LabelValue) string {
  62. vb := &tagencoding.Values{}
  63. for _, v := range labelVals {
  64. b := make([]byte, 1, len(v.Value)+1)
  65. if v.Present {
  66. b[0] = 1
  67. b = append(b, []byte(v.Value)...)
  68. }
  69. vb.WriteValue(b)
  70. }
  71. return string(vb.Bytes())
  72. }
  73. func (g *gauge) labelValues(s string) []metricdata.LabelValue {
  74. vals := make([]metricdata.LabelValue, 0, len(g.keys))
  75. vb := &tagencoding.Values{Buffer: []byte(s)}
  76. for range g.keys {
  77. v := vb.ReadValue()
  78. if v[0] == 0 {
  79. vals = append(vals, metricdata.LabelValue{})
  80. } else {
  81. vals = append(vals, metricdata.NewLabelValue(string(v[1:])))
  82. }
  83. }
  84. return vals
  85. }
  86. func (g *gauge) entryForValues(labelVals []metricdata.LabelValue, newEntry func() gaugeEntry) (interface{}, error) {
  87. if len(labelVals) != len(g.keys) {
  88. return nil, errKeyValueMismatch
  89. }
  90. mapKey := g.mapKey(labelVals)
  91. if entry, ok := g.vals.Load(mapKey); ok {
  92. return entry, nil
  93. }
  94. entry, _ := g.vals.LoadOrStore(mapKey, newEntry())
  95. return entry, nil
  96. }
  97. func (g *gauge) upsertEntry(labelVals []metricdata.LabelValue, newEntry func() gaugeEntry) error {
  98. if len(labelVals) != len(g.keys) {
  99. return errKeyValueMismatch
  100. }
  101. mapKey := g.mapKey(labelVals)
  102. g.vals.Delete(mapKey)
  103. g.vals.Store(mapKey, newEntry())
  104. return nil
  105. }
  106. // Float64Gauge represents a float64 value that can go up and down.
  107. //
  108. // Float64Gauge maintains a float64 value for each combination of of label values
  109. // passed to the Set or Add methods.
  110. type Float64Gauge struct {
  111. g gauge
  112. }
  113. // Float64Entry represents a single value of the gauge corresponding to a set
  114. // of label values.
  115. type Float64Entry struct {
  116. val uint64 // needs to be uint64 for atomic access, interpret with math.Float64frombits
  117. }
  118. func (e *Float64Entry) read(t time.Time) metricdata.Point {
  119. v := math.Float64frombits(atomic.LoadUint64(&e.val))
  120. if v < 0 {
  121. v = 0
  122. }
  123. return metricdata.NewFloat64Point(t, v)
  124. }
  125. // GetEntry returns a gauge entry where each key for this gauge has the value
  126. // given.
  127. //
  128. // The number of label values supplied must be exactly the same as the number
  129. // of keys supplied when this gauge was created.
  130. func (g *Float64Gauge) GetEntry(labelVals ...metricdata.LabelValue) (*Float64Entry, error) {
  131. entry, err := g.g.entryForValues(labelVals, func() gaugeEntry {
  132. return &Float64Entry{}
  133. })
  134. if err != nil {
  135. return nil, err
  136. }
  137. return entry.(*Float64Entry), nil
  138. }
  139. // Set sets the gauge entry value to val.
  140. func (e *Float64Entry) Set(val float64) {
  141. atomic.StoreUint64(&e.val, math.Float64bits(val))
  142. }
  143. // Add increments the gauge entry value by val.
  144. func (e *Float64Entry) Add(val float64) {
  145. var swapped bool
  146. for !swapped {
  147. oldVal := atomic.LoadUint64(&e.val)
  148. newVal := math.Float64bits(math.Float64frombits(oldVal) + val)
  149. swapped = atomic.CompareAndSwapUint64(&e.val, oldVal, newVal)
  150. }
  151. }
  152. // Int64Gauge represents a int64 gauge value that can go up and down.
  153. //
  154. // Int64Gauge maintains an int64 value for each combination of label values passed to the
  155. // Set or Add methods.
  156. type Int64Gauge struct {
  157. g gauge
  158. }
  159. // Int64GaugeEntry represents a single value of the gauge corresponding to a set
  160. // of label values.
  161. type Int64GaugeEntry struct {
  162. val int64
  163. }
  164. func (e *Int64GaugeEntry) read(t time.Time) metricdata.Point {
  165. v := atomic.LoadInt64(&e.val)
  166. if v < 0 {
  167. v = 0.0
  168. }
  169. return metricdata.NewInt64Point(t, v)
  170. }
  171. // GetEntry returns a gauge entry where each key for this gauge has the value
  172. // given.
  173. //
  174. // The number of label values supplied must be exactly the same as the number
  175. // of keys supplied when this gauge was created.
  176. func (g *Int64Gauge) GetEntry(labelVals ...metricdata.LabelValue) (*Int64GaugeEntry, error) {
  177. entry, err := g.g.entryForValues(labelVals, func() gaugeEntry {
  178. return &Int64GaugeEntry{}
  179. })
  180. if err != nil {
  181. return nil, err
  182. }
  183. return entry.(*Int64GaugeEntry), nil
  184. }
  185. // Set sets the value of the gauge entry to the provided value.
  186. func (e *Int64GaugeEntry) Set(val int64) {
  187. atomic.StoreInt64(&e.val, val)
  188. }
  189. // Add increments the current gauge entry value by val, which may be negative.
  190. func (e *Int64GaugeEntry) Add(val int64) {
  191. atomic.AddInt64(&e.val, val)
  192. }
  193. // Int64DerivedGauge represents int64 gauge value that is derived from an object.
  194. //
  195. // Int64DerivedGauge maintains objects for each combination of label values.
  196. // These objects implement Int64DerivedGaugeInterface to read instantaneous value
  197. // representing the object.
  198. type Int64DerivedGauge struct {
  199. g gauge
  200. }
  201. type int64DerivedGaugeEntry struct {
  202. fn func() int64
  203. }
  204. func (e *int64DerivedGaugeEntry) read(t time.Time) metricdata.Point {
  205. return metricdata.NewInt64Point(t, e.fn())
  206. }
  207. // UpsertEntry inserts or updates a derived gauge entry for the given set of label values.
  208. // The object for which this gauge entry is inserted or updated, must implement func() int64
  209. //
  210. // It returns an error if
  211. // 1. The number of label values supplied are not the same as the number
  212. // of keys supplied when this gauge was created.
  213. // 2. fn func() int64 is nil.
  214. func (g *Int64DerivedGauge) UpsertEntry(fn func() int64, labelVals ...metricdata.LabelValue) error {
  215. if fn == nil {
  216. return errInvalidParam
  217. }
  218. return g.g.upsertEntry(labelVals, func() gaugeEntry {
  219. return &int64DerivedGaugeEntry{fn}
  220. })
  221. }
  222. // Float64DerivedGauge represents float64 gauge value that is derived from an object.
  223. //
  224. // Float64DerivedGauge maintains objects for each combination of label values.
  225. // These objects implement Float64DerivedGaugeInterface to read instantaneous value
  226. // representing the object.
  227. type Float64DerivedGauge struct {
  228. g gauge
  229. }
  230. type float64DerivedGaugeEntry struct {
  231. fn func() float64
  232. }
  233. func (e *float64DerivedGaugeEntry) read(t time.Time) metricdata.Point {
  234. return metricdata.NewFloat64Point(t, e.fn())
  235. }
  236. // UpsertEntry inserts or updates a derived gauge entry for the given set of label values.
  237. // The object for which this gauge entry is inserted or updated, must implement func() float64
  238. //
  239. // It returns an error if
  240. // 1. The number of label values supplied are not the same as the number
  241. // of keys supplied when this gauge was created.
  242. // 2. fn func() float64 is nil.
  243. func (g *Float64DerivedGauge) UpsertEntry(fn func() float64, labelVals ...metricdata.LabelValue) error {
  244. if fn == nil {
  245. return errInvalidParam
  246. }
  247. return g.g.upsertEntry(labelVals, func() gaugeEntry {
  248. return &float64DerivedGaugeEntry{fn}
  249. })
  250. }