-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ac8062f
commit 123af7c
Showing
7 changed files
with
424 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-FileCopyrightText: 2022-present Intel Corporation | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package otelemetry | ||
|
||
import ( | ||
"context" | ||
"github.com/gogo/protobuf/proto" | ||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" | ||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/trace" | ||
) | ||
|
||
// Event telemetry event | ||
type event struct { | ||
id int | ||
message interface{} | ||
messageType attribute.KeyValue | ||
} | ||
|
||
// Send sends a telemetry event | ||
func (e event) Send(ctx context.Context) { | ||
span := trace.SpanFromContext(ctx) | ||
if p, ok := e.message.(proto.Message); ok { | ||
span.AddEvent("event", trace.WithAttributes( | ||
e.messageType, | ||
otelgrpc.RPCMessageIDKey.Int(e.id), | ||
otelgrpc.RPCMessageUncompressedSizeKey.Int(proto.Size(p)), | ||
)) | ||
} else { | ||
span.AddEvent("event", trace.WithAttributes( | ||
e.messageType, | ||
otelgrpc.RPCMessageIDKey.Int(e.id), | ||
)) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// SPDX-FileCopyrightText: 2022-present Intel Corporation | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package otelemetry | ||
|
||
import ( | ||
"context" | ||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" | ||
"go.opentelemetry.io/otel/baggage" | ||
"go.opentelemetry.io/otel/codes" | ||
"go.opentelemetry.io/otel/trace" | ||
"google.golang.org/grpc" | ||
grpccodes "google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/metadata" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
// UnaryServerTelemetryInterceptor returns a grpc.UnaryServerInterceptor suitable | ||
// for use in a grpc.NewServer call. | ||
func UnaryServerTelemetryInterceptor(opts ...InstrumentationOption) grpc.UnaryServerInterceptor { | ||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, | ||
) (interface{}, error) { | ||
requestMetadata, _ := metadata.FromIncomingContext(ctx) | ||
metadataCopy := requestMetadata.Copy() | ||
|
||
instrumentation := NewInstrumentation(opts) | ||
bags, spanCtx := instrumentation.Extract(ctx, &metadataCopy) | ||
ctx = baggage.ContextWithBaggage(ctx, bags) | ||
|
||
tracer := instrumentation.NewTracer(trace.WithInstrumentationVersion("1.0.0")) | ||
|
||
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) | ||
ctx, span := tracer.Start( | ||
trace.ContextWithRemoteSpanContext(ctx, spanCtx), | ||
name, | ||
trace.WithSpanKind(trace.SpanKindServer), | ||
trace.WithAttributes(attr...), | ||
) | ||
|
||
defer span.End() | ||
e := event{ | ||
messageType: otelgrpc.RPCMessageTypeReceived, | ||
message: req, | ||
id: 1, | ||
} | ||
e.Send(ctx) | ||
|
||
resp, err := handler(ctx, req) | ||
if err != nil { | ||
s, _ := status.FromError(err) | ||
span.SetStatus(codes.Error, s.Message()) | ||
span.SetAttributes(statusCodeAttr(s.Code())) | ||
e = event{ | ||
messageType: otelgrpc.RPCMessageTypeSent, | ||
message: s.Proto(), | ||
id: 1, | ||
} | ||
e.Send(ctx) | ||
|
||
} else { | ||
span.SetAttributes(statusCodeAttr(grpccodes.OK)) | ||
e = event{ | ||
messageType: otelgrpc.RPCMessageTypeSent, | ||
message: resp, | ||
id: 1, | ||
} | ||
} | ||
|
||
return resp, err | ||
} | ||
} | ||
|
||
// StreamTelemetryServerInterceptor returns a grpc.StreamServerInterceptor suitable | ||
// for use in a grpc.NewServer call. | ||
func StreamTelemetryServerInterceptor(opts ...InstrumentationOption) grpc.StreamServerInterceptor { | ||
return func( | ||
srv interface{}, | ||
stream grpc.ServerStream, | ||
info *grpc.StreamServerInfo, | ||
handler grpc.StreamHandler, | ||
) error { | ||
ctx := stream.Context() | ||
|
||
requestMetadata, _ := metadata.FromIncomingContext(ctx) | ||
metadataCopy := requestMetadata.Copy() | ||
|
||
instrumentation := NewInstrumentation(opts) | ||
bags, spanCtx := instrumentation.Extract(ctx, &metadataCopy) | ||
ctx = baggage.ContextWithBaggage(ctx, bags) | ||
|
||
tracer := instrumentation.NewTracer(trace.WithInstrumentationVersion("1.0.0")) | ||
|
||
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) | ||
ctx, span := tracer.Start( | ||
trace.ContextWithRemoteSpanContext(ctx, spanCtx), | ||
name, | ||
trace.WithSpanKind(trace.SpanKindServer), | ||
trace.WithAttributes(attr...), | ||
) | ||
|
||
defer span.End() | ||
err := handler(srv, wrapServerStream(ctx, stream)) | ||
|
||
if err != nil { | ||
s, _ := status.FromError(err) | ||
span.SetStatus(codes.Error, s.Message()) | ||
span.SetAttributes(statusCodeAttr(s.Code())) | ||
} else { | ||
span.SetAttributes(statusCodeAttr(grpccodes.OK)) | ||
} | ||
|
||
return err | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// SPDX-FileCopyrightText: 2022-present Intel Corporation | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package otelemetry | ||
|
||
import ( | ||
"context" | ||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/baggage" | ||
"go.opentelemetry.io/otel/propagation" | ||
"go.opentelemetry.io/otel/trace" | ||
"google.golang.org/grpc/metadata" | ||
) | ||
|
||
// Instrumentation interface | ||
type Instrumentation interface { | ||
Extract(ctx context.Context, metadata *metadata.MD) (baggage.Baggage, trace.SpanContext) | ||
Inject(ctx context.Context, metadata *metadata.MD) | ||
} | ||
|
||
// InstrumentationOptions is a group of options for this instrumentation. | ||
type InstrumentationOptions struct { | ||
propagators propagation.TextMapPropagator | ||
tracerProvider trace.TracerProvider | ||
name string | ||
} | ||
|
||
func (o *InstrumentationOptions) Inject(ctx context.Context, metadata *metadata.MD) { | ||
o.propagators.Inject(ctx, &metadataInfo{ | ||
metadata: metadata, | ||
}) | ||
} | ||
|
||
func (o *InstrumentationOptions) Extract(ctx context.Context, metadata *metadata.MD) (baggage.Baggage, trace.SpanContext) { | ||
ctx = o.propagators.Extract(ctx, &metadataInfo{ | ||
metadata: metadata, | ||
}) | ||
|
||
return baggage.FromContext(ctx), trace.SpanContextFromContext(ctx) | ||
} | ||
|
||
// InstrumentationOption function | ||
type InstrumentationOption func(*InstrumentationOptions) | ||
|
||
// NewInstrumentation creates a configuration for an instrumentation using a set of given options | ||
func NewInstrumentation(opts []InstrumentationOption) *InstrumentationOptions { | ||
c := &InstrumentationOptions{ | ||
propagators: otel.GetTextMapPropagator(), | ||
tracerProvider: trace.NewNoopTracerProvider(), | ||
name: "", | ||
} | ||
for _, option := range opts { | ||
option(c) | ||
} | ||
|
||
return c | ||
} | ||
|
||
func (o InstrumentationOptions) apply(opts ...InstrumentationOption) { | ||
for _, opt := range opts { | ||
opt(&o) | ||
} | ||
} | ||
|
||
func (o InstrumentationOptions) NewTracer(opts ...trace.TracerOption) trace.Tracer { | ||
return o.tracerProvider.Tracer(o.name, opts...) | ||
} | ||
|
||
// WithPropagators sets propagators | ||
func WithPropagators(propagators propagation.TextMapPropagator) InstrumentationOption { | ||
return func(options *InstrumentationOptions) { | ||
options.propagators = propagators | ||
} | ||
} | ||
|
||
// WithTraceProvider sets trace provider | ||
func WithTraceProvider(tracerProvider trace.TracerProvider) InstrumentationOption { | ||
return func(options *InstrumentationOptions) { | ||
options.tracerProvider = tracerProvider | ||
} | ||
} | ||
|
||
// WithInstrumentationName sets instrumentation name | ||
func WithInstrumentationName(name string) InstrumentationOption { | ||
return func(options *InstrumentationOptions) { | ||
options.name = name | ||
} | ||
} | ||
|
||
var _ Instrumentation = &InstrumentationOptions{} | ||
|
||
type metadataInfo struct { | ||
metadata *metadata.MD | ||
} | ||
|
||
// assert that metadataSupplier implements the TextMapCarrier interface | ||
var _ propagation.TextMapCarrier = &metadataInfo{} | ||
|
||
func (s *metadataInfo) Get(key string) string { | ||
values := s.metadata.Get(key) | ||
if len(values) == 0 { | ||
return "" | ||
} | ||
return values[0] | ||
} | ||
|
||
func (s *metadataInfo) Set(key string, value string) { | ||
s.metadata.Set(key, value) | ||
} | ||
|
||
func (s *metadataInfo) Keys() []string { | ||
out := make([]string, 0, len(*s.metadata)) | ||
for key := range *s.metadata { | ||
out = append(out, key) | ||
} | ||
return out | ||
} |
Oops, something went wrong.