3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-26 05:49:25 +01:00
ergo/irc/logger.go

170 lines
4.4 KiB
Go
Raw Normal View History

2017-03-06 04:05:33 +01:00
// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package irc
import (
"bufio"
"fmt"
"os"
"time"
2017-03-06 07:28:38 +01:00
"strings"
2017-03-06 07:28:38 +01:00
"github.com/mgutz/ansi"
2017-03-06 04:05:33 +01:00
)
// LogLevel represents the level to log messages at.
type LogLevel int
const (
// LogDebug represents debug messages.
2017-03-06 06:16:00 +01:00
LogDebug LogLevel = iota
2017-03-06 04:05:33 +01:00
// LogInfo represents informational messages.
LogInfo
// LogWarn represents warnings.
LogWarn
// LogError represents errors.
LogError
)
2017-03-06 04:31:10 +01:00
var (
logLevelNames = map[string]LogLevel{
"debug": LogDebug,
"info": LogInfo,
"warn": LogWarn,
"warning": LogWarn,
"warnings": LogWarn,
"error": LogError,
"errors": LogError,
}
2017-03-06 06:50:23 +01:00
logLevelDisplayNames = map[LogLevel]string{
LogDebug: "debug",
LogInfo: "info",
LogWarn: "warning",
LogError: "error",
}
2017-03-06 04:31:10 +01:00
)
2017-03-06 04:05:33 +01:00
// Logger is the main interface used to log debug/info/error messages.
type Logger struct {
loggers []SingleLogger
DumpingRawInOut bool
2017-03-06 04:05:33 +01:00
}
// NewLogger returns a new Logger.
2017-03-06 06:16:00 +01:00
func NewLogger(config []LoggingConfig) (*Logger, error) {
var logger Logger
for _, logConfig := range config {
sLogger := SingleLogger{
MethodSTDERR: logConfig.Methods["stderr"],
MethodFile: fileMethod{
Enabled: logConfig.Methods["file"],
Filename: logConfig.Filename,
},
Level: logConfig.Level,
Types: logConfig.Types,
ExcludedTypes: logConfig.ExcludedTypes,
}
if logConfig.Types["userinput"] || logConfig.Types["useroutput"] || (logConfig.Types["*"] && !(logConfig.ExcludedTypes["userinput"] && logConfig.ExcludedTypes["useroutput"])) {
logger.DumpingRawInOut = true
}
2017-03-06 06:16:00 +01:00
if sLogger.MethodFile.Enabled {
2017-03-06 06:50:23 +01:00
file, err := os.OpenFile(sLogger.MethodFile.Filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
2017-03-06 06:16:00 +01:00
if err != nil {
return nil, fmt.Errorf("Could not open log file %s [%s]", sLogger.MethodFile.Filename, err.Error())
}
writer := bufio.NewWriter(file)
sLogger.MethodFile.File = file
sLogger.MethodFile.Writer = writer
}
2017-03-06 06:50:23 +01:00
logger.loggers = append(logger.loggers, sLogger)
2017-03-06 06:16:00 +01:00
}
return &logger, nil
2017-03-06 04:05:33 +01:00
}
// Log logs the given message with the given details.
2017-03-06 11:15:28 +01:00
func (logger *Logger) Log(level LogLevel, logType string, messageParts ...string) {
2017-03-06 04:05:33 +01:00
for _, singleLogger := range logger.loggers {
2017-03-06 11:15:28 +01:00
singleLogger.Log(level, logType, messageParts...)
2017-03-06 04:05:33 +01:00
}
}
2017-03-06 06:16:00 +01:00
type fileMethod struct {
Enabled bool
Filename string
File *os.File
Writer *bufio.Writer
}
2017-03-06 04:05:33 +01:00
// SingleLogger represents a single logger instance.
type SingleLogger struct {
2017-03-06 06:16:00 +01:00
MethodSTDERR bool
MethodFile fileMethod
2017-03-06 04:05:33 +01:00
Level LogLevel
Types map[string]bool
ExcludedTypes map[string]bool
}
// Log logs the given message with the given details.
2017-03-06 11:15:28 +01:00
func (logger *SingleLogger) Log(level LogLevel, logType string, messageParts ...string) {
2017-03-06 04:05:33 +01:00
// no logging enabled
if !(logger.MethodSTDERR || logger.MethodFile.Enabled) {
return
}
// ensure we're logging to the given level
if level < logger.Level {
return
}
// ensure we're capturing this logType
logTypeCleaned := strings.ToLower(strings.TrimSpace(logType))
capturing := (logger.Types["*"] || logger.Types[logTypeCleaned]) && !logger.ExcludedTypes["*"] && !logger.ExcludedTypes[logTypeCleaned]
2017-03-06 04:05:33 +01:00
if !capturing {
return
}
// assemble full line
2017-03-06 11:15:28 +01:00
timeGrey := ansi.ColorFunc("243")
2017-03-06 07:28:38 +01:00
grey := ansi.ColorFunc("8")
alert := ansi.ColorFunc("232+b:red")
warn := ansi.ColorFunc("black:214")
2017-03-06 11:15:28 +01:00
info := ansi.ColorFunc("117")
2017-03-06 07:28:38 +01:00
debug := ansi.ColorFunc("78")
2017-03-06 11:15:28 +01:00
section := ansi.ColorFunc("229")
2017-03-06 07:28:38 +01:00
levelDisplay := logLevelDisplayNames[level]
if level == LogError {
levelDisplay = alert(levelDisplay)
} else if level == LogWarn {
levelDisplay = warn(levelDisplay)
} else if level == LogInfo {
levelDisplay = info(levelDisplay)
} else if level == LogDebug {
levelDisplay = debug(levelDisplay)
}
2017-03-06 11:15:28 +01:00
sep := grey(":")
fullStringFormatted := fmt.Sprintf("%s %s %s %s %s %s ", timeGrey(time.Now().UTC().Format("2006-01-02T15:04:05Z")), sep, levelDisplay, sep, section(logType), sep)
fullStringRaw := fmt.Sprintf("%s : %s : %s : ", time.Now().UTC().Format("2006-01-02T15:04:05Z"), logLevelDisplayNames[level], section(logType))
for i, p := range messageParts {
fullStringFormatted += p
fullStringRaw += p
if i != len(messageParts)-1 {
fullStringFormatted += " " + sep + " "
fullStringRaw += " : "
}
}
2017-03-06 04:05:33 +01:00
// output
if logger.MethodSTDERR {
2017-03-06 07:28:38 +01:00
fmt.Fprintln(os.Stderr, fullStringFormatted)
2017-03-06 04:05:33 +01:00
}
if logger.MethodFile.Enabled {
2017-03-06 11:15:28 +01:00
logger.MethodFile.Writer.WriteString(fullStringRaw + "\n")
2017-03-06 04:05:33 +01:00
}
}