Skip to content

Commit

Permalink
Merge pull request moby#45737 from pkwarren/pkw/issue-44940-dockerd-j…
Browse files Browse the repository at this point in the history
…son-logs

Update dockerd to support JSON logging format
  • Loading branch information
corhere committed Jul 13, 2023
2 parents 193f162 + a08abec commit 0c2699d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 5 deletions.
30 changes: 25 additions & 5 deletions cmd/dockerd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
conf.Debug = opts.Debug
conf.Hosts = opts.Hosts
conf.LogLevel = opts.LogLevel
conf.LogFormat = opts.LogFormat

if flags.Changed(FlagTLS) {
conf.TLS = &opts.TLS
Expand Down Expand Up @@ -657,6 +658,10 @@ func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error)
opts = append(opts, supervisor.WithLogLevel(cli.LogLevel))
}

if logFormat := cli.Config.LogFormat; logFormat != "" {
opts = append(opts, supervisor.WithLogFormat(logFormat))
}

if !cli.CriContainerd {
// CRI support in the managed daemon is currently opt-in.
//
Expand Down Expand Up @@ -867,11 +872,26 @@ func configureDaemonLogs(conf *config.Config) {
} else {
logrus.SetLevel(logrus.InfoLevel)
}
logrus.SetFormatter(&logrus.TextFormatter{
TimestampFormat: jsonmessage.RFC3339NanoFixed,
DisableColors: conf.RawLogs,
FullTimestamp: true,
})
logFormat := conf.LogFormat
if logFormat == "" {
logFormat = log.TextFormat
}
var formatter logrus.Formatter
switch logFormat {
case log.JSONFormat:
formatter = &logrus.JSONFormatter{
TimestampFormat: jsonmessage.RFC3339NanoFixed,
}
case log.TextFormat:
formatter = &logrus.TextFormatter{
TimestampFormat: jsonmessage.RFC3339NanoFixed,
DisableColors: conf.RawLogs,
FullTimestamp: true,
}
default:
panic("unsupported log format " + logFormat)
}
logrus.SetFormatter(formatter)
}

func configureProxyEnv(conf *config.Config) {
Expand Down
21 changes: 21 additions & 0 deletions cmd/dockerd/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"testing"

"github.com/containerd/containerd/log"
"github.com/docker/docker/daemon/config"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -155,6 +156,26 @@ func TestLoadDaemonCliConfigWithLogLevel(t *testing.T) {
assert.Check(t, is.Equal("warn", loadedConfig.LogLevel))
}

func TestLoadDaemonCliConfigWithLogFormat(t *testing.T) {
tempFile := fs.NewFile(t, "config", fs.WithContent(`{"log-format": "json"}`))
defer tempFile.Remove()

opts := defaultOptions(t, tempFile.Path())
loadedConfig, err := loadDaemonCliConfig(opts)
assert.NilError(t, err)
assert.Assert(t, loadedConfig != nil)
assert.Check(t, is.Equal(log.JSONFormat, loadedConfig.LogFormat))
}

func TestLoadDaemonCliConfigWithInvalidLogFormat(t *testing.T) {
tempFile := fs.NewFile(t, "config", fs.WithContent(`{"log-format": "foo"}`))
defer tempFile.Remove()

opts := defaultOptions(t, tempFile.Path())
_, err := loadDaemonCliConfig(opts)
assert.Check(t, is.ErrorContains(err, "invalid log format: foo"))
}

func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {
content := `{"tlscacert": "/etc/certs/ca.pem", "log-driver": "syslog"}`
tempFile := fs.NewFile(t, "config", fs.WithContent(content))
Expand Down
5 changes: 5 additions & 0 deletions cmd/dockerd/options.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package main

import (
"fmt"
"os"
"path/filepath"

"github.com/containerd/containerd/log"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/homedir"
Expand Down Expand Up @@ -72,6 +74,7 @@ type daemonOptions struct {
Debug bool
Hosts []string
LogLevel string
LogFormat string
TLS bool
TLSVerify bool
TLSOptions *tlsconfig.Options
Expand Down Expand Up @@ -104,6 +107,8 @@ func (o *daemonOptions) installFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&o.Debug, "debug", "D", false, "Enable debug mode")
flags.BoolVar(&o.Validate, "validate", false, "Validate daemon configuration and exit")
flags.StringVarP(&o.LogLevel, "log-level", "l", "info", `Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")`)
flags.StringVar(&o.LogFormat, "log-format", log.TextFormat,
fmt.Sprintf(`Set the logging format ("%s"|"%s")`, log.TextFormat, log.JSONFormat))
flags.BoolVar(&o.TLS, FlagTLS, DefaultTLSValue, "Use TLS; implied by --tlsverify")
flags.BoolVar(&o.TLSVerify, FlagTLSVerify, dockerTLSVerify || DefaultTLSValue, "Use TLS and verify the remote")

Expand Down
11 changes: 11 additions & 0 deletions daemon/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ type CommonConfig struct {
Debug bool `json:"debug,omitempty"`
Hosts []string `json:"hosts,omitempty"`
LogLevel string `json:"log-level,omitempty"`
LogFormat string `json:"log-format,omitempty"`
TLS *bool `json:"tls,omitempty"`
TLSVerify *bool `json:"tlsverify,omitempty"`

Expand Down Expand Up @@ -592,6 +593,16 @@ func Validate(config *Config) error {
}
}

// validate log-format
if logFormat := config.LogFormat; logFormat != "" {
switch logFormat {
case log.TextFormat, log.JSONFormat:
// These are valid
default:
return errors.Errorf("invalid log format: %s", logFormat)
}
}

// validate DNS
for _, dns := range config.DNS {
if _, err := opts.ValidateIPAddress(dns); err != nil {
Expand Down
9 changes: 9 additions & 0 deletions libcontainerd/supervisor/remote_daemon_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ func WithLogLevel(lvl string) DaemonOpt {
}
}

// WithLogFormat defines the containerd log format.
// This only makes sense if WithStartDaemon() was set to true.
func WithLogFormat(format string) DaemonOpt {
return func(r *remote) error {
r.Debug.Format = format
return nil
}
}

// WithCRIDisabled disables the CRI plugin.
func WithCRIDisabled() DaemonOpt {
return func(r *remote) error {
Expand Down

0 comments on commit 0c2699d

Please sign in to comment.