Repository: scionproto/scion
Pull request #3816 (2020-07-03 12:21:59)

log: add json logging
Add JSON format to set of supported logging output formats.

It can be enabled by setting `log.console.format` and/or `log.file.format`
to `json`. The default remains the structured `human`-readable approach.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3816)
<!-- Reviewable:end -->



Patch:
diff --git a/go/lib/log/config.go b/go/lib/log/config.go
index 476a3111d..313107495 100644
--- a/go/lib/log/config.go
+++ b/go/lib/log/config.go
@@ -17,6 +17,7 @@ package log
 import (
 	"fmt"
 	"io"
+	"strings"
 
 	"github.com/scionproto/scion/go/lib/config"
 )
@@ -92,6 +93,8 @@ type FileConfig struct {
 	FlushInterval *uint `toml:"flush_interval,omitempty"`
 	// Compress can be set to enable rotated file compression.
 	Compress bool `toml:"compress,omitempty"`
+	// Format of the file logging. (human|json)
+	Format string `toml:"format,omitempty"`
 }
 
 // InitDefaults populates unset fields in cfg to their default values (if they
@@ -113,12 +116,17 @@ func (c *FileConfig) InitDefaults() {
 		s := DefaultFileFlushSeconds
 		c.FlushInterval = &s
 	}
+	if !strings.EqualFold(c.Format, "json") {
+		c.Format = "human"
+	}
 }
 
 // ConsoleConfig is the config for the console logger.
 type ConsoleConfig struct {
 	// Level of console logging (defaults to DefaultConsoleLevel).
 	Level string `toml:"level,omitempty"`
+	// Format of the console logging. (human|json)
+	Format string `toml:"format,omitempty"`
 }
 
 // InitDefaults populates unset fields in cfg to their default values (if they
@@ -127,4 +135,7 @@ func (c *ConsoleConfig) InitDefaults() {
 	if c.Level == "" {
 		c.Level = DefaultConsoleLevel
 	}
+	if !strings.EqualFold(c.Format, "json") {
+		c.Format = "human"
+	}
 }
diff --git a/go/lib/log/log.go b/go/lib/log/log.go
index 9d2e443a0..02326e941 100644
--- a/go/lib/log/log.go
+++ b/go/lib/log/log.go
@@ -20,6 +20,7 @@ import (
 	"os"
 	"path/filepath"
 	"runtime/debug"
+	"strings"
 	"time"
 
 	"github.com/inconshreveable/log15"
@@ -81,8 +82,11 @@ func setupFile(cfg FileConfig) (log15.Handler, error) {
 		logBuf = newSyncBuf(logger)
 		logger = logBuf
 	}
-
-	handler := log15.LvlFilterHandler(logLvl, log15.StreamHandler(logger, fmt15.Fmt15Format(nil)))
+	format := fmt15.Fmt15Format(nil)
+	if strings.EqualFold(cfg.Format, "json") {
+		format = log15.JsonFormat()
+	}
+	handler := log15.LvlFilterHandler(logLvl, log15.StreamHandler(logger, format))
 
 	if cfg.FlushInterval != nil && *cfg.FlushInterval > 0 {
 		go func() {
@@ -104,7 +108,11 @@ func setupConsole(cfg ConsoleConfig) (log15.Handler, error) {
 	if isatty.IsTerminal(os.Stderr.Fd()) {
 		cMap = fmt15.ColorMap
 	}
-	handler := log15.LvlFilterHandler(lvl, log15.StreamHandler(os.Stderr, fmt15.Fmt15Format(cMap)))
+	format := fmt15.Fmt15Format(cMap)
+	if strings.EqualFold(cfg.Format, "json") {
+		format = log15.JsonFormat()
+	}
+	handler := log15.LvlFilterHandler(lvl, log15.StreamHandler(os.Stderr, format))
 	return handler, nil
 }
 
diff --git a/go/lib/log/sample.go b/go/lib/log/sample.go
index a412731bd..dc62d0753 100644
--- a/go/lib/log/sample.go
+++ b/go/lib/log/sample.go
@@ -34,9 +34,15 @@ max_backups = 10
 # are immediately flushed. If negative, messages are never flushed
 # automatically. (default 5)
 flush_interval = 5
+
+# Logging fromat (human|json) (default human)
+format = "human"
 `
 
 const loggingConsoleSample = `
 # Console logging level (trace|debug|info|warn|error|crit) (default crit)
 level = "crit"
+
+# Logging fromat (human|json) (default human)
+format = "human"
 `


Test patch:
diff --git a/go/lib/log/logtest/config.go b/go/lib/log/logtest/config.go
index e018e429d..ea13343d2 100644
--- a/go/lib/log/logtest/config.go
+++ b/go/lib/log/logtest/config.go
@@ -35,4 +35,6 @@ func CheckTestLogging(t *testing.T, cfg *log.Config, id string) {
 	assert.Equal(t, log.DefaultFileMaxBackups, int(cfg.File.MaxBackups))
 	assert.Equal(t, log.DefaultFileFlushSeconds, *cfg.File.FlushInterval)
 	assert.Equal(t, log.DefaultConsoleLevel, cfg.Console.Level)
+	assert.Equal(t, "human", cfg.File.Format)
+	assert.Equal(t, "human", cfg.Console.Format)
 }