Skip to content

Commit d09ae3b

Browse files
Address remaining test implementation, add functional options
Signed-off-by: Joseph Woodward <joseph.woodward@xeuse.com>
1 parent 9aa3bfd commit d09ae3b

File tree

5 files changed

+145
-57
lines changed

5 files changed

+145
-57
lines changed

client/opentelemetry.go

Lines changed: 112 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,97 @@ import (
88
"go.opentelemetry.io/otel"
99
"go.opentelemetry.io/otel/attribute"
1010
"go.opentelemetry.io/otel/codes"
11+
"go.opentelemetry.io/otel/propagation"
1112
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
1213
"go.opentelemetry.io/otel/trace"
1314
)
1415

16+
type config struct {
17+
Tracer trace.Tracer
18+
Propagators propagation.TextMapPropagator
19+
SpanStartOptions []trace.SpanStartOption
20+
SpanNameFormatter func(string, *http.Request) string
21+
TracerProvider trace.TracerProvider
22+
}
23+
24+
type OpenTelemetryOption interface {
25+
apply(*config)
26+
}
27+
28+
type optionFunc func(*config)
29+
30+
func (o optionFunc) apply(c *config) {
31+
o(c)
32+
}
33+
34+
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
35+
// If none is specified, the global provider is used.
36+
func WithTracerProvider(provider trace.TracerProvider) OpenTelemetryOption {
37+
return optionFunc(func(c *config) {
38+
if provider != nil {
39+
c.TracerProvider = provider
40+
}
41+
})
42+
}
43+
44+
// WithPropagators configures specific propagators. If this
45+
// option isn't specified, then the global TextMapPropagator is used.
46+
func WithPropagators(ps propagation.TextMapPropagator) OpenTelemetryOption {
47+
return optionFunc(func(c *config) {
48+
if ps != nil {
49+
c.Propagators = ps
50+
}
51+
})
52+
}
53+
54+
// WithSpanOptions configures an additional set of
55+
// trace.SpanOptions, which are applied to each new span.
56+
func WithSpanOptions(opts ...trace.SpanStartOption) OpenTelemetryOption {
57+
return optionFunc(func(c *config) {
58+
c.SpanStartOptions = append(c.SpanStartOptions, opts...)
59+
})
60+
}
61+
1562
type openTelemetryTransport struct {
16-
transport runtime.ClientTransport
17-
host string
18-
opts []trace.SpanStartOption
63+
transport runtime.ClientTransport
64+
host string
65+
spanStartOptions []trace.SpanStartOption
66+
propagator propagation.TextMapPropagator
67+
provider trace.TracerProvider
68+
tracer trace.Tracer
69+
config *config
70+
}
71+
72+
// newConfig creates a new config struct and applies opts to it.
73+
func newConfig(opts ...OpenTelemetryOption) *config {
74+
c := &config{
75+
Propagators: otel.GetTextMapPropagator(),
76+
}
77+
78+
for _, opt := range opts {
79+
opt.apply(c)
80+
}
81+
82+
// Tracer is only initialized if manually specified. Otherwise, can be passed with the tracing context.
83+
if c.TracerProvider != nil {
84+
c.Tracer = newTracer(c.TracerProvider)
85+
}
86+
87+
return c
1988
}
2089

21-
func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, opts []trace.SpanStartOption) runtime.ClientTransport {
22-
return &openTelemetryTransport{
23-
transport: transport,
24-
host: host,
25-
opts: opts,
90+
func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, opts []OpenTelemetryOption) *openTelemetryTransport {
91+
t := &openTelemetryTransport{
92+
transport: transport,
93+
host: host,
94+
provider: otel.GetTracerProvider(),
95+
propagator: otel.GetTextMapPropagator(),
2696
}
97+
98+
c := newConfig(opts...)
99+
t.config = c
100+
101+
return t
27102
}
28103

29104
func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{}, error) {
@@ -42,7 +117,7 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{
42117
}()
43118

44119
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
45-
span = createOpenTelemetryClientSpan(op, req.GetHeaderParams(), t.host, t.opts)
120+
span = t.newOpenTelemetrySpan(op, req.GetHeaderParams())
46121
return params.WriteToRequest(req, reg)
47122
})
48123

@@ -65,50 +140,42 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{
65140
return submit, err
66141
}
67142

68-
func createOpenTelemetryClientSpan(op *runtime.ClientOperation, _ http.Header, host string, opts []trace.SpanStartOption) trace.Span {
143+
func (t *openTelemetryTransport) newOpenTelemetrySpan(op *runtime.ClientOperation, header http.Header) trace.Span {
69144
ctx := op.Context
70-
if span := trace.SpanFromContext(ctx); span.IsRecording() {
71-
// TODO: Can we get the version number for use with trace.WithInstrumentationVersion?
72-
tracer := otel.GetTracerProvider().Tracer("")
73145

74-
ctx, span = tracer.Start(ctx, operationName(op), opts...)
75-
op.Context = ctx
76-
77-
//TODO: There's got to be a better way to do this without the request, right?
78-
var scheme string
79-
if len(op.Schemes) == 1 {
80-
scheme = op.Schemes[0]
146+
tracer := t.tracer
147+
if tracer == nil {
148+
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
149+
tracer = newTracer(span.TracerProvider())
150+
} else {
151+
tracer = newTracer(otel.GetTracerProvider())
81152
}
153+
}
82154

83-
span.SetAttributes(
84-
attribute.String("net.peer.name", host),
85-
// attribute.String("net.peer.port", ""),
86-
attribute.String(string(semconv.HTTPRouteKey), op.PathPattern),
87-
attribute.String(string(semconv.HTTPMethodKey), op.Method),
88-
attribute.String("span.kind", trace.SpanKindClient.String()),
89-
attribute.String("http.scheme", scheme),
90-
)
155+
ctx, span := tracer.Start(ctx, operationName(op), t.spanStartOptions...)
91156

92-
return span
157+
// TODO: Can we get the underlying request so we can wire these bits up easily?
158+
// span.SetAttributes(semconv.HTTPClientAttributesFromHTTPRequest()...)
159+
var scheme string
160+
if len(op.Schemes) == 1 {
161+
scheme = op.Schemes[0]
93162
}
94163

95-
// if span != nil {
96-
// opts = append(opts, ext.SpanKindRPCClient)
97-
// span, _ = opentracing.StartSpanFromContextWithTracer(
98-
// ctx, span.Tracer(), operationName(op), opts...)
164+
span.SetAttributes(
165+
attribute.String("net.peer.name", t.host),
166+
// attribute.String("net.peer.port", ""),
167+
attribute.String(string(semconv.HTTPRouteKey), op.PathPattern),
168+
attribute.String(string(semconv.HTTPMethodKey), op.Method),
169+
attribute.String("span.kind", trace.SpanKindClient.String()),
170+
attribute.String("http.scheme", scheme),
171+
)
99172

100-
// ext.Component.Set(span, "go-openapi")
101-
// ext.PeerHostname.Set(span, host)
102-
// span.SetTag("http.path", op.PathPattern)
103-
// ext.HTTPMethod.Set(span, op.Method)
173+
carrier := propagation.HeaderCarrier(header)
174+
t.propagator.Inject(ctx, carrier)
104175

105-
// _ = span.Tracer().Inject(
106-
// span.Context(),
107-
// opentracing.HTTPHeaders,
108-
// opentracing.HTTPHeadersCarrier(header))
109-
110-
// return span
111-
// }
176+
return span
177+
}
112178

113-
return nil
179+
func newTracer(tp trace.TracerProvider) trace.Tracer {
180+
return tp.Tracer("go-runtime", trace.WithInstrumentationVersion("1.0.0"))
114181
}

client/opentelemetry_test.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go.opentelemetry.io/otel"
1111
"go.opentelemetry.io/otel/attribute"
1212
"go.opentelemetry.io/otel/codes"
13+
"go.opentelemetry.io/otel/propagation"
1314
tracesdk "go.opentelemetry.io/otel/sdk/trace"
1415
"go.opentelemetry.io/otel/sdk/trace/tracetest"
1516
"go.opentelemetry.io/otel/trace"
@@ -71,22 +72,36 @@ func Test_OpenTelemetryRuntime_submit_nilContext(t *testing.T) {
7172
assertOpenTelemetrySubmit(t, operation, exporter, 0) // just don't panic
7273
}
7374

74-
// func Test_injectOpenTelemetrySpanContext(t *testing.T) {
75-
// t.Parallel()
76-
// tracer := mocktracer.New()
77-
// _, ctx := opentracing.StartSpanFromContextWithTracer(context.Background(), tracer, "op")
78-
// header := map[string][]string{}
79-
// createOpenTelemetryClientSpan(testOperation(ctx), header, "", nil)
75+
func Test_injectOpenTelemetrySpanContext(t *testing.T) {
76+
t.Parallel()
77+
78+
exporter := tracetest.NewInMemoryExporter()
8079

81-
// // values are random - just check that something was injected
82-
// assert.Len(t, header, 3)
83-
// }
80+
tp := tracesdk.NewTracerProvider(
81+
tracesdk.WithSampler(tracesdk.AlwaysSample()),
82+
tracesdk.WithSyncer(exporter),
83+
)
84+
85+
otel.SetTracerProvider(tp)
86+
87+
tracer := tp.Tracer("go-runtime")
88+
ctx, _ := tracer.Start(context.Background(), "op")
89+
operation := testOperation(ctx)
90+
91+
header := map[string][]string{}
92+
tr := newOpenTelemetryTransport(&mockRuntime{runtime.TestClientRequest{Headers: header}}, "", nil)
93+
tr.propagator = propagation.TraceContext{}
94+
tr.Submit(operation)
95+
96+
// values are random - just check that something was injected
97+
assert.Len(t, header, 1)
98+
}
8499

85100
func assertOpenTelemetrySubmit(t *testing.T, operation *runtime.ClientOperation, exporter *tracetest.InMemoryExporter, expectedSpanCount int) {
86101
header := map[string][]string{}
87102
r := newOpenTelemetryTransport(&mockRuntime{runtime.TestClientRequest{Headers: header}},
88103
"remote_host",
89-
[]trace.SpanStartOption{})
104+
nil)
90105

91106
_, err := r.Submit(operation)
92107
require.NoError(t, err)

client/runtime.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"time"
3333

3434
"github.com/opentracing/opentracing-go"
35-
"go.opentelemetry.io/otel/trace"
3635

3736
"github.com/go-openapi/runtime"
3837
"github.com/go-openapi/runtime/logger"
@@ -306,7 +305,7 @@ func (r *Runtime) WithOpenTracing(opts ...opentracing.StartSpanOption) runtime.C
306305
// A new client span is created for each request.
307306
// If the context of the client operation does not contain an active span, no span is created.
308307
// The provided opts are applied to each spans - for example to add global tags.
309-
func (r *Runtime) WithOpenTelemetry(opts ...trace.SpanStartOption) runtime.ClientTransport {
308+
func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOption) runtime.ClientTransport {
310309
return newOpenTelemetryTransport(r, r.Host, opts)
311310
}
312311

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/opentracing/opentracing-go v1.2.0
1717
github.com/stretchr/testify v1.8.0
1818
go.mongodb.org/mongo-driver v1.8.3 // indirect
19+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4
1920
go.opentelemetry.io/otel v1.11.1 // indirect
2021
go.opentelemetry.io/otel/sdk v1.11.1
2122
go.opentelemetry.io/otel/trace v1.11.1

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
1212
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1313
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
1414
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
15+
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
16+
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
1517
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
1618
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
1719
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -141,8 +143,12 @@ go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R7
141143
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
142144
go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
143145
go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
146+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio=
147+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA=
144148
go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4=
145149
go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE=
150+
go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E=
151+
go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI=
146152
go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs=
147153
go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys=
148154
go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=

0 commit comments

Comments
 (0)