Merge pull request #8238 from vbatts/vbatts-daemon_timestamps

daemon logging: unifying output and timestamps
This commit is contained in:
Alexandr Morozov 2014-10-16 15:55:49 -07:00
commit 9ac922face
4 changed files with 69 additions and 36 deletions

View file

@ -4,11 +4,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"os"
"os/exec" "os/exec"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/docker/docker/pkg/log"
) )
type Action string type Action string
@ -175,9 +176,7 @@ func Raw(args ...string) ([]byte, error) {
args = append([]string{"--wait"}, args...) args = append([]string{"--wait"}, args...)
} }
if os.Getenv("DEBUG") != "" { log.Debugf("%s, %v", path, args)
fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s, %v\n", path, args))
}
output, err := exec.Command(path, args...).CombinedOutput() output, err := exec.Command(path, args...).CombinedOutput()
if err != nil { if err != nil {

View file

@ -6,18 +6,21 @@ import (
"os" "os"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/docker/docker/pkg/timeutils"
) )
type priority int type priority int
const ( const (
errorFormat = "[%s] %s:%d %s\n" errorFormat = "[%s] [%s] %s:%d %s\n"
logFormat = "[%s] %s\n" logFormat = "[%s] [%s] %s\n"
fatal priority = iota fatalPriority priority = iota
error errorPriority
info infoPriority
debug debugPriority
) )
// A common interface to access the Fatal method of // A common interface to access the Fatal method of
@ -28,44 +31,72 @@ type Fataler interface {
func (p priority) String() string { func (p priority) String() string {
switch p { switch p {
case fatal: case fatalPriority:
return "fatal" return "fatal"
case error: case errorPriority:
return "error" return "error"
case info: case infoPriority:
return "info" return "info"
case debug: case debugPriority:
return "debug" return "debug"
} }
return "" return ""
} }
var DefaultLogger = Logger{Out: os.Stdout, Err: os.Stderr}
// Debug function, if the debug flag is set, then display. Do nothing otherwise // Debug function, if the debug flag is set, then display. Do nothing otherwise
// If Docker is in damon mode, also send the debug info on the socket // If Docker is in damon mode, also send the debug info on the socket
func Debugf(format string, a ...interface{}) { func Debugf(format string, a ...interface{}) (int, error) {
if os.Getenv("DEBUG") != "" { return DefaultLogger.Debugf(format, a...)
logf(os.Stderr, debug, format, a...)
}
} }
func Infof(format string, a ...interface{}) { func Infof(format string, a ...interface{}) (int, error) {
logf(os.Stdout, info, format, a...) return DefaultLogger.Infof(format, a...)
} }
func Errorf(format string, a ...interface{}) { func Errorf(format string, a ...interface{}) (int, error) {
logf(os.Stderr, error, format, a...) return DefaultLogger.Errorf(format, a...)
}
func Fatal(a ...interface{}) {
DefaultLogger.Fatalf("%s", a...)
} }
func Fatalf(format string, a ...interface{}) { func Fatalf(format string, a ...interface{}) {
logf(os.Stderr, fatal, format, a...) DefaultLogger.Fatalf(format, a...)
}
type Logger struct {
Err io.Writer
Out io.Writer
}
func (l Logger) Debugf(format string, a ...interface{}) (int, error) {
if os.Getenv("DEBUG") != "" {
return l.logf(l.Err, debugPriority, format, a...)
}
return 0, nil
}
func (l Logger) Infof(format string, a ...interface{}) (int, error) {
return l.logf(l.Out, infoPriority, format, a...)
}
func (l Logger) Errorf(format string, a ...interface{}) (int, error) {
return l.logf(l.Err, errorPriority, format, a...)
}
func (l Logger) Fatalf(format string, a ...interface{}) {
l.logf(l.Err, fatalPriority, format, a...)
os.Exit(1) os.Exit(1)
} }
func logf(stream io.Writer, level priority, format string, a ...interface{}) { func (l Logger) logf(stream io.Writer, level priority, format string, a ...interface{}) (int, error) {
var prefix string var prefix string
if level <= error || level == debug { if level <= errorPriority || level == debugPriority {
// Retrieve the stack infos // Retrieve the stack infos
_, file, line, ok := runtime.Caller(2) _, file, line, ok := runtime.Caller(2)
if !ok { if !ok {
@ -74,10 +105,10 @@ func logf(stream io.Writer, level priority, format string, a ...interface{}) {
} else { } else {
file = file[strings.LastIndex(file, "/")+1:] file = file[strings.LastIndex(file, "/")+1:]
} }
prefix = fmt.Sprintf(errorFormat, level.String(), file, line, format) prefix = fmt.Sprintf(errorFormat, time.Now().Format(timeutils.RFC3339NanoFixed), level.String(), file, line, format)
} else { } else {
prefix = fmt.Sprintf(logFormat, level.String(), format) prefix = fmt.Sprintf(logFormat, time.Now().Format(timeutils.RFC3339NanoFixed), level.String(), format)
} }
fmt.Fprintf(stream, prefix, a...) return fmt.Fprintf(stream, prefix, a...)
} }

View file

@ -7,6 +7,8 @@ import (
"testing" "testing"
) )
var reRFC3339NanoFixed = "[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{9}.([0-9]{2}:[0-9]{2})?"
func TestLogFatalf(t *testing.T) { func TestLogFatalf(t *testing.T) {
var output *bytes.Buffer var output *bytes.Buffer
@ -16,15 +18,15 @@ func TestLogFatalf(t *testing.T) {
Values []interface{} Values []interface{}
ExpectedPattern string ExpectedPattern string
}{ }{
{fatal, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[fatal\\] testing.go:\\d+ 1 \\+ 1 = 2"}, {fatalPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[fatal\\] testing.go:\\d+ 1 \\+ 1 = 2"},
{error, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[error\\] testing.go:\\d+ 1 \\+ 1 = 2"}, {errorPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[error\\] testing.go:\\d+ 1 \\+ 1 = 2"},
{info, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[info\\] 1 \\+ 1 = 2"}, {infoPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[info\\] 1 \\+ 1 = 2"},
{debug, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[debug\\] testing.go:\\d+ 1 \\+ 1 = 2"}, {debugPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[debug\\] testing.go:\\d+ 1 \\+ 1 = 2"},
} }
for i, test := range tests { for i, test := range tests {
output = &bytes.Buffer{} output = &bytes.Buffer{}
logf(output, test.Level, test.Format, test.Values...) DefaultLogger.logf(output, test.Level, test.Format, test.Values...)
expected := regexp.MustCompile(test.ExpectedPattern) expected := regexp.MustCompile(test.ExpectedPattern)
if !expected.MatchString(output.String()) { if !expected.MatchString(output.String()) {

View file

@ -1,11 +1,12 @@
package signal package signal
import ( import (
"log"
"os" "os"
gosignal "os/signal" gosignal "os/signal"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
"github.com/docker/docker/pkg/log"
) )
// Trap sets up a simplified signal "trap", appropriate for common // Trap sets up a simplified signal "trap", appropriate for common
@ -28,7 +29,7 @@ func Trap(cleanup func()) {
interruptCount := uint32(0) interruptCount := uint32(0)
for sig := range c { for sig := range c {
go func(sig os.Signal) { go func(sig os.Signal) {
log.Printf("Received signal '%v', starting shutdown of docker...\n", sig) log.Infof("Received signal '%v', starting shutdown of docker...", sig)
switch sig { switch sig {
case os.Interrupt, syscall.SIGTERM: case os.Interrupt, syscall.SIGTERM:
// If the user really wants to interrupt, let him do so. // If the user really wants to interrupt, let him do so.
@ -43,7 +44,7 @@ func Trap(cleanup func()) {
return return
} }
} else { } else {
log.Printf("Force shutdown of docker, interrupting cleanup\n") log.Infof("Force shutdown of docker, interrupting cleanup")
} }
case syscall.SIGQUIT: case syscall.SIGQUIT:
} }