diff --git a/contrib/docker-device-tool/device_tool.go b/contrib/docker-device-tool/device_tool.go index 23d19f0237..8ab53de8da 100644 --- a/contrib/docker-device-tool/device_tool.go +++ b/contrib/docker-device-tool/device_tool.go @@ -60,6 +60,7 @@ func main() { if *flDebug { os.Setenv("DEBUG", "1") + log.SetLevel("debug") } if flag.NArg() < 1 { diff --git a/daemon/daemon.go b/daemon/daemon.go index 88fb9fde66..145a466486 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -719,7 +719,6 @@ func NewDaemon(config *Config, eng *engine.Engine) (*Daemon, error) { } func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) { - // Apply configuration defaults if config.Mtu == 0 { config.Mtu = getDefaultNetworkMtu() } diff --git a/docker/docker.go b/docker/docker.go index 92cdd95e0f..bb61d51725 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -5,10 +5,10 @@ import ( "crypto/x509" "fmt" "io/ioutil" - "log" // see gh#8745, client needs to use go log pkg "os" "strings" + log "github.com/Sirupsen/logrus" "github.com/docker/docker/api" "github.com/docker/docker/api/client" "github.com/docker/docker/dockerversion" @@ -36,11 +36,23 @@ func main() { showVersion() return } - if *flDebug { - os.Setenv("DEBUG", "1") + + if *flLogLevel != "" { + lvl, err := log.ParseLevel(*flLogLevel) + if err != nil { + log.Fatalf("Unable to parse logging level: %s", *flLogLevel) + } + initLogging(lvl) + } else { + initLogging(log.InfoLevel) } - initLogging(*flDebug) + // -D, --debug, -l/--log-level=debug processing + // When/if -D is removed this block can be deleted + if *flDebug { + os.Setenv("DEBUG", "1") + initLogging(log.DebugLevel) + } if len(flHosts) == 0 { defaultHost := os.Getenv("DOCKER_HOST") diff --git a/docker/flags.go b/docker/flags.go index 31dcbe2cff..78d6b18993 100644 --- a/docker/flags.go +++ b/docker/flags.go @@ -25,6 +25,7 @@ var ( flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") + flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level") flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags") flTlsVerify = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)") diff --git a/docker/log.go b/docker/log.go index a245aed1fb..cdbbd4408f 100644 --- a/docker/log.go +++ b/docker/log.go @@ -6,11 +6,7 @@ import ( log "github.com/Sirupsen/logrus" ) -func initLogging(debug bool) { +func initLogging(lvl log.Level) { log.SetOutput(os.Stderr) - if debug { - log.SetLevel(log.DebugLevel) - } else { - log.SetLevel(log.InfoLevel) - } + log.SetLevel(lvl) } diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index 26f5c2133a..f3ff68bc9f 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -65,6 +65,9 @@ unix://[/path/to/socket] to use. **--iptables**=*true*|*false* Disable Docker's addition of iptables rules. Default is true. +**-l**, **--log-level**="*debug*|*info*|*error*|*fatal*"" + Set the logging level. Default is `info`. + **--mtu**=VALUE Set the containers network mtu. Default is `1500`. diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 2da65a2bd1..7526954b12 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -75,6 +75,8 @@ expect an integer, and they can only be specified once. --ip-forward=true Enable net.ipv4.ip_forward --ip-masq=true Enable IP masquerading for bridge's IP range --iptables=true Enable Docker's addition of iptables rules + -l, --log-level="info" Set the logging level + --mtu=0 Set the containers network MTU if no value is provided: default to the default route MTU or 1500 if no default route is available -p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index fa7901d82d..31bfac3f67 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "io/ioutil" "os" "os/exec" "strings" @@ -223,3 +224,63 @@ func TestDaemonIptablesCreate(t *testing.T) { logDone("daemon - run,iptables - iptables rules for always restarted container created after daemon restart") } + +func TestDaemonLoggingLevel(t *testing.T) { + d := NewDaemon(t) + + if err := d.Start("--log-level=bogus"); err == nil { + t.Fatal("Daemon should not have been able to start") + } + + d = NewDaemon(t) + if err := d.Start("--log-level=debug"); err != nil { + t.Fatal(err) + } + d.Stop() + content, _ := ioutil.ReadFile(d.logFile.Name()) + if !strings.Contains(string(content), `level="debug"`) { + t.Fatalf(`Missing level="debug" in log file:\n%s`, string(content)) + } + + d = NewDaemon(t) + if err := d.Start("--log-level=fatal"); err != nil { + t.Fatal(err) + } + d.Stop() + content, _ = ioutil.ReadFile(d.logFile.Name()) + if strings.Contains(string(content), `level="debug"`) { + t.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content)) + } + + d = NewDaemon(t) + if err := d.Start("-D"); err != nil { + t.Fatal(err) + } + d.Stop() + content, _ = ioutil.ReadFile(d.logFile.Name()) + if !strings.Contains(string(content), `level="debug"`) { + t.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content)) + } + + d = NewDaemon(t) + if err := d.Start("--debug"); err != nil { + t.Fatal(err) + } + d.Stop() + content, _ = ioutil.ReadFile(d.logFile.Name()) + if !strings.Contains(string(content), `level="debug"`) { + t.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content)) + } + + d = NewDaemon(t) + if err := d.Start("--debug", "--log-level=fatal"); err != nil { + t.Fatal(err) + } + d.Stop() + content, _ = ioutil.ReadFile(d.logFile.Name()) + if !strings.Contains(string(content), `level="debug"`) { + t.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content)) + } + + logDone("daemon - Logging Level") +} diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 54949730a1..ce85f7741b 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1804,7 +1804,7 @@ func TestRunWithBadDevice(t *testing.T) { if err == nil { t.Fatal("Run should fail with bad device") } - expected := `"/etc": not a device node` + expected := `\"/etc\": not a device node` if !strings.Contains(out, expected) { t.Fatalf("Output should contain %q, actual out: %q", expected, out) } diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index b9660d20b6..61a616ceb2 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -41,7 +41,7 @@ func NewDaemon(t *testing.T) *Daemon { t.Fatal("Please set the DEST environment variable") } - dir := filepath.Join(dest, fmt.Sprintf("daemon%d", time.Now().Unix())) + dir := filepath.Join(dest, fmt.Sprintf("daemon%d", time.Now().UnixNano()%100000000)) daemonFolder, err := filepath.Abs(dir) if err != nil { t.Fatalf("Could not make %q an absolute path: %v", dir, err) @@ -69,10 +69,23 @@ func (d *Daemon) Start(arg ...string) error { args := []string{ "--host", d.sock(), - "--daemon", "--debug", + "--daemon", "--graph", fmt.Sprintf("%s/graph", d.folder), "--pidfile", fmt.Sprintf("%s/docker.pid", d.folder), } + + // If we don't explicitly set the log-level or debug flag(-D) then + // turn on debug mode + foundIt := false + for _, a := range arg { + if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") { + foundIt = true + } + } + if !foundIt { + args = append(args, "--debug") + } + if d.storageDriver != "" { args = append(args, "--storage-driver", d.storageDriver) } @@ -83,7 +96,7 @@ func (d *Daemon) Start(arg ...string) error { args = append(args, arg...) d.cmd = exec.Command(dockerBinary, args...) - d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600) + d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) if err != nil { d.t.Fatalf("Could not create %s/docker.log: %v", d.folder, err) } @@ -107,8 +120,13 @@ func (d *Daemon) Start(arg ...string) error { tick := time.Tick(500 * time.Millisecond) // make sure daemon is ready to receive requests + startTime := time.Now().Unix() for { d.t.Log("waiting for daemon to start") + if time.Now().Unix()-startTime > 5 { + // After 5 seconds, give up + return errors.New("Daemon exited and never started") + } select { case <-time.After(2 * time.Second): return errors.New("timeout: daemon does not respond")