Skip to content

Commit

Permalink
Add request id to logs.
Browse files Browse the repository at this point in the history
This change adds a GRPC interceptor that fetches the header
`Grpc-Metadata-Request-Id` and adds it to the logger. It also returns
the request id to the client in the trailer, which is helpful for
debugging.

CLI command `minder history list` was modified to show its usage, but
those changes should be reverted.
  • Loading branch information
blkt committed Sep 12, 2024
1 parent 5d2e740 commit 9d1d981
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 1 deletion.
9 changes: 8 additions & 1 deletion cmd/cli/app/history/history_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import (
"strings"
"time"

"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/stacklok/minder/cmd/cli/app"
Expand Down Expand Up @@ -116,7 +118,12 @@ func listCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grpc
req.To = timestamppb.New(to)
}

resp, err := client.ListEvaluationHistory(ctx, req)
rID := uuid.New().String()
md := metadata.Pairs("request-id", rID)
ctx = metadata.NewOutgoingContext(ctx, md)

var header, trailer metadata.MD
resp, err := client.ListEvaluationHistory(ctx, req, grpc.Header(&header), grpc.Trailer(&trailer))
if err != nil {
return cli.MessageAndError("Error getting profile status", err)
}
Expand Down
1 change: 1 addition & 0 deletions internal/controlplane/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ func (s *Server) StartGRPCServer(ctx context.Context) error {
// TODO: this has no test coverage!
util.SanitizingInterceptor(),
logger.Interceptor(s.cfg.LoggingConfig),
logger.RequestIDInterceptor(),
TokenValidationInterceptor,
EntityContextProjectInterceptor,
ProjectAuthorizationInterceptor,
Expand Down
43 changes: 43 additions & 0 deletions internal/logger/logging_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"path"
"time"

"github.com/google/uuid"
"github.com/rs/zerolog"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
Expand Down Expand Up @@ -101,3 +102,45 @@ func Interceptor(cfg config.LoggingConfig) grpc.UnaryServerInterceptor {
return resp, err
}
}

// RequestIDInterceptor traces request ids.
//
// It tries to use the request id from the request context, creating a
// new one if that is missing. It also sends back in the trailer the
// request id, ensuring that the client receives it.
func RequestIDInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
rID := maybeGetRequestID(ctx)
ctx = zerolog.Ctx(ctx).With().Str("request_id", rID).Logger().WithContext(ctx)

resp, err := handler(ctx, req)

if err := grpc.SetTrailer(ctx, metadata.Pairs("request-id", rID)); err != nil {
zerolog.Ctx(ctx).Trace().Err(err).Msg("unable to attach request id to trailer")
}

return resp, err
}
}

func maybeGetRequestID(ctx context.Context) string {
var rID string
if md, ok := metadata.FromIncomingContext(ctx); ok {
if rIDs, ok := md["request-id"]; ok {
if len(rIDs) != 0 {
rID = rIDs[0]
}
}
}

if rID == "" {
return uuid.New().String()
}

if _, err := uuid.Parse(rID); err != nil {
zerolog.Ctx(ctx).Trace().Err(err).Msg("request id is not valid uuid")
return uuid.New().String()
}

return rID
}

0 comments on commit 9d1d981

Please sign in to comment.