Browse code

Add --log-level support

Next steps, in another PR, would be:
- make all logging go through the logrus stuff
- I'd like to see if we can remove the env var stuff (like DEBUG) but we'll see

Closes #5198

Signed-off-by: Doug Davis <dug@us.ibm.com>

Doug Davis authored on 2014/10/01 22:07:24
Showing 10 changed files
... ...
@@ -60,6 +60,7 @@ func main() {
60 60
 
61 61
 	if *flDebug {
62 62
 		os.Setenv("DEBUG", "1")
63
+		log.SetLevel("debug")
63 64
 	}
64 65
 
65 66
 	if flag.NArg() < 1 {
... ...
@@ -719,7 +719,6 @@ func NewDaemon(config *Config, eng *engine.Engine) (*Daemon, error) {
719 719
 }
720 720
 
721 721
 func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) {
722
-	// Apply configuration defaults
723 722
 	if config.Mtu == 0 {
724 723
 		config.Mtu = getDefaultNetworkMtu()
725 724
 	}
... ...
@@ -5,10 +5,10 @@ import (
5 5
 	"crypto/x509"
6 6
 	"fmt"
7 7
 	"io/ioutil"
8
-	"log" // see gh#8745, client needs to use go log pkg
9 8
 	"os"
10 9
 	"strings"
11 10
 
11
+	log "github.com/Sirupsen/logrus"
12 12
 	"github.com/docker/docker/api"
13 13
 	"github.com/docker/docker/api/client"
14 14
 	"github.com/docker/docker/dockerversion"
... ...
@@ -36,12 +36,24 @@ func main() {
36 36
 		showVersion()
37 37
 		return
38 38
 	}
39
+
40
+	if *flLogLevel != "" {
41
+		lvl, err := log.ParseLevel(*flLogLevel)
42
+		if err != nil {
43
+			log.Fatalf("Unable to parse logging level: %s", *flLogLevel)
44
+		}
45
+		initLogging(lvl)
46
+	} else {
47
+		initLogging(log.InfoLevel)
48
+	}
49
+
50
+	// -D, --debug, -l/--log-level=debug processing
51
+	// When/if -D is removed this block can be deleted
39 52
 	if *flDebug {
40 53
 		os.Setenv("DEBUG", "1")
54
+		initLogging(log.DebugLevel)
41 55
 	}
42 56
 
43
-	initLogging(*flDebug)
44
-
45 57
 	if len(flHosts) == 0 {
46 58
 		defaultHost := os.Getenv("DOCKER_HOST")
47 59
 		if defaultHost == "" || *flDaemon {
... ...
@@ -25,6 +25,7 @@ var (
25 25
 	flDaemon      = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
26 26
 	flDebug       = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
27 27
 	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")
28
+	flLogLevel    = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
28 29
 	flEnableCors  = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
29 30
 	flTls         = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags")
30 31
 	flTlsVerify   = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
... ...
@@ -6,11 +6,7 @@ import (
6 6
 	log "github.com/Sirupsen/logrus"
7 7
 )
8 8
 
9
-func initLogging(debug bool) {
9
+func initLogging(lvl log.Level) {
10 10
 	log.SetOutput(os.Stderr)
11
-	if debug {
12
-		log.SetLevel(log.DebugLevel)
13
-	} else {
14
-		log.SetLevel(log.InfoLevel)
15
-	}
11
+	log.SetLevel(lvl)
16 12
 }
... ...
@@ -65,6 +65,9 @@ unix://[/path/to/socket] to use.
65 65
 **--iptables**=*true*|*false*
66 66
   Disable Docker's addition of iptables rules. Default is true.
67 67
 
68
+**-l**, **--log-level**="*debug*|*info*|*error*|*fatal*""
69
+  Set the logging level. Default is `info`.
70
+
68 71
 **--mtu**=VALUE
69 72
   Set the containers network mtu. Default is `1500`.
70 73
 
... ...
@@ -75,6 +75,8 @@ expect an integer, and they can only be specified once.
75 75
       --ip-forward=true                          Enable net.ipv4.ip_forward
76 76
       --ip-masq=true                             Enable IP masquerading for bridge's IP range
77 77
       --iptables=true                            Enable Docker's addition of iptables rules
78
+       -l, --log-level="info"                    Set the logging level
79
+
78 80
       --mtu=0                                    Set the containers network MTU
79 81
                                                    if no value is provided: default to the default route MTU or 1500 if no default route is available
80 82
       -p, --pidfile="/var/run/docker.pid"        Path to use for daemon PID file
... ...
@@ -2,6 +2,7 @@ package main
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
+	"io/ioutil"
5 6
 	"os"
6 7
 	"os/exec"
7 8
 	"strings"
... ...
@@ -223,3 +224,63 @@ func TestDaemonIptablesCreate(t *testing.T) {
223 223
 
224 224
 	logDone("daemon - run,iptables - iptables rules for always restarted container created after daemon restart")
225 225
 }
226
+
227
+func TestDaemonLoggingLevel(t *testing.T) {
228
+	d := NewDaemon(t)
229
+
230
+	if err := d.Start("--log-level=bogus"); err == nil {
231
+		t.Fatal("Daemon should not have been able to start")
232
+	}
233
+
234
+	d = NewDaemon(t)
235
+	if err := d.Start("--log-level=debug"); err != nil {
236
+		t.Fatal(err)
237
+	}
238
+	d.Stop()
239
+	content, _ := ioutil.ReadFile(d.logFile.Name())
240
+	if !strings.Contains(string(content), `level="debug"`) {
241
+		t.Fatalf(`Missing level="debug" in log file:\n%s`, string(content))
242
+	}
243
+
244
+	d = NewDaemon(t)
245
+	if err := d.Start("--log-level=fatal"); err != nil {
246
+		t.Fatal(err)
247
+	}
248
+	d.Stop()
249
+	content, _ = ioutil.ReadFile(d.logFile.Name())
250
+	if strings.Contains(string(content), `level="debug"`) {
251
+		t.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content))
252
+	}
253
+
254
+	d = NewDaemon(t)
255
+	if err := d.Start("-D"); err != nil {
256
+		t.Fatal(err)
257
+	}
258
+	d.Stop()
259
+	content, _ = ioutil.ReadFile(d.logFile.Name())
260
+	if !strings.Contains(string(content), `level="debug"`) {
261
+		t.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content))
262
+	}
263
+
264
+	d = NewDaemon(t)
265
+	if err := d.Start("--debug"); err != nil {
266
+		t.Fatal(err)
267
+	}
268
+	d.Stop()
269
+	content, _ = ioutil.ReadFile(d.logFile.Name())
270
+	if !strings.Contains(string(content), `level="debug"`) {
271
+		t.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content))
272
+	}
273
+
274
+	d = NewDaemon(t)
275
+	if err := d.Start("--debug", "--log-level=fatal"); err != nil {
276
+		t.Fatal(err)
277
+	}
278
+	d.Stop()
279
+	content, _ = ioutil.ReadFile(d.logFile.Name())
280
+	if !strings.Contains(string(content), `level="debug"`) {
281
+		t.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content))
282
+	}
283
+
284
+	logDone("daemon - Logging Level")
285
+}
... ...
@@ -1804,7 +1804,7 @@ func TestRunWithBadDevice(t *testing.T) {
1804 1804
 	if err == nil {
1805 1805
 		t.Fatal("Run should fail with bad device")
1806 1806
 	}
1807
-	expected := `"/etc": not a device node`
1807
+	expected := `\"/etc\": not a device node`
1808 1808
 	if !strings.Contains(out, expected) {
1809 1809
 		t.Fatalf("Output should contain %q, actual out: %q", expected, out)
1810 1810
 	}
... ...
@@ -41,7 +41,7 @@ func NewDaemon(t *testing.T) *Daemon {
41 41
 		t.Fatal("Please set the DEST environment variable")
42 42
 	}
43 43
 
44
-	dir := filepath.Join(dest, fmt.Sprintf("daemon%d", time.Now().Unix()))
44
+	dir := filepath.Join(dest, fmt.Sprintf("daemon%d", time.Now().UnixNano()%100000000))
45 45
 	daemonFolder, err := filepath.Abs(dir)
46 46
 	if err != nil {
47 47
 		t.Fatalf("Could not make %q an absolute path: %v", dir, err)
... ...
@@ -69,10 +69,23 @@ func (d *Daemon) Start(arg ...string) error {
69 69
 
70 70
 	args := []string{
71 71
 		"--host", d.sock(),
72
-		"--daemon", "--debug",
72
+		"--daemon",
73 73
 		"--graph", fmt.Sprintf("%s/graph", d.folder),
74 74
 		"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
75 75
 	}
76
+
77
+	// If we don't explicitly set the log-level or debug flag(-D) then
78
+	// turn on debug mode
79
+	foundIt := false
80
+	for _, a := range arg {
81
+		if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") {
82
+			foundIt = true
83
+		}
84
+	}
85
+	if !foundIt {
86
+		args = append(args, "--debug")
87
+	}
88
+
76 89
 	if d.storageDriver != "" {
77 90
 		args = append(args, "--storage-driver", d.storageDriver)
78 91
 	}
... ...
@@ -83,7 +96,7 @@ func (d *Daemon) Start(arg ...string) error {
83 83
 	args = append(args, arg...)
84 84
 	d.cmd = exec.Command(dockerBinary, args...)
85 85
 
86
-	d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
86
+	d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
87 87
 	if err != nil {
88 88
 		d.t.Fatalf("Could not create %s/docker.log: %v", d.folder, err)
89 89
 	}
... ...
@@ -107,8 +120,13 @@ func (d *Daemon) Start(arg ...string) error {
107 107
 
108 108
 	tick := time.Tick(500 * time.Millisecond)
109 109
 	// make sure daemon is ready to receive requests
110
+	startTime := time.Now().Unix()
110 111
 	for {
111 112
 		d.t.Log("waiting for daemon to start")
113
+		if time.Now().Unix()-startTime > 5 {
114
+			// After 5 seconds, give up
115
+			return errors.New("Daemon exited and never started")
116
+		}
112 117
 		select {
113 118
 		case <-time.After(2 * time.Second):
114 119
 			return errors.New("timeout: daemon does not respond")