Files
revel-cmd/logger/logger.go

228 lines
6.5 KiB
Go

package logger
import (
"fmt"
"github.com/revel/config"
"github.com/revel/log15"
"log"
"os"
)
// The LogHandler defines the interface to handle the log records
type (
// The Multilogger reduces the number of exposed defined logging variables,
// and allows the output to be easily refined
MultiLogger interface {
//log15.Logger
//// New returns a new Logger that has this logger's context plus the given context
New(ctx ...interface{}) MultiLogger
//
//// SetHandler updates the logger to write records to the specified handler.
SetHandler(h LogHandler)
SetStackDepth(int) MultiLogger
//
//// Log a message at the given level with context key/value pairs
Debug(msg string, ctx ...interface{})
Debugf(msg string, params ...interface{})
Info(msg string, ctx ...interface{})
Infof(msg string, params ...interface{})
Warn(msg string, ctx ...interface{})
Warnf(msg string, params ...interface{})
Error(msg string, ctx ...interface{})
Errorf(msg string, params ...interface{})
Crit(msg string, ctx ...interface{})
Critf(msg string, params ...interface{})
//// Logs a message as an Crit and exits
Fatal(msg string, ctx ...interface{})
Fatalf(msg string, params ...interface{})
//// Logs a message as an Crit and panics
Panic(msg string, ctx ...interface{})
Panicf(msg string, params ...interface{})
}
LogHandler interface {
log15.Handler
}
LogStackHandler interface {
LogHandler
GetStack() int
}
ParentLogHandler interface {
SetChild(handler LogHandler) LogHandler
}
LogFormat interface {
log15.Format
}
LogLevel log15.Lvl
RevelLogger struct {
log15.Logger
}
// Used for the callback to LogFunctionMap
LogOptions struct {
Ctx *config.Context
ReplaceExistingHandler bool
HandlerWrap ParentLogHandler
Levels []LogLevel
ExtendedOptions map[string]interface{}
}
)
const (
LvlDebug = LogLevel(log15.LvlDebug)
LvlInfo = LogLevel(log15.LvlInfo)
LvlWarn = LogLevel(log15.LvlWarn)
LvlError = LogLevel(log15.LvlError)
LvlCrit = LogLevel(log15.LvlCrit)
)
// A list of all the log levels
var LvlAllList = []LogLevel{LvlDebug, LvlInfo, LvlWarn, LvlError, LvlCrit}
// The log function map can be added to, so that you can specify your own logging mechanism
var LogFunctionMap = map[string]func(*CompositeMultiHandler, *LogOptions){
// Do nothing - set the logger off
"off": func(c *CompositeMultiHandler, logOptions *LogOptions) {
// Only drop the results if there is a parent handler defined
if logOptions.HandlerWrap != nil {
for _, l := range logOptions.Levels {
c.SetHandler(logOptions.HandlerWrap.SetChild(NilHandler()), logOptions.ReplaceExistingHandler, l)
}
}
},
// Do nothing - set the logger off
"": func(*CompositeMultiHandler, *LogOptions) {},
// Set the levels to stdout, replace existing
"stdout": func(c *CompositeMultiHandler, logOptions *LogOptions) {
if logOptions.Ctx != nil {
logOptions.SetExtendedOptions(
"noColor", !logOptions.Ctx.BoolDefault("log.colorize", true),
"smallDate", logOptions.Ctx.BoolDefault("log.smallDate", true))
}
c.SetTerminal(os.Stdout, logOptions)
},
// Set the levels to stderr output to terminal
"stderr": func(c *CompositeMultiHandler, logOptions *LogOptions) {
c.SetTerminal(os.Stderr, logOptions)
},
}
// Set the systems default logger
// Default logs will be captured and handled by revel at level info
func SetDefaultLog(fromLog MultiLogger) {
log.SetOutput(loggerRewrite{Logger: fromLog, Level: log15.LvlInfo, hideDeprecated: true})
// No need to show date and time, that will be logged with revel
log.SetFlags(0)
}
// Formatted debug call
func (rl *RevelLogger) Debugf(msg string, param ...interface{}) {
rl.Debug(fmt.Sprintf(msg, param...))
}
// Formatted info call
func (rl *RevelLogger) Infof(msg string, param ...interface{}) {
rl.Info(fmt.Sprintf(msg, param...))
}
func (rl *RevelLogger) Warnf(msg string, param ...interface{}) {
rl.Warn(fmt.Sprintf(msg, param...))
}
func (rl *RevelLogger) Errorf(msg string, param ...interface{}) {
rl.Error(fmt.Sprintf(msg, param...))
}
func (rl *RevelLogger) Critf(msg string, param ...interface{}) {
rl.Crit(fmt.Sprintf(msg, param...))
}
func (rl *RevelLogger) Fatalf(msg string, param ...interface{}) {
rl.Crit(fmt.Sprintf(msg, param...))
os.Exit(1)
}
func (rl *RevelLogger) Panicf(msg string, param ...interface{}) {
rl.Crit(fmt.Sprintf(msg, param...))
panic(msg)
}
func (rl *RevelLogger) Fatal(msg string, ctx ...interface{}) {
rl.Crit(msg, ctx...)
os.Exit(1)
}
func (rl *RevelLogger) Panic(msg string, ctx ...interface{}) {
rl.Crit(msg, ctx...)
panic(msg)
}
// Override log15 method
func (rl *RevelLogger) New(ctx ...interface{}) MultiLogger {
old := &RevelLogger{Logger: rl.Logger.New(ctx...)}
return old
}
// Set the stack level to check for the caller
func (rl *RevelLogger) SetStackDepth(amount int) MultiLogger {
rl.Logger.SetStackDepth(amount) // Ignore the logger returned
return rl
}
// Create a new logger
func New(ctx ...interface{}) MultiLogger {
r := &RevelLogger{Logger: log15.New(ctx...)}
r.SetStackDepth(1)
return r
}
// Set the handler in the Logger
func (rl *RevelLogger) SetHandler(h LogHandler) {
rl.Logger.SetHandler(h)
}
type parentLogHandler struct {
setChild func(handler LogHandler) LogHandler
}
func NewParentLogHandler(callBack func(child LogHandler) LogHandler) ParentLogHandler {
return &parentLogHandler{callBack}
}
func (p *parentLogHandler) SetChild(child LogHandler) LogHandler {
return p.setChild(child)
}
// Create a new log options
func NewLogOptions(cfg *config.Context, replaceHandler bool, phandler ParentLogHandler, lvl ...LogLevel) (logOptions *LogOptions) {
logOptions = &LogOptions{
Ctx: cfg,
ReplaceExistingHandler: replaceHandler,
HandlerWrap: phandler,
Levels: lvl,
ExtendedOptions: map[string]interface{}{},
}
return
}
// Assumes options will be an even number and have a string, value syntax
func (l *LogOptions) SetExtendedOptions(options ...interface{}) {
for x := 0; x < len(options); x += 2 {
l.ExtendedOptions[options[x].(string)] = options[x+1]
}
}
func (l *LogOptions) GetStringDefault(option, value string) string {
if v, found := l.ExtendedOptions[option]; found {
return v.(string)
}
return value
}
func (l *LogOptions) GetIntDefault(option string, value int) int {
if v, found := l.ExtendedOptions[option]; found {
return v.(int)
}
return value
}
func (l *LogOptions) GetBoolDefault(option string, value bool) bool {
if v, found := l.ExtendedOptions[option]; found {
return v.(bool)
}
return value
}