From e972f2c98a6492be015ea8f95a820f1efc90eb33 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 30 Dec 2020 13:06:43 +0000 Subject: [PATCH] log: make it easier to add parameters to JSON logging --- fs/accounting/stats.go | 2 +- fs/log.go | 32 +++++++++++++++++++++++++------- fs/log_test.go | 24 +++++++++++++++++++++++- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/fs/accounting/stats.go b/fs/accounting/stats.go index dcd93d5ee..742a4ef6c 100644 --- a/fs/accounting/stats.go +++ b/fs/accounting/stats.go @@ -368,7 +368,7 @@ func (s *StatsInfo) Transferred() []TransferSnapshot { func (s *StatsInfo) Log() { if s.ci.UseJSONLog { out, _ := s.RemoteStats() - fs.LogLevelPrintf(s.ci.StatsLogLevel, nil, "%v%v\n", s, fs.LogValue("stats", out)) + fs.LogLevelPrintf(s.ci.StatsLogLevel, nil, "%v%v\n", s, fs.LogValueHide("stats", out)) } else { fs.LogLevelPrintf(s.ci.StatsLogLevel, nil, "%v\n", s) } diff --git a/fs/log.go b/fs/log.go index b7c16e290..1ded32694 100644 --- a/fs/log.go +++ b/fs/log.go @@ -77,8 +77,9 @@ var LogPrint = func(level LogLevel, text string) { // LogValueItem describes keyed item for a JSON log entry type LogValueItem struct { - key string - value interface{} + key string + value interface{} + render bool } // LogValue should be used as an argument to any logging calls to @@ -86,14 +87,31 @@ type LogValueItem struct { // // key is the dictionary parameter used to store value. func LogValue(key string, value interface{}) LogValueItem { - return LogValueItem{key: key, value: value} + return LogValueItem{key: key, value: value, render: true} } -// String returns an empty string so LogValueItem entries won't show -// in the textual representation of logs. They need to be put in so -// the number of parameters of the log call matches. +// LogValueHide should be used as an argument to any logging calls to +// augment the JSON output with more structured information. +// +// key is the dictionary parameter used to store value. +// +// String() will return a blank string - this is useful to put items +// in which don't print into the log. +func LogValueHide(key string, value interface{}) LogValueItem { + return LogValueItem{key: key, value: value, render: false} +} + +// String returns the representation of value. If render is fals this +// is an empty string so LogValueItem entries won't show in the +// textual representation of logs. func (j LogValueItem) String() string { - return "" + if !j.render { + return "" + } + if do, ok := j.value.(fmt.Stringer); ok { + return do.String() + } + return fmt.Sprint(j.value) } // LogPrintf produces a log string from the arguments passed in diff --git a/fs/log_test.go b/fs/log_test.go index 4e6d23f95..b3bddcef3 100644 --- a/fs/log_test.go +++ b/fs/log_test.go @@ -1,6 +1,28 @@ package fs -import "github.com/spf13/pflag" +import ( + "fmt" + "testing" + + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" +) // Check it satisfies the interface var _ pflag.Value = (*LogLevel)(nil) +var _ fmt.Stringer = LogValueItem{} + +type withString struct{} + +func (withString) String() string { + return "hello" +} + +func TestLogValue(t *testing.T) { + x := LogValue("x", 1) + assert.Equal(t, "1", x.String()) + x = LogValue("x", withString{}) + assert.Equal(t, "hello", x.String()) + x = LogValueHide("x", withString{}) + assert.Equal(t, "", x.String()) +}