I'm a bit lost; help me figure out this. Im trying to add some extra data (like User ID) to a context that I will use later in the log interceptor.
here is how my gRPC call looks like
import (
"context"
"yourpbpackage/pb"
)
func (s *YourGRPCServer) SomeGRPCFunction(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) {
// Add user ID to the context
userID := "12345" // This would be dynamically determined, for example from the request
ctx = context.WithValue(ctx, userIDKey, userID) // HERE IM ADDING METADATA
// Process and return the response
return &pb.YourResponse{}, nil
}
here in interceptor Im trying to catch user ID
func GRPCLogger(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
// Invoke the handler with the modified context
resp, err = handler(ctx, req)
// Now retrieve user ID from the context after the handler has modified it
if userID, ok := ctx.Value(userIDKey).(string); ok {
log.Info().Str("userID", userID).Msg("User ID from handler context in interceptor")
}
return resp, err
}
here is code how I use interceptor
func runGrpcServer(conf util.Config, store db.Store, taskDistributor worker.TaskDistributor, authClient auth.AuthClient, logClient logsrv.LogClient) {
server, err := gapi.NewServer(conf, store, taskDistributor, authClient)
if err != nil {
log.Fatal().Err(err).Msg("cannot create server")
}
grpLogger := grpc.UnaryInterceptor(gapi.GRPCLogger)
grpcServer := grpc.NewServer(grpLogger)
pb.RegisterStoneServer(grpcServer, server)
reflection.Register(grpcServer)
listener, err := net.Listen("tcp", conf.GRPCServerAddress)
if err != nil {
log.Fatal().Err(err).Msg("cannot create listener")
}
log.Info().Msgf("start gRPC server at %s", listener.Addr().String())
err = grpcServer.Serve(listener)
if err != nil {
log.Fatal().Err(err).Msg("cannot start gRPC server:")
}
}
Any suggestions what it could be ? where I'm wrong ?
I tried to modify context with values context.WithValue(ctx, userIDKey, userID) or set headers. If I set the header i can see it ctx.val (*transport.Stream) but I can't extract it from there
When you add a value to a context, you receive a new context containing that value and wrapping the old context. The old context does not know anything about that value.
One way to achieve what you are trying to do is to prepare the context in the interceptor so that the handler can modify it:
type HandlerData struct {
UserID string
...
}
func GRPCLogger(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
// Prepare the context with a writable struct
handlerData:=&HandlerData{}
newCtx:=context.WithValue(ctx,key, handlerData)
// Invoke the handler with the modified context
resp, err = handler(newCtx, req)
// Now retrieve user ID from
if handlerData.UserID!="" {
// Work with it
}
return resp, err
}
In your grpc handler:
func (s *YourGRPCServer) SomeGRPCFunction(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) {
handlerData,_:=ctx.Value(key).(*HandlerData)
if handlerData!=nil {
// Add user ID to the context
handlerData.UserID := "12345" METADATA
}
// Process and return the response
return &pb.YourResponse{}, nil
}