mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-28 21:09:17 +02:00
90 lines
2.9 KiB
Go
90 lines
2.9 KiB
Go
|
// 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 {
|
||
|
status, _ := status.FromError(err)
|
||
|
trace.CurrentSpan(ctx).SetStatus(status.Code())
|
||
|
} else {
|
||
|
trace.CurrentSpan(ctx).SetStatus(codes.OK)
|
||
|
}
|
||
|
}
|