1// Copyright (c) 2017 Uber Technologies, Inc. 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 15package rpcmetrics 16 17import ( 18 "fmt" 19 "testing" 20 "time" 21 22 opentracing "github.com/opentracing/opentracing-go" 23 "github.com/stretchr/testify/assert" 24 u "github.com/uber/jaeger-lib/metrics/metricstest" 25 26 "github.com/opentracing/opentracing-go/ext" 27 jaeger "github.com/uber/jaeger-client-go" 28) 29 30func ExampleObserver() { 31 metricsFactory := u.NewFactory(0) 32 metricsObserver := NewObserver( 33 metricsFactory, 34 DefaultNameNormalizer, 35 ) 36 tracer, closer := jaeger.NewTracer( 37 "serviceName", 38 jaeger.NewConstSampler(true), 39 jaeger.NewInMemoryReporter(), 40 jaeger.TracerOptions.Observer(metricsObserver), 41 ) 42 defer closer.Close() 43 44 span := tracer.StartSpan("test", ext.SpanKindRPCServer) 45 span.Finish() 46 47 c, _ := metricsFactory.Snapshot() 48 fmt.Printf("requests (success): %d\n", c["requests|endpoint=test|error=false"]) 49 fmt.Printf("requests (failure): %d\n", c["requests|endpoint=test|error=true"]) 50 // Output: 51 // requests (success): 1 52 // requests (failure): 0 53} 54 55type testTracer struct { 56 metrics *u.Factory 57 tracer opentracing.Tracer 58} 59 60func withTestTracer(runTest func(tt *testTracer)) { 61 sampler := jaeger.NewConstSampler(true) 62 reporter := jaeger.NewInMemoryReporter() 63 metrics := u.NewFactory(time.Minute) 64 observer := NewObserver(metrics, DefaultNameNormalizer) 65 tracer, closer := jaeger.NewTracer( 66 "test", 67 sampler, 68 reporter, 69 jaeger.TracerOptions.Observer(observer)) 70 defer closer.Close() 71 runTest(&testTracer{ 72 metrics: metrics, 73 tracer: tracer, 74 }) 75} 76 77func TestObserver(t *testing.T) { 78 withTestTracer(func(testTracer *testTracer) { 79 ts := time.Now() 80 finishOptions := opentracing.FinishOptions{ 81 FinishTime: ts.Add(50 * time.Millisecond), 82 } 83 84 testCases := []struct { 85 name string 86 tag opentracing.Tag 87 opNameOverride string 88 err bool 89 }{ 90 {name: "local-span", tag: opentracing.Tag{Key: "x", Value: "y"}}, 91 {name: "get-user", tag: ext.SpanKindRPCServer}, 92 {name: "get-user", tag: ext.SpanKindRPCServer, opNameOverride: "get-user-override"}, 93 {name: "get-user", tag: ext.SpanKindRPCServer, err: true}, 94 {name: "get-user-client", tag: ext.SpanKindRPCClient}, 95 } 96 97 for _, testCase := range testCases { 98 span := testTracer.tracer.StartSpan( 99 testCase.name, 100 testCase.tag, 101 opentracing.StartTime(ts), 102 ) 103 if testCase.opNameOverride != "" { 104 span.SetOperationName(testCase.opNameOverride) 105 } 106 if testCase.err { 107 ext.Error.Set(span, true) 108 } 109 span.FinishWithOptions(finishOptions) 110 } 111 112 testTracer.metrics.AssertCounterMetrics(t, 113 u.ExpectedMetric{Name: "requests", Tags: endpointTags("local-span", "error", "false"), Value: 0}, 114 u.ExpectedMetric{Name: "requests", Tags: endpointTags("get-user", "error", "false"), Value: 1}, 115 u.ExpectedMetric{Name: "requests", Tags: endpointTags("get-user", "error", "true"), Value: 1}, 116 u.ExpectedMetric{Name: "requests", Tags: endpointTags("get-user-override", "error", "false"), Value: 1}, 117 u.ExpectedMetric{Name: "requests", Tags: endpointTags("get-user-client", "error", "false"), Value: 0}, 118 ) 119 // TODO something wrong with string generation, .P99 should not be appended to the tag 120 // as a result we cannot use u.AssertGaugeMetrics 121 _, g := testTracer.metrics.Snapshot() 122 assert.EqualValues(t, 51, g["request_latency|endpoint=get-user|error=false.P99"]) 123 assert.EqualValues(t, 51, g["request_latency|endpoint=get-user|error=true.P99"]) 124 }) 125} 126 127func TestTags(t *testing.T) { 128 type tagTestCase struct { 129 key string 130 value interface{} 131 metrics []u.ExpectedMetric 132 } 133 134 testCases := []tagTestCase{ 135 {key: "something", value: 42, metrics: []u.ExpectedMetric{ 136 {Name: "requests", Value: 1, Tags: tags("error", "false")}, 137 }}, 138 {key: "error", value: true, metrics: []u.ExpectedMetric{ 139 {Name: "requests", Value: 1, Tags: tags("error", "true")}, 140 }}, 141 {key: "error", value: "true", metrics: []u.ExpectedMetric{ 142 {Name: "requests", Value: 1, Tags: tags("error", "true")}, 143 }}, 144 } 145 146 for i := 2; i <= 5; i++ { 147 values := []interface{}{ 148 i * 100, 149 uint16(i * 100), 150 fmt.Sprintf("%d00", i), 151 } 152 for _, v := range values { 153 testCases = append(testCases, tagTestCase{ 154 key: "http.status_code", value: v, metrics: []u.ExpectedMetric{ 155 {Name: "http_requests", Value: 1, Tags: tags("status_code", fmt.Sprintf("%dxx", i))}, 156 }, 157 }) 158 } 159 } 160 161 for _, tc := range testCases { 162 testCase := tc // capture loop var 163 for i := range testCase.metrics { 164 testCase.metrics[i].Tags["endpoint"] = "span" 165 } 166 t.Run(fmt.Sprintf("%s-%v", testCase.key, testCase.value), func(t *testing.T) { 167 withTestTracer(func(testTracer *testTracer) { 168 span := testTracer.tracer.StartSpan("span", ext.SpanKindRPCServer) 169 span.SetTag(testCase.key, testCase.value) 170 span.Finish() 171 testTracer.metrics.AssertCounterMetrics(t, testCase.metrics...) 172 }) 173 }) 174 } 175} 176