go.temporal.io/server@v1.23.0/common/metrics/config_test.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 "testing" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 "github.com/stretchr/testify/suite" 34 "github.com/uber-go/tally/v4" 35 "github.com/uber-go/tally/v4/m3" 36 37 "go.temporal.io/server/common/log" 38 ) 39 40 type MetricsSuite struct { 41 *require.Assertions 42 suite.Suite 43 controller *gomock.Controller 44 } 45 46 func TestMetricsSuite(t *testing.T) { 47 suite.Run(t, new(MetricsSuite)) 48 } 49 50 func (s *MetricsSuite) SetupTest() { 51 s.Assertions = require.New(s.T()) 52 s.controller = gomock.NewController(s.T()) 53 } 54 55 func (s *MetricsSuite) TestStatsd() { 56 statsd := &StatsdConfig{ 57 HostPort: "127.0.0.1:8125", 58 Prefix: "testStatsd", 59 } 60 61 config := new(Config) 62 config.Statsd = statsd 63 scope := NewScope(log.NewNoopLogger(), config) 64 s.NotNil(scope) 65 } 66 67 func (s *MetricsSuite) TestM3() { 68 m3 := &m3.Configuration{ 69 HostPort: "127.0.0.1:8125", 70 Service: "testM3", 71 Env: "devel", 72 } 73 config := new(Config) 74 config.M3 = m3 75 scope := NewScope(log.NewNoopLogger(), config) 76 s.NotNil(scope) 77 } 78 79 func (s *MetricsSuite) TestPrometheus() { 80 prom := &PrometheusConfig{ 81 OnError: "panic", 82 TimerType: "histogram", 83 ListenAddress: "127.0.0.1:0", 84 } 85 config := new(Config) 86 config.Prometheus = prom 87 scope := NewScope(log.NewNoopLogger(), config) 88 s.NotNil(scope) 89 } 90 91 func (s *MetricsSuite) TestPrometheusWithSanitizeOptions() { 92 validChars := &ValidCharacters{ 93 Ranges: []SanitizeRange{ 94 { 95 StartRange: "a", 96 EndRange: "z", 97 }, 98 { 99 StartRange: "A", 100 EndRange: "Z", 101 }, 102 { 103 StartRange: "0", 104 EndRange: "9", 105 }, 106 }, 107 SafeCharacters: "-", 108 } 109 110 prom := &PrometheusConfig{ 111 OnError: "panic", 112 TimerType: "histogram", 113 ListenAddress: "127.0.0.1:0", 114 SanitizeOptions: &SanitizeOptions{ 115 NameCharacters: validChars, 116 KeyCharacters: validChars, 117 ValueCharacters: validChars, 118 ReplacementCharacter: "_", 119 }, 120 } 121 config := new(Config) 122 config.Prometheus = prom 123 scope := NewScope(log.NewNoopLogger(), config) 124 s.NotNil(scope) 125 } 126 127 func (s *MetricsSuite) TestNoop() { 128 config := &Config{} 129 scope := NewScope(log.NewNoopLogger(), config) 130 s.Equal(tally.NoopScope, scope) 131 } 132 133 func (s *MetricsSuite) TestSetDefaultPerUnitHistogramBoundaries() { 134 type histogramTest struct { 135 input map[string][]float64 136 expectResult map[string][]float64 137 } 138 139 customizedBoundaries := map[string][]float64{ 140 Dimensionless: {1}, 141 Milliseconds: defaultPerUnitHistogramBoundaries[Milliseconds], 142 Bytes: defaultPerUnitHistogramBoundaries[Bytes], 143 } 144 testCases := []histogramTest{ 145 { 146 input: nil, 147 expectResult: defaultPerUnitHistogramBoundaries, 148 }, 149 { 150 input: map[string][]float64{ 151 UnitNameDimensionless: {1}, 152 "notDefine": {1}, 153 }, 154 expectResult: customizedBoundaries, 155 }, 156 } 157 158 for _, test := range testCases { 159 config := &ClientConfig{PerUnitHistogramBoundaries: test.input} 160 setDefaultPerUnitHistogramBoundaries(config) 161 s.Equal(test.expectResult, config.PerUnitHistogramBoundaries) 162 } 163 } 164 165 func TestMetricsHandlerFromConfig(t *testing.T) { 166 t.Parallel() 167 168 logger := log.NewTestLogger() 169 170 for _, c := range []struct { 171 name string 172 cfg *Config 173 expectedType interface{} 174 }{ 175 { 176 name: "nil config", 177 cfg: nil, 178 expectedType: &noopMetricsHandler{}, 179 }, 180 { 181 name: "tally", 182 cfg: &Config{ 183 Prometheus: &PrometheusConfig{ 184 Framework: FrameworkTally, 185 ListenAddress: "localhost:0", 186 }, 187 }, 188 expectedType: &tallyMetricsHandler{}, 189 }, 190 { 191 name: "opentelemetry", 192 cfg: &Config{ 193 Prometheus: &PrometheusConfig{ 194 Framework: FrameworkOpentelemetry, 195 ListenAddress: "localhost:0", 196 }, 197 }, 198 expectedType: &otelMetricsHandler{}, 199 }, 200 } { 201 c := c 202 t.Run(c.name, func(t *testing.T) { 203 t.Parallel() 204 205 handler, err := MetricsHandlerFromConfig(logger, c.cfg) 206 require.NoError(t, err) 207 t.Cleanup(func() { 208 handler.Stop(logger) 209 }) 210 assert.IsType(t, c.expectedType, handler) 211 }) 212 } 213 214 }