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