-
Notifications
You must be signed in to change notification settings - Fork 18
/
tracer_client.go
110 lines (88 loc) · 3.14 KB
/
tracer_client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2022 CloudWeGo Authors.
//
// 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 tracing
import (
"context"
"time"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/pkg/rpcinfo"
"github.com/cloudwego/kitex/pkg/stats"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
oteltrace "go.opentelemetry.io/otel/trace"
)
var _ stats.Tracer = (*clientTracer)(nil)
type clientTracer struct {
config *config
histogramRecorder map[string]metric.Float64Histogram
}
func newClientOption(opts ...Option) (client.Option, *config) {
cfg := newConfig(opts)
ct := &clientTracer{config: cfg}
ct.createMeasures()
return client.WithTracer(ct), cfg
}
func (c *clientTracer) createMeasures() {
clientDurationMeasure, err := c.config.meter.Float64Histogram(ClientDuration)
handleErr(err)
c.histogramRecorder = map[string]metric.Float64Histogram{
ClientDuration: clientDurationMeasure,
}
}
func (c *clientTracer) Start(ctx context.Context) context.Context {
ri := rpcinfo.GetRPCInfo(ctx)
ctx, _ = c.config.tracer.Start(
ctx,
spanNaming(ri),
oteltrace.WithTimestamp(getStartTimeOrNow(ri)),
oteltrace.WithSpanKind(oteltrace.SpanKindClient),
)
return ctx
}
func (c *clientTracer) Finish(ctx context.Context) {
span := oteltrace.SpanFromContext(ctx)
if span == nil || !span.IsRecording() {
return
}
ri := rpcinfo.GetRPCInfo(ctx)
if ri.Stats().Level() == stats.LevelDisabled {
return
}
st := ri.Stats()
rpcStart := st.GetEvent(stats.RPCStart)
rpcFinish := st.GetEvent(stats.RPCFinish)
duration := rpcFinish.Time().Sub(rpcStart.Time())
elapsedTime := float64(duration) / float64(time.Millisecond)
attrs := []attribute.KeyValue{
RPCSystemKitex,
semconv.RPCMethodKey.String(ri.To().Method()),
semconv.RPCServiceKey.String(ri.To().ServiceName()),
RPCSystemKitexRecvSize.Int64(int64(st.RecvSize())),
RPCSystemKitexSendSize.Int64(int64(st.SendSize())),
RequestProtocolKey.String(ri.Config().TransportProtocol().String()),
}
// The source operation dimension maybe cause high cardinality issues
if c.config.recordSourceOperation {
attrs = append(attrs, SourceOperationKey.String(ri.From().Method()))
}
span.SetAttributes(attrs...)
injectStatsEventsToSpan(span, st)
if panicMsg, panicStack, rpcErr := parseRPCError(ri); rpcErr != nil || len(panicMsg) > 0 {
recordErrorSpanWithStack(span, rpcErr, panicMsg, panicStack)
}
span.End(oteltrace.WithTimestamp(getEndTimeOrNow(ri)))
metricsAttributes := extractMetricsAttributesFromSpan(span)
c.histogramRecorder[ClientDuration].Record(ctx, elapsedTime, metric.WithAttributes(metricsAttributes...))
}