Skip to content

Commit

Permalink
add build tag to disable tracing (#754)
Browse files Browse the repository at this point in the history
* add build tag to disable tracing

* add new build tag `-build=retrynotrace` to support dead code elimination

* fix copyright headers

* Update interceptors/retry/trace_notrace.go

Co-authored-by: Johan Brandhorst-Satzkorn <[email protected]>

* add interceptors/retry/README.md

---------

Co-authored-by: Johan Brandhorst-Satzkorn <[email protected]>
  • Loading branch information
rashmi-tondare and johanbrandhorst authored Mar 4, 2025
1 parent 8b26373 commit 509959f
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 2 deletions.
49 changes: 49 additions & 0 deletions interceptors/retry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Retry Interceptor

The `retry` interceptor is a client-side middleware for gRPC that provides a generic mechanism to retry requests based on gRPC response codes.

### Build Flags

The `retry` interceptor supports a build flag `retrynotrace` to disable tracing for retry attempts.
This can be useful to avoid importing `golang.org/x/net/trace`, which allows for more aggressive deadcode elimination. This can yield improvements in binary size when tracing is not needed.

To build your application with the `retrynotrace` flag, use the following command:

```shell
go build -tags retrynotrace -o your_application
```

### Usage

To use the `retry` interceptor, you need to add it to your gRPC client interceptor chain:

```go
import (
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
"google.golang.org/grpc"
)

func main() {
opts := []grpc.DialOption{
grpc.WithUnaryInterceptor(retry.UnaryClientInterceptor(
retry.WithMax(3), // Maximum number of retries
retry.WithPerRetryTimeout(2*time.Second), // Timeout per retry
)),
}

conn, err := grpc.NewClient("your_grpc_server_address", opts...)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()

// Your gRPC client code here
}
```

### Configuration Options

- `retry.WithMax(maxRetries int)`: Sets the maximum number of retry attempts.
- `retry.WithPerRetryTimeout(timeout time.Duration)`: Sets the timeout for each retry attempt.
- `retry.WithBackoff(backoffFunc retry.BackoffFunc)`: Sets a custom backoff strategy.
- `retry.WithCodes(codes ...codes.Code)`: Specifies the gRPC response codes that should trigger a retry.
3 changes: 1 addition & 2 deletions interceptors/retry/retry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"time"

"github.com/grpc-ecosystem/go-grpc-middleware/v2/metadata"
"golang.org/x/net/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
grpcMetadata "google.golang.org/grpc/metadata"
Expand Down Expand Up @@ -320,7 +319,7 @@ func contextErrToGrpcErr(err error) error {
}

func logTrace(ctx context.Context, format string, a ...any) {
tr, ok := trace.FromContext(ctx)
tr, ok := traceFromCtx(ctx)
if !ok {
return
}
Expand Down
29 changes: 29 additions & 0 deletions interceptors/retry/trace_notrace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.

//go:build retrynotrace

package retry

// retrynotrace can be used to avoid importing golang.org/x/net/trace,
// which allows for more aggressive deadcode elimination, which can
// yield improvements in binary size when tracing is not needed.

import (
"context"
"fmt"
)

type notrace struct{}

func (notrace) LazyLog(x fmt.Stringer, sensitive bool) {}
func (notrace) LazyPrintf(format string, a ...any) {}
func (notrace) SetError() {}
func (notrace) SetRecycler(f func(any)) {}
func (notrace) SetTraceInfo(traceID, spanID uint64) {}
func (notrace) SetMaxEvents(m int) {}
func (notrace) Finish() {}

func traceFromCtx(ctx context.Context) (notrace, bool) {
return notrace{}, true
}
42 changes: 42 additions & 0 deletions interceptors/retry/trace_notrace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.

//go:build retrynotrace

package retry

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_traceFromCtx(t *testing.T) {
tr := notrace{}
ctx := context.Background()

type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
want notrace
want1 bool
}{
{
name: "should return notrace",
args: args{ctx: ctx},
want: tr,
want1: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := traceFromCtx(tt.args.ctx)
assert.Equalf(t, tt.want, got, "traceFromCtx(%v)", tt.args.ctx)
assert.Equalf(t, tt.want1, got1, "traceFromCtx(%v)", tt.args.ctx)
})
}
}
16 changes: 16 additions & 0 deletions interceptors/retry/trace_withtrace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.

//go:build !retrynotrace

package retry

import (
"context"

t "golang.org/x/net/trace"
)

func traceFromCtx(ctx context.Context) (t.Trace, bool) {
return t.FromContext(ctx)
}
49 changes: 49 additions & 0 deletions interceptors/retry/trace_withtrace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.

//go:build !retrynotrace

package retry

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"golang.org/x/net/trace"
)

func Test_traceFromCtx(t *testing.T) {
tr := trace.New("test", "with trace")
ctx := trace.NewContext(context.Background(), tr)

type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
want trace.Trace
want1 bool
}{
{
name: "should return trace",
args: args{ctx: ctx},
want: tr,
want1: true,
},
{
name: "should return false if trace not found in ctx",
args: args{ctx: context.Background()},
want: nil,
want1: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := traceFromCtx(tt.args.ctx)
assert.Equalf(t, tt.want, got, "traceFromCtx(%v)", tt.args.ctx)
assert.Equalf(t, tt.want1, got1, "traceFromCtx(%v)", tt.args.ctx)
})
}
}

0 comments on commit 509959f

Please sign in to comment.