107 lines
2.9 KiB
Go
107 lines
2.9 KiB
Go
// +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.
|
|
}
|