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"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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 04:05:33 +01:00
|
|
|
// ClientLogger is a logger dedicated to a single client. This is a convenience class that
|
|
|
|
// automagically adds the client nick to logged messages.
|
|
|
|
type ClientLogger struct {
|
|
|
|
client *Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewClientLogger returns a new ClientLogger.
|
|
|
|
func NewClientLogger(client *Client) ClientLogger {
|
|
|
|
logger := ClientLogger{
|
|
|
|
client: client,
|
|
|
|
}
|
|
|
|
return logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log logs the given message with the given details.
|
|
|
|
func (logger *ClientLogger) Log(level LogLevel, logType, object, message string) {
|
|
|
|
object = fmt.Sprintf("%s : %s", logger.client.nick, object)
|
|
|
|
logger.client.server.logger.Log(level, logType, object, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logger is the main interface used to log debug/info/error messages.
|
|
|
|
type Logger struct {
|
|
|
|
loggers []SingleLogger
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 sLogger.MethodFile.Enabled {
|
|
|
|
file, err := os.OpenFile(sLogger.MethodFile.Filename, os.O_APPEND, 0666)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &logger, nil
|
2017-03-06 04:05:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Log logs the given message with the given details.
|
|
|
|
func (logger *Logger) Log(level LogLevel, logType, object, message string) {
|
|
|
|
for _, singleLogger := range logger.loggers {
|
|
|
|
singleLogger.Log(level, logType, object, message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
func (logger *SingleLogger) Log(level LogLevel, logType, object, message string) {
|
|
|
|
// 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
|
|
|
|
capturing := (logger.Types["*"] || logger.Types[logType]) && !logger.ExcludedTypes["*"] && !logger.ExcludedTypes[logType]
|
|
|
|
if !capturing {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// assemble full line
|
|
|
|
fullString := fmt.Sprintf("%s : %s : %s : %s", time.Now().UTC().Format("2006-01-02T15:04:05.999Z"), logType, object, message)
|
|
|
|
|
|
|
|
// output
|
|
|
|
if logger.MethodSTDERR {
|
|
|
|
fmt.Fprintln(os.Stderr, fullString)
|
|
|
|
}
|
|
|
|
if logger.MethodFile.Enabled {
|
|
|
|
logger.MethodFile.Writer.WriteString(fullString + "\n")
|
|
|
|
}
|
|
|
|
}
|