github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/middleware/logging/context.go (about) 1 package logging 2 3 import ( 4 "context" 5 "strings" 6 7 log "github.com/authzed/spicedb/internal/logging" 8 9 "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors" 10 "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" 11 "google.golang.org/grpc" 12 "google.golang.org/grpc/metadata" 13 ) 14 15 // FieldSpec provides a mapping between a metadata context field and a logging field. 16 type FieldSpec struct { 17 metadataKey string 18 tagKey string 19 } 20 21 // ExtractMetadataField creates a specification for converting gRPC metadata fields 22 // to log tags. 23 func ExtractMetadataField(metadataKey, tagKey string) FieldSpec { 24 return FieldSpec{metadataKey, tagKey} 25 } 26 27 type extractMetadata struct { 28 fields []FieldSpec 29 } 30 31 func (r *extractMetadata) ServerReporter(ctx context.Context, _ interceptors.CallMeta) (interceptors.Reporter, context.Context) { 32 md, ok := metadata.FromIncomingContext(ctx) 33 if ok { 34 fields := logging.Fields{} 35 logContext := log.With() 36 for _, field := range r.fields { 37 value, ok := md[field.metadataKey] 38 if ok { 39 joinedValue := strings.Join(value, ",") 40 fields = append(fields, field.tagKey) 41 fields = append(fields, joinedValue) 42 logContext = logContext.Str(field.tagKey, joinedValue) 43 } 44 } 45 46 ctx = logging.InjectFields(ctx, fields) 47 loggerForContext := logContext.Logger() 48 ctx = loggerForContext.WithContext(ctx) 49 } 50 51 return interceptors.NoopReporter{}, ctx 52 } 53 54 // UnaryServerInterceptor creates an interceptor for extracting fields from requests 55 // and setting them as log tags. 56 func UnaryServerInterceptor(fields ...FieldSpec) grpc.UnaryServerInterceptor { 57 return interceptors.UnaryServerInterceptor(&extractMetadata{fields}) 58 } 59 60 // StreamServerInterceptor creates an interceptor for extracting fields from requests 61 // and setting them as log tags. 62 func StreamServerInterceptor(fields ...FieldSpec) grpc.StreamServerInterceptor { 63 return interceptors.StreamServerInterceptor(&extractMetadata{fields}) 64 }