go.temporal.io/server@v1.23.0/common/metrics/tally_metrics_handler.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package metrics 26 27 import ( 28 "time" 29 30 "github.com/uber-go/tally/v4" 31 32 "go.temporal.io/server/common/log" 33 ) 34 35 var sanitizer = tally.NewSanitizer(tally.SanitizeOptions{ 36 NameCharacters: tally.ValidCharacters{Ranges: tally.AlphanumericRange, Characters: tally.UnderscoreCharacters}, 37 KeyCharacters: tally.ValidCharacters{Ranges: tally.AlphanumericRange, Characters: tally.UnderscoreCharacters}, 38 ValueCharacters: tally.ValidCharacters{Ranges: tally.AlphanumericRange, Characters: tally.UnderscoreCharacters}, 39 ReplacementCharacter: '_', 40 }) 41 42 type ( 43 excludeTags map[string]map[string]struct{} 44 45 tallyMetricsHandler struct { 46 scope tally.Scope 47 perUnitBuckets map[MetricUnit]tally.Buckets 48 excludeTags excludeTags 49 } 50 ) 51 52 var _ Handler = (*tallyMetricsHandler)(nil) 53 54 func NewTallyMetricsHandler(cfg ClientConfig, scope tally.Scope) *tallyMetricsHandler { 55 perUnitBuckets := make(map[MetricUnit]tally.Buckets) 56 57 for unit, boundariesList := range cfg.PerUnitHistogramBoundaries { 58 perUnitBuckets[MetricUnit(unit)] = tally.ValueBuckets(boundariesList) 59 } 60 61 return &tallyMetricsHandler{ 62 scope: scope, 63 perUnitBuckets: perUnitBuckets, 64 excludeTags: configExcludeTags(cfg), 65 } 66 } 67 68 // WithTags creates a new MetricProvder with provided []Tag 69 // Tags are merged with registered Tags from the source MetricsHandler 70 func (tmp *tallyMetricsHandler) WithTags(tags ...Tag) Handler { 71 return &tallyMetricsHandler{ 72 scope: tmp.scope.Tagged(tagsToMap(tags, tmp.excludeTags)), 73 perUnitBuckets: tmp.perUnitBuckets, 74 excludeTags: tmp.excludeTags, 75 } 76 } 77 78 // Counter obtains a counter for the given name. 79 func (tmp *tallyMetricsHandler) Counter(counter string) CounterIface { 80 return CounterFunc(func(i int64, t ...Tag) { 81 scope := tmp.scope 82 if len(t) > 0 { 83 scope = tmp.scope.Tagged(tagsToMap(t, tmp.excludeTags)) 84 } 85 scope.Counter(counter).Inc(i) 86 }) 87 } 88 89 // Gauge obtains a gauge for the given name. 90 func (tmp *tallyMetricsHandler) Gauge(gauge string) GaugeIface { 91 return GaugeFunc(func(f float64, t ...Tag) { 92 scope := tmp.scope 93 if len(t) > 0 { 94 scope = tmp.scope.Tagged(tagsToMap(t, tmp.excludeTags)) 95 } 96 scope.Gauge(gauge).Update(f) 97 }) 98 } 99 100 // Timer obtains a timer for the given name. 101 func (tmp *tallyMetricsHandler) Timer(timer string) TimerIface { 102 return TimerFunc(func(d time.Duration, t ...Tag) { 103 scope := tmp.scope 104 if len(t) > 0 { 105 scope = tmp.scope.Tagged(tagsToMap(t, tmp.excludeTags)) 106 } 107 scope.Timer(timer).Record(d) 108 }) 109 } 110 111 // Histogram obtains a histogram for the given name. 112 func (tmp *tallyMetricsHandler) Histogram(histogram string, unit MetricUnit) HistogramIface { 113 return HistogramFunc(func(i int64, t ...Tag) { 114 scope := tmp.scope 115 if len(t) > 0 { 116 scope = tmp.scope.Tagged(tagsToMap(t, tmp.excludeTags)) 117 } 118 scope.Histogram(histogram, tmp.perUnitBuckets[unit]).RecordValue(float64(i)) 119 }) 120 } 121 122 func (*tallyMetricsHandler) Stop(log.Logger) {} 123 124 func tagsToMap(t1 []Tag, e excludeTags) map[string]string { 125 if len(t1) == 0 { 126 return nil 127 } 128 129 m := make(map[string]string, len(t1)) 130 131 convert := func(tag Tag) { 132 if vals, ok := e[tag.Key()]; ok { 133 if _, ok := vals[tag.Value()]; !ok { 134 m[tag.Key()] = tagExcludedValue 135 return 136 } 137 } 138 139 m[tag.Key()] = tag.Value() 140 } 141 142 for i := range t1 { 143 convert(t1[i]) 144 } 145 146 return m 147 }