You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.7 KiB
150 lines
4.7 KiB
8 months ago
|
// Copyright (c) 2023 The Jaeger Authors.
|
||
|
// Copyright (c) 2017 Uber Technologies, Inc.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package rpcmetrics
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"go.opentelemetry.io/otel/attribute"
|
||
|
"go.opentelemetry.io/otel/codes"
|
||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||
|
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||
|
"go.opentelemetry.io/otel/trace"
|
||
|
|
||
|
u "github.com/jaegertracing/jaeger/internal/metricstest"
|
||
|
)
|
||
|
|
||
|
type testTracer struct {
|
||
|
metrics *u.Factory
|
||
|
tracer trace.Tracer
|
||
|
}
|
||
|
|
||
|
func withTestTracer(runTest func(tt *testTracer)) {
|
||
|
metrics := u.NewFactory(time.Minute)
|
||
|
defer metrics.Stop()
|
||
|
observer := NewObserver(metrics, DefaultNameNormalizer)
|
||
|
|
||
|
tp := sdktrace.NewTracerProvider(
|
||
|
sdktrace.WithSpanProcessor(observer),
|
||
|
sdktrace.WithResource(resource.NewWithAttributes(
|
||
|
semconv.SchemaURL,
|
||
|
semconv.ServiceNameKey.String("test"),
|
||
|
)),
|
||
|
)
|
||
|
runTest(&testTracer{
|
||
|
metrics: metrics,
|
||
|
tracer: tp.Tracer("test"),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestObserver(t *testing.T) {
|
||
|
withTestTracer(func(testTracer *testTracer) {
|
||
|
ts := time.Now()
|
||
|
finishOptions := trace.WithTimestamp(ts.Add((50 * time.Millisecond)))
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
spanKind trace.SpanKind
|
||
|
opNameOverride string
|
||
|
err bool
|
||
|
}{
|
||
|
{name: "local-span", spanKind: trace.SpanKindInternal},
|
||
|
{name: "get-user", spanKind: trace.SpanKindServer},
|
||
|
{name: "get-user", spanKind: trace.SpanKindServer, opNameOverride: "get-user-override"},
|
||
|
{name: "get-user", spanKind: trace.SpanKindServer, err: true},
|
||
|
{name: "get-user-client", spanKind: trace.SpanKindClient},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
_, span := testTracer.tracer.Start(
|
||
|
context.Background(),
|
||
|
testCase.name, trace.WithSpanKind(testCase.spanKind),
|
||
|
trace.WithTimestamp(ts),
|
||
|
)
|
||
|
if testCase.opNameOverride != "" {
|
||
|
span.SetName(testCase.opNameOverride)
|
||
|
}
|
||
|
if testCase.err {
|
||
|
span.SetStatus(codes.Error, "An error occurred")
|
||
|
}
|
||
|
span.End(finishOptions)
|
||
|
}
|
||
|
|
||
|
testTracer.metrics.AssertCounterMetrics(t,
|
||
|
u.ExpectedMetric{Name: "requests", Tags: endpointTags("local_span", "error", "false"), Value: 0},
|
||
|
u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user", "error", "false"), Value: 1},
|
||
|
u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user", "error", "true"), Value: 1},
|
||
|
u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user_override", "error", "false"), Value: 1},
|
||
|
u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user_client", "error", "false"), Value: 0},
|
||
|
)
|
||
|
// TODO something wrong with string generation, .P99 should not be appended to the tag
|
||
|
// as a result we cannot use u.AssertGaugeMetrics
|
||
|
_, g := testTracer.metrics.Snapshot()
|
||
|
assert.EqualValues(t, 51, g["request_latency|endpoint=get_user|error=false.P99"])
|
||
|
assert.EqualValues(t, 51, g["request_latency|endpoint=get_user|error=true.P99"])
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestTags(t *testing.T) {
|
||
|
type tagTestCase struct {
|
||
|
attr attribute.KeyValue
|
||
|
err bool
|
||
|
metrics []u.ExpectedMetric
|
||
|
}
|
||
|
testCases := []tagTestCase{
|
||
|
{err: false, metrics: []u.ExpectedMetric{
|
||
|
{Name: "requests", Value: 1, Tags: tags("error", "false")},
|
||
|
}},
|
||
|
{err: true, metrics: []u.ExpectedMetric{
|
||
|
{Name: "requests", Value: 1, Tags: tags("error", "true")},
|
||
|
}},
|
||
|
}
|
||
|
|
||
|
for i := 200; i <= 500; i += 100 {
|
||
|
testCases = append(testCases, tagTestCase{
|
||
|
attr: semconv.HTTPResponseStatusCode(i),
|
||
|
metrics: []u.ExpectedMetric{
|
||
|
{Name: "http_requests", Value: 1, Tags: tags("status_code", fmt.Sprintf("%dxx", i/100))},
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
for i := range testCase.metrics {
|
||
|
testCase.metrics[i].Tags["endpoint"] = "span"
|
||
|
}
|
||
|
t.Run(fmt.Sprintf("%s-%v", testCase.attr.Key, testCase.attr.Value), func(t *testing.T) {
|
||
|
withTestTracer(func(testTracer *testTracer) {
|
||
|
_, span := testTracer.tracer.Start(
|
||
|
context.Background(),
|
||
|
"span", trace.WithSpanKind(trace.SpanKindServer),
|
||
|
)
|
||
|
span.SetAttributes(testCase.attr)
|
||
|
if testCase.err {
|
||
|
span.SetStatus(codes.Error, "An error occurred")
|
||
|
}
|
||
|
span.End()
|
||
|
testTracer.metrics.AssertCounterMetrics(t, testCase.metrics...)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
}
|