2016-11-13 12:46:32 +00:00
|
|
|
// Copyright 2013 bee authors
|
|
|
|
//
|
|
|
|
// 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.
|
2017-03-06 23:58:53 +00:00
|
|
|
package beeLogger
|
2016-11-13 12:46:32 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
|
|
|
"text/template"
|
2017-03-06 23:58:53 +00:00
|
|
|
"time"
|
|
|
|
|
2020-12-16 05:20:41 +00:00
|
|
|
"github.com/beego/bee/v2/logger/colors"
|
2016-11-13 12:46:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var errInvalidLogLevel = errors.New("logger: invalid log level")
|
|
|
|
|
|
|
|
const (
|
2017-03-10 18:32:22 +00:00
|
|
|
levelDebug = iota
|
|
|
|
levelError
|
2016-11-13 12:46:32 +00:00
|
|
|
levelFatal
|
2017-03-10 18:32:22 +00:00
|
|
|
levelCritical
|
2016-11-13 12:46:32 +00:00
|
|
|
levelSuccess
|
|
|
|
levelWarn
|
2017-03-10 18:32:22 +00:00
|
|
|
levelInfo
|
|
|
|
levelHint
|
2016-11-13 12:46:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
sequenceNo uint64
|
2016-11-16 11:33:01 +00:00
|
|
|
instance *BeeLogger
|
|
|
|
once sync.Once
|
2016-11-13 12:46:32 +00:00
|
|
|
)
|
2017-03-11 07:14:24 +00:00
|
|
|
var debugMode = os.Getenv("DEBUG_ENABLED") == "1"
|
2017-03-10 18:32:22 +00:00
|
|
|
|
|
|
|
var logLevel = levelInfo
|
2016-11-13 12:46:32 +00:00
|
|
|
|
|
|
|
// BeeLogger logs logging records to the specified io.Writer
|
|
|
|
type BeeLogger struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
output io.Writer
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogRecord represents a log record and contains the timestamp when the record
|
|
|
|
// was created, an increasing id, level and the actual formatted log line.
|
|
|
|
type LogRecord struct {
|
2016-11-13 14:06:34 +00:00
|
|
|
ID string
|
2016-11-13 12:46:32 +00:00
|
|
|
Level string
|
|
|
|
Message string
|
|
|
|
Filename string
|
|
|
|
LineNo int
|
|
|
|
}
|
|
|
|
|
2017-03-06 23:58:53 +00:00
|
|
|
var Log = GetBeeLogger(os.Stdout)
|
|
|
|
|
2016-11-13 12:46:32 +00:00
|
|
|
var (
|
|
|
|
logRecordTemplate *template.Template
|
|
|
|
debugLogRecordTemplate *template.Template
|
|
|
|
)
|
|
|
|
|
2016-11-16 11:33:01 +00:00
|
|
|
// GetBeeLogger initializes the logger instance with a NewColorWriter output
|
|
|
|
// and returns a singleton
|
|
|
|
func GetBeeLogger(w io.Writer) *BeeLogger {
|
|
|
|
once.Do(func() {
|
2016-11-20 10:54:12 +00:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
simpleLogFormat = `{{Now "2006/01/02 15:04:05"}} {{.Level}} ▶ {{.ID}} {{.Message}}{{EndLine}}`
|
|
|
|
debugLogFormat = `{{Now "2006/01/02 15:04:05"}} {{.Level}} ▶ {{.ID}} {{.Filename}}:{{.LineNo}} {{.Message}}{{EndLine}}`
|
|
|
|
)
|
|
|
|
|
|
|
|
// Initialize and parse logging templates
|
|
|
|
funcs := template.FuncMap{
|
|
|
|
"Now": Now,
|
|
|
|
"EndLine": EndLine,
|
|
|
|
}
|
|
|
|
logRecordTemplate, err = template.New("simpleLogFormat").Funcs(funcs).Parse(simpleLogFormat)
|
2017-03-06 23:58:53 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2016-11-20 10:54:12 +00:00
|
|
|
debugLogRecordTemplate, err = template.New("debugLogFormat").Funcs(funcs).Parse(debugLogFormat)
|
2017-03-06 23:58:53 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2016-11-20 10:54:12 +00:00
|
|
|
|
2017-03-06 23:58:53 +00:00
|
|
|
instance = &BeeLogger{output: colors.NewColorWriter(w)}
|
2016-11-16 11:33:01 +00:00
|
|
|
})
|
|
|
|
return instance
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetOutput sets the logger output destination
|
|
|
|
func (l *BeeLogger) SetOutput(w io.Writer) {
|
|
|
|
l.mu.Lock()
|
|
|
|
defer l.mu.Unlock()
|
2017-03-06 23:58:53 +00:00
|
|
|
l.output = colors.NewColorWriter(w)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now returns the current local time in the specified layout
|
|
|
|
func Now(layout string) string {
|
|
|
|
return time.Now().Format(layout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// EndLine returns the a newline escape character
|
|
|
|
func EndLine() string {
|
|
|
|
return "\n"
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *BeeLogger) getLevelTag(level int) string {
|
|
|
|
switch level {
|
|
|
|
case levelFatal:
|
|
|
|
return "FATAL "
|
|
|
|
case levelSuccess:
|
|
|
|
return "SUCCESS "
|
|
|
|
case levelHint:
|
|
|
|
return "HINT "
|
|
|
|
case levelDebug:
|
|
|
|
return "DEBUG "
|
|
|
|
case levelInfo:
|
|
|
|
return "INFO "
|
|
|
|
case levelWarn:
|
|
|
|
return "WARN "
|
|
|
|
case levelError:
|
|
|
|
return "ERROR "
|
|
|
|
case levelCritical:
|
|
|
|
return "CRITICAL"
|
|
|
|
default:
|
|
|
|
panic(errInvalidLogLevel)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *BeeLogger) getColorLevel(level int) string {
|
|
|
|
switch level {
|
|
|
|
case levelCritical:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.RedBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelFatal:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.RedBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelInfo:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.BlueBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelHint:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.CyanBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelDebug:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.YellowBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelError:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.RedBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelWarn:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.YellowBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
case levelSuccess:
|
2017-03-06 23:58:53 +00:00
|
|
|
return colors.GreenBold(l.getLevelTag(level))
|
2016-11-13 12:46:32 +00:00
|
|
|
default:
|
|
|
|
panic(errInvalidLogLevel)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mustLog logs the message according to the specified level and arguments.
|
|
|
|
// It panics in case of an error.
|
|
|
|
func (l *BeeLogger) mustLog(level int, message string, args ...interface{}) {
|
2017-03-10 18:32:22 +00:00
|
|
|
if level > logLevel {
|
|
|
|
return
|
|
|
|
}
|
2016-11-15 11:25:37 +00:00
|
|
|
// Acquire the lock
|
|
|
|
l.mu.Lock()
|
|
|
|
defer l.mu.Unlock()
|
|
|
|
|
2016-11-13 12:46:32 +00:00
|
|
|
// Create the logging record and pass into the output
|
|
|
|
record := LogRecord{
|
2016-11-13 14:06:34 +00:00
|
|
|
ID: fmt.Sprintf("%04d", atomic.AddUint64(&sequenceNo, 1)),
|
2016-11-13 12:46:32 +00:00
|
|
|
Level: l.getColorLevel(level),
|
|
|
|
Message: fmt.Sprintf(message, args...),
|
|
|
|
}
|
|
|
|
|
|
|
|
err := logRecordTemplate.Execute(l.output, record)
|
2017-03-06 23:58:53 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// mustLogDebug logs a debug message only if debug mode
|
|
|
|
// is enabled. i.e. DEBUG_ENABLED="1"
|
2016-11-14 17:02:29 +00:00
|
|
|
func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ...interface{}) {
|
2017-03-10 18:32:22 +00:00
|
|
|
if !debugMode {
|
|
|
|
return
|
|
|
|
}
|
2016-11-13 12:46:32 +00:00
|
|
|
|
|
|
|
// Change the output to Stderr
|
|
|
|
l.SetOutput(os.Stderr)
|
|
|
|
|
2016-11-14 17:02:29 +00:00
|
|
|
// Create the log record
|
2016-11-13 12:46:32 +00:00
|
|
|
record := LogRecord{
|
2016-11-13 14:06:34 +00:00
|
|
|
ID: fmt.Sprintf("%04d", atomic.AddUint64(&sequenceNo, 1)),
|
2016-11-13 12:46:32 +00:00
|
|
|
Level: l.getColorLevel(levelDebug),
|
|
|
|
Message: fmt.Sprintf(message, args...),
|
|
|
|
LineNo: line,
|
|
|
|
Filename: filepath.Base(file),
|
|
|
|
}
|
|
|
|
err := debugLogRecordTemplate.Execute(l.output, record)
|
2017-03-06 23:58:53 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Debug outputs a debug log message
|
2016-11-14 17:02:29 +00:00
|
|
|
func (l *BeeLogger) Debug(message string, file string, line int) {
|
|
|
|
l.mustLogDebug(message, file, line)
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Debugf outputs a formatted debug log message
|
2016-11-14 17:02:29 +00:00
|
|
|
func (l *BeeLogger) Debugf(message string, file string, line int, vars ...interface{}) {
|
|
|
|
l.mustLogDebug(message, file, line, vars...)
|
2016-11-13 12:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Info outputs an information log message
|
|
|
|
func (l *BeeLogger) Info(message string) {
|
|
|
|
l.mustLog(levelInfo, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Infof outputs a formatted information log message
|
|
|
|
func (l *BeeLogger) Infof(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelInfo, message, vars...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warn outputs a warning log message
|
|
|
|
func (l *BeeLogger) Warn(message string) {
|
|
|
|
l.mustLog(levelWarn, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warnf outputs a formatted warning log message
|
|
|
|
func (l *BeeLogger) Warnf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelWarn, message, vars...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error outputs an error log message
|
|
|
|
func (l *BeeLogger) Error(message string) {
|
|
|
|
l.mustLog(levelError, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Errorf outputs a formatted error log message
|
|
|
|
func (l *BeeLogger) Errorf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelError, message, vars...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fatal outputs a fatal log message and exists
|
|
|
|
func (l *BeeLogger) Fatal(message string) {
|
|
|
|
l.mustLog(levelFatal, message)
|
|
|
|
os.Exit(255)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fatalf outputs a formatted log message and exists
|
|
|
|
func (l *BeeLogger) Fatalf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelFatal, message, vars...)
|
|
|
|
os.Exit(255)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Success outputs a success log message
|
|
|
|
func (l *BeeLogger) Success(message string) {
|
|
|
|
l.mustLog(levelSuccess, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Successf outputs a formatted success log message
|
|
|
|
func (l *BeeLogger) Successf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelSuccess, message, vars...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hint outputs a hint log message
|
|
|
|
func (l *BeeLogger) Hint(message string) {
|
|
|
|
l.mustLog(levelHint, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hintf outputs a formatted hint log message
|
|
|
|
func (l *BeeLogger) Hintf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelHint, message, vars...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Critical outputs a critical log message
|
|
|
|
func (l *BeeLogger) Critical(message string) {
|
|
|
|
l.mustLog(levelCritical, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Criticalf outputs a formatted critical log message
|
|
|
|
func (l *BeeLogger) Criticalf(message string, vars ...interface{}) {
|
|
|
|
l.mustLog(levelCritical, message, vars...)
|
|
|
|
}
|