2020-07-22 14:50:08 +00:00
|
|
|
// Copyright 2014 beego Author. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Package logs provide a general log interface
|
|
|
|
// Usage:
|
|
|
|
//
|
|
|
|
// import "github.com/astaxie/beego/logs"
|
|
|
|
//
|
|
|
|
// log := NewLogger(10000)
|
|
|
|
// log.SetLogger("console", "")
|
|
|
|
//
|
|
|
|
// > the first params stand for how many channel
|
|
|
|
//
|
|
|
|
// Use it like this:
|
|
|
|
//
|
|
|
|
// log.Trace("trace")
|
|
|
|
// log.Info("info")
|
|
|
|
// log.Warn("warning")
|
|
|
|
// log.Debug("debug")
|
|
|
|
// log.Critical("critical")
|
|
|
|
//
|
|
|
|
// more docs http://beego.me/docs/module/logs.md
|
|
|
|
package logs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path"
|
2020-08-28 17:00:45 +00:00
|
|
|
"reflect"
|
2020-07-22 14:50:08 +00:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
2020-08-28 17:00:45 +00:00
|
|
|
|
2020-09-10 15:31:49 +00:00
|
|
|
"github.com/astaxie/beego/pkg/infrastructure/utils"
|
2020-07-22 14:50:08 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// RFC5424 log message levels.
|
|
|
|
const (
|
|
|
|
LevelEmergency = iota
|
|
|
|
LevelAlert
|
|
|
|
LevelCritical
|
|
|
|
LevelError
|
|
|
|
LevelWarning
|
|
|
|
LevelNotice
|
|
|
|
LevelInformational
|
|
|
|
LevelDebug
|
|
|
|
)
|
|
|
|
|
|
|
|
// levelLogLogger is defined to implement log.Logger
|
|
|
|
// the real log level will be LevelEmergency
|
|
|
|
const levelLoggerImpl = -1
|
|
|
|
|
|
|
|
// Name for adapter with beego official support
|
|
|
|
const (
|
|
|
|
AdapterConsole = "console"
|
|
|
|
AdapterFile = "file"
|
|
|
|
AdapterMultiFile = "multifile"
|
|
|
|
AdapterMail = "smtp"
|
|
|
|
AdapterConn = "conn"
|
|
|
|
AdapterEs = "es"
|
|
|
|
AdapterJianLiao = "jianliao"
|
|
|
|
AdapterSlack = "slack"
|
|
|
|
AdapterAliLS = "alils"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Legacy log level constants to ensure backwards compatibility.
|
|
|
|
const (
|
|
|
|
LevelInfo = LevelInformational
|
|
|
|
LevelTrace = LevelDebug
|
|
|
|
LevelWarn = LevelWarning
|
|
|
|
)
|
|
|
|
|
|
|
|
type newLoggerFunc func() Logger
|
|
|
|
|
|
|
|
// Logger defines the behavior of a log provider.
|
|
|
|
type Logger interface {
|
2020-09-10 15:31:49 +00:00
|
|
|
Init(config string, opts ...utils.KV) error
|
2020-08-18 20:30:11 +00:00
|
|
|
WriteMsg(lm *LogMsg) error
|
2020-08-20 18:00:35 +00:00
|
|
|
Format(lm *LogMsg) string
|
2020-07-22 14:50:08 +00:00
|
|
|
Destroy()
|
|
|
|
Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
var adapters = make(map[string]newLoggerFunc)
|
|
|
|
var levelPrefix = [LevelDebug + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]"}
|
|
|
|
|
|
|
|
// Register makes a log provide available by the provided name.
|
|
|
|
// If Register is called twice with the same name or if driver is nil,
|
|
|
|
// it panics.
|
|
|
|
func Register(name string, log newLoggerFunc) {
|
|
|
|
if log == nil {
|
|
|
|
panic("logs: Register provide is nil")
|
|
|
|
}
|
|
|
|
if _, dup := adapters[name]; dup {
|
|
|
|
panic("logs: Register called twice for provider " + name)
|
|
|
|
}
|
|
|
|
adapters[name] = log
|
|
|
|
}
|
|
|
|
|
|
|
|
// BeeLogger is default logger in beego application.
|
2020-08-06 15:07:18 +00:00
|
|
|
// Can contain several providers and log message into all providers.
|
2020-07-22 14:50:08 +00:00
|
|
|
type BeeLogger struct {
|
|
|
|
lock sync.Mutex
|
|
|
|
level int
|
|
|
|
init bool
|
|
|
|
enableFuncCallDepth bool
|
|
|
|
loggerFuncCallDepth int
|
2020-08-24 19:22:38 +00:00
|
|
|
globalFormatter func(*LogMsg) string
|
2020-08-18 20:30:39 +00:00
|
|
|
enableFullFilePath bool
|
2020-07-22 14:50:08 +00:00
|
|
|
asynchronous bool
|
|
|
|
prefix string
|
|
|
|
msgChanLen int64
|
2020-08-18 20:30:11 +00:00
|
|
|
msgChan chan *LogMsg
|
2020-07-22 14:50:08 +00:00
|
|
|
signalChan chan string
|
|
|
|
wg sync.WaitGroup
|
|
|
|
outputs []*nameLogger
|
|
|
|
}
|
|
|
|
|
|
|
|
const defaultAsyncMsgLen = 1e3
|
|
|
|
|
|
|
|
type nameLogger struct {
|
|
|
|
Logger
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:30:11 +00:00
|
|
|
type LogMsg struct {
|
|
|
|
Level int
|
|
|
|
Msg string
|
|
|
|
When time.Time
|
|
|
|
FilePath string
|
|
|
|
LineNumber int
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
2020-08-20 18:00:35 +00:00
|
|
|
type LogFormatter interface {
|
|
|
|
Format(lm *LogMsg) string
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
var logMsgPool *sync.Pool
|
|
|
|
|
|
|
|
// NewLogger returns a new BeeLogger.
|
2020-08-06 15:07:18 +00:00
|
|
|
// channelLen: the number of messages in chan(used where asynchronous is true).
|
2020-07-22 14:50:08 +00:00
|
|
|
// if the buffering chan is full, logger adapters write to file or other way.
|
|
|
|
func NewLogger(channelLens ...int64) *BeeLogger {
|
|
|
|
bl := new(BeeLogger)
|
|
|
|
bl.level = LevelDebug
|
|
|
|
bl.loggerFuncCallDepth = 2
|
|
|
|
bl.msgChanLen = append(channelLens, 0)[0]
|
|
|
|
if bl.msgChanLen <= 0 {
|
|
|
|
bl.msgChanLen = defaultAsyncMsgLen
|
|
|
|
}
|
|
|
|
bl.signalChan = make(chan string, 1)
|
|
|
|
bl.setLogger(AdapterConsole)
|
|
|
|
return bl
|
|
|
|
}
|
|
|
|
|
2020-08-06 15:07:18 +00:00
|
|
|
// Async sets the log to asynchronous and start the goroutine
|
2020-07-22 14:50:08 +00:00
|
|
|
func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger {
|
|
|
|
bl.lock.Lock()
|
|
|
|
defer bl.lock.Unlock()
|
|
|
|
if bl.asynchronous {
|
|
|
|
return bl
|
|
|
|
}
|
|
|
|
bl.asynchronous = true
|
|
|
|
if len(msgLen) > 0 && msgLen[0] > 0 {
|
|
|
|
bl.msgChanLen = msgLen[0]
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
bl.msgChan = make(chan *LogMsg, bl.msgChanLen)
|
2020-07-22 14:50:08 +00:00
|
|
|
logMsgPool = &sync.Pool{
|
|
|
|
New: func() interface{} {
|
2020-08-18 20:30:11 +00:00
|
|
|
return &LogMsg{}
|
2020-07-22 14:50:08 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
bl.wg.Add(1)
|
|
|
|
go bl.startLogger()
|
|
|
|
return bl
|
|
|
|
}
|
|
|
|
|
2020-08-20 18:00:35 +00:00
|
|
|
func Format(lm *LogMsg) string {
|
|
|
|
return lm.Msg
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
2020-08-06 15:07:18 +00:00
|
|
|
// config must in in JSON format like {"interval":360}}
|
2020-07-22 14:50:08 +00:00
|
|
|
func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error {
|
|
|
|
config := append(configs, "{}")[0]
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
if l.name == adapterName {
|
|
|
|
return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logAdapter, ok := adapters[adapterName]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
|
|
|
|
}
|
|
|
|
|
|
|
|
lg := logAdapter()
|
2020-08-24 19:22:38 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
// Global formatter overrides the default set formatter
|
|
|
|
// but not adapter specific formatters set with logs.SetLoggerWithOpts()
|
|
|
|
if bl.globalFormatter != nil {
|
2020-09-10 15:31:49 +00:00
|
|
|
err = lg.Init(config, &utils.SimpleKV{Key: "formatter", Value: bl.globalFormatter})
|
2020-08-24 19:22:38 +00:00
|
|
|
} else {
|
|
|
|
err = lg.Init(config)
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
2020-08-06 15:07:18 +00:00
|
|
|
// config must in in JSON format like {"interval":360}}
|
2020-07-22 14:50:08 +00:00
|
|
|
func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error {
|
|
|
|
bl.lock.Lock()
|
|
|
|
defer bl.lock.Unlock()
|
|
|
|
if !bl.init {
|
|
|
|
bl.outputs = []*nameLogger{}
|
|
|
|
bl.init = true
|
|
|
|
}
|
|
|
|
return bl.setLogger(adapterName, configs...)
|
|
|
|
}
|
|
|
|
|
2020-08-06 15:07:18 +00:00
|
|
|
// DelLogger removes a logger adapter in BeeLogger.
|
2020-07-22 14:50:08 +00:00
|
|
|
func (bl *BeeLogger) DelLogger(adapterName string) error {
|
|
|
|
bl.lock.Lock()
|
|
|
|
defer bl.lock.Unlock()
|
|
|
|
outputs := []*nameLogger{}
|
|
|
|
for _, lg := range bl.outputs {
|
|
|
|
if lg.name == adapterName {
|
|
|
|
lg.Destroy()
|
|
|
|
} else {
|
|
|
|
outputs = append(outputs, lg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(outputs) == len(bl.outputs) {
|
|
|
|
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
|
|
|
|
}
|
|
|
|
bl.outputs = outputs
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:30:11 +00:00
|
|
|
func (bl *BeeLogger) writeToLoggers(lm *LogMsg) {
|
2020-07-22 14:50:08 +00:00
|
|
|
for _, l := range bl.outputs {
|
2020-08-18 20:30:11 +00:00
|
|
|
err := l.WriteMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bl *BeeLogger) Write(p []byte) (n int, err error) {
|
|
|
|
if len(p) == 0 {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
// writeMsg will always add a '\n' character
|
|
|
|
if p[len(p)-1] == '\n' {
|
|
|
|
p = p[0 : len(p)-1]
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Msg: string(p),
|
|
|
|
Level: levelLoggerImpl,
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
// set levelLoggerImpl to ensure all log message will be write out
|
2020-08-18 20:30:11 +00:00
|
|
|
err = bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
if err == nil {
|
|
|
|
return len(p), err
|
|
|
|
}
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:30:11 +00:00
|
|
|
func (bl *BeeLogger) writeMsg(lm *LogMsg, v ...interface{}) error {
|
2020-07-22 14:50:08 +00:00
|
|
|
if !bl.init {
|
|
|
|
bl.lock.Lock()
|
|
|
|
bl.setLogger(AdapterConsole)
|
|
|
|
bl.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(v) > 0 {
|
2020-08-18 20:30:11 +00:00
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 20:30:11 +00:00
|
|
|
lm.Msg = bl.prefix + " " + lm.Msg
|
2020-07-22 14:50:08 +00:00
|
|
|
|
2020-08-19 14:07:46 +00:00
|
|
|
var (
|
|
|
|
file string
|
|
|
|
line int
|
|
|
|
ok bool
|
|
|
|
)
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
if bl.enableFuncCallDepth {
|
2020-08-19 14:07:46 +00:00
|
|
|
_, file, line, ok = runtime.Caller(bl.loggerFuncCallDepth)
|
2020-07-22 14:50:08 +00:00
|
|
|
if !ok {
|
|
|
|
file = "???"
|
|
|
|
line = 0
|
|
|
|
}
|
2020-08-19 14:07:46 +00:00
|
|
|
|
|
|
|
if !bl.enableFullFilePath {
|
|
|
|
_, file = path.Split(file)
|
|
|
|
}
|
|
|
|
lm.FilePath = file
|
|
|
|
lm.LineNumber = line
|
|
|
|
lm.Msg = fmt.Sprintf("[%s:%d] %s", lm.FilePath, lm.LineNumber, lm.Msg)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
2020-09-10 15:31:49 +00:00
|
|
|
// set level info in front of filename info
|
2020-08-18 20:30:11 +00:00
|
|
|
if lm.Level == levelLoggerImpl {
|
2020-07-22 14:50:08 +00:00
|
|
|
// set to emergency to ensure all log will be print out correctly
|
2020-08-18 20:30:11 +00:00
|
|
|
lm.Level = LevelEmergency
|
2020-07-22 14:50:08 +00:00
|
|
|
} else {
|
2020-08-18 20:30:11 +00:00
|
|
|
lm.Msg = levelPrefix[lm.Level] + " " + lm.Msg
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if bl.asynchronous {
|
2020-08-18 20:30:11 +00:00
|
|
|
logM := logMsgPool.Get().(*LogMsg)
|
|
|
|
logM.Level = lm.Level
|
|
|
|
logM.Msg = lm.Msg
|
|
|
|
logM.When = lm.When
|
2020-07-22 14:50:08 +00:00
|
|
|
if bl.outputs != nil {
|
|
|
|
bl.msgChan <- lm
|
|
|
|
} else {
|
|
|
|
logMsgPool.Put(lm)
|
|
|
|
}
|
|
|
|
} else {
|
2020-08-18 20:30:11 +00:00
|
|
|
bl.writeToLoggers(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-06 15:07:18 +00:00
|
|
|
// SetLevel sets log message level.
|
2020-07-22 14:50:08 +00:00
|
|
|
// If message level (such as LevelDebug) is higher than logger level (such as LevelWarning),
|
2020-08-06 15:07:18 +00:00
|
|
|
// log providers will not be sent the message.
|
2020-07-22 14:50:08 +00:00
|
|
|
func (bl *BeeLogger) SetLevel(l int) {
|
|
|
|
bl.level = l
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLevel Get Current log message level.
|
|
|
|
func (bl *BeeLogger) GetLevel() int {
|
|
|
|
return bl.level
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogFuncCallDepth set log funcCallDepth
|
|
|
|
func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
|
|
|
|
bl.loggerFuncCallDepth = d
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLogFuncCallDepth return log funcCallDepth for wrapper
|
|
|
|
func (bl *BeeLogger) GetLogFuncCallDepth() int {
|
|
|
|
return bl.loggerFuncCallDepth
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnableFuncCallDepth enable log funcCallDepth
|
|
|
|
func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
|
|
|
|
bl.enableFuncCallDepth = b
|
|
|
|
}
|
|
|
|
|
|
|
|
// set prefix
|
|
|
|
func (bl *BeeLogger) SetPrefix(s string) {
|
|
|
|
bl.prefix = s
|
|
|
|
}
|
|
|
|
|
|
|
|
// start logger chan reading.
|
|
|
|
// when chan is not empty, write logs.
|
|
|
|
func (bl *BeeLogger) startLogger() {
|
|
|
|
gameOver := false
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case bm := <-bl.msgChan:
|
2020-08-18 20:30:11 +00:00
|
|
|
bl.writeToLoggers(bm)
|
2020-07-22 14:50:08 +00:00
|
|
|
logMsgPool.Put(bm)
|
|
|
|
case sg := <-bl.signalChan:
|
|
|
|
// Now should only send "flush" or "close" to bl.signalChan
|
|
|
|
bl.flush()
|
|
|
|
if sg == "close" {
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
l.Destroy()
|
|
|
|
}
|
|
|
|
bl.outputs = nil
|
|
|
|
gameOver = true
|
|
|
|
}
|
|
|
|
bl.wg.Done()
|
|
|
|
}
|
|
|
|
if gameOver {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 17:00:45 +00:00
|
|
|
// Get the formatter from the opts common.SimpleKV structure
|
|
|
|
// Looks for a key: "formatter" with value: func(*LogMsg) string
|
2020-09-10 15:31:49 +00:00
|
|
|
func GetFormatter(opts utils.KV) (func(*LogMsg) string, error) {
|
|
|
|
if strings.ToLower(opts.GetKey().(string)) == "formatter" {
|
|
|
|
formatterInterface := reflect.ValueOf(opts.GetValue()).Interface()
|
2020-08-28 17:00:45 +00:00
|
|
|
formatterFunc := formatterInterface.(func(*LogMsg) string)
|
|
|
|
return formatterFunc, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("no \"formatter\" key given in simpleKV")
|
|
|
|
}
|
|
|
|
|
2020-08-24 19:22:38 +00:00
|
|
|
// SetLoggerWithOpts sets a log adapter with a user defined logging format. Config must be valid JSON
|
|
|
|
// such as: {"interval":360}
|
2020-09-10 15:31:49 +00:00
|
|
|
func (bl *BeeLogger) setLoggerWithOpts(adapterName string, opts utils.KV, configs ...string) error {
|
2020-08-24 19:22:38 +00:00
|
|
|
config := append(configs, "{}")[0]
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
if l.name == adapterName {
|
|
|
|
return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logAdapter, ok := adapters[adapterName]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
|
|
|
|
}
|
|
|
|
|
2020-09-10 15:31:49 +00:00
|
|
|
if opts.GetKey() == nil {
|
2020-08-28 17:00:45 +00:00
|
|
|
return fmt.Errorf("No SimpleKV struct set for %s log adapter", adapterName)
|
2020-08-24 19:22:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lg := logAdapter()
|
2020-08-28 17:00:45 +00:00
|
|
|
err := lg.Init(config, opts)
|
2020-08-24 19:22:38 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.outputs = append(bl.outputs, &nameLogger{
|
|
|
|
name: adapterName,
|
|
|
|
Logger: lg,
|
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogger provides a given logger adapter into BeeLogger with config string.
|
2020-09-10 15:31:49 +00:00
|
|
|
func (bl *BeeLogger) SetLoggerWithOpts(adapterName string, opts utils.KV, configs ...string) error {
|
2020-08-24 19:22:38 +00:00
|
|
|
bl.lock.Lock()
|
|
|
|
defer bl.lock.Unlock()
|
|
|
|
if !bl.init {
|
|
|
|
bl.outputs = []*nameLogger{}
|
|
|
|
bl.init = true
|
|
|
|
}
|
2020-08-28 17:00:45 +00:00
|
|
|
return bl.setLoggerWithOpts(adapterName, opts, configs...)
|
2020-08-24 19:22:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetLoggerWIthOpts sets a given log adapter with a custom log adapter.
|
|
|
|
// Log Adapter must be given in the form common.SimpleKV{Key: "formatter": Value: struct.FormatFunc}
|
|
|
|
// where FormatFunc has the signature func(*LogMsg) string
|
2020-08-28 17:00:45 +00:00
|
|
|
// func SetLoggerWithOpts(adapter string, config []string, formatterFunc func(*LogMsg) string) error {
|
2020-09-10 15:31:49 +00:00
|
|
|
func SetLoggerWithOpts(adapter string, config []string, opts utils.KV) error {
|
2020-08-28 17:00:45 +00:00
|
|
|
err := beeLogger.SetLoggerWithOpts(adapter, opts, config...)
|
2020-08-24 19:22:38 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bl *BeeLogger) setGlobalFormatter(fmtter func(*LogMsg) string) error {
|
|
|
|
bl.globalFormatter = fmtter
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetGlobalFormatter sets the global formatter for all log adapters
|
|
|
|
// This overrides and other individually set adapter
|
|
|
|
func SetGlobalFormatter(fmtter func(*LogMsg) string) error {
|
|
|
|
return beeLogger.setGlobalFormatter(fmtter)
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
// Emergency Log EMERGENCY level message.
|
|
|
|
func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
|
|
|
|
if LevelEmergency > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
|
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelEmergency,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Alert Log ALERT level message.
|
|
|
|
func (bl *BeeLogger) Alert(format string, v ...interface{}) {
|
|
|
|
if LevelAlert > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
|
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelAlert,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Critical Log CRITICAL level message.
|
|
|
|
func (bl *BeeLogger) Critical(format string, v ...interface{}) {
|
|
|
|
if LevelCritical > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelCritical,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error Log ERROR level message.
|
|
|
|
func (bl *BeeLogger) Error(format string, v ...interface{}) {
|
|
|
|
if LevelError > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelError,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Warning Log WARNING level message.
|
|
|
|
func (bl *BeeLogger) Warning(format string, v ...interface{}) {
|
|
|
|
if LevelWarn > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelWarn,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Notice Log NOTICE level message.
|
|
|
|
func (bl *BeeLogger) Notice(format string, v ...interface{}) {
|
|
|
|
if LevelNotice > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelNotice,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Informational Log INFORMATIONAL level message.
|
|
|
|
func (bl *BeeLogger) Informational(format string, v ...interface{}) {
|
|
|
|
if LevelInfo > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelInfo,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Debug Log DEBUG level message.
|
|
|
|
func (bl *BeeLogger) Debug(format string, v ...interface{}) {
|
|
|
|
if LevelDebug > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelDebug,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Warn Log WARN level message.
|
|
|
|
// compatibility alias for Warning()
|
|
|
|
func (bl *BeeLogger) Warn(format string, v ...interface{}) {
|
|
|
|
if LevelWarn > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelWarn,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Info Log INFO level message.
|
|
|
|
// compatibility alias for Informational()
|
|
|
|
func (bl *BeeLogger) Info(format string, v ...interface{}) {
|
|
|
|
if LevelInfo > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelInfo,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Trace Log TRACE level message.
|
|
|
|
// compatibility alias for Debug()
|
|
|
|
func (bl *BeeLogger) Trace(format string, v ...interface{}) {
|
|
|
|
if LevelDebug > bl.level {
|
|
|
|
return
|
|
|
|
}
|
2020-08-18 20:30:11 +00:00
|
|
|
lm := &LogMsg{
|
|
|
|
Level: LevelDebug,
|
|
|
|
Msg: format,
|
|
|
|
When: time.Now(),
|
|
|
|
}
|
|
|
|
if len(v) > 0 {
|
|
|
|
lm.Msg = fmt.Sprintf(lm.Msg, v...)
|
|
|
|
}
|
|
|
|
|
|
|
|
bl.writeMsg(lm)
|
2020-07-22 14:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flush flush all chan data.
|
|
|
|
func (bl *BeeLogger) Flush() {
|
|
|
|
if bl.asynchronous {
|
|
|
|
bl.signalChan <- "flush"
|
|
|
|
bl.wg.Wait()
|
|
|
|
bl.wg.Add(1)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
bl.flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close close logger, flush all chan data and destroy all adapters in BeeLogger.
|
|
|
|
func (bl *BeeLogger) Close() {
|
|
|
|
if bl.asynchronous {
|
|
|
|
bl.signalChan <- "close"
|
|
|
|
bl.wg.Wait()
|
|
|
|
close(bl.msgChan)
|
|
|
|
} else {
|
|
|
|
bl.flush()
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
l.Destroy()
|
|
|
|
}
|
|
|
|
bl.outputs = nil
|
|
|
|
}
|
|
|
|
close(bl.signalChan)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset close all outputs, and set bl.outputs to nil
|
|
|
|
func (bl *BeeLogger) Reset() {
|
|
|
|
bl.Flush()
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
l.Destroy()
|
|
|
|
}
|
|
|
|
bl.outputs = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bl *BeeLogger) flush() {
|
|
|
|
if bl.asynchronous {
|
|
|
|
for {
|
|
|
|
if len(bl.msgChan) > 0 {
|
|
|
|
bm := <-bl.msgChan
|
2020-08-18 20:30:11 +00:00
|
|
|
bl.writeToLoggers(bm)
|
2020-07-22 14:50:08 +00:00
|
|
|
logMsgPool.Put(bm)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, l := range bl.outputs {
|
|
|
|
l.Flush()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// beeLogger references the used application logger.
|
|
|
|
var beeLogger = NewLogger()
|
|
|
|
|
|
|
|
// GetBeeLogger returns the default BeeLogger
|
|
|
|
func GetBeeLogger() *BeeLogger {
|
|
|
|
return beeLogger
|
|
|
|
}
|
|
|
|
|
|
|
|
var beeLoggerMap = struct {
|
|
|
|
sync.RWMutex
|
|
|
|
logs map[string]*log.Logger
|
|
|
|
}{
|
|
|
|
logs: map[string]*log.Logger{},
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLogger returns the default BeeLogger
|
|
|
|
func GetLogger(prefixes ...string) *log.Logger {
|
|
|
|
prefix := append(prefixes, "")[0]
|
|
|
|
if prefix != "" {
|
|
|
|
prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix))
|
|
|
|
}
|
|
|
|
beeLoggerMap.RLock()
|
|
|
|
l, ok := beeLoggerMap.logs[prefix]
|
|
|
|
if ok {
|
|
|
|
beeLoggerMap.RUnlock()
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
beeLoggerMap.RUnlock()
|
|
|
|
beeLoggerMap.Lock()
|
|
|
|
defer beeLoggerMap.Unlock()
|
|
|
|
l, ok = beeLoggerMap.logs[prefix]
|
|
|
|
if !ok {
|
|
|
|
l = log.New(beeLogger, prefix, 0)
|
|
|
|
beeLoggerMap.logs[prefix] = l
|
|
|
|
}
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
2020-08-18 20:30:39 +00:00
|
|
|
// EnableFullFilePath enables full file path logging. Disabled by default
|
|
|
|
// e.g "/home/Documents/GitHub/beego/mainapp/" instead of "mainapp"
|
|
|
|
func EnableFullFilePath(b bool) {
|
|
|
|
beeLogger.enableFullFilePath = b
|
|
|
|
}
|
|
|
|
|
2020-07-22 14:50:08 +00:00
|
|
|
// Reset will remove all the adapter
|
|
|
|
func Reset() {
|
|
|
|
beeLogger.Reset()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Async set the beelogger with Async mode and hold msglen messages
|
|
|
|
func Async(msgLen ...int64) *BeeLogger {
|
|
|
|
return beeLogger.Async(msgLen...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLevel sets the global log level used by the simple logger.
|
|
|
|
func SetLevel(l int) {
|
|
|
|
beeLogger.SetLevel(l)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPrefix sets the prefix
|
|
|
|
func SetPrefix(s string) {
|
|
|
|
beeLogger.SetPrefix(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// EnableFuncCallDepth enable log funcCallDepth
|
|
|
|
func EnableFuncCallDepth(b bool) {
|
|
|
|
beeLogger.enableFuncCallDepth = b
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogFuncCall set the CallDepth, default is 4
|
|
|
|
func SetLogFuncCall(b bool) {
|
|
|
|
beeLogger.EnableFuncCallDepth(b)
|
|
|
|
beeLogger.SetLogFuncCallDepth(4)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogFuncCallDepth set log funcCallDepth
|
|
|
|
func SetLogFuncCallDepth(d int) {
|
|
|
|
beeLogger.loggerFuncCallDepth = d
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogger sets a new logger.
|
|
|
|
func SetLogger(adapter string, config ...string) error {
|
|
|
|
return beeLogger.SetLogger(adapter, config...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emergency logs a message at emergency level.
|
|
|
|
func Emergency(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Emergency(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alert logs a message at alert level.
|
|
|
|
func Alert(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Alert(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Critical logs a message at critical level.
|
|
|
|
func Critical(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Critical(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error logs a message at error level.
|
|
|
|
func Error(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Error(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warning logs a message at warning level.
|
|
|
|
func Warning(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Warn(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warn compatibility alias for Warning()
|
|
|
|
func Warn(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Warn(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notice logs a message at notice level.
|
|
|
|
func Notice(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Notice(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Informational logs a message at info level.
|
|
|
|
func Informational(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Info(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Info compatibility alias for Warning()
|
|
|
|
func Info(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Info(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debug logs a message at debug level.
|
|
|
|
func Debug(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Debug(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trace logs a message at trace level.
|
|
|
|
// compatibility alias for Warning()
|
|
|
|
func Trace(f interface{}, v ...interface{}) {
|
|
|
|
beeLogger.Trace(formatLog(f, v...))
|
|
|
|
}
|
|
|
|
|
|
|
|
func formatLog(f interface{}, v ...interface{}) string {
|
|
|
|
var msg string
|
|
|
|
switch f.(type) {
|
|
|
|
case string:
|
|
|
|
msg = f.(string)
|
|
|
|
if len(v) == 0 {
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
|
2020-09-10 15:31:49 +00:00
|
|
|
// format string
|
2020-07-22 14:50:08 +00:00
|
|
|
} else {
|
2020-09-10 15:31:49 +00:00
|
|
|
// do not contain format char
|
2020-07-22 14:50:08 +00:00
|
|
|
msg += strings.Repeat(" %v", len(v))
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
msg = fmt.Sprint(f)
|
|
|
|
if len(v) == 0 {
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
msg += strings.Repeat(" %v", len(v))
|
|
|
|
}
|
|
|
|
return fmt.Sprintf(msg, v...)
|
|
|
|
}
|