123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- // Package lfshook is hook for sirupsen/logrus that used for writing the logs to local files.
- package lfshook
- import (
- "fmt"
- "io"
- "reflect"
- "sync"
- "github.com/sirupsen/logrus"
- "gopkg.in/natefinch/lumberjack.v2"
- )
- // We are logging to file, strip colors to make the output more readable.
- var defaultFormatter = &logrus.TextFormatter{DisableColors: true}
- // PathMap is map for mapping a log level to a file's path.
- // Multiple levels may share a file, but multiple files may not be used for one level.
- // type PathMap map[logrus.Level]string
- // 一个 level 对应 一个 logger
- type LoggerMap map[logrus.Level]*lumberjack.Logger
- // WriterMap is map for mapping a log level to an io.Writer.
- // Multiple levels may share a writer, but multiple writers may not be used for one level.
- type WriterMap map[logrus.Level]io.Writer
- type RotateFileConfig struct {
- Filename string
- MaxSize int
- MaxBackups int
- MaxAge int
- Level logrus.Level
- Formatter logrus.Formatter
- }
- // LfsHook is a hook to handle writing to local log files.
- type LfsHook struct {
- loggers LoggerMap
- writers WriterMap
- levels []logrus.Level
- lock *sync.Mutex
- formatter logrus.Formatter
- Config RotateFileConfig
- defaultPath string
- defaultWriter io.Writer
- hasDefaultPath bool
- hasDefaultWriter bool
- }
- // NewHook returns new LFS hook.
- // Output can be a string, io.Writer, WriterMap or PathMap.
- // If using io.Writer or WriterMap, user is responsible for closing the used io.Writer.
- func NewHook(output interface{}, formatter logrus.Formatter) *LfsHook {
- hook := &LfsHook{
- lock: new(sync.Mutex),
- }
- hook.SetFormatter(formatter)
- switch output.(type) {
- case string:
- hook.SetDefaultPath(output.(string))
- break
- case io.Writer:
- hook.SetDefaultWriter(output.(io.Writer))
- break
- case LoggerMap:
- hook.loggers = output.(LoggerMap)
- for level := range output.(LoggerMap) {
- hook.levels = append(hook.levels, level)
- }
- break
- case WriterMap:
- hook.writers = output.(WriterMap)
- for level := range output.(WriterMap) {
- hook.levels = append(hook.levels, level)
- }
- break
- default:
- panic(fmt.Sprintf("unsupported level map type: %v", reflect.TypeOf(output)))
- }
- return hook
- }
- // SetFormatter sets the format that will be used by hook.
- // If using text formatter, this method will disable color output to make the log file more readable.
- func (hook *LfsHook) SetFormatter(formatter logrus.Formatter) {
- hook.lock.Lock()
- defer hook.lock.Unlock()
- if formatter == nil {
- formatter = defaultFormatter
- } else {
- switch formatter.(type) {
- case *logrus.TextFormatter:
- textFormatter := formatter.(*logrus.TextFormatter)
- textFormatter.DisableColors = true
- }
- }
- hook.formatter = formatter
- }
- // SetDefaultPath sets default path for levels that don't have any defined output path.
- func (hook *LfsHook) SetDefaultPath(defaultPath string) {
- hook.lock.Lock()
- defer hook.lock.Unlock()
- hook.defaultPath = defaultPath
- hook.hasDefaultPath = true
- }
- // SetDefaultWriter sets default writer for levels that don't have any defined writer.
- func (hook *LfsHook) SetDefaultWriter(defaultWriter io.Writer) {
- hook.lock.Lock()
- defer hook.lock.Unlock()
- hook.defaultWriter = defaultWriter
- hook.hasDefaultWriter = true
- }
- // Fire writes the log file to defined path or using the defined writer.
- // User who run this function needs write permissions to the file or directory if the file does not yet exist.
- func (hook *LfsHook) Fire(entry *logrus.Entry) error {
- hook.lock.Lock()
- defer hook.lock.Unlock()
- if hook.writers != nil || hook.hasDefaultWriter {
- return hook.ioWrite(entry)
- } else if hook.loggers != nil || hook.hasDefaultPath {
- return hook.fileWrite(entry)
- }
- return nil
- }
- // Write a log line to an io.Writer.
- func (hook *LfsHook) ioWrite(entry *logrus.Entry) error {
- var (
- writer io.Writer
- msg []byte
- err error
- ok bool
- )
- if writer, ok = hook.writers[entry.Level]; !ok {
- if hook.hasDefaultWriter {
- writer = hook.defaultWriter
- } else {
- return nil
- }
- }
- // use our formatter instead of entry.String()
- msg, err = hook.formatter.Format(entry)
- if err != nil {
- log.Println("failed to generate string for entry:", err)
- return err
- }
- _, err = writer.Write(msg)
- return err
- }
- // Write a log line directly to a file.
- func (hook *LfsHook) fileWrite(entry *logrus.Entry) error {
- var (
- logger *lumberjack.Logger
- msg []byte
- err error
- ok bool
- )
- if logger, ok = hook.loggers[entry.Level]; !ok {
- if hook.hasDefaultPath {
- logger = &lumberjack.Logger{
- Filename: hook.defaultPath,
- MaxSize: 10, // maxSize M
- MaxBackups: 5, // keep 5 file
- MaxAge: 7, // 7 day
- }
- } else {
- return nil
- }
- }
- // use our formatter instead of entry.String()
- msg, err = hook.formatter.Format(entry)
- if err != nil {
- log.Println("failed to generate string for entry:", err)
- return err
- }
- defer logger.Close()
- logger.Write(msg)
- return nil
- }
- // Levels returns configured log levels.
- func (hook *LfsHook) Levels() []logrus.Level {
- return logrus.AllLevels
- }
- var log *logrus.Entry
- var once sync.Once
- //NewLogger 初始化 logger
- func NewLogger() *logrus.Entry {
- once.Do(func() {
- log = logrus.New().WithFields(
- logrus.Fields{
- "appname": "pbx-api-v4",
- },
- )
- })
- return log
- }
|