Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

otelgrpc: Add Filter for stats handler #5196

Merged
merged 23 commits into from May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3203812
otelgrpc: Add filter for stats handler
ymtdzzz Mar 3, 2024
93304ee
Add entries to CHANGELOG
ymtdzzz Mar 3, 2024
6da878b
fix CHANGELOG
ymtdzzz Mar 5, 2024
b2268ee
Merge branch 'main' into grpc-stats-filter
ymtdzzz Mar 5, 2024
a67ce81
keep Deprecated comment of `WithInterceptorFilter`
ymtdzzz Mar 6, 2024
bdd913c
deprecate `InterceptorFilter` type
ymtdzzz Mar 6, 2024
f17ccf9
Merge branch 'main' into grpc-stats-filter
ymtdzzz May 6, 2024
0f3cda4
Merge branch 'main' into grpc-stats-filter
dashpole May 6, 2024
24f7819
change the location of `gctx.record` nil check location to reduce hea…
ymtdzzz May 7, 2024
c517508
add documentation for filters and interceptor packages
ymtdzzz May 7, 2024
9e67c22
Merge branch 'main' into grpc-stats-filter
ymtdzzz May 7, 2024
733f3be
fix the location of entries in CHANGELOG
ymtdzzz May 8, 2024
94aa442
Merge branch 'open-telemetry:main' into grpc-stats-filter
ymtdzzz May 8, 2024
02f36b3
more reasonable doc comment for interceptor package
ymtdzzz May 8, 2024
e523a2d
more reasonable doc comment for interceptor package
ymtdzzz May 8, 2024
28f6c1c
Use more appropriate word in the comment of InterceptorFilter
ymtdzzz May 8, 2024
a779640
more reasonable doc comment for filters package
ymtdzzz May 8, 2024
ebabbaa
fix the comment of `Filter`
ymtdzzz May 8, 2024
28a27de
Clearly describe the effects of the change
ymtdzzz May 8, 2024
79cf21a
Merge branch 'main' into grpc-stats-filter
pellared May 8, 2024
d22a1c9
add tests for `stats_handler.go`
ymtdzzz May 9, 2024
a7b6221
Merge branch 'main' into grpc-stats-filter
ymtdzzz May 9, 2024
95bca4e
Merge branch 'main' into grpc-stats-filter
MrAlias May 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added

- Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068, #3108)
- Add gRPC trace `Filter` for stats handler to `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#5196)

### Changed

- The gRPC trace `Filter` for interceptor is renamed to `InterceptorFilter`. (#5196)
- The gRPC trace filter functions `Any`, `All`, `None`, `Not`, `MethodName`, `MethodPrefix`, `FullMethodName`, `ServiceName`, `ServicePrefix` and `HealthCheck` for interceptor are moved to `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters/interceptor`. (#5196)
pellared marked this conversation as resolved.
Show resolved Hide resolved
pellared marked this conversation as resolved.
Show resolved Hide resolved

### Removed

Expand Down
41 changes: 31 additions & 10 deletions instrumentation/google.golang.org/grpc/otelgrpc/config.go
Expand Up @@ -4,6 +4,8 @@
package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

import (
"google.golang.org/grpc/stats"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
Expand All @@ -20,18 +22,24 @@
GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
)

// InterceptorFilter is a predicate used to determine whether a given request in
// interceptor info should be traced. A InterceptorFilter must return true if
ymtdzzz marked this conversation as resolved.
Show resolved Hide resolved
// the request should be traced.
type InterceptorFilter func(*InterceptorInfo) bool
dashpole marked this conversation as resolved.
Show resolved Hide resolved

// Filter is a predicate used to determine whether a given request in
// interceptor info should be traced. A Filter must return true if
// the request should be traced.
pellared marked this conversation as resolved.
Show resolved Hide resolved
type Filter func(*InterceptorInfo) bool
type Filter func(*stats.RPCTagInfo) bool

// config is a group of options for this instrumentation.
type config struct {
Filter Filter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
Filter Filter
InterceptorFilter InterceptorFilter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption

ReceivedEvent bool
SentEvent bool
Expand Down Expand Up @@ -150,17 +158,30 @@
}

// WithInterceptorFilter returns an Option to use the request filter.
//
// Deprecated: Use stats handlers instead.
func WithInterceptorFilter(f Filter) Option {
func WithInterceptorFilter(f InterceptorFilter) Option {

Check warning on line 161 in instrumentation/google.golang.org/grpc/otelgrpc/config.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/google.golang.org/grpc/otelgrpc/config.go#L161

Added line #L161 was not covered by tests
dashpole marked this conversation as resolved.
Show resolved Hide resolved
return interceptorFilterOption{f: f}
}

type interceptorFilterOption struct {
f Filter
f InterceptorFilter
}

func (o interceptorFilterOption) apply(c *config) {
if o.f != nil {
c.InterceptorFilter = o.f

Check warning on line 171 in instrumentation/google.golang.org/grpc/otelgrpc/config.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/google.golang.org/grpc/otelgrpc/config.go#L170-L171

Added lines #L170 - L171 were not covered by tests
}
}

// WithFilter returns an Option to use the request filter.
func WithFilter(f Filter) Option {
return filterOption{f: f}

Check warning on line 177 in instrumentation/google.golang.org/grpc/otelgrpc/config.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/google.golang.org/grpc/otelgrpc/config.go#L176-L177

Added lines #L176 - L177 were not covered by tests
}

type filterOption struct {
f Filter
}

func (o filterOption) apply(c *config) {

Check warning on line 184 in instrumentation/google.golang.org/grpc/otelgrpc/config.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/google.golang.org/grpc/otelgrpc/config.go#L184

Added line #L184 was not covered by tests
if o.f != nil {
c.Filter = o.f
}
Expand Down
Expand Up @@ -7,6 +7,8 @@ import (
"path"
"strings"

"google.golang.org/grpc/stats"

"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)

Expand All @@ -19,20 +21,8 @@ type gRPCPath struct {
// and returns as gRPCPath object that has divided service and method names
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
// If name is not FullMethod, returned gRPCPath has empty service field.
func splitFullMethod(i *otelgrpc.InterceptorInfo) gRPCPath {
var name string
switch i.Type {
case otelgrpc.UnaryServer:
name = i.UnaryServerInfo.FullMethod
case otelgrpc.StreamServer:
name = i.StreamServerInfo.FullMethod
case otelgrpc.UnaryClient, otelgrpc.StreamClient:
name = i.Method
default:
name = i.Method
}

s, m := path.Split(name)
func splitFullMethod(i *stats.RPCTagInfo) gRPCPath {
s, m := path.Split(i.FullMethodName)
if s != "" {
s = path.Clean(s)
s = strings.TrimLeft(s, "/")
Expand All @@ -47,7 +37,7 @@ func splitFullMethod(i *otelgrpc.InterceptorInfo) gRPCPath {
// Any takes a list of Filters and returns a Filter that
// returns true if any Filter in the list returns true.
func Any(fs ...otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
for _, f := range fs {
if f(i) {
return true
Expand All @@ -60,7 +50,7 @@ func Any(fs ...otelgrpc.Filter) otelgrpc.Filter {
// All takes a list of Filters and returns a Filter that
// returns true only if all Filters in the list return true.
func All(fs ...otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
for _, f := range fs {
if !f(i) {
return false
Expand All @@ -78,15 +68,15 @@ func None(fs ...otelgrpc.Filter) otelgrpc.Filter {

// Not provides a convenience mechanism for inverting a Filter.
func Not(f otelgrpc.Filter) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
return !f(i)
}
}

// MethodName returns a Filter that returns true if the request's
// method name matches the provided string n.
func MethodName(n string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return p.method == n
}
Expand All @@ -95,7 +85,7 @@ func MethodName(n string) otelgrpc.Filter {
// MethodPrefix returns a Filter that returns true if the request's
// method starts with the provided string pre.
func MethodPrefix(pre string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return strings.HasPrefix(p.method, pre)
}
Expand All @@ -105,26 +95,15 @@ func MethodPrefix(pre string) otelgrpc.Filter {
// full RPC method string, i.e. /package.service/method, starts with
// the provided string n.
func FullMethodName(n string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
var fm string
switch i.Type {
case otelgrpc.UnaryClient, otelgrpc.StreamClient:
fm = i.Method
case otelgrpc.UnaryServer:
fm = i.UnaryServerInfo.FullMethod
case otelgrpc.StreamServer:
fm = i.StreamServerInfo.FullMethod
default:
fm = i.Method
}
return fm == n
return func(i *stats.RPCTagInfo) bool {
return i.FullMethodName == n
}
}

// ServiceName returns a Filter that returns true if the request's
// service name, i.e. package.service, matches s.
func ServiceName(s string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return p.service == s
}
Expand All @@ -133,7 +112,7 @@ func ServiceName(s string) otelgrpc.Filter {
// ServicePrefix returns a Filter that returns true if the request's
// service name, i.e. package.service, starts with the provided string pre.
func ServicePrefix(pre string) otelgrpc.Filter {
return func(i *otelgrpc.InterceptorInfo) bool {
return func(i *stats.RPCTagInfo) bool {
p := splitFullMethod(i)
return strings.HasPrefix(p.service, pre)
}
Expand Down