| // +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. |
| } |