Skip to content

Commit

Permalink
Add debug logging interceptor for RPC logs (#3496)
Browse files Browse the repository at this point in the history
Co-authored-by: Edward McFarlane <[email protected]>
  • Loading branch information
doriable and emcfarlane authored Nov 25, 2024
1 parent 3623d54 commit 1d8835c
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
1 change: 1 addition & 0 deletions private/buf/bufcli/connectclient_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func newConnectClientConfigWithOptions(container appext.Container, opts ...conne
bufconnect.NewAugmentedConnectErrorInterceptor(),
bufconnect.NewSetCLIVersionInterceptor(Version),
bufconnect.NewCLIWarningInterceptor(container),
bufconnect.NewDebugLoggingInterceptor(container),
otelconnectInterceptor,
},
),
Expand Down
54 changes: 54 additions & 0 deletions private/bufpkg/bufconnect/interceptors.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"strings"
"time"

"connectrpc.com/connect"
"github.com/bufbuild/buf/private/pkg/app/appext"
"google.golang.org/protobuf/proto"
)

const (
Expand Down Expand Up @@ -140,3 +144,53 @@ func NewAuthorizationInterceptorProvider(tokenProviders ...TokenProvider) func(s
return interceptor
}
}

// NewDebugLoggingInterceptor returns a new Connect Interceptor that adds debug log
// statements for each rpc call.
//
// The following information is collected for logging: duration, status code, peer name,
// rpc system, request size, and response size.
func NewDebugLoggingInterceptor(container appext.LoggerContainer) connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
var requestSize int
if req.Any() != nil {
msg, ok := req.Any().(proto.Message)
if ok {
requestSize = proto.Size(msg)
}
}
startTime := time.Now()
resp, err := next(ctx, req)
duration := time.Since(startTime)
var status connect.Code
if err != nil {
status = connect.CodeOf(err)
}
var responseSize int
if resp != nil && resp.Any() != nil {
msg, ok := resp.Any().(proto.Message)
if ok {
responseSize = proto.Size(msg)
}
}
attrs := []slog.Attr{
slog.Duration("duration", duration),
slog.String("status", status.String()),
slog.String("net.peer.name", req.Peer().Addr),
slog.String("rpc.system", req.Peer().Protocol),
slog.Int("message.sent.uncompressed_size", requestSize),
slog.Int("message.received.uncompressed_size", responseSize),
}
container.Logger().LogAttrs(
ctx,
slog.LevelDebug,
// Remove the leading "/" from Procedure name
strings.TrimPrefix(req.Spec().Procedure, "/"),
attrs...,
)
return resp, err
}
}
return interceptor
}

0 comments on commit 1d8835c

Please sign in to comment.