blob: b8dc92c67a1dfb6d7838b3d2c0b57ebdd4b3bfbf [file] [log] [blame]
// +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.
}