OpenDiablo2/d2common/d2util/logger.go

223 lines
4.4 KiB
Go

package d2util
import (
"fmt"
"io"
"log"
"os"
"runtime"
)
// LogLevel determines how verbose the logging is (higher is more verbose)
type LogLevel = int
// Log levels
const (
LogLevelNone LogLevel = iota
LogLevelFatal
LogLevelError
LogLevelWarning
LogLevelInfo
LogLevelDebug
LogLevelUnspecified
)
// LogLevelDefault is the default log level
const LogLevelDefault = LogLevelInfo
const (
red = 1
green = 2
yellow = 3
magenta = 5
cyan = 6
)
const fmtColorEscape = "\033[3%dm"
const colorEscapeReset = "\033[0m"
// Log format strings for log levels
const (
fmtPrefix = "[%s]"
LogFmtDebug = "[DEBUG]" + colorEscapeReset + " %s\r\n"
LogFmtInfo = "[INFO]" + colorEscapeReset + " %s\r\n"
LogFmtWarning = "[WARNING]" + colorEscapeReset + " %s\r\n"
LogFmtError = "[ERROR]" + colorEscapeReset + " %s\r\n"
LogFmtFatal = "[FATAL]" + colorEscapeReset + " %s\r\n"
)
// NewLogger creates a new logger with a default
func NewLogger() *Logger {
l := &Logger{
level: LogLevelDefault,
colorEnabled: true,
}
l.Writer = log.Writer()
return l
}
// Logger is used to write log messages, and can have a log level to determine verbosity
type Logger struct {
prefix string
io.Writer
level LogLevel
colorEnabled bool
}
// SetPrefix sets a prefix for the message.
// example:
// logger.SetPrefix("XYZ")
// logger.Debug("ABC") will print "[XYZ] [DEBUG] ABC"
func (l *Logger) SetPrefix(s string) {
l.prefix = s
}
// SetLevel sets the log level
func (l *Logger) SetLevel(level LogLevel) {
if level == LogLevelUnspecified {
level = LogLevelDefault
}
l.level = level
}
// SetColorEnabled adds color escape-sequences to the logging output
func (l *Logger) SetColorEnabled(b bool) {
if runtime.GOOS == "windows" {
b = false
}
l.colorEnabled = b
}
// Info logs an info message
func (l *Logger) Info(msg string) {
if l == nil || l.level < LogLevelInfo {
return
}
l.print(LogLevelInfo, msg)
}
// Infof formats and then logs an info message
func (l *Logger) Infof(fmtMsg string, args ...interface{}) {
l.Info(fmt.Sprintf(fmtMsg, args...))
}
// Warning logs a warning message
func (l *Logger) Warning(msg string) {
if l == nil || l.level < LogLevelWarning {
return
}
l.print(LogLevelWarning, msg)
}
// Warningf formats and then logs a warning message
func (l *Logger) Warningf(fmtMsg string, args ...interface{}) {
l.Warning(fmt.Sprintf(fmtMsg, args...))
}
// Error logs an error message
func (l *Logger) Error(msg string) {
if l == nil || l.level < LogLevelError {
return
}
l.print(LogLevelError, msg)
}
// Errorf formats and then logs a error message
func (l *Logger) Errorf(fmtMsg string, args ...interface{}) {
l.Error(fmt.Sprintf(fmtMsg, args...))
}
// Fatal logs an fatal error message and exits programm
func (l *Logger) Fatal(msg string) {
defer os.Exit(1)
if l == nil || l.level < LogLevelFatal {
return
}
l.print(LogLevelFatal, msg)
}
// Fatalf formats and then logs a error message
func (l *Logger) Fatalf(fmtMsg string, args ...interface{}) {
l.Fatal(fmt.Sprintf(fmtMsg, args...))
}
// Debug logs a debug message
func (l *Logger) Debug(msg string) {
if l == nil || l.level < LogLevelDebug {
return
}
l.print(LogLevelDebug, msg)
}
// Debugf formats and then logs a debug message
func (l *Logger) Debugf(fmtMsg string, args ...interface{}) {
l.Debug(fmt.Sprintf(fmtMsg, args...))
}
func (l *Logger) print(level LogLevel, msg string) {
if l == nil || l.level < level {
return
}
colors := map[LogLevel]int{
LogLevelDebug: cyan,
LogLevelInfo: green,
LogLevelWarning: yellow,
LogLevelError: red,
LogLevelFatal: red,
}
fmtString := ""
if l.prefix != "" {
if l.colorEnabled {
fmtString = fmt.Sprintf(fmtColorEscape, magenta)
}
fmtString += fmt.Sprintf(fmtPrefix, l.prefix)
}
if l.colorEnabled {
fmtString += fmt.Sprintf(fmtColorEscape, colors[level])
}
switch level {
case LogLevelDebug:
fmtString += LogFmtDebug
case LogLevelInfo:
fmtString += LogFmtInfo
case LogLevelWarning:
fmtString += LogFmtWarning
case LogLevelError:
fmtString += LogFmtError
case LogLevelFatal:
fmtString += LogFmtFatal
case LogLevelNone:
default:
return
}
_, err := l.Write(format(fmtString, []byte(msg)))
if err != nil {
log.Print(err)
}
}
func format(fmtStr string, fmtInput []byte) []byte {
return []byte(fmt.Sprintf(fmtStr, string(fmtInput)))
}
func (l *Logger) Write(p []byte) (n int, err error) {
return l.Writer.Write(p)
}