Skip to content

Commit

Permalink
add metric rpc.server.duration for unary request and stream request
Browse files Browse the repository at this point in the history
Signed-off-by: Ziqi Zhao <zhaoziqi9146@gmail.com>
  • Loading branch information
fatsheep9146 committed Oct 15, 2022
1 parent c011266 commit d3a3a28
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 74 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added

- Add trace context propagation support to `instrumentation/github.com/aws/aws-sdk-go-v2/otelaws` (#2856).
- [otelgrpc] add metric `rpc.server.duration` to otelgrpc instrumentation library. (#2700)

## [1.11.0/0.36.3/0.5.1]

Expand All @@ -31,6 +32,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `Inject` function in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` is deprecated. (#2838)
- The `Extract` function in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` is deprecated. (#2838)

### Added

- [otelgrpc] Add `WithMeterProvider` function to enable metric and add metric `rpc.server.duration` to otelgrpc instrumentation library. (#2700)

## [0.36.1]

### Changed
Expand Down
Expand Up @@ -15,14 +15,13 @@
package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

import (
"context"

"google.golang.org/grpc/metadata"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
"go.opentelemetry.io/otel/trace"
)

Expand All @@ -43,6 +42,10 @@ type config struct {
Filter Filter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider

meter metric.Meter
rpcServerDuration syncint64.Histogram
}

// Option applies an option value for a config.
Expand All @@ -55,10 +58,23 @@ func newConfig(opts []Option) *config {
c := &config{
Propagators: otel.GetTextMapPropagator(),
TracerProvider: otel.GetTracerProvider(),
MeterProvider: global.MeterProvider(),
}
for _, o := range opts {
o.apply(c)
}

c.meter = c.MeterProvider.Meter(
instrumentationName,
metric.WithInstrumentationVersion(SemVersion()),
metric.WithSchemaURL(semconv.SchemaURL),
)
var err error
// the unit of rpc.server.duration is milliseconds
if c.rpcServerDuration, err = c.meter.SyncInt64().Histogram("rpc.server.duration"); err != nil {
otel.Handle(err)
}

return c
}

Expand Down Expand Up @@ -105,75 +121,16 @@ func WithTracerProvider(tp trace.TracerProvider) Option {
return tracerProviderOption{tp: tp}
}

type metadataSupplier struct {
metadata *metadata.MD
}

// assert that metadataSupplier implements the TextMapCarrier interface.
var _ propagation.TextMapCarrier = &metadataSupplier{}

func (s *metadataSupplier) Get(key string) string {
values := s.metadata.Get(key)
if len(values) == 0 {
return ""
}
return values[0]
}

func (s *metadataSupplier) Set(key string, value string) {
s.metadata.Set(key, value)
}
type meterProviderOption struct{ mp metric.MeterProvider }

func (s *metadataSupplier) Keys() []string {
out := make([]string, 0, len(*s.metadata))
for key := range *s.metadata {
out = append(out, key)
func (o meterProviderOption) apply(c *config) {
if o.mp != nil {
c.MeterProvider = o.mp
}
return out
}

// Inject injects correlation context and span context into the gRPC
// metadata object. This function is meant to be used on outgoing
// requests.
// Deprecated: Unnecessary public func.
func Inject(ctx context.Context, md *metadata.MD, opts ...Option) {
c := newConfig(opts)
c.Propagators.Inject(ctx, &metadataSupplier{
metadata: md,
})
}

func inject(ctx context.Context, propagators propagation.TextMapPropagator) context.Context {
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
md = metadata.MD{}
}
propagators.Inject(ctx, &metadataSupplier{
metadata: &md,
})
return metadata.NewOutgoingContext(ctx, md)
}

// Extract returns the correlation context and span context that
// another service encoded in the gRPC metadata object with Inject.
// This function is meant to be used on incoming requests.
// Deprecated: Unnecessary public func.
func Extract(ctx context.Context, md *metadata.MD, opts ...Option) (baggage.Baggage, trace.SpanContext) {
c := newConfig(opts)
ctx = c.Propagators.Extract(ctx, &metadataSupplier{
metadata: md,
})

return baggage.FromContext(ctx), trace.SpanContextFromContext(ctx)
}

func extract(ctx context.Context, propagators propagation.TextMapPropagator) context.Context {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.MD{}
}

return propagators.Extract(ctx, &metadataSupplier{
metadata: &md,
})
// WithMeterProvider returns an Option to use the MeterProvider when
// creating a Meter. If this option is not provide the global MeterProvider will be used.
func WithMeterProvider(mp metric.MeterProvider) Option {
return meterProviderOption{mp: mp}
}
Expand Up @@ -19,6 +19,7 @@ require (
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
go.opentelemetry.io/otel/metric v0.31.0 // indirect
golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.28.1 // indirect
Expand Down
Expand Up @@ -37,6 +37,8 @@ go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk=
go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.0 h1:rzpQkvma82S+jQvJHqJaAGQdeRBtH6HASrgrZa45rx4=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.0/go.mod h1:nMt8nBu01qC+8LfJu4puk/OYHovohkISNuy/MMG8yRk=
go.opentelemetry.io/otel/metric v0.31.0 h1:6SiklT+gfWAwWUR0meEMxQBtihpiEs4c+vL9spDTqUs=
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo=
go.opentelemetry.io/otel/sdk v1.11.0/go.mod h1:REusa8RsyKaq0OlyangWXaw97t2VogoO4SSEeKkSTAk=
go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtTAOVFI=
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/google.golang.org/grpc/otelgrpc/go.mod
Expand Up @@ -3,7 +3,9 @@ module go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgr
go 1.18

require (
github.com/golang/protobuf v1.5.2
go.opentelemetry.io/otel v1.11.0
go.opentelemetry.io/otel/metric v0.31.0
go.opentelemetry.io/otel/trace v1.11.0
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/google.golang.org/grpc/otelgrpc/go.sum
Expand Up @@ -36,6 +36,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk=
go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk=
go.opentelemetry.io/otel/metric v0.31.0 h1:6SiklT+gfWAwWUR0meEMxQBtihpiEs4c+vL9spDTqUs=
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtTAOVFI=
go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down
11 changes: 10 additions & 1 deletion instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"io"
"net"
"time"

"google.golang.org/grpc"
grpc_codes "google.golang.org/grpc/codes"
Expand Down Expand Up @@ -338,13 +339,22 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {

messageReceived.Event(ctx, 1, req)

var statusCode grpc_codes.Code
defer func(t time.Time) {
elapsedTime := time.Since(t) / time.Millisecond
attr = append(attr, semconv.RPCGRPCStatusCodeKey.Int64(int64(statusCode)))
cfg.rpcServerDuration.Record(ctx, int64(elapsedTime), attr...)
}(time.Now())

resp, err := handler(ctx, req)
if err != nil {
s, _ := status.FromError(err)
statusCode = s.Code()
span.SetStatus(codes.Error, s.Message())
span.SetAttributes(statusCodeAttr(s.Code()))
messageSent.Event(ctx, 1, s.Proto())
} else {
statusCode = grpc_codes.OK
span.SetAttributes(statusCodeAttr(grpc_codes.OK))
messageSent.Event(ctx, 1, resp)
}
Expand Down Expand Up @@ -430,7 +440,6 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
defer span.End()

err := handler(srv, wrapServerStream(ctx, ss))

if err != nil {
s, _ := status.FromError(err)
span.SetStatus(codes.Error, s.Message())
Expand Down
@@ -0,0 +1,98 @@
// Copyright The 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 otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

import (
"context"

"google.golang.org/grpc/metadata"

"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)

type metadataSupplier struct {
metadata *metadata.MD
}

// assert that metadataSupplier implements the TextMapCarrier interface.
var _ propagation.TextMapCarrier = &metadataSupplier{}

func (s *metadataSupplier) Get(key string) string {
values := s.metadata.Get(key)
if len(values) == 0 {
return ""
}
return values[0]
}

func (s *metadataSupplier) Set(key string, value string) {
s.metadata.Set(key, value)
}

func (s *metadataSupplier) Keys() []string {
out := make([]string, 0, len(*s.metadata))
for key := range *s.metadata {
out = append(out, key)
}
return out
}

// Inject injects correlation context and span context into the gRPC
// metadata object. This function is meant to be used on outgoing
// requests.
// Deprecated: Unnecessary public func.
func Inject(ctx context.Context, md *metadata.MD, opts ...Option) {
c := newConfig(opts)
c.Propagators.Inject(ctx, &metadataSupplier{
metadata: md,
})
}

func inject(ctx context.Context, propagators propagation.TextMapPropagator) context.Context {
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
md = metadata.MD{}
}
propagators.Inject(ctx, &metadataSupplier{
metadata: &md,
})
return metadata.NewOutgoingContext(ctx, md)
}

// Extract returns the correlation context and span context that
// another service encoded in the gRPC metadata object with Inject.
// This function is meant to be used on incoming requests.
// Deprecated: Unnecessary public func.
func Extract(ctx context.Context, md *metadata.MD, opts ...Option) (baggage.Baggage, trace.SpanContext) {
c := newConfig(opts)
ctx = c.Propagators.Extract(ctx, &metadataSupplier{
metadata: md,
})

return baggage.FromContext(ctx), trace.SpanContextFromContext(ctx)
}

func extract(ctx context.Context, propagators propagation.TextMapPropagator) context.Context {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.MD{}
}

return propagators.Extract(ctx, &metadataSupplier{
metadata: &md,
})
}
2 changes: 2 additions & 0 deletions instrumentation/google.golang.org/grpc/otelgrpc/test/go.mod
Expand Up @@ -7,6 +7,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3
go.opentelemetry.io/otel v1.11.0
go.opentelemetry.io/otel/sdk v1.11.0
go.opentelemetry.io/otel/sdk/metric v0.31.0
go.uber.org/goleak v1.2.0
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
Expand All @@ -21,6 +22,7 @@ require (
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel/trace v1.11.0 // indirect
go.opentelemetry.io/otel/metric v0.31.0 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
Expand Down
5 changes: 5 additions & 0 deletions instrumentation/google.golang.org/grpc/otelgrpc/test/go.sum
Expand Up @@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
Expand Down Expand Up @@ -47,8 +48,12 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk=
go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk=
go.opentelemetry.io/otel/metric v0.31.0 h1:6SiklT+gfWAwWUR0meEMxQBtihpiEs4c+vL9spDTqUs=
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo=
go.opentelemetry.io/otel/sdk v1.11.0/go.mod h1:REusa8RsyKaq0OlyangWXaw97t2VogoO4SSEeKkSTAk=
go.opentelemetry.io/otel/sdk/metric v0.31.0 h1:2sZx4R43ZMhJdteKAlKoHvRgrMp53V1aRxvEf5lCq8Q=
go.opentelemetry.io/otel/sdk/metric v0.31.0/go.mod h1:fl0SmNnX9mN9xgU6OLYLMBMrNAsaZQi7qBwprwO3abk=
go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtTAOVFI=
go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
Expand Down

0 comments on commit d3a3a28

Please sign in to comment.