Parcourir la source

Merge pull request #8770 from LK4D4/logrus_support

Logrus support
Jessie Frazelle il y a 10 ans
Parent
commit
15b6b7be01
89 fichiers modifiés avec 1932 ajouts et 236 suppressions
  1. 1 1
      api/client/commands.go
  2. 1 1
      api/client/hijack.go
  3. 1 1
      api/client/utils.go
  4. 1 1
      api/common.go
  5. 1 1
      api/server/server.go
  6. 1 1
      builder/dispatchers.go
  7. 1 1
      builder/evaluator.go
  8. 1 1
      builder/internals.go
  9. 1 1
      daemon/attach.go
  10. 1 1
      daemon/container.go
  11. 4 3
      daemon/daemon.go
  12. 1 1
      daemon/daemon_aufs.go
  13. 1 1
      daemon/delete.go
  14. 1 1
      daemon/exec.go
  15. 1 1
      daemon/execdriver/lxc/driver.go
  16. 1 1
      daemon/graphdriver/aufs/aufs.go
  17. 1 1
      daemon/graphdriver/aufs/mount.go
  18. 1 1
      daemon/graphdriver/devmapper/attach_loopback.go
  19. 1 1
      daemon/graphdriver/devmapper/deviceset.go
  20. 1 1
      daemon/graphdriver/devmapper/devmapper.go
  21. 1 1
      daemon/graphdriver/devmapper/driver.go
  22. 1 1
      daemon/graphdriver/fsdiff.go
  23. 1 1
      daemon/info.go
  24. 1 1
      daemon/logs.go
  25. 1 1
      daemon/monitor.go
  26. 1 1
      daemon/networkdriver/bridge/driver.go
  27. 1 1
      daemon/networkdriver/portmapper/mapper.go
  28. 1 1
      daemon/volumes.go
  29. 1 1
      docker/daemon.go
  30. 3 0
      docker/docker.go
  31. 16 0
      docker/log.go
  32. 8 4
      engine/job.go
  33. 1 1
      graph/export.go
  34. 1 1
      graph/graph.go
  35. 1 1
      graph/load.go
  36. 1 1
      graph/pull.go
  37. 1 1
      graph/push.go
  38. 1 1
      graph/service.go
  39. 2 0
      hack/vendor.sh
  40. 1 1
      image/image.go
  41. 1 1
      integration/commands_test.go
  42. 1 1
      integration/runtime_test.go
  43. 23 20
      integration/utils_test.go
  44. 1 1
      pkg/archive/archive.go
  45. 1 1
      pkg/archive/changes.go
  46. 1 1
      pkg/broadcastwriter/broadcastwriter.go
  47. 1 1
      pkg/fileutils/fileutils.go
  48. 1 1
      pkg/httputils/resumablerequestreader.go
  49. 1 1
      pkg/iptables/iptables.go
  50. 0 114
      pkg/log/log.go
  51. 0 39
      pkg/log/log_test.go
  52. 1 1
      pkg/signal/trap.go
  53. 1 1
      pkg/stdcopy/stdcopy.go
  54. 1 1
      pkg/tarsum/tarsum.go
  55. 1 1
      registry/endpoint.go
  56. 1 1
      registry/registry_mock_test.go
  57. 1 1
      registry/session.go
  58. 1 1
      registry/session_v2.go
  59. 1 1
      runconfig/merge.go
  60. 1 1
      trust/service.go
  61. 1 1
      trust/trusts.go
  62. 1 1
      utils/http.go
  63. 1 1
      utils/utils.go
  64. 1 0
      vendor/src/github.com/Sirupsen/logrus/.gitignore
  65. 7 0
      vendor/src/github.com/Sirupsen/logrus/.travis.yml
  66. 21 0
      vendor/src/github.com/Sirupsen/logrus/LICENSE
  67. 336 0
      vendor/src/github.com/Sirupsen/logrus/README.md
  68. 242 0
      vendor/src/github.com/Sirupsen/logrus/entry.go
  69. 29 0
      vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go
  70. 35 0
      vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go
  71. 177 0
      vendor/src/github.com/Sirupsen/logrus/exported.go
  72. 54 0
      vendor/src/github.com/Sirupsen/logrus/formatter.go
  73. 122 0
      vendor/src/github.com/Sirupsen/logrus/hook_test.go
  74. 34 0
      vendor/src/github.com/Sirupsen/logrus/hooks.go
  75. 54 0
      vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
  76. 20 0
      vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
  77. 59 0
      vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
  78. 26 0
      vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
  79. 19 0
      vendor/src/github.com/Sirupsen/logrus/json_formatter.go
  80. 161 0
      vendor/src/github.com/Sirupsen/logrus/logger.go
  81. 72 0
      vendor/src/github.com/Sirupsen/logrus/logrus.go
  82. 173 0
      vendor/src/github.com/Sirupsen/logrus/logrus_test.go
  83. 12 0
      vendor/src/github.com/Sirupsen/logrus/terminal_darwin.go
  84. 20 0
      vendor/src/github.com/Sirupsen/logrus/terminal_freebsd.go
  85. 12 0
      vendor/src/github.com/Sirupsen/logrus/terminal_linux.go
  86. 21 0
      vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go
  87. 27 0
      vendor/src/github.com/Sirupsen/logrus/terminal_windows.go
  88. 86 0
      vendor/src/github.com/Sirupsen/logrus/text_formatter.go
  89. 1 1
      volumes/repository.go

+ 1 - 1
api/client/commands.go

@@ -23,6 +23,7 @@ import (
 	"text/template"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/engine"
@@ -30,7 +31,6 @@ import (
 	"github.com/docker/docker/nat"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers/filters"

+ 1 - 1
api/client/hijack.go

@@ -11,9 +11,9 @@ import (
 	"runtime"
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/dockerversion"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/term"

+ 1 - 1
api/client/utils.go

@@ -16,10 +16,10 @@ import (
 	"strings"
 	"syscall"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/registry"

+ 1 - 1
api/common.go

@@ -5,8 +5,8 @@ import (
 	"mime"
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/version"
 )

+ 1 - 1
api/server/server.go

@@ -23,10 +23,10 @@ import (
 	"github.com/docker/libcontainer/user"
 	"github.com/gorilla/mux"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/listenbuffer"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/systemd"

+ 1 - 1
builder/dispatchers.go

@@ -14,8 +14,8 @@ import (
 	"regexp"
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/nat"
-	"github.com/docker/docker/pkg/log"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/runconfig"
 )

+ 1 - 1
builder/evaluator.go

@@ -27,10 +27,10 @@ import (
 	"path"
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/builder/parser"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/runconfig"

+ 1 - 1
builder/internals.go

@@ -18,11 +18,11 @@ import (
 	"syscall"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/builder/parser"
 	"github.com/docker/docker/daemon"
 	imagepkg "github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/pkg/system"

+ 1 - 1
daemon/attach.go

@@ -6,10 +6,10 @@ import (
 	"os"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/jsonlog"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/utils"
 )

+ 1 - 1
daemon/container.go

@@ -17,6 +17,7 @@ import (
 	"github.com/docker/libcontainer/devices"
 	"github.com/docker/libcontainer/label"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/image"
@@ -25,7 +26,6 @@ import (
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/broadcastwriter"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/networkfs/etchosts"
 	"github.com/docker/docker/pkg/networkfs/resolvconf"
 	"github.com/docker/docker/pkg/promise"

+ 4 - 3
daemon/daemon.go

@@ -14,6 +14,7 @@ import (
 
 	"github.com/docker/libcontainer/label"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver/execdrivers"
 	"github.com/docker/docker/daemon/execdriver/lxc"
@@ -29,7 +30,6 @@ import (
 	"github.com/docker/docker/pkg/broadcastwriter"
 	"github.com/docker/docker/pkg/graphdb"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/namesgenerator"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers/kernel"
@@ -304,7 +304,7 @@ func (daemon *Daemon) restore() error {
 	)
 
 	if !debug {
-		log.Infof("Loading containers: ")
+		log.Infof("Loading containers: start.")
 	}
 	dir, err := ioutil.ReadDir(daemon.repository)
 	if err != nil {
@@ -392,7 +392,8 @@ func (daemon *Daemon) restore() error {
 	}
 
 	if !debug {
-		log.Infof(": done.")
+		fmt.Println()
+		log.Infof("Loading containers: done.")
 	}
 
 	return nil

+ 1 - 1
daemon/daemon_aufs.go

@@ -3,10 +3,10 @@
 package daemon
 
 import (
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/daemon/graphdriver/aufs"
 	"github.com/docker/docker/graph"
-	"github.com/docker/docker/pkg/log"
 )
 
 // Given the graphdriver ad, if it is aufs, then migrate it.

+ 1 - 1
daemon/delete.go

@@ -5,8 +5,8 @@ import (
 	"os"
 	"path"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 )
 
 func (daemon *Daemon) ContainerRm(job *engine.Job) engine.Status {

+ 1 - 1
daemon/exec.go

@@ -9,12 +9,12 @@ import (
 	"strings"
 	"sync"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver/lxc"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/broadcastwriter"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"

+ 1 - 1
daemon/execdriver/lxc/driver.go

@@ -17,8 +17,8 @@ import (
 
 	"github.com/kr/pty"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libcontainer/cgroups"

+ 1 - 1
daemon/graphdriver/aufs/aufs.go

@@ -30,9 +30,9 @@ import (
 	"sync"
 	"syscall"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	mountpk "github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libcontainer/label"

+ 1 - 1
daemon/graphdriver/aufs/mount.go

@@ -4,7 +4,7 @@ import (
 	"os/exec"
 	"syscall"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 func Unmount(target string) error {

+ 1 - 1
daemon/graphdriver/devmapper/attach_loopback.go

@@ -7,7 +7,7 @@ import (
 	"os"
 	"syscall"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 func stringToLoopName(src string) [LoNameSize]uint8 {

+ 1 - 1
daemon/graphdriver/devmapper/deviceset.go

@@ -18,8 +18,8 @@ import (
 	"syscall"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/units"
 	"github.com/docker/libcontainer/label"

+ 1 - 1
daemon/graphdriver/devmapper/devmapper.go

@@ -9,7 +9,7 @@ import (
 	"runtime"
 	"syscall"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 type DevmapperLogger interface {

+ 1 - 1
daemon/graphdriver/devmapper/driver.go

@@ -8,8 +8,8 @@ import (
 	"os"
 	"path"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/units"
 )

+ 1 - 1
daemon/graphdriver/fsdiff.go

@@ -4,9 +4,9 @@ import (
 	"fmt"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/utils"
 )
 

+ 1 - 1
daemon/info.go

@@ -4,9 +4,9 @@ import (
 	"os"
 	"runtime"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/parsers/operatingsystem"
 	"github.com/docker/docker/registry"

+ 1 - 1
daemon/logs.go

@@ -8,9 +8,9 @@ import (
 	"os"
 	"strconv"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/jsonlog"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/tailfile"
 	"github.com/docker/docker/pkg/timeutils"
 )

+ 1 - 1
daemon/monitor.go

@@ -6,8 +6,8 @@ import (
 	"sync"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/runconfig"
 )
 

+ 1 - 1
daemon/networkdriver/bridge/driver.go

@@ -8,13 +8,13 @@ import (
 	"strings"
 	"sync"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/networkdriver"
 	"github.com/docker/docker/daemon/networkdriver/ipallocator"
 	"github.com/docker/docker/daemon/networkdriver/portallocator"
 	"github.com/docker/docker/daemon/networkdriver/portmapper"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/iptables"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/networkfs/resolvconf"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/libcontainer/netlink"

+ 1 - 1
daemon/networkdriver/portmapper/mapper.go

@@ -6,9 +6,9 @@ import (
 	"net"
 	"sync"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/networkdriver/portallocator"
 	"github.com/docker/docker/pkg/iptables"
-	"github.com/docker/docker/pkg/log"
 )
 
 type mapping struct {

+ 1 - 1
daemon/volumes.go

@@ -10,9 +10,9 @@ import (
 	"strings"
 	"syscall"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/volumes"
 )

+ 1 - 1
docker/daemon.go

@@ -3,6 +3,7 @@
 package main
 
 import (
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builtins"
 	"github.com/docker/docker/daemon"
@@ -10,7 +11,6 @@ import (
 	_ "github.com/docker/docker/daemon/execdriver/native"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/signal"
 )

+ 3 - 0
docker/docker.go

@@ -28,6 +28,7 @@ func main() {
 	if reexec.Init() {
 		return
 	}
+
 	flag.Parse()
 	// FIXME: validate daemon flags here
 
@@ -39,6 +40,8 @@ func main() {
 		os.Setenv("DEBUG", "1")
 	}
 
+	initLogging(*flDebug)
+
 	if len(flHosts) == 0 {
 		defaultHost := os.Getenv("DOCKER_HOST")
 		if defaultHost == "" || *flDaemon {

+ 16 - 0
docker/log.go

@@ -0,0 +1,16 @@
+package main
+
+import (
+	"os"
+
+	log "github.com/Sirupsen/logrus"
+)
+
+func initLogging(debug bool) {
+	log.SetOutput(os.Stderr)
+	if debug {
+		log.SetLevel(log.DebugLevel)
+	} else {
+		log.SetLevel(log.InfoLevel)
+	}
+}

+ 8 - 4
engine/job.go

@@ -6,6 +6,8 @@ import (
 	"io"
 	"strings"
 	"time"
+
+	log "github.com/Sirupsen/logrus"
 )
 
 // A job is the fundamental unit of work in the docker engine.
@@ -66,10 +68,12 @@ func (job *Job) Run() error {
 		return fmt.Errorf("%s: job has already completed", job.Name)
 	}
 	// Log beginning and end of the job
-	job.Eng.Logf("+job %s", job.CallString())
-	defer func() {
-		job.Eng.Logf("-job %s%s", job.CallString(), job.StatusString())
-	}()
+	if job.Eng.Logging {
+		log.Infof("+job %s", job.CallString())
+		defer func() {
+			log.Infof("-job %s%s", job.CallString(), job.StatusString())
+		}()
+	}
 	var errorMessage = bytes.NewBuffer(nil)
 	job.Stderr.Add(errorMessage)
 	if job.handler == nil {

+ 1 - 1
graph/export.go

@@ -7,9 +7,9 @@ import (
 	"os"
 	"path"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
 )
 

+ 1 - 1
graph/graph.go

@@ -12,11 +12,11 @@ import (
 	"syscall"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/truncindex"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"

+ 1 - 1
graph/load.go

@@ -7,10 +7,10 @@ import (
 	"os"
 	"path"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 )
 
 // Loads a set of images into the repository. This is the complementary of ImageExport.

+ 1 - 1
graph/pull.go

@@ -12,9 +12,9 @@ import (
 	"strings"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/image"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libtrust"

+ 1 - 1
graph/push.go

@@ -7,9 +7,9 @@ import (
 	"os"
 	"path"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/utils"
 )

+ 1 - 1
graph/service.go

@@ -4,9 +4,9 @@ import (
 	"fmt"
 	"io"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/image"
-	"github.com/docker/docker/pkg/log"
 )
 
 func (s *TagStore) Install(eng *engine.Engine) error {

+ 2 - 0
hack/vendor.sh

@@ -53,6 +53,8 @@ clone hg code.google.com/p/gosqlite 74691fb6f837
 
 clone git github.com/docker/libtrust d273ef2565ca
 
+clone git github.com/Sirupsen/logrus v0.5.1
+
 # get Go tip's archive/tar, for xattr support and improved performance
 # TODO after Go 1.4 drops, bump our minimum supported version and drop this vendored dep
 if [ "$1" = '--go' ]; then

+ 1 - 1
image/image.go

@@ -9,8 +9,8 @@ import (
 	"strconv"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"
 )

+ 1 - 1
integration/commands_test.go

@@ -9,9 +9,9 @@ import (
 	"testing"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/client"
 	"github.com/docker/docker/daemon"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/utils"
 	"github.com/docker/libtrust"

+ 1 - 1
integration/runtime_test.go

@@ -16,12 +16,12 @@ import (
 	"testing"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/nat"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/reexec"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"

+ 23 - 20
integration/utils_test.go

@@ -18,20 +18,23 @@ import (
 	"github.com/docker/docker/builtins"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/sysinfo"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"
 )
 
+type Fataler interface {
+	Fatal(...interface{})
+}
+
 // This file contains utility functions for docker's unit test suite.
 // It has to be named XXX_test.go, apparently, in other to access private functions
 // from other XXX_test.go functions.
 
 // Create a temporary daemon suitable for unit testing.
 // Call t.Fatal() at the first error.
-func mkDaemon(f log.Fataler) *daemon.Daemon {
+func mkDaemon(f Fataler) *daemon.Daemon {
 	eng := newTestEngine(f, false, "")
 	return mkDaemonFromEngine(eng, f)
 	// FIXME:
@@ -40,7 +43,7 @@ func mkDaemon(f log.Fataler) *daemon.Daemon {
 	// [...]
 }
 
-func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f log.Fataler, name string) (shortId string) {
+func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler, name string) (shortId string) {
 	job := eng.Job("create", name)
 	if err := job.ImportEnv(config); err != nil {
 		f.Fatal(err)
@@ -53,23 +56,23 @@ func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f lo
 	return engine.Tail(outputBuffer, 1)
 }
 
-func createTestContainer(eng *engine.Engine, config *runconfig.Config, f log.Fataler) (shortId string) {
+func createTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler) (shortId string) {
 	return createNamedTestContainer(eng, config, f, "")
 }
 
-func startContainer(eng *engine.Engine, id string, t log.Fataler) {
+func startContainer(eng *engine.Engine, id string, t Fataler) {
 	job := eng.Job("start", id)
 	if err := job.Run(); err != nil {
 		t.Fatal(err)
 	}
 }
 
-func containerRun(eng *engine.Engine, id string, t log.Fataler) {
+func containerRun(eng *engine.Engine, id string, t Fataler) {
 	startContainer(eng, id, t)
 	containerWait(eng, id, t)
 }
 
-func containerFileExists(eng *engine.Engine, id, dir string, t log.Fataler) bool {
+func containerFileExists(eng *engine.Engine, id, dir string, t Fataler) bool {
 	c := getContainer(eng, id, t)
 	if err := c.Mount(); err != nil {
 		t.Fatal(err)
@@ -84,7 +87,7 @@ func containerFileExists(eng *engine.Engine, id, dir string, t log.Fataler) bool
 	return true
 }
 
-func containerAttach(eng *engine.Engine, id string, t log.Fataler) (io.WriteCloser, io.ReadCloser) {
+func containerAttach(eng *engine.Engine, id string, t Fataler) (io.WriteCloser, io.ReadCloser) {
 	c := getContainer(eng, id, t)
 	i, err := c.StdinPipe()
 	if err != nil {
@@ -97,31 +100,31 @@ func containerAttach(eng *engine.Engine, id string, t log.Fataler) (io.WriteClos
 	return i, o
 }
 
-func containerWait(eng *engine.Engine, id string, t log.Fataler) int {
+func containerWait(eng *engine.Engine, id string, t Fataler) int {
 	ex, _ := getContainer(eng, id, t).WaitStop(-1 * time.Second)
 	return ex
 }
 
-func containerWaitTimeout(eng *engine.Engine, id string, t log.Fataler) error {
+func containerWaitTimeout(eng *engine.Engine, id string, t Fataler) error {
 	_, err := getContainer(eng, id, t).WaitStop(500 * time.Millisecond)
 	return err
 }
 
-func containerKill(eng *engine.Engine, id string, t log.Fataler) {
+func containerKill(eng *engine.Engine, id string, t Fataler) {
 	if err := eng.Job("kill", id).Run(); err != nil {
 		t.Fatal(err)
 	}
 }
 
-func containerRunning(eng *engine.Engine, id string, t log.Fataler) bool {
+func containerRunning(eng *engine.Engine, id string, t Fataler) bool {
 	return getContainer(eng, id, t).IsRunning()
 }
 
-func containerAssertExists(eng *engine.Engine, id string, t log.Fataler) {
+func containerAssertExists(eng *engine.Engine, id string, t Fataler) {
 	getContainer(eng, id, t)
 }
 
-func containerAssertNotExists(eng *engine.Engine, id string, t log.Fataler) {
+func containerAssertNotExists(eng *engine.Engine, id string, t Fataler) {
 	daemon := mkDaemonFromEngine(eng, t)
 	if c := daemon.Get(id); c != nil {
 		t.Fatal(fmt.Errorf("Container %s should not exist", id))
@@ -130,7 +133,7 @@ func containerAssertNotExists(eng *engine.Engine, id string, t log.Fataler) {
 
 // assertHttpNotError expect the given response to not have an error.
 // Otherwise the it causes the test to fail.
-func assertHttpNotError(r *httptest.ResponseRecorder, t log.Fataler) {
+func assertHttpNotError(r *httptest.ResponseRecorder, t Fataler) {
 	// Non-error http status are [200, 400)
 	if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest {
 		t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code))
@@ -139,14 +142,14 @@ func assertHttpNotError(r *httptest.ResponseRecorder, t log.Fataler) {
 
 // assertHttpError expect the given response to have an error.
 // Otherwise the it causes the test to fail.
-func assertHttpError(r *httptest.ResponseRecorder, t log.Fataler) {
+func assertHttpError(r *httptest.ResponseRecorder, t Fataler) {
 	// Non-error http status are [200, 400)
 	if !(r.Code < http.StatusOK || r.Code >= http.StatusBadRequest) {
 		t.Fatal(fmt.Errorf("Unexpected http success code: %v", r.Code))
 	}
 }
 
-func getContainer(eng *engine.Engine, id string, t log.Fataler) *daemon.Container {
+func getContainer(eng *engine.Engine, id string, t Fataler) *daemon.Container {
 	daemon := mkDaemonFromEngine(eng, t)
 	c := daemon.Get(id)
 	if c == nil {
@@ -155,7 +158,7 @@ func getContainer(eng *engine.Engine, id string, t log.Fataler) *daemon.Containe
 	return c
 }
 
-func mkDaemonFromEngine(eng *engine.Engine, t log.Fataler) *daemon.Daemon {
+func mkDaemonFromEngine(eng *engine.Engine, t Fataler) *daemon.Daemon {
 	iDaemon := eng.Hack_GetGlobalVar("httpapi.daemon")
 	if iDaemon == nil {
 		panic("Legacy daemon field not set in engine")
@@ -167,7 +170,7 @@ func mkDaemonFromEngine(eng *engine.Engine, t log.Fataler) *daemon.Daemon {
 	return daemon
 }
 
-func newTestEngine(t log.Fataler, autorestart bool, root string) *engine.Engine {
+func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
 	if root == "" {
 		if dir, err := newTestDirectory(unitTestStoreBase); err != nil {
 			t.Fatal(err)
@@ -200,7 +203,7 @@ func newTestEngine(t log.Fataler, autorestart bool, root string) *engine.Engine
 	return eng
 }
 
-func NewTestEngine(t log.Fataler) *engine.Engine {
+func NewTestEngine(t Fataler) *engine.Engine {
 	return newTestEngine(t, false, "")
 }
 

+ 1 - 1
pkg/archive/archive.go

@@ -18,8 +18,8 @@ import (
 
 	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/fileutils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/pools"
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/pkg/system"

+ 1 - 1
pkg/archive/changes.go

@@ -12,7 +12,7 @@ import (
 
 	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/pools"
 	"github.com/docker/docker/pkg/system"
 )

+ 1 - 1
pkg/broadcastwriter/broadcastwriter.go

@@ -6,8 +6,8 @@ import (
 	"sync"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/jsonlog"
-	"github.com/docker/docker/pkg/log"
 )
 
 // BroadcastWriter accumulate multiple io.WriteCloser by stream.

+ 1 - 1
pkg/fileutils/fileutils.go

@@ -1,7 +1,7 @@
 package fileutils
 
 import (
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 	"path/filepath"
 )
 

+ 1 - 1
pkg/httputils/resumablerequestreader.go

@@ -6,7 +6,7 @@ import (
 	"net/http"
 	"time"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 type resumableRequestReader struct {

+ 1 - 1
pkg/iptables/iptables.go

@@ -9,7 +9,7 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 type Action string

+ 0 - 114
pkg/log/log.go

@@ -1,114 +0,0 @@
-package log
-
-import (
-	"fmt"
-	"io"
-	"os"
-	"runtime"
-	"strings"
-	"time"
-
-	"github.com/docker/docker/pkg/timeutils"
-)
-
-type priority int
-
-const (
-	errorFormat = "[%s] [%s] %s:%d %s\n"
-	logFormat   = "[%s] [%s] %s\n"
-
-	fatalPriority priority = iota
-	errorPriority
-	infoPriority
-	debugPriority
-)
-
-// A common interface to access the Fatal method of
-// both testing.B and testing.T.
-type Fataler interface {
-	Fatal(args ...interface{})
-}
-
-func (p priority) String() string {
-	switch p {
-	case fatalPriority:
-		return "fatal"
-	case errorPriority:
-		return "error"
-	case infoPriority:
-		return "info"
-	case debugPriority:
-		return "debug"
-	}
-
-	return ""
-}
-
-var DefaultLogger = Logger{Out: os.Stdout, Err: os.Stderr}
-
-// 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
-func Debugf(format string, a ...interface{}) (int, error) {
-	return DefaultLogger.Debugf(format, a...)
-}
-
-func Infof(format string, a ...interface{}) (int, error) {
-	return DefaultLogger.Infof(format, a...)
-}
-
-func Errorf(format string, a ...interface{}) (int, error) {
-	return DefaultLogger.Errorf(format, a...)
-}
-
-func Fatal(a ...interface{}) {
-	DefaultLogger.Fatalf("%s", a...)
-}
-
-func Fatalf(format string, a ...interface{}) {
-	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)
-}
-
-func (l Logger) logf(stream io.Writer, level priority, format string, a ...interface{}) (int, error) {
-	var prefix string
-
-	if level <= errorPriority || level == debugPriority {
-		// Retrieve the stack infos
-		_, file, line, ok := runtime.Caller(2)
-		if !ok {
-			file = "<unknown>"
-			line = -1
-		} else {
-			file = file[strings.LastIndex(file, "/")+1:]
-		}
-		prefix = fmt.Sprintf(errorFormat, time.Now().Format(timeutils.RFC3339NanoFixed), level.String(), file, line, format)
-	} else {
-		prefix = fmt.Sprintf(logFormat, time.Now().Format(timeutils.RFC3339NanoFixed), level.String(), format)
-	}
-
-	return fmt.Fprintf(stream, prefix, a...)
-}

+ 0 - 39
pkg/log/log_test.go

@@ -1,39 +0,0 @@
-package log
-
-import (
-	"bytes"
-	"regexp"
-
-	"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) {
-	var output *bytes.Buffer
-
-	tests := []struct {
-		Level           priority
-		Format          string
-		Values          []interface{}
-		ExpectedPattern string
-	}{
-		{fatalPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[fatal\\] testing.go:\\d+ 1 \\+ 1 = 2"},
-		{errorPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[error\\] testing.go:\\d+ 1 \\+ 1 = 2"},
-		{infoPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[info\\] 1 \\+ 1 = 2"},
-		{debugPriority, "%d + %d = %d", []interface{}{1, 1, 2}, "\\[" + reRFC3339NanoFixed + "\\] \\[debug\\] testing.go:\\d+ 1 \\+ 1 = 2"},
-	}
-
-	for i, test := range tests {
-		output = &bytes.Buffer{}
-		DefaultLogger.logf(output, test.Level, test.Format, test.Values...)
-
-		expected := regexp.MustCompile(test.ExpectedPattern)
-		if !expected.MatchString(output.String()) {
-			t.Errorf("[%d] Log output does not match expected pattern:\n\tExpected: %s\n\tOutput: %s",
-				i,
-				expected.String(),
-				output.String())
-		}
-	}
-}

+ 1 - 1
pkg/signal/trap.go

@@ -6,7 +6,7 @@ import (
 	"sync/atomic"
 	"syscall"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 // Trap sets up a simplified signal "trap", appropriate for common

+ 1 - 1
pkg/stdcopy/stdcopy.go

@@ -5,7 +5,7 @@ import (
 	"errors"
 	"io"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 const (

+ 1 - 1
pkg/tarsum/tarsum.go

@@ -13,7 +13,7 @@ import (
 
 	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 const (

+ 1 - 1
registry/endpoint.go

@@ -9,7 +9,7 @@ import (
 	"net/url"
 	"strings"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 // scans string for api version in the URL path. returns the trimmed hostname, if version found, string and API version.

+ 1 - 1
registry/registry_mock_test.go

@@ -15,7 +15,7 @@ import (
 
 	"github.com/gorilla/mux"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 var (

+ 1 - 1
registry/session.go

@@ -17,8 +17,8 @@ import (
 	"strings"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/httputils"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/docker/docker/utils"
 )

+ 1 - 1
registry/session_v2.go

@@ -8,7 +8,7 @@ import (
 	"net/url"
 	"strconv"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/utils"
 	"github.com/gorilla/mux"
 )

+ 1 - 1
runconfig/merge.go

@@ -3,8 +3,8 @@ package runconfig
 import (
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/nat"
-	"github.com/docker/docker/pkg/log"
 )
 
 func Merge(userConf, imageConf *Config) error {

+ 1 - 1
trust/service.go

@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"time"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/libtrust"
 )
 

+ 1 - 1
trust/trusts.go

@@ -12,7 +12,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libtrust/trustgraph"
 )
 

+ 1 - 1
utils/http.go

@@ -5,7 +5,7 @@ import (
 	"net/http"
 	"strings"
 
-	"github.com/docker/docker/pkg/log"
+	log "github.com/Sirupsen/logrus"
 )
 
 // VersionInfo is used to model entities which has a version.

+ 1 - 1
utils/utils.go

@@ -20,10 +20,10 @@ import (
 	"sync"
 	"syscall"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/pkg/fileutils"
 	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/log"
 )
 
 type KeyValuePair struct {

+ 1 - 0
vendor/src/github.com/Sirupsen/logrus/.gitignore

@@ -0,0 +1 @@
+logrus

+ 7 - 0
vendor/src/github.com/Sirupsen/logrus/.travis.yml

@@ -0,0 +1,7 @@
+language: go
+go:
+  - 1.1
+  - 1.2
+  - tip
+before_script:
+  - go get github.com/stretchr/testify

+ 21 - 0
vendor/src/github.com/Sirupsen/logrus/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 336 - 0
vendor/src/github.com/Sirupsen/logrus/README.md

@@ -0,0 +1,336 @@
+# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)
+
+Logrus is a structured logger for Go (golang), completely API compatible with
+the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
+yet stable (pre 1.0), the core API is unlikely change much but please version
+control your Logrus to make sure you aren't fetching latest `master` on every
+build.**
+
+Nicely color-coded in development (when a TTY is attached, otherwise just
+plain text):
+
+![Colored](http://i.imgur.com/PY7qMwd.png)
+
+With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
+or Splunk:
+
+```json
+{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
+ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
+
+{"level":"warning","msg":"The group's number increased tremendously!",
+"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
+"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
+"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
+
+{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
+"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
+```
+
+With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
+attached, the output is compatible with the
+[l2met](http://r.32k.io/l2met-introduction) format:
+
+```text
+time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
+time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
+time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
+time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
+time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
+```
+
+#### Example
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+```go
+package main
+
+import (
+  log "github.com/Sirupsen/logrus"
+)
+
+func main() {
+  log.WithFields(log.Fields{
+    "animal": "walrus",
+  }).Info("A walrus appears")
+}
+```
+
+Note that it's completely api-compatible with the stdlib logger, so you can
+replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
+and you'll now have the flexibility of Logrus. You can customize it all you
+want:
+
+```go
+package main
+
+import (
+  "os"
+  log "github.com/Sirupsen/logrus"
+  "github.com/Sirupsen/logrus/hooks/airbrake"
+)
+
+func init() {
+  // Log as JSON instead of the default ASCII formatter.
+  log.SetFormatter(&log.JSONFormatter{})
+
+  // Use the Airbrake hook to report errors that have Error severity or above to
+  // an exception tracker. You can create custom hooks, see the Hooks section.
+  log.AddHook(logrus_airbrake.AirbrakeHook)
+
+  // Output to stderr instead of stdout, could also be a file.
+  log.SetOutput(os.Stderr)
+
+  // Only log the warning severity or above.
+  log.SetLevel(log.WarnLevel)
+}
+
+func main() {
+  log.WithFields(log.Fields{
+    "animal": "walrus",
+    "size":   10,
+  }).Info("A group of walrus emerges from the ocean")
+
+  log.WithFields(log.Fields{
+    "omg":    true,
+    "number": 122,
+  }).Warn("The group's number increased tremendously!")
+
+  log.WithFields(log.Fields{
+    "omg":    true,
+    "number": 100,
+  }).Fatal("The ice breaks!")
+}
+```
+
+For more advanced usage such as logging to multiple locations from the same
+application, you can also create an instance of the `logrus` Logger:
+
+```go
+package main
+
+import (
+  "github.com/Sirupsen/logrus"
+)
+
+// Create a new instance of the logger. You can have any number of instances.
+var log = logrus.New()
+
+func main() {
+  // The API for setting attributes is a little different than the package level
+  // exported logger. See Godoc.
+  log.Out = os.Stderr
+
+  log.WithFields(log.Fields{
+    "animal": "walrus",
+    "size":   10,
+  }).Info("A group of walrus emerges from the ocean")
+}
+```
+
+#### Fields
+
+Logrus encourages careful, structured logging though logging fields instead of
+long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
+to send event %s to topic %s with key %d")`, you should log the much more
+discoverable:
+
+```go
+log.WithFields(log.Fields{
+  "event": event,
+  "topic": topic,
+  "key": key,
+}).Fatal("Failed to send event")
+```
+
+We've found this API forces you to think about logging in a way that produces
+much more useful logging messages. We've been in countless situations where just
+a single added field to a log statement that was already there would've saved us
+hours. The `WithFields` call is optional.
+
+In general, with Logrus using any of the `printf`-family functions should be
+seen as a hint you should add a field, however, you can still use the
+`printf`-family functions with Logrus.
+
+#### Hooks
+
+You can add hooks for logging levels. For example to send errors to an exception
+tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
+multiple places simultaneously, e.g. syslog.
+
+```go
+// Not the real implementation of the Airbrake hook. Just a simple sample.
+import (
+  log "github.com/Sirupsen/logrus"
+)
+
+func init() {
+  log.AddHook(new(AirbrakeHook))
+}
+
+type AirbrakeHook struct{}
+
+// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
+// the fields for the entry. See the Fields section of the README.
+func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
+  err := airbrake.Notify(entry.Data["error"].(error))
+  if err != nil {
+    log.WithFields(log.Fields{
+      "source":   "airbrake",
+      "endpoint": airbrake.Endpoint,
+    }).Info("Failed to send error to Airbrake")
+  }
+
+  return nil
+}
+
+// `Levels()` returns a slice of `Levels` the hook is fired for.
+func (hook *AirbrakeHook) Levels() []log.Level {
+  return []log.Level{
+    log.ErrorLevel,
+    log.FatalLevel,
+    log.PanicLevel,
+  }
+}
+```
+
+Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
+
+```go
+import (
+  log "github.com/Sirupsen/logrus"
+  "github.com/Sirupsen/logrus/hooks/airbrake"
+  "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func init() {
+  log.AddHook(new(logrus_airbrake.AirbrakeHook))
+  log.AddHook(logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""))
+}
+```
+
+* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go).
+  Send errors to an exception tracking service compatible with the Airbrake API.
+  Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
+
+* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go).
+  Send errors to remote syslog server.
+  Uses standard library `log/syslog` behind the scenes.
+
+#### Level logging
+
+Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
+
+```go
+log.Debug("Useful debugging information.")
+log.Info("Something noteworthy happened!")
+log.Warn("You should probably take a look at this.")
+log.Error("Something failed but I'm not quitting.")
+// Calls os.Exit(1) after logging
+log.Fatal("Bye.")
+// Calls panic() after logging
+log.Panic("I'm bailing.")
+```
+
+You can set the logging level on a `Logger`, then it will only log entries with
+that severity or anything above it:
+
+```go
+// Will log anything that is info or above (warn, error, fatal, panic). Default.
+log.SetLevel(log.InfoLevel)
+```
+
+It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
+environment if your application has that.
+
+#### Entries
+
+Besides the fields added with `WithField` or `WithFields` some fields are
+automatically added to all logging events:
+
+1. `time`. The timestamp when the entry was created.
+2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
+   the `AddFields` call. E.g. `Failed to send event.`
+3. `level`. The logging level. E.g. `info`.
+
+#### Environments
+
+Logrus has no notion of environment.
+
+If you wish for hooks and formatters to only be used in specific environments,
+you should handle that yourself. For example, if your application has a global
+variable `Environment`, which is a string representation of the environment you
+could do:
+
+```go
+import (
+  log "github.com/Sirupsen/logrus"
+)
+
+init() {
+  // do something here to set environment depending on an environment variable
+  // or command-line flag
+  if Environment == "production" {
+    log.SetFormatter(logrus.JSONFormatter)
+  } else {
+    // The TextFormatter is default, you don't actually have to do this.
+    log.SetFormatter(logrus.TextFormatter)
+  }
+}
+```
+
+This configuration is how `logrus` was intended to be used, but JSON in
+production is mostly only useful if you do log aggregation with tools like
+Splunk or Logstash.
+
+#### Formatters
+
+The built-in logging formatters are:
+
+* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
+  without colors.
+  * *Note:* to force colored output when there is no TTY, set the `ForceColors`
+    field to `true`.  To force no colored output even if there is a TTY  set the 
+    `DisableColors` field to `true`
+* `logrus.JSONFormatter`. Logs fields as JSON.
+
+Third party logging formatters:
+
+* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+
+You can define your formatter by implementing the `Formatter` interface,
+requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
+`Fields` type (`map[string]interface{}`) with all your fields as well as the
+default ones (see Entries section above):
+
+```go
+type MyJSONFormatter struct {
+}
+
+log.SetFormatter(new(MyJSONFormatter))
+
+func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
+  // Note this doesn't include Time, Level and Message which are available on
+  // the Entry. Consult `godoc` on information about those fields or read the
+  // source of the official loggers.
+  serialized, err := json.Marshal(entry.Data)
+    if err != nil {
+      return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+    }
+  return append(serialized, '\n'), nil
+}
+```
+
+#### Rotation
+
+Log rotation is not provided with Logrus. Log rotation should be done by an
+external program (like `logrotated(8)`) that can compress and delete old log
+entries. It should not be a feature of the application-level logger.
+
+
+[godoc]: https://godoc.org/github.com/Sirupsen/logrus

+ 242 - 0
vendor/src/github.com/Sirupsen/logrus/entry.go

@@ -0,0 +1,242 @@
+package logrus
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"time"
+)
+
+// An entry is the final or intermediate Logrus logging entry. It containts all
+// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
+// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+type Entry struct {
+	Logger *Logger
+
+	// Contains all the fields set by the user.
+	Data Fields
+
+	// Time at which the log entry was created
+	Time time.Time
+
+	// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
+	Level Level
+
+	// Message passed to Debug, Info, Warn, Error, Fatal or Panic
+	Message string
+}
+
+var baseTimestamp time.Time
+
+func NewEntry(logger *Logger) *Entry {
+	return &Entry{
+		Logger: logger,
+		// Default is three fields, give a little extra room
+		Data: make(Fields, 5),
+	}
+}
+
+// Returns a reader for the entry, which is a proxy to the formatter.
+func (entry *Entry) Reader() (*bytes.Buffer, error) {
+	serialized, err := entry.Logger.Formatter.Format(entry)
+	return bytes.NewBuffer(serialized), err
+}
+
+// Returns the string representation from the reader and ultimately the
+// formatter.
+func (entry *Entry) String() (string, error) {
+	reader, err := entry.Reader()
+	if err != nil {
+		return "", err
+	}
+
+	return reader.String(), err
+}
+
+// Add a single field to the Entry.
+func (entry *Entry) WithField(key string, value interface{}) *Entry {
+	return entry.WithFields(Fields{key: value})
+}
+
+// Add a map of fields to the Entry.
+func (entry *Entry) WithFields(fields Fields) *Entry {
+	data := Fields{}
+	for k, v := range entry.Data {
+		data[k] = v
+	}
+	for k, v := range fields {
+		data[k] = v
+	}
+	return &Entry{Logger: entry.Logger, Data: data}
+}
+
+func (entry *Entry) log(level Level, msg string) string {
+	entry.Time = time.Now()
+	entry.Level = level
+	entry.Message = msg
+
+	if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to fire hook", err)
+	}
+
+	reader, err := entry.Reader()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
+	}
+
+	entry.Logger.mu.Lock()
+	defer entry.Logger.mu.Unlock()
+
+	_, err = io.Copy(entry.Logger.Out, reader)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to write to log, %v", err)
+	}
+
+	return reader.String()
+}
+
+func (entry *Entry) Debug(args ...interface{}) {
+	if entry.Logger.Level >= DebugLevel {
+		entry.log(DebugLevel, fmt.Sprint(args...))
+	}
+}
+
+func (entry *Entry) Print(args ...interface{}) {
+	entry.Info(args...)
+}
+
+func (entry *Entry) Info(args ...interface{}) {
+	if entry.Logger.Level >= InfoLevel {
+		entry.log(InfoLevel, fmt.Sprint(args...))
+	}
+}
+
+func (entry *Entry) Warn(args ...interface{}) {
+	if entry.Logger.Level >= WarnLevel {
+		entry.log(WarnLevel, fmt.Sprint(args...))
+	}
+}
+
+func (entry *Entry) Error(args ...interface{}) {
+	if entry.Logger.Level >= ErrorLevel {
+		entry.log(ErrorLevel, fmt.Sprint(args...))
+	}
+}
+
+func (entry *Entry) Fatal(args ...interface{}) {
+	if entry.Logger.Level >= FatalLevel {
+		entry.log(FatalLevel, fmt.Sprint(args...))
+	}
+	os.Exit(1)
+}
+
+func (entry *Entry) Panic(args ...interface{}) {
+	if entry.Logger.Level >= PanicLevel {
+		msg := entry.log(PanicLevel, fmt.Sprint(args...))
+		panic(msg)
+	}
+	panic(fmt.Sprint(args...))
+}
+
+// Entry Printf family functions
+
+func (entry *Entry) Debugf(format string, args ...interface{}) {
+	if entry.Logger.Level >= DebugLevel {
+		entry.Debug(fmt.Sprintf(format, args...))
+	}
+}
+
+func (entry *Entry) Infof(format string, args ...interface{}) {
+	if entry.Logger.Level >= InfoLevel {
+		entry.Info(fmt.Sprintf(format, args...))
+	}
+}
+
+func (entry *Entry) Printf(format string, args ...interface{}) {
+	entry.Infof(format, args...)
+}
+
+func (entry *Entry) Warnf(format string, args ...interface{}) {
+	if entry.Logger.Level >= WarnLevel {
+		entry.Warn(fmt.Sprintf(format, args...))
+	}
+}
+
+func (entry *Entry) Warningf(format string, args ...interface{}) {
+	entry.Warnf(format, args...)
+}
+
+func (entry *Entry) Errorf(format string, args ...interface{}) {
+	if entry.Logger.Level >= ErrorLevel {
+		entry.Error(fmt.Sprintf(format, args...))
+	}
+}
+
+func (entry *Entry) Fatalf(format string, args ...interface{}) {
+	if entry.Logger.Level >= FatalLevel {
+		entry.Fatal(fmt.Sprintf(format, args...))
+	}
+}
+
+func (entry *Entry) Panicf(format string, args ...interface{}) {
+	if entry.Logger.Level >= PanicLevel {
+		entry.Panic(fmt.Sprintf(format, args...))
+	}
+}
+
+// Entry Println family functions
+
+func (entry *Entry) Debugln(args ...interface{}) {
+	if entry.Logger.Level >= DebugLevel {
+		entry.Debug(entry.sprintlnn(args...))
+	}
+}
+
+func (entry *Entry) Infoln(args ...interface{}) {
+	if entry.Logger.Level >= InfoLevel {
+		entry.Info(entry.sprintlnn(args...))
+	}
+}
+
+func (entry *Entry) Println(args ...interface{}) {
+	entry.Infoln(args...)
+}
+
+func (entry *Entry) Warnln(args ...interface{}) {
+	if entry.Logger.Level >= WarnLevel {
+		entry.Warn(entry.sprintlnn(args...))
+	}
+}
+
+func (entry *Entry) Warningln(args ...interface{}) {
+	entry.Warnln(args...)
+}
+
+func (entry *Entry) Errorln(args ...interface{}) {
+	if entry.Logger.Level >= ErrorLevel {
+		entry.Error(entry.sprintlnn(args...))
+	}
+}
+
+func (entry *Entry) Fatalln(args ...interface{}) {
+	if entry.Logger.Level >= FatalLevel {
+		entry.Fatal(entry.sprintlnn(args...))
+	}
+}
+
+func (entry *Entry) Panicln(args ...interface{}) {
+	if entry.Logger.Level >= PanicLevel {
+		entry.Panic(entry.sprintlnn(args...))
+	}
+}
+
+// Sprintlnn => Sprint no newline. This is to get the behavior of how
+// fmt.Sprintln where spaces are always added between operands, regardless of
+// their type. Instead of vendoring the Sprintln implementation to spare a
+// string allocation, we do the simplest thing.
+func (entry *Entry) sprintlnn(args ...interface{}) string {
+	msg := fmt.Sprintln(args...)
+	return msg[:len(msg)-1]
+}

+ 29 - 0
vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go

@@ -0,0 +1,29 @@
+package main
+
+import (
+	"github.com/Sirupsen/logrus"
+)
+
+var log = logrus.New()
+
+func init() {
+	log.Formatter = new(logrus.JSONFormatter)
+	log.Formatter = new(logrus.TextFormatter) // default
+}
+
+func main() {
+	log.WithFields(logrus.Fields{
+		"animal": "walrus",
+		"size":   10,
+	}).Info("A group of walrus emerges from the ocean")
+
+	log.WithFields(logrus.Fields{
+		"omg":    true,
+		"number": 122,
+	}).Warn("The group's number increased tremendously!")
+
+	log.WithFields(logrus.Fields{
+		"omg":    true,
+		"number": 100,
+	}).Fatal("The ice breaks!")
+}

+ 35 - 0
vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go

@@ -0,0 +1,35 @@
+package main
+
+import (
+	"github.com/Sirupsen/logrus"
+	"github.com/Sirupsen/logrus/hooks/airbrake"
+	"github.com/tobi/airbrake-go"
+)
+
+var log = logrus.New()
+
+func init() {
+	log.Formatter = new(logrus.TextFormatter) // default
+	log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
+}
+
+func main() {
+	airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
+	airbrake.ApiKey = "whatever"
+	airbrake.Environment = "production"
+
+	log.WithFields(logrus.Fields{
+		"animal": "walrus",
+		"size":   10,
+	}).Info("A group of walrus emerges from the ocean")
+
+	log.WithFields(logrus.Fields{
+		"omg":    true,
+		"number": 122,
+	}).Warn("The group's number increased tremendously!")
+
+	log.WithFields(logrus.Fields{
+		"omg":    true,
+		"number": 100,
+	}).Fatal("The ice breaks!")
+}

+ 177 - 0
vendor/src/github.com/Sirupsen/logrus/exported.go

@@ -0,0 +1,177 @@
+package logrus
+
+import (
+	"io"
+)
+
+var (
+	// std is the name of the standard logger in stdlib `log`
+	std = New()
+)
+
+// SetOutput sets the standard logger output.
+func SetOutput(out io.Writer) {
+	std.mu.Lock()
+	defer std.mu.Unlock()
+	std.Out = out
+}
+
+// SetFormatter sets the standard logger formatter.
+func SetFormatter(formatter Formatter) {
+	std.mu.Lock()
+	defer std.mu.Unlock()
+	std.Formatter = formatter
+}
+
+// SetLevel sets the standard logger level.
+func SetLevel(level Level) {
+	std.mu.Lock()
+	defer std.mu.Unlock()
+	std.Level = level
+}
+
+// AddHook adds a hook to the standard logger hooks.
+func AddHook(hook Hook) {
+	std.mu.Lock()
+	defer std.mu.Unlock()
+	std.Hooks.Add(hook)
+}
+
+// WithField creates an entry from the standard logger and adds a field to
+// it. If you want multiple fields, use `WithFields`.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithField(key string, value interface{}) *Entry {
+	return std.WithField(key, value)
+}
+
+// WithFields creates an entry from the standard logger and adds multiple
+// fields to it. This is simply a helper for `WithField`, invoking it
+// once for each field.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithFields(fields Fields) *Entry {
+	return std.WithFields(fields)
+}
+
+// Debug logs a message at level Debug on the standard logger.
+func Debug(args ...interface{}) {
+	std.Debug(args...)
+}
+
+// Print logs a message at level Info on the standard logger.
+func Print(args ...interface{}) {
+	std.Print(args...)
+}
+
+// Info logs a message at level Info on the standard logger.
+func Info(args ...interface{}) {
+	std.Info(args...)
+}
+
+// Warn logs a message at level Warn on the standard logger.
+func Warn(args ...interface{}) {
+	std.Warn(args...)
+}
+
+// Warning logs a message at level Warn on the standard logger.
+func Warning(args ...interface{}) {
+	std.Warning(args...)
+}
+
+// Error logs a message at level Error on the standard logger.
+func Error(args ...interface{}) {
+	std.Error(args...)
+}
+
+// Panic logs a message at level Panic on the standard logger.
+func Panic(args ...interface{}) {
+	std.Panic(args...)
+}
+
+// Fatal logs a message at level Fatal on the standard logger.
+func Fatal(args ...interface{}) {
+	std.Fatal(args...)
+}
+
+// Debugf logs a message at level Debugf on the standard logger.
+func Debugf(format string, args ...interface{}) {
+	std.Debugf(format, args...)
+}
+
+// Printf logs a message at level Info on the standard logger.
+func Printf(format string, args ...interface{}) {
+	std.Printf(format, args...)
+}
+
+// Infof logs a message at level Info on the standard logger.
+func Infof(format string, args ...interface{}) {
+	std.Infof(format, args...)
+}
+
+// Warnf logs a message at level Warn on the standard logger.
+func Warnf(format string, args ...interface{}) {
+	std.Warnf(format, args...)
+}
+
+// Warningf logs a message at level Warn on the standard logger.
+func Warningf(format string, args ...interface{}) {
+	std.Warningf(format, args...)
+}
+
+// Errorf logs a message at level Error on the standard logger.
+func Errorf(format string, args ...interface{}) {
+	std.Errorf(format, args...)
+}
+
+// Panicf logs a message at level Pancf on the standard logger.
+func Panicf(format string, args ...interface{}) {
+	std.Panicf(format, args...)
+}
+
+// Fatalf logs a message at level Fatal on the standard logger.
+func Fatalf(format string, args ...interface{}) {
+	std.Fatalf(format, args...)
+}
+
+// Debugln logs a message at level Debug on the standard logger.
+func Debugln(args ...interface{}) {
+	std.Debugln(args...)
+}
+
+// Println logs a message at level Info on the standard logger.
+func Println(args ...interface{}) {
+	std.Println(args...)
+}
+
+// Infoln logs a message at level Info on the standard logger.
+func Infoln(args ...interface{}) {
+	std.Infoln(args...)
+}
+
+// Warnln logs a message at level Warn on the standard logger.
+func Warnln(args ...interface{}) {
+	std.Warnln(args...)
+}
+
+// Warningln logs a message at level Warn on the standard logger.
+func Warningln(args ...interface{}) {
+	std.Warningln(args...)
+}
+
+// Errorln logs a message at level Error on the standard logger.
+func Errorln(args ...interface{}) {
+	std.Errorln(args...)
+}
+
+// Panicln logs a message at level Panic on the standard logger.
+func Panicln(args ...interface{}) {
+	std.Panicln(args...)
+}
+
+// Fatalln logs a message at level Fatal on the standard logger.
+func Fatalln(args ...interface{}) {
+	std.Fatalln(args...)
+}

+ 54 - 0
vendor/src/github.com/Sirupsen/logrus/formatter.go

@@ -0,0 +1,54 @@
+package logrus
+
+import (
+	"time"
+)
+
+// The Formatter interface is used to implement a custom Formatter. It takes an
+// `Entry`. It exposes all the fields, including the default ones:
+//
+// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
+// * `entry.Data["time"]`. The timestamp.
+// * `entry.Data["level"]. The level the entry was logged at.
+//
+// Any additional fields added with `WithField` or `WithFields` are also in
+// `entry.Data`. Format is expected to return an array of bytes which are then
+// logged to `logger.Out`.
+type Formatter interface {
+	Format(*Entry) ([]byte, error)
+}
+
+// This is to not silently overwrite `time`, `msg` and `level` fields when
+// dumping it. If this code wasn't there doing:
+//
+//  logrus.WithField("level", 1).Info("hello")
+//
+// Would just silently drop the user provided level. Instead with this code
+// it'll logged as:
+//
+//  {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
+//
+// It's not exported because it's still using Data in an opionated way. It's to
+// avoid code duplication between the two default formatters.
+func prefixFieldClashes(entry *Entry) {
+	_, ok := entry.Data["time"]
+	if ok {
+		entry.Data["fields.time"] = entry.Data["time"]
+	}
+
+	entry.Data["time"] = entry.Time.Format(time.RFC3339)
+
+	_, ok = entry.Data["msg"]
+	if ok {
+		entry.Data["fields.msg"] = entry.Data["msg"]
+	}
+
+	entry.Data["msg"] = entry.Message
+
+	_, ok = entry.Data["level"]
+	if ok {
+		entry.Data["fields.level"] = entry.Data["level"]
+	}
+
+	entry.Data["level"] = entry.Level.String()
+}

+ 122 - 0
vendor/src/github.com/Sirupsen/logrus/hook_test.go

@@ -0,0 +1,122 @@
+package logrus
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+type TestHook struct {
+	Fired bool
+}
+
+func (hook *TestHook) Fire(entry *Entry) error {
+	hook.Fired = true
+	return nil
+}
+
+func (hook *TestHook) Levels() []Level {
+	return []Level{
+		DebugLevel,
+		InfoLevel,
+		WarnLevel,
+		ErrorLevel,
+		FatalLevel,
+		PanicLevel,
+	}
+}
+
+func TestHookFires(t *testing.T) {
+	hook := new(TestHook)
+
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Hooks.Add(hook)
+		assert.Equal(t, hook.Fired, false)
+
+		log.Print("test")
+	}, func(fields Fields) {
+		assert.Equal(t, hook.Fired, true)
+	})
+}
+
+type ModifyHook struct {
+}
+
+func (hook *ModifyHook) Fire(entry *Entry) error {
+	entry.Data["wow"] = "whale"
+	return nil
+}
+
+func (hook *ModifyHook) Levels() []Level {
+	return []Level{
+		DebugLevel,
+		InfoLevel,
+		WarnLevel,
+		ErrorLevel,
+		FatalLevel,
+		PanicLevel,
+	}
+}
+
+func TestHookCanModifyEntry(t *testing.T) {
+	hook := new(ModifyHook)
+
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Hooks.Add(hook)
+		log.WithField("wow", "elephant").Print("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["wow"], "whale")
+	})
+}
+
+func TestCanFireMultipleHooks(t *testing.T) {
+	hook1 := new(ModifyHook)
+	hook2 := new(TestHook)
+
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Hooks.Add(hook1)
+		log.Hooks.Add(hook2)
+
+		log.WithField("wow", "elephant").Print("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["wow"], "whale")
+		assert.Equal(t, hook2.Fired, true)
+	})
+}
+
+type ErrorHook struct {
+	Fired bool
+}
+
+func (hook *ErrorHook) Fire(entry *Entry) error {
+	hook.Fired = true
+	return nil
+}
+
+func (hook *ErrorHook) Levels() []Level {
+	return []Level{
+		ErrorLevel,
+	}
+}
+
+func TestErrorHookShouldntFireOnInfo(t *testing.T) {
+	hook := new(ErrorHook)
+
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Hooks.Add(hook)
+		log.Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, hook.Fired, false)
+	})
+}
+
+func TestErrorHookShouldFireOnError(t *testing.T) {
+	hook := new(ErrorHook)
+
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Hooks.Add(hook)
+		log.Error("test")
+	}, func(fields Fields) {
+		assert.Equal(t, hook.Fired, true)
+	})
+}

+ 34 - 0
vendor/src/github.com/Sirupsen/logrus/hooks.go

@@ -0,0 +1,34 @@
+package logrus
+
+// A hook to be fired when logging on the logging levels returned from
+// `Levels()` on your implementation of the interface. Note that this is not
+// fired in a goroutine or a channel with workers, you should handle such
+// functionality yourself if your call is non-blocking and you don't wish for
+// the logging calls for levels returned from `Levels()` to block.
+type Hook interface {
+	Levels() []Level
+	Fire(*Entry) error
+}
+
+// Internal type for storing the hooks on a logger instance.
+type levelHooks map[Level][]Hook
+
+// Add a hook to an instance of logger. This is called with
+// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
+func (hooks levelHooks) Add(hook Hook) {
+	for _, level := range hook.Levels() {
+		hooks[level] = append(hooks[level], hook)
+	}
+}
+
+// Fire all the hooks for the passed level. Used by `entry.log` to fire
+// appropriate hooks for a log entry.
+func (hooks levelHooks) Fire(level Level, entry *Entry) error {
+	for _, hook := range hooks[level] {
+		if err := hook.Fire(entry); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}

+ 54 - 0
vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go

@@ -0,0 +1,54 @@
+package logrus_airbrake
+
+import (
+	"github.com/Sirupsen/logrus"
+	"github.com/tobi/airbrake-go"
+)
+
+// AirbrakeHook to send exceptions to an exception-tracking service compatible
+// with the Airbrake API. You must set:
+// * airbrake.Endpoint
+// * airbrake.ApiKey
+// * airbrake.Environment (only sends exceptions when set to "production")
+//
+// Before using this hook, to send an error. Entries that trigger an Error,
+// Fatal or Panic should now include an "error" field to send to Airbrake.
+type AirbrakeHook struct{}
+
+func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
+	if entry.Data["error"] == nil {
+		entry.Logger.WithFields(logrus.Fields{
+			"source":   "airbrake",
+			"endpoint": airbrake.Endpoint,
+		}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
+		return nil
+	}
+
+	err, ok := entry.Data["error"].(error)
+	if !ok {
+		entry.Logger.WithFields(logrus.Fields{
+			"source":   "airbrake",
+			"endpoint": airbrake.Endpoint,
+		}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
+		return nil
+	}
+
+	airErr := airbrake.Notify(err)
+	if airErr != nil {
+		entry.Logger.WithFields(logrus.Fields{
+			"source":   "airbrake",
+			"endpoint": airbrake.Endpoint,
+			"error":    airErr,
+		}).Warn("Failed to send error to Airbrake")
+	}
+
+	return nil
+}
+
+func (hook *AirbrakeHook) Levels() []logrus.Level {
+	return []logrus.Level{
+		logrus.ErrorLevel,
+		logrus.FatalLevel,
+		logrus.PanicLevel,
+	}
+}

+ 20 - 0
vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md

@@ -0,0 +1,20 @@
+# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
+
+## Usage
+
+```go
+import (
+  "log/syslog"
+  "github.com/Sirupsen/logrus"
+  "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+  log       := logrus.New()
+  hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+  if err == nil {
+    log.Hooks.Add(hook)
+  }
+}
+```

+ 59 - 0
vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go

@@ -0,0 +1,59 @@
+package logrus_syslog
+
+import (
+	"fmt"
+	"github.com/Sirupsen/logrus"
+	"log/syslog"
+	"os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+	Writer        *syslog.Writer
+	SyslogNetwork string
+	SyslogRaddr   string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+	w, err := syslog.Dial(network, raddr, priority, tag)
+	return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+	line, err := entry.String()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+		return err
+	}
+
+	switch entry.Data["level"] {
+	case "panic":
+		return hook.Writer.Crit(line)
+	case "fatal":
+		return hook.Writer.Crit(line)
+	case "error":
+		return hook.Writer.Err(line)
+	case "warn":
+		return hook.Writer.Warning(line)
+	case "info":
+		return hook.Writer.Info(line)
+	case "debug":
+		return hook.Writer.Debug(line)
+	default:
+		return nil
+	}
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+	return []logrus.Level{
+		logrus.PanicLevel,
+		logrus.FatalLevel,
+		logrus.ErrorLevel,
+		logrus.WarnLevel,
+		logrus.InfoLevel,
+		logrus.DebugLevel,
+	}
+}

+ 26 - 0
vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go

@@ -0,0 +1,26 @@
+package logrus_syslog
+
+import (
+	"github.com/Sirupsen/logrus"
+	"log/syslog"
+	"testing"
+)
+
+func TestLocalhostAddAndPrint(t *testing.T) {
+	log := logrus.New()
+	hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+	if err != nil {
+		t.Errorf("Unable to connect to local syslog.")
+	}
+
+	log.Hooks.Add(hook)
+
+	for _, level := range hook.Levels() {
+		if len(log.Hooks[level]) != 1 {
+			t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
+		}
+	}
+
+	log.Info("Congratulations!")
+}

+ 19 - 0
vendor/src/github.com/Sirupsen/logrus/json_formatter.go

@@ -0,0 +1,19 @@
+package logrus
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+type JSONFormatter struct {
+}
+
+func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
+	prefixFieldClashes(entry)
+
+	serialized, err := json.Marshal(entry.Data)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+	}
+	return append(serialized, '\n'), nil
+}

+ 161 - 0
vendor/src/github.com/Sirupsen/logrus/logger.go

@@ -0,0 +1,161 @@
+package logrus
+
+import (
+	"io"
+	"os"
+	"sync"
+)
+
+type Logger struct {
+	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
+	// file, or leave it default which is `os.Stdout`. You can also set this to
+	// something more adventorous, such as logging to Kafka.
+	Out io.Writer
+	// Hooks for the logger instance. These allow firing events based on logging
+	// levels and log entries. For example, to send errors to an error tracking
+	// service, log to StatsD or dump the core on fatal errors.
+	Hooks levelHooks
+	// All log entries pass through the formatter before logged to Out. The
+	// included formatters are `TextFormatter` and `JSONFormatter` for which
+	// TextFormatter is the default. In development (when a TTY is attached) it
+	// logs with colors, but to a file it wouldn't. You can easily implement your
+	// own that implements the `Formatter` interface, see the `README` or included
+	// formatters for examples.
+	Formatter Formatter
+	// The logging level the logger should log at. This is typically (and defaults
+	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
+	// logged. `logrus.Debug` is useful in
+	Level Level
+	// Used to sync writing to the log.
+	mu sync.Mutex
+}
+
+// Creates a new logger. Configuration should be set by changing `Formatter`,
+// `Out` and `Hooks` directly on the default logger instance. You can also just
+// instantiate your own:
+//
+//    var log = &Logger{
+//      Out: os.Stderr,
+//      Formatter: new(JSONFormatter),
+//      Hooks: make(levelHooks),
+//      Level: logrus.Debug,
+//    }
+//
+// It's recommended to make this a global instance called `log`.
+func New() *Logger {
+	return &Logger{
+		Out:       os.Stdout,
+		Formatter: new(TextFormatter),
+		Hooks:     make(levelHooks),
+		Level:     InfoLevel,
+	}
+}
+
+// Adds a field to the log entry, note that you it doesn't log until you call
+// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
+// Ff you want multiple fields, use `WithFields`.
+func (logger *Logger) WithField(key string, value interface{}) *Entry {
+	return NewEntry(logger).WithField(key, value)
+}
+
+// Adds a struct of fields to the log entry. All it does is call `WithField` for
+// each `Field`.
+func (logger *Logger) WithFields(fields Fields) *Entry {
+	return NewEntry(logger).WithFields(fields)
+}
+
+func (logger *Logger) Debugf(format string, args ...interface{}) {
+	NewEntry(logger).Debugf(format, args...)
+}
+
+func (logger *Logger) Infof(format string, args ...interface{}) {
+	NewEntry(logger).Infof(format, args...)
+}
+
+func (logger *Logger) Printf(format string, args ...interface{}) {
+	NewEntry(logger).Printf(format, args...)
+}
+
+func (logger *Logger) Warnf(format string, args ...interface{}) {
+	NewEntry(logger).Warnf(format, args...)
+}
+
+func (logger *Logger) Warningf(format string, args ...interface{}) {
+	NewEntry(logger).Warnf(format, args...)
+}
+
+func (logger *Logger) Errorf(format string, args ...interface{}) {
+	NewEntry(logger).Errorf(format, args...)
+}
+
+func (logger *Logger) Fatalf(format string, args ...interface{}) {
+	NewEntry(logger).Fatalf(format, args...)
+}
+
+func (logger *Logger) Panicf(format string, args ...interface{}) {
+	NewEntry(logger).Panicf(format, args...)
+}
+
+func (logger *Logger) Debug(args ...interface{}) {
+	NewEntry(logger).Debug(args...)
+}
+
+func (logger *Logger) Info(args ...interface{}) {
+	NewEntry(logger).Info(args...)
+}
+
+func (logger *Logger) Print(args ...interface{}) {
+	NewEntry(logger).Info(args...)
+}
+
+func (logger *Logger) Warn(args ...interface{}) {
+	NewEntry(logger).Warn(args...)
+}
+
+func (logger *Logger) Warning(args ...interface{}) {
+	NewEntry(logger).Warn(args...)
+}
+
+func (logger *Logger) Error(args ...interface{}) {
+	NewEntry(logger).Error(args...)
+}
+
+func (logger *Logger) Fatal(args ...interface{}) {
+	NewEntry(logger).Fatal(args...)
+}
+
+func (logger *Logger) Panic(args ...interface{}) {
+	NewEntry(logger).Panic(args...)
+}
+
+func (logger *Logger) Debugln(args ...interface{}) {
+	NewEntry(logger).Debugln(args...)
+}
+
+func (logger *Logger) Infoln(args ...interface{}) {
+	NewEntry(logger).Infoln(args...)
+}
+
+func (logger *Logger) Println(args ...interface{}) {
+	NewEntry(logger).Println(args...)
+}
+
+func (logger *Logger) Warnln(args ...interface{}) {
+	NewEntry(logger).Warnln(args...)
+}
+
+func (logger *Logger) Warningln(args ...interface{}) {
+	NewEntry(logger).Warnln(args...)
+}
+
+func (logger *Logger) Errorln(args ...interface{}) {
+	NewEntry(logger).Errorln(args...)
+}
+
+func (logger *Logger) Fatalln(args ...interface{}) {
+	NewEntry(logger).Fatalln(args...)
+}
+
+func (logger *Logger) Panicln(args ...interface{}) {
+	NewEntry(logger).Panicln(args...)
+}

+ 72 - 0
vendor/src/github.com/Sirupsen/logrus/logrus.go

@@ -0,0 +1,72 @@
+package logrus
+
+import (
+	"log"
+)
+
+// Fields type, used to pass to `WithFields`.
+type Fields map[string]interface{}
+
+// Level type
+type Level uint8
+
+// Convert the Level to a string. E.g. PanicLevel becomes "panic".
+func (level Level) String() string {
+	switch level {
+	case DebugLevel:
+		return "debug"
+	case InfoLevel:
+		return "info"
+	case WarnLevel:
+		return "warning"
+	case ErrorLevel:
+		return "error"
+	case FatalLevel:
+		return "fatal"
+	case PanicLevel:
+		return "panic"
+	}
+
+	return "unknown"
+}
+
+// These are the different logging levels. You can set the logging level to log
+// on your instance of logger, obtained with `logrus.New()`.
+const (
+	// PanicLevel level, highest level of severity. Logs and then calls panic with the
+	// message passed to Debug, Info, ...
+	PanicLevel Level = iota
+	// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
+	// logging level is set to Panic.
+	FatalLevel
+	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
+	// Commonly used for hooks to send errors to an error tracking service.
+	ErrorLevel
+	// WarnLevel level. Non-critical entries that deserve eyes.
+	WarnLevel
+	// InfoLevel level. General operational entries about what's going on inside the
+	// application.
+	InfoLevel
+	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
+	DebugLevel
+)
+
+// Won't compile if StdLogger can't be realized by a log.Logger
+var _ StdLogger = &log.Logger{}
+
+// StdLogger is what your logrus-enabled library should take, that way
+// it'll accept a stdlib logger and a logrus logger. There's no standard
+// interface, this is the closest we get, unfortunately.
+type StdLogger interface {
+	Print(...interface{})
+	Printf(string, ...interface{})
+	Println(...interface{})
+
+	Fatal(...interface{})
+	Fatalf(string, ...interface{})
+	Fatalln(...interface{})
+
+	Panic(...interface{})
+	Panicf(string, ...interface{})
+	Panicln(...interface{})
+}

+ 173 - 0
vendor/src/github.com/Sirupsen/logrus/logrus_test.go

@@ -0,0 +1,173 @@
+package logrus
+
+import (
+	"bytes"
+	"encoding/json"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
+	var buffer bytes.Buffer
+	var fields Fields
+
+	logger := New()
+	logger.Out = &buffer
+	logger.Formatter = new(JSONFormatter)
+
+	log(logger)
+
+	err := json.Unmarshal(buffer.Bytes(), &fields)
+	assert.Nil(t, err)
+
+	assertions(fields)
+}
+
+func TestPrint(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Print("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test")
+		assert.Equal(t, fields["level"], "info")
+	})
+}
+
+func TestInfo(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test")
+		assert.Equal(t, fields["level"], "info")
+	})
+}
+
+func TestWarn(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Warn("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test")
+		assert.Equal(t, fields["level"], "warning")
+	})
+}
+
+func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Infoln("test", "test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test test")
+	})
+}
+
+func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Infoln("test", 10)
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test 10")
+	})
+}
+
+func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Infoln(10, 10)
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "10 10")
+	})
+}
+
+func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Infoln(10, 10)
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "10 10")
+	})
+}
+
+func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Info("test", 10)
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test10")
+	})
+}
+
+func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.Info("test", "test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "testtest")
+	})
+}
+
+func TestWithFieldsShouldAllowAssignments(t *testing.T) {
+	var buffer bytes.Buffer
+	var fields Fields
+
+	logger := New()
+	logger.Out = &buffer
+	logger.Formatter = new(JSONFormatter)
+
+	localLog := logger.WithFields(Fields{
+		"key1": "value1",
+	})
+
+	localLog.WithField("key2", "value2").Info("test")
+	err := json.Unmarshal(buffer.Bytes(), &fields)
+	assert.Nil(t, err)
+
+	assert.Equal(t, "value2", fields["key2"])
+	assert.Equal(t, "value1", fields["key1"])
+
+	buffer = bytes.Buffer{}
+	fields = Fields{}
+	localLog.Info("test")
+	err = json.Unmarshal(buffer.Bytes(), &fields)
+	assert.Nil(t, err)
+
+	_, ok := fields["key2"]
+	assert.Equal(t, false, ok)
+	assert.Equal(t, "value1", fields["key1"])
+}
+
+func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.WithField("msg", "hello").Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test")
+	})
+}
+
+func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.WithField("msg", "hello").Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["msg"], "test")
+		assert.Equal(t, fields["fields.msg"], "hello")
+	})
+}
+
+func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.WithField("time", "hello").Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["fields.time"], "hello")
+	})
+}
+
+func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
+	LogAndAssertJSON(t, func(log *Logger) {
+		log.WithField("level", 1).Info("test")
+	}, func(fields Fields) {
+		assert.Equal(t, fields["level"], "info")
+		assert.Equal(t, fields["fields.level"], 1)
+	})
+}
+
+func TestConvertLevelToString(t *testing.T) {
+	assert.Equal(t, "debug", DebugLevel.String())
+	assert.Equal(t, "info", InfoLevel.String())
+	assert.Equal(t, "warning", WarnLevel.String())
+	assert.Equal(t, "error", ErrorLevel.String())
+	assert.Equal(t, "fatal", FatalLevel.String())
+	assert.Equal(t, "panic", PanicLevel.String())
+}

+ 12 - 0
vendor/src/github.com/Sirupsen/logrus/terminal_darwin.go

@@ -0,0 +1,12 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios

+ 20 - 0
vendor/src/github.com/Sirupsen/logrus/terminal_freebsd.go

@@ -0,0 +1,20 @@
+/*
+  Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
+*/
+package logrus
+
+import (
+	"syscall"
+)
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}

+ 12 - 0
vendor/src/github.com/Sirupsen/logrus/terminal_linux.go

@@ -0,0 +1,12 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TCGETS
+
+type Termios syscall.Termios

+ 21 - 0
vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go

@@ -0,0 +1,21 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,!appengine darwin freebsd
+
+package logrus
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal() bool {
+	fd := syscall.Stdout
+	var termios Termios
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+	return err == 0
+}

+ 27 - 0
vendor/src/github.com/Sirupsen/logrus/terminal_windows.go

@@ -0,0 +1,27 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package logrus
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+	procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal() bool {
+	fd := syscall.Stdout
+	var st uint32
+	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+	return r != 0 && e == 0
+}

+ 86 - 0
vendor/src/github.com/Sirupsen/logrus/text_formatter.go

@@ -0,0 +1,86 @@
+package logrus
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+	"strings"
+	"time"
+)
+
+const (
+	nocolor = 0
+	red     = 31
+	green   = 32
+	yellow  = 33
+	blue    = 34
+)
+
+func init() {
+	baseTimestamp = time.Now()
+}
+
+func miniTS() int {
+	return int(time.Since(baseTimestamp) / time.Second)
+}
+
+type TextFormatter struct {
+	// Set to true to bypass checking for a TTY before outputting colors.
+	ForceColors   bool
+	DisableColors bool
+}
+
+func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
+	b := &bytes.Buffer{}
+
+	prefixFieldClashes(entry)
+
+	if (f.ForceColors || IsTerminal()) && !f.DisableColors {
+		levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]
+
+		levelColor := blue
+
+		if entry.Data["level"] == "warning" {
+			levelColor = yellow
+		} else if entry.Data["level"] == "error" ||
+			entry.Data["level"] == "fatal" ||
+			entry.Data["level"] == "panic" {
+			levelColor = red
+		}
+
+		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Data["msg"])
+
+		keys := make([]string, 0)
+		for k, _ := range entry.Data {
+			if k != "level" && k != "time" && k != "msg" {
+				keys = append(keys, k)
+			}
+		}
+		sort.Strings(keys)
+		for _, k := range keys {
+			v := entry.Data[k]
+			fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
+		}
+	} else {
+		f.AppendKeyValue(b, "time", entry.Data["time"].(string))
+		f.AppendKeyValue(b, "level", entry.Data["level"].(string))
+		f.AppendKeyValue(b, "msg", entry.Data["msg"].(string))
+
+		for key, value := range entry.Data {
+			if key != "time" && key != "level" && key != "msg" {
+				f.AppendKeyValue(b, key, value)
+			}
+		}
+	}
+
+	b.WriteByte('\n')
+	return b.Bytes(), nil
+}
+
+func (f *TextFormatter) AppendKeyValue(b *bytes.Buffer, key, value interface{}) {
+	if _, ok := value.(string); ok {
+		fmt.Fprintf(b, "%v=%q ", key, value)
+	} else {
+		fmt.Fprintf(b, "%v=%v ", key, value)
+	}
+}

+ 1 - 1
volumes/repository.go

@@ -7,8 +7,8 @@ import (
 	"path/filepath"
 	"sync"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/utils"
 )