github.com/uber-go/tally/v4@v4.1.17/m3/scope_test.go (about) 1 // Copyright (c) 2023 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package m3 22 23 import ( 24 "sync" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/require" 29 tally "github.com/uber-go/tally/v4" 30 ) 31 32 var commonTags = map[string]string{"env": "test"} 33 34 type doneFn func() 35 36 func newTestReporterScope( 37 t *testing.T, 38 addr string, 39 scopePrefix string, 40 scopeTags map[string]string, 41 ) (Reporter, tally.Scope, doneFn) { 42 r, err := NewReporter(Options{ 43 HostPorts: []string{addr}, 44 Service: "testService", 45 CommonTags: commonTags, 46 IncludeHost: includeHost, 47 MaxQueueSize: queueSize, 48 MaxPacketSizeBytes: maxPacketSize, 49 }) 50 require.NoError(t, err) 51 52 scope, closer := tally.NewRootScope(tally.ScopeOptions{ 53 Prefix: scopePrefix, 54 Tags: scopeTags, 55 CachedReporter: r, 56 OmitCardinalityMetrics: false, 57 }, shortInterval) 58 59 return r, scope, func() { 60 require.NoError(t, closer.Close()) 61 require.True(t, r.(*reporter).done.Load()) 62 } 63 } 64 65 // TestScope tests that scope works as expected 66 func TestScope(t *testing.T) { 67 var wg sync.WaitGroup 68 server := newFakeM3Server(t, &wg, true, Compact) 69 go server.Serve() 70 defer server.Close() 71 72 tags := map[string]string{"testTag": "TestValue", "testTag2": "TestValue2"} 73 74 _, scope, close := newTestReporterScope(t, server.Addr, "honk", tags) 75 wg.Add(1) 76 77 timer := scope.Timer("dazzle") 78 timer.Start().Stop() 79 close() 80 81 wg.Wait() 82 83 require.Equal(t, 1, len(server.Service.getBatches())) 84 require.NotNil(t, server.Service.getBatches()[0]) 85 86 emittedTimers := server.Service.getBatches()[0].GetMetrics() 87 require.Equal(t, internalMetrics+cardinalityMetrics+1, len(emittedTimers)) 88 require.Equal(t, "honk.dazzle", emittedTimers[0].GetName()) 89 } 90 91 // TestScopeCounter tests that scope works as expected 92 func TestScopeCounter(t *testing.T) { 93 var wg sync.WaitGroup 94 server := newFakeM3Server(t, &wg, true, Compact) 95 go server.Serve() 96 defer server.Close() 97 98 tags := map[string]string{"testTag": "TestValue", "testTag2": "TestValue2"} 99 100 _, scope, close := newTestReporterScope(t, server.Addr, "honk", tags) 101 102 wg.Add(1) 103 counter := scope.Counter("foobar") 104 counter.Inc(42) 105 close() 106 wg.Wait() 107 108 require.Equal(t, 1, len(server.Service.getBatches())) 109 require.NotNil(t, server.Service.getBatches()[0]) 110 111 emittedMetrics := server.Service.getBatches()[0].GetMetrics() 112 require.Equal(t, internalMetrics+cardinalityMetrics+1, len(emittedMetrics)) 113 require.Equal(t, "honk.foobar", emittedMetrics[cardinalityMetrics].GetName()) 114 } 115 116 // TestScopeGauge tests that scope works as expected 117 func TestScopeGauge(t *testing.T) { 118 var wg sync.WaitGroup 119 server := newFakeM3Server(t, &wg, true, Compact) 120 go server.Serve() 121 defer server.Close() 122 123 tags := map[string]string{"testTag": "TestValue", "testTag2": "TestValue2"} 124 125 _, scope, close := newTestReporterScope(t, server.Addr, "honk", tags) 126 127 wg.Add(1) 128 gauge := scope.Gauge("foobaz") 129 gauge.Update(42) 130 close() 131 wg.Wait() 132 133 require.Equal(t, 1, len(server.Service.getBatches())) 134 require.NotNil(t, server.Service.getBatches()[0]) 135 136 emittedMetrics := server.Service.getBatches()[0].GetMetrics() 137 require.Equal(t, internalMetrics+cardinalityMetrics+1, len(emittedMetrics)) 138 require.Equal(t, "honk.foobaz", emittedMetrics[cardinalityMetrics].GetName()) 139 } 140 141 func BenchmarkScopeReportTimer(b *testing.B) { 142 backend, err := NewReporter(Options{ 143 HostPorts: []string{"127.0.0.1:4444"}, 144 Service: "my-service", 145 MaxQueueSize: 10000, 146 MaxPacketSizeBytes: maxPacketSize, 147 }) 148 if err != nil { 149 b.Error(err.Error()) 150 return 151 } 152 153 scope, closer := tally.NewRootScope(tally.ScopeOptions{ 154 Prefix: "bench", 155 CachedReporter: backend, 156 }, 1*time.Second) 157 158 perEndpointScope := scope.Tagged( 159 map[string]string{ 160 "endpointid": "health", 161 "handlerid": "health", 162 }, 163 ) 164 timer := perEndpointScope.Timer("inbound.latency") 165 b.ResetTimer() 166 167 b.RunParallel(func(pb *testing.PB) { 168 for pb.Next() { 169 timer.Record(500) 170 } 171 }) 172 173 b.StopTimer() 174 closer.Close() 175 b.StartTimer() 176 } 177 178 func BenchmarkScopeReportHistogram(b *testing.B) { 179 backend, err := NewReporter(Options{ 180 HostPorts: []string{"127.0.0.1:4444"}, 181 Service: "my-service", 182 MaxQueueSize: 10000, 183 MaxPacketSizeBytes: maxPacketSize, 184 Env: "test", 185 }) 186 if err != nil { 187 b.Error(err.Error()) 188 return 189 } 190 191 scope, closer := tally.NewRootScope(tally.ScopeOptions{ 192 Prefix: "bench", 193 CachedReporter: backend, 194 }, 1*time.Second) 195 196 perEndpointScope := scope.Tagged( 197 map[string]string{ 198 "endpointid": "health", 199 "handlerid": "health", 200 }, 201 ) 202 buckets := tally.DurationBuckets{ 203 0 * time.Millisecond, 204 10 * time.Millisecond, 205 25 * time.Millisecond, 206 50 * time.Millisecond, 207 75 * time.Millisecond, 208 100 * time.Millisecond, 209 200 * time.Millisecond, 210 300 * time.Millisecond, 211 400 * time.Millisecond, 212 500 * time.Millisecond, 213 600 * time.Millisecond, 214 800 * time.Millisecond, 215 1 * time.Second, 216 2 * time.Second, 217 5 * time.Second, 218 } 219 220 histogram := perEndpointScope.Histogram("inbound.latency", buckets) 221 b.ReportAllocs() 222 b.ResetTimer() 223 224 bucketsLen := len(buckets) 225 for i := 0; i < b.N; i++ { 226 histogram.RecordDuration(buckets[i%bucketsLen]) 227 } 228 229 b.StopTimer() 230 closer.Close() 231 }