github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/middleware/grpc_logging.go (about)

     1  package middleware
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"golang.org/x/net/context"
     8  	"google.golang.org/grpc"
     9  
    10  	grpcUtils "github.com/weaveworks/common/grpc"
    11  	"github.com/weaveworks/common/logging"
    12  	"github.com/weaveworks/common/user"
    13  )
    14  
    15  const (
    16  	gRPC     = "gRPC"
    17  	errorKey = "err"
    18  )
    19  
    20  // An error can implement ShouldLog() to control whether GRPCServerLog will log.
    21  type OptionalLogging interface {
    22  	ShouldLog(ctx context.Context, duration time.Duration) bool
    23  }
    24  
    25  // GRPCServerLog logs grpc requests, errors, and latency.
    26  type GRPCServerLog struct {
    27  	Log logging.Interface
    28  	// WithRequest will log the entire request rather than just the error
    29  	WithRequest              bool
    30  	DisableRequestSuccessLog bool
    31  }
    32  
    33  // UnaryServerInterceptor returns an interceptor that logs gRPC requests
    34  func (s GRPCServerLog) UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    35  	begin := time.Now()
    36  	resp, err := handler(ctx, req)
    37  	if err == nil && s.DisableRequestSuccessLog {
    38  		return resp, nil
    39  	}
    40  	var optional OptionalLogging
    41  	if errors.As(err, &optional) && !optional.ShouldLog(ctx, time.Since(begin)) {
    42  		return resp, err
    43  	}
    44  
    45  	entry := user.LogWith(ctx, s.Log).WithFields(logging.Fields{"method": info.FullMethod, "duration": time.Since(begin)})
    46  	if err != nil {
    47  		if s.WithRequest {
    48  			entry = entry.WithField("request", req)
    49  		}
    50  		if grpcUtils.IsCanceled(err) {
    51  			entry.WithField(errorKey, err).Debugln(gRPC)
    52  		} else {
    53  			entry.WithField(errorKey, err).Warnln(gRPC)
    54  		}
    55  	} else {
    56  		entry.Debugf("%s (success)", gRPC)
    57  	}
    58  	return resp, err
    59  }
    60  
    61  // StreamServerInterceptor returns an interceptor that logs gRPC requests
    62  func (s GRPCServerLog) StreamServerInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    63  	begin := time.Now()
    64  	err := handler(srv, ss)
    65  	if err == nil && s.DisableRequestSuccessLog {
    66  		return nil
    67  	}
    68  
    69  	entry := user.LogWith(ss.Context(), s.Log).WithFields(logging.Fields{"method": info.FullMethod, "duration": time.Since(begin)})
    70  	if err != nil {
    71  		if grpcUtils.IsCanceled(err) {
    72  			entry.WithField(errorKey, err).Debugln(gRPC)
    73  		} else {
    74  			entry.WithField(errorKey, err).Warnln(gRPC)
    75  		}
    76  	} else {
    77  		entry.Debugf("%s (success)", gRPC)
    78  	}
    79  	return err
    80  }