From f392c0c6274d188f7d38e7eea36694a5995893be Mon Sep 17 00:00:00 2001 From: Wei Shen Date: Wed, 26 Apr 2017 12:47:56 +0800 Subject: [PATCH 1/4] support windows color via https://github.com/mattn/go-colorable --- log_nix.go => log.go | 2 - log_windows.go | 107 ------------------------------------------- logger.go | 12 ++++- 3 files changed, 10 insertions(+), 111 deletions(-) rename log_nix.go => log.go (99%) delete mode 100644 log_windows.go diff --git a/log_nix.go b/log.go similarity index 99% rename from log_nix.go rename to log.go index 4ff2ab1..bb29a8f 100644 --- a/log_nix.go +++ b/log.go @@ -1,5 +1,3 @@ -// +build !windows - // Copyright 2013, Örjan Persson. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/log_windows.go b/log_windows.go deleted file mode 100644 index b8dc92c..0000000 --- a/log_windows.go +++ /dev/null @@ -1,107 +0,0 @@ -// +build windows -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "io" - "log" - "syscall" -) - -var ( - kernel32DLL = syscall.NewLazyDLL("kernel32.dll") - setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") -) - -// Character attributes -// Note: -// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). -// Clearing all foreground or background colors results in black; setting all creates white. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. -const ( - fgBlack = 0x0000 - fgBlue = 0x0001 - fgGreen = 0x0002 - fgCyan = 0x0003 - fgRed = 0x0004 - fgMagenta = 0x0005 - fgYellow = 0x0006 - fgWhite = 0x0007 - fgIntensity = 0x0008 - fgMask = 0x000F -) - -var ( - colors = []uint16{ - INFO: fgWhite, - CRITICAL: fgMagenta, - ERROR: fgRed, - WARNING: fgYellow, - NOTICE: fgGreen, - DEBUG: fgCyan, - } - boldcolors = []uint16{ - INFO: fgWhite | fgIntensity, - CRITICAL: fgMagenta | fgIntensity, - ERROR: fgRed | fgIntensity, - WARNING: fgYellow | fgIntensity, - NOTICE: fgGreen | fgIntensity, - DEBUG: fgCyan | fgIntensity, - } -) - -type file interface { - Fd() uintptr -} - -// LogBackend utilizes the standard log module. -type LogBackend struct { - Logger *log.Logger - Color bool - - // f is set to a non-nil value if the underlying writer which logs writes to - // implements the file interface. This makes us able to colorise the output. - f file -} - -// NewLogBackend creates a new LogBackend. -func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend { - b := &LogBackend{Logger: log.New(out, prefix, flag)} - - // Unfortunately, the API used only takes an io.Writer where the Windows API - // need the actual fd to change colors. - if f, ok := out.(file); ok { - b.f = f - } - - return b -} - -func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error { - if b.Color && b.f != nil { - buf := &bytes.Buffer{} - setConsoleTextAttribute(b.f, colors[level]) - buf.Write([]byte(rec.Formatted(calldepth + 1))) - err := b.Logger.Output(calldepth+2, buf.String()) - setConsoleTextAttribute(b.f, fgWhite) - return err - } - return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1)) -} - -// setConsoleTextAttribute sets the attributes of characters written to the -// console screen buffer by the WriteFile or WriteConsole function. -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. -func setConsoleTextAttribute(f file, attribute uint16) bool { - ok, _, _ := setConsoleTextAttributeProc.Call(f.Fd(), uintptr(attribute), 0) - return ok != 0 -} - -func doFmtVerbLevelColor(layout string, level Level, output io.Writer) { - // TODO not supported on Windows since the io.Writer here is actually a - // bytes.Buffer. -} diff --git a/logger.go b/logger.go index 535ed9b..0331e5b 100644 --- a/logger.go +++ b/logger.go @@ -12,9 +12,12 @@ import ( "fmt" "log" "os" + "runtime" "strings" "sync/atomic" "time" + + colorable "github.com/mattn/go-colorable" ) // Redactor is an interface for types that may contain sensitive information @@ -129,8 +132,13 @@ func Reset() { // if there's no backends at all configured, we could use some tricks to // automatically setup backends based if we have a TTY or not. sequenceNo = 0 - b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags)) - b.SetLevel(DEBUG, "") + if runtime.GOOS == "windows" { + b := SetBackend(NewLogBackend(colorable.NewColorableStderr(), "", log.LstdFlags)) + b.SetLevel(DEBUG, "") + } else { + b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags)) + b.SetLevel(DEBUG, "") + } SetFormatter(DefaultFormatter) timeNow = time.Now } From 826720d64bbcd9dc2ffa71562baed729387187f7 Mon Sep 17 00:00:00 2001 From: Wei Shen Date: Wed, 26 Apr 2017 13:03:21 +0800 Subject: [PATCH 2/4] update example to support windows color --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0a7326b..a358c56 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ import ( "os" "github.com/op/go-logging" + "github.com/mattn/go-colorable" ) var log = logging.MustGetLogger("example") @@ -46,8 +47,14 @@ func (p Password) Redacted() interface{} { func main() { // For demo purposes, create two backend for os.Stderr. - backend1 := logging.NewLogBackend(os.Stderr, "", 0) - backend2 := logging.NewLogBackend(os.Stderr, "", 0) + // To support windows, a colorable stderr is needed! + var stderr io.Writer = os.Stderr + if runtime.GOOS == "windows" { + stderr = colorable.NewColorableStderr() + } + + backend1 := logging.NewLogBackend(stderr, "", 0) + backend2 := logging.NewLogBackend(stderr, "", 0) // For messages written to backend2 we want to add some additional // information to the output, including the used log level and the name of From 3ea69e665244ba11edf85367ac18b4c4678882a9 Mon Sep 17 00:00:00 2001 From: Wei Shen Date: Thu, 27 Apr 2017 13:37:52 +0800 Subject: [PATCH 3/4] update doc of format.go --- format.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/format.go b/format.go index 7160674..ca5e968 100644 --- a/format.go +++ b/format.go @@ -183,9 +183,6 @@ type stringFormatter struct { // For the 'callpath' verb, the output can be adjusted to limit the printing // the stack depth. i.e. '%{callpath:3}' will print '~.a.b.c' // -// Colors on Windows is unfortunately not supported right now and is currently -// a no-op. -// // There's also a couple of experimental 'verbs'. These are exposed to get // feedback and needs a bit of tinkering. Hence, they might change in the // future. From c6b9702d88ba878b81c49272d3fc470593698733 Mon Sep 17 00:00:00 2001 From: Wei Shen Date: Fri, 13 Oct 2017 01:15:22 +0800 Subject: [PATCH 4/4] remove unneeded code --- logger.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/logger.go b/logger.go index 0331e5b..cc1a4b8 100644 --- a/logger.go +++ b/logger.go @@ -12,7 +12,6 @@ import ( "fmt" "log" "os" - "runtime" "strings" "sync/atomic" "time" @@ -132,13 +131,8 @@ func Reset() { // if there's no backends at all configured, we could use some tricks to // automatically setup backends based if we have a TTY or not. sequenceNo = 0 - if runtime.GOOS == "windows" { - b := SetBackend(NewLogBackend(colorable.NewColorableStderr(), "", log.LstdFlags)) - b.SetLevel(DEBUG, "") - } else { - b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags)) - b.SetLevel(DEBUG, "") - } + b := SetBackend(NewLogBackend(colorable.NewColorableStderr(), "", log.LstdFlags)) + b.SetLevel(DEBUG, "") SetFormatter(DefaultFormatter) timeNow = time.Now }