Skip to content

Commit e696b76

Browse files
Add logging option to disable fields in log entry (#631)
* add option to choose grpc log fields Signed-off-by: Coleen Iona Quadros <[email protected]> * test changes Signed-off-by: Coleen Iona Quadros <[email protected]> * use existing func Signed-off-by: Coleen Iona Quadros <[email protected]> * lint Signed-off-by: Coleen Iona Quadros <[email protected]> * refactor Signed-off-by: Coleen Iona Quadros <[email protected]> * refactor adding log fields Signed-off-by: Coleen Iona Quadros <[email protected]> * change to disable logging fields Signed-off-by: Coleen Iona Quadros <[email protected]> * refactor and add comment Signed-off-by: Coleen Iona Quadros <[email protected]> * comment Signed-off-by: Coleen Iona Quadros <[email protected]> * refactor deleting Signed-off-by: Coleen Iona Quadros <[email protected]> * Update interceptors/logging/logging.go Co-authored-by: Johan Brandhorst-Satzkorn <[email protected]> * add test case for Delete(k string) --------- Signed-off-by: Coleen Iona Quadros <[email protected]> Co-authored-by: Johan Brandhorst-Satzkorn <[email protected]>
1 parent 96ef884 commit e696b76

File tree

7 files changed

+207
-8
lines changed

7 files changed

+207
-8
lines changed

interceptors/logging/examples/go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/rs/zerolog v1.29.0
1111
github.com/sirupsen/logrus v1.9.0
1212
go.uber.org/zap v1.24.0
13-
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
13+
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
1414
google.golang.org/grpc v1.53.0
1515
k8s.io/klog/v2 v2.90.1
1616
)
@@ -22,11 +22,11 @@ require (
2222
github.com/mattn/go-isatty v0.0.14 // indirect
2323
go.uber.org/atomic v1.7.0 // indirect
2424
go.uber.org/multierr v1.6.0 // indirect
25-
golang.org/x/net v0.8.0 // indirect
26-
golang.org/x/sys v0.6.0 // indirect
27-
golang.org/x/text v0.8.0 // indirect
25+
golang.org/x/net v0.14.0 // indirect
26+
golang.org/x/sys v0.11.0 // indirect
27+
golang.org/x/text v0.12.0 // indirect
2828
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
29-
google.golang.org/protobuf v1.30.0 // indirect
29+
google.golang.org/protobuf v1.31.0 // indirect
3030
)
3131

3232
replace github.com/grpc-ecosystem/go-grpc-middleware/v2 => ../../../

interceptors/logging/examples/go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,19 @@ go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
4444
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
4545
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
4646
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
47+
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
4748
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
4849
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
50+
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
4951
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5052
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5153
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5254
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
5355
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
56+
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5457
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
5558
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
59+
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
5660
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
5761
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
5862
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
@@ -62,6 +66,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
6266
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
6367
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
6468
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
69+
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
6570
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
6671
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6772
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

interceptors/logging/interceptors.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ func reportable(logger Logger, opts *options) interceptors.CommonReportableFunc
142142
}
143143

144144
// Field dups from context override the common fields.
145-
fields := newCommonFields(kind, c).WithUnique(ExtractFields(ctx))
145+
fields := newCommonFields(kind, c)
146+
if opts.disableGrpcLogFields != nil {
147+
fields = disableCommonLoggingFields(kind, c, opts.disableGrpcLogFields)
148+
}
149+
fields = fields.WithUnique(ExtractFields(ctx))
150+
146151
if !c.IsClient {
147152
if peer, ok := peer.FromContext(ctx); ok {
148153
fields = append(fields, "peer.address", peer.Addr.String())

interceptors/logging/interceptors_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,149 @@ func (s *loggingPayloadSuite) assertPayloadLogLinesForMessage(lines LogLines, me
630630
}
631631
}
632632

633+
type loggingCustomGrpcLogFieldsSuite struct {
634+
*baseLoggingSuite
635+
}
636+
637+
func TestCustomGrpcLogFieldsSuite(t *testing.T) {
638+
if strings.HasPrefix(runtime.Version(), "go1.7") {
639+
t.Skipf("Skipping due to json.RawMessage incompatibility with go1.7")
640+
return
641+
}
642+
s := &loggingCustomGrpcLogFieldsSuite{
643+
baseLoggingSuite: &baseLoggingSuite{
644+
logger: newMockLogger(),
645+
InterceptorTestSuite: &testpb.InterceptorTestSuite{
646+
TestService: &testpb.TestPingService{},
647+
},
648+
},
649+
}
650+
s.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
651+
grpc.WithUnaryInterceptor(logging.UnaryClientInterceptor(s.logger, logging.WithDisableLoggingFields(logging.ComponentFieldKey, logging.MethodTypeFieldKey, logging.SystemTag[0], "custom-field-should-be-ignored"))),
652+
grpc.WithStreamInterceptor(logging.StreamClientInterceptor(s.logger, logging.WithDisableLoggingFields(logging.ComponentFieldKey, logging.MethodTypeFieldKey, logging.SystemTag[0], "custom-field-should-be-ignored"))),
653+
}
654+
s.InterceptorTestSuite.ServerOpts = []grpc.ServerOption{
655+
grpc.StreamInterceptor(logging.StreamServerInterceptor(s.logger, logging.WithDisableLoggingFields(logging.ComponentFieldKey, logging.MethodTypeFieldKey, logging.SystemTag[0], "custom-field-should-be-ignored"))),
656+
grpc.UnaryInterceptor(logging.UnaryServerInterceptor(s.logger, logging.WithDisableLoggingFields(logging.ComponentFieldKey, logging.MethodTypeFieldKey, logging.SystemTag[0], "custom-field-should-be-ignore"))),
657+
}
658+
suite.Run(t, s)
659+
}
660+
661+
// Test that fields are added to logs using withGrpcLogFields.
662+
func (s *loggingCustomGrpcLogFieldsSuite) TestCustomGrpcLogFieldsWithPing() {
663+
_, err := s.Client.Ping(s.SimpleCtx(), testpb.GoodPing)
664+
assert.NoError(s.T(), err, "there must be not be an on a successful call")
665+
666+
lines := s.logger.o.Lines()
667+
sort.Sort(lines)
668+
require.Len(s.T(), lines, 4)
669+
670+
clientStartCallLogLine := lines[2]
671+
assert.Equal(s.T(), logging.LevelDebug, clientStartCallLogLine.lvl)
672+
assert.Equal(s.T(), "started call", clientStartCallLogLine.msg)
673+
clientStartCallFields := clientStartCallLogLine.fields
674+
clientStartCallFields.AssertFieldNotEmpty(s.T(), "grpc.start_time").
675+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
676+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
677+
AssertField(s.T(), logging.MethodFieldKey, "Ping").
678+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
679+
680+
serverStartCallLogLine := lines[3]
681+
assert.Equal(s.T(), logging.LevelInfo, serverStartCallLogLine.lvl)
682+
assert.Equal(s.T(), "started call", serverStartCallLogLine.msg)
683+
serverStartCallFields := serverStartCallLogLine.fields
684+
serverStartCallFields.AssertFieldNotEmpty(s.T(), "peer.address").
685+
AssertFieldNotEmpty(s.T(), "grpc.start_time").
686+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
687+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
688+
AssertField(s.T(), logging.MethodFieldKey, "Ping").
689+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
690+
691+
serverFinishCallLogLine := lines[0]
692+
assert.Equal(s.T(), logging.LevelInfo, serverFinishCallLogLine.lvl)
693+
assert.Equal(s.T(), "finished call", serverFinishCallLogLine.msg)
694+
serverFinishCallFields := serverFinishCallLogLine.fields
695+
serverFinishCallFields.AssertFieldNotEmpty(s.T(), "peer.address").
696+
AssertFieldNotEmpty(s.T(), "grpc.start_time").
697+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
698+
AssertField(s.T(), "grpc.code", "OK").
699+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
700+
AssertField(s.T(), logging.MethodFieldKey, "Ping").
701+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
702+
703+
clientFinishCallLogLine := lines[1]
704+
assert.Equal(s.T(), logging.LevelDebug, clientFinishCallLogLine.lvl)
705+
assert.Equal(s.T(), "finished call", clientFinishCallLogLine.msg)
706+
707+
clientFinishCallFields := clientFinishCallLogLine.fields
708+
clientFinishCallFields.AssertFieldNotEmpty(s.T(), "grpc.start_time").
709+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
710+
AssertField(s.T(), "grpc.code", "OK").
711+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
712+
AssertField(s.T(), logging.MethodFieldKey, "Ping").
713+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
714+
}
715+
716+
func (s *loggingCustomGrpcLogFieldsSuite) TestCustomGrpcLogFieldsWithPingList() {
717+
stream, err := s.Client.PingList(s.SimpleCtx(), testpb.GoodPingList)
718+
require.NoError(s.T(), err, "should not fail on establishing the stream")
719+
for {
720+
_, err := stream.Recv()
721+
if err == io.EOF {
722+
break
723+
}
724+
require.NoError(s.T(), err, "reading stream should not fail")
725+
}
726+
lines := s.logger.o.Lines()
727+
sort.Sort(lines)
728+
require.Len(s.T(), lines, 4)
729+
730+
clientStartCallLogLine := lines[2]
731+
assert.Equal(s.T(), logging.LevelDebug, clientStartCallLogLine.lvl)
732+
assert.Equal(s.T(), "started call", clientStartCallLogLine.msg)
733+
clientStartCallFields := clientStartCallLogLine.fields
734+
clientStartCallFields.AssertFieldNotEmpty(s.T(), "grpc.start_time").
735+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
736+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
737+
AssertField(s.T(), logging.MethodFieldKey, "PingList").
738+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
739+
740+
serverStartCallLogLine := lines[3]
741+
assert.Equal(s.T(), logging.LevelInfo, serverStartCallLogLine.lvl)
742+
assert.Equal(s.T(), "started call", serverStartCallLogLine.msg)
743+
serverStartCallFields := serverStartCallLogLine.fields
744+
serverStartCallFields.AssertFieldNotEmpty(s.T(), "peer.address").
745+
AssertFieldNotEmpty(s.T(), "grpc.start_time").
746+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
747+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
748+
AssertField(s.T(), logging.MethodFieldKey, "PingList").
749+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
750+
751+
serverFinishCallLogLine := lines[0]
752+
assert.Equal(s.T(), logging.LevelInfo, serverFinishCallLogLine.lvl)
753+
assert.Equal(s.T(), "finished call", serverFinishCallLogLine.msg)
754+
serverFinishCallFields := serverFinishCallLogLine.fields
755+
serverFinishCallFields.AssertFieldNotEmpty(s.T(), "peer.address").
756+
AssertFieldNotEmpty(s.T(), "grpc.start_time").
757+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
758+
AssertField(s.T(), "grpc.code", "OK").
759+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
760+
AssertField(s.T(), logging.MethodFieldKey, "PingList").
761+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
762+
763+
clientFinishCallLogLine := lines[1]
764+
assert.Equal(s.T(), logging.LevelDebug, clientFinishCallLogLine.lvl)
765+
assert.Equal(s.T(), "finished call", clientFinishCallLogLine.msg)
766+
767+
clientFinishCallFields := clientFinishCallLogLine.fields
768+
clientFinishCallFields.AssertFieldNotEmpty(s.T(), "grpc.start_time").
769+
AssertFieldNotEmpty(s.T(), "grpc.request.deadline").
770+
AssertField(s.T(), "grpc.code", "OK").
771+
AssertFieldNotEmpty(s.T(), "grpc.time_ms").
772+
AssertField(s.T(), logging.MethodFieldKey, "PingList").
773+
AssertField(s.T(), logging.ServiceFieldKey, testpb.TestServiceFullName).AssertNoMoreTags(s.T())
774+
}
775+
633776
// waitUntil executes f every interval seconds until timeout or no error is returned from f.
634777
func waitUntil(interval time.Duration, stopc <-chan struct{}, f func() error) error {
635778
tick := time.NewTicker(interval)

interceptors/logging/logging.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ func newCommonFields(kind string, c interceptors.CallMeta) Fields {
3838
}
3939
}
4040

41+
// disableCommonLoggingFields returns copy of newCommonFields with disabled fields removed from the following
42+
// default list. The following are the default logging fields:
43+
// - SystemTag[0]
44+
// - ComponentFieldKey
45+
// - ServiceFieldKey
46+
// - MethodFieldKey
47+
// - MethodTypeFieldKey
48+
func disableCommonLoggingFields(kind string, c interceptors.CallMeta, disableFields []string) Fields {
49+
commonFields := newCommonFields(kind, c)
50+
for _, key := range disableFields {
51+
commonFields.Delete(key)
52+
}
53+
return commonFields
54+
}
55+
4156
// Fields loosely represents key value pairs that adds context to log lines. The key has to be type of string, whereas
4257
// value can be an arbitrary object.
4358
type Fields []any
@@ -76,6 +91,18 @@ func (i *iter) At() (k string, v any) {
7691
return i.f[i.i].(string), i.f[i.i+1]
7792
}
7893

94+
func (f *Fields) Delete(key string) {
95+
i := f.Iterator()
96+
for i.Next() {
97+
k, _ := i.At()
98+
if k != key {
99+
continue
100+
}
101+
*f = append((*f)[:i.i], (*f)[i.i+2:]...)
102+
return
103+
}
104+
}
105+
79106
// WithUnique returns copy of fields which is the union of all unique keys.
80107
// Any duplicates in the added or current fields will be deduplicated where first occurrence takes precedence.
81108
func (f Fields) WithUnique(add Fields) Fields {

interceptors/logging/logging_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ func TestFieldsInjectExtractFromContext(t *testing.T) {
3939
f = ExtractFields(c3)
4040
require.Equal(t, Fields{"a", "changed", "b", "2"}, f)
4141
}
42+
43+
func TestFieldsDelete(t *testing.T) {
44+
f := Fields{"a", "1", "b", "2"}
45+
f.Delete("a")
46+
require.Equal(t, Fields{"b", "2"}, f)
47+
f.Delete("b")
48+
require.Equal(t, Fields{}, f)
49+
f.Delete("c")
50+
require.Equal(t, Fields{}, f)
51+
}

interceptors/logging/options.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ var (
4848
codeFunc: DefaultErrorToCode,
4949
durationFieldFunc: DefaultDurationToFields,
5050
// levelFunc depends if it's client or server.
51-
levelFunc: nil,
52-
timestampFormat: time.RFC3339,
51+
levelFunc: nil,
52+
timestampFormat: time.RFC3339,
53+
disableGrpcLogFields: nil,
5354
}
5455
)
5556

@@ -60,6 +61,7 @@ type options struct {
6061
durationFieldFunc DurationToFields
6162
timestampFormat string
6263
fieldsFromCtxCallMetaFn fieldsFromCtxCallMetaFn
64+
disableGrpcLogFields []string
6365
}
6466

6567
type Option func(*options)
@@ -204,3 +206,10 @@ func WithTimestampFormat(format string) Option {
204206
o.timestampFormat = format
205207
}
206208
}
209+
210+
// WithDisableLoggingFields disables logging of gRPC fields provided.
211+
func WithDisableLoggingFields(disableGrpcLogFields ...string) Option {
212+
return func(o *options) {
213+
o.disableGrpcLogFields = disableGrpcLogFields
214+
}
215+
}

0 commit comments

Comments
 (0)