1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-28 21:09:17 +02:00
opentelemetry-go/example/grpc/middleware/tracing/tracing.go

90 lines
2.9 KiB
Go
Raw Normal View History

// Copyright 2019, OpenTelemetry 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
// gRPC tracing middleware
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-rpc.md
import (
"context"
"go.opentelemetry.io/otel/plugin/grpctrace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"go.opentelemetry.io/otel/api/core"
"go.opentelemetry.io/otel/api/distributedcontext"
"go.opentelemetry.io/otel/api/global"
"go.opentelemetry.io/otel/api/key"
"go.opentelemetry.io/otel/api/trace"
)
// UnaryServerInterceptor intercepts and extracts incoming trace data
func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
requestMetadata, _ := metadata.FromIncomingContext(ctx)
metadataCopy := requestMetadata.Copy()
entries, spanCtx := grpctrace.Extract(ctx, &metadataCopy)
ctx = distributedcontext.WithMap(ctx, distributedcontext.NewMap(distributedcontext.MapUpdate{
MultiKV: entries,
}))
grpcServerKey := key.New("grpc.server")
serverSpanAttrs := []core.KeyValue{
grpcServerKey.String("hello-world-server"),
}
tr := global.TraceProvider().Tracer("example/grpc")
ctx, span := tr.Start(
ctx,
"hello-api-op",
trace.WithAttributes(serverSpanAttrs...),
trace.ChildOf(spanCtx),
trace.WithSpanKind(trace.SpanKindServer),
)
defer span.End()
return handler(ctx, req)
}
// UnaryClientInterceptor intercepts and injects outgoing trace
func UnaryClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
requestMetadata, _ := metadata.FromOutgoingContext(ctx)
metadataCopy := requestMetadata.Copy()
tr := global.TraceProvider().Tracer("example/grpc")
err := tr.WithSpan(ctx, "hello-api-op",
func(ctx context.Context) error {
grpctrace.Inject(ctx, &metadataCopy)
ctx = metadata.NewOutgoingContext(ctx, metadataCopy)
err := invoker(ctx, method, req, reply, cc, opts...)
setTraceStatus(ctx, err)
return err
})
return err
}
func setTraceStatus(ctx context.Context, err error) {
if err != nil {
s, _ := status.FromError(err)
trace.CurrentSpan(ctx).SetStatus(s.Code())
} else {
trace.CurrentSpan(ctx).SetStatus(codes.OK)
}
}