From 740691b080162e61f504760a6e08769fdd1e2ecb Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 11 Aug 2016 16:32:05 +0800 Subject: [PATCH] update package beego/logs --- Godeps/Godeps.json | 4 +- vendor/github.com/astaxie/beego/logs/conn.go | 43 +-- .../github.com/astaxie/beego/logs/console.go | 80 +++--- vendor/github.com/astaxie/beego/logs/file.go | 261 +++++++++--------- vendor/github.com/astaxie/beego/logs/log.go | 246 +++++++++++------ .../github.com/astaxie/beego/logs/logger.go | 79 ++++++ .../astaxie/beego/logs/multifile.go | 116 ++++++++ vendor/github.com/astaxie/beego/logs/smtp.go | 49 ++-- 8 files changed, 573 insertions(+), 305 deletions(-) create mode 100644 vendor/github.com/astaxie/beego/logs/logger.go create mode 100644 vendor/github.com/astaxie/beego/logs/multifile.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index dd435272..16593114 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -8,8 +8,8 @@ "Deps": [ { "ImportPath": "github.com/astaxie/beego/logs", - "Comment": "v1.5.0-9-gfb7314f", - "Rev": "fb7314f8ac86b83ccd34386518d97cf2363e2ae5" + "Comment": "v1.6.1-5-g88c5dfa", + "Rev": "88c5dfa6ead42e624c2e7d9e04eab6cb2d07412a" }, { "ImportPath": "github.com/docopt/docopt-go", diff --git a/vendor/github.com/astaxie/beego/logs/conn.go b/vendor/github.com/astaxie/beego/logs/conn.go index 2240eece..1db1a427 100644 --- a/vendor/github.com/astaxie/beego/logs/conn.go +++ b/vendor/github.com/astaxie/beego/logs/conn.go @@ -17,14 +17,14 @@ package logs import ( "encoding/json" "io" - "log" "net" + "time" ) -// ConnWriter implements LoggerInterface. +// connWriter implements LoggerInterface. // it writes messages in keep-live tcp connection. -type ConnWriter struct { - lg *log.Logger +type connWriter struct { + lg *logWriter innerWriter io.WriteCloser ReconnectOnMsg bool `json:"reconnectOnMsg"` Reconnect bool `json:"reconnect"` @@ -33,26 +33,26 @@ type ConnWriter struct { Level int `json:"level"` } -// create new ConnWrite returning as LoggerInterface. -func NewConn() LoggerInterface { - conn := new(ConnWriter) +// NewConn create new ConnWrite returning as LoggerInterface. +func NewConn() Logger { + conn := new(connWriter) conn.Level = LevelTrace return conn } -// init connection writer with json config. +// Init init connection writer with json config. // json config only need key "level". -func (c *ConnWriter) Init(jsonconfig string) error { - return json.Unmarshal([]byte(jsonconfig), c) +func (c *connWriter) Init(jsonConfig string) error { + return json.Unmarshal([]byte(jsonConfig), c) } -// write message in connection. +// WriteMsg write message in connection. // if connection is down, try to re-connect. -func (c *ConnWriter) WriteMsg(msg string, level int) error { +func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil } - if c.neddedConnectOnMsg() { + if c.needToConnectOnMsg() { err := c.connect() if err != nil { return err @@ -62,23 +62,24 @@ func (c *ConnWriter) WriteMsg(msg string, level int) error { if c.ReconnectOnMsg { defer c.innerWriter.Close() } - c.lg.Println(msg) + + c.lg.println(when, msg) return nil } -// implementing method. empty. -func (c *ConnWriter) Flush() { +// Flush implementing method. empty. +func (c *connWriter) Flush() { } -// destroy connection writer and close tcp listener. -func (c *ConnWriter) Destroy() { +// Destroy destroy connection writer and close tcp listener. +func (c *connWriter) Destroy() { if c.innerWriter != nil { c.innerWriter.Close() } } -func (c *ConnWriter) connect() error { +func (c *connWriter) connect() error { if c.innerWriter != nil { c.innerWriter.Close() c.innerWriter = nil @@ -94,11 +95,11 @@ func (c *ConnWriter) connect() error { } c.innerWriter = conn - c.lg = log.New(conn, "", log.Ldate|log.Ltime) + c.lg = newLogWriter(conn) return nil } -func (c *ConnWriter) neddedConnectOnMsg() bool { +func (c *connWriter) needToConnectOnMsg() bool { if c.Reconnect { c.Reconnect = false return true diff --git a/vendor/github.com/astaxie/beego/logs/console.go b/vendor/github.com/astaxie/beego/logs/console.go index ce7ecd54..dc41dd7d 100644 --- a/vendor/github.com/astaxie/beego/logs/console.go +++ b/vendor/github.com/astaxie/beego/logs/console.go @@ -16,14 +16,16 @@ package logs import ( "encoding/json" - "log" "os" "runtime" + "time" ) -type Brush func(string) string +// brush is a color join function +type brush func(string) string -func NewBrush(color string) Brush { +// newBrush return a fix color Brush +func newBrush(color string) brush { pre := "\033[" reset := "\033[0m" return func(text string) string { @@ -31,62 +33,66 @@ func NewBrush(color string) Brush { } } -var colors = []Brush{ - NewBrush("1;37"), // Emergency white - NewBrush("1;36"), // Alert cyan - NewBrush("1;35"), // Critical magenta - NewBrush("1;31"), // Error red - NewBrush("1;33"), // Warning yellow - NewBrush("1;32"), // Notice green - NewBrush("1;34"), // Informational blue - NewBrush("1;34"), // Debug blue +var colors = []brush{ + newBrush("1;37"), // Emergency white + newBrush("1;36"), // Alert cyan + newBrush("1;35"), // Critical magenta + newBrush("1;31"), // Error red + newBrush("1;33"), // Warning yellow + newBrush("1;32"), // Notice green + newBrush("1;34"), // Informational blue + newBrush("1;34"), // Debug blue } -// ConsoleWriter implements LoggerInterface and writes messages to terminal. -type ConsoleWriter struct { - lg *log.Logger - Level int `json:"level"` +// consoleWriter implements LoggerInterface and writes messages to terminal. +type consoleWriter struct { + lg *logWriter + Level int `json:"level"` + Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color } -// create ConsoleWriter returning as LoggerInterface. -func NewConsole() LoggerInterface { - cw := &ConsoleWriter{ - lg: log.New(os.Stdout, "", log.Ldate|log.Ltime), - Level: LevelDebug, +// NewConsole create ConsoleWriter returning as LoggerInterface. +func NewConsole() Logger { + cw := &consoleWriter{ + lg: newLogWriter(os.Stdout), + Level: LevelDebug, + Colorful: runtime.GOOS != "windows", } return cw } -// init console logger. -// jsonconfig like '{"level":LevelTrace}'. -func (c *ConsoleWriter) Init(jsonconfig string) error { - if len(jsonconfig) == 0 { +// Init init console logger. +// jsonConfig like '{"level":LevelTrace}'. +func (c *consoleWriter) Init(jsonConfig string) error { + if len(jsonConfig) == 0 { return nil } - return json.Unmarshal([]byte(jsonconfig), c) + err := json.Unmarshal([]byte(jsonConfig), c) + if runtime.GOOS == "windows" { + c.Colorful = false + } + return err } -// write message in console. -func (c *ConsoleWriter) WriteMsg(msg string, level int) error { +// WriteMsg write message in console. +func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil } - if goos := runtime.GOOS; goos == "windows" { - c.lg.Println(msg) - return nil + if c.Colorful { + msg = colors[level](msg) } - c.lg.Println(colors[level](msg)) - + c.lg.println(when, msg) return nil } -// implementing method. empty. -func (c *ConsoleWriter) Destroy() { +// Destroy implementing method. empty. +func (c *consoleWriter) Destroy() { } -// implementing method. empty. -func (c *ConsoleWriter) Flush() { +// Flush implementing method. empty. +func (c *consoleWriter) Flush() { } diff --git a/vendor/github.com/astaxie/beego/logs/file.go b/vendor/github.com/astaxie/beego/logs/file.go index 2d3449ce..9d3f78a0 100644 --- a/vendor/github.com/astaxie/beego/logs/file.go +++ b/vendor/github.com/astaxie/beego/logs/file.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" "io" - "log" "os" "path/filepath" "strings" @@ -28,156 +27,154 @@ import ( "time" ) -// FileLogWriter implements LoggerInterface. +// fileLogWriter implements LoggerInterface. // It writes messages by lines limit, file size limit, or time frequency. -type FileLogWriter struct { - *log.Logger - mw *MuxWriter +type fileLogWriter struct { + sync.Mutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize // The opened file - Filename string `json:"filename"` + Filename string `json:"filename"` + fileWriter *os.File - Maxlines int `json:"maxlines"` - maxlines_curlines int + // Rotate at line + MaxLines int `json:"maxlines"` + maxLinesCurLines int // Rotate at size - Maxsize int `json:"maxsize"` - maxsize_cursize int + MaxSize int `json:"maxsize"` + maxSizeCurSize int // Rotate daily - Daily bool `json:"daily"` - Maxdays int64 `json:"maxdays"` - daily_opendate int + Daily bool `json:"daily"` + MaxDays int64 `json:"maxdays"` + dailyOpenDate int Rotate bool `json:"rotate"` - startLock sync.Mutex // Only one log can write to the file - Level int `json:"level"` + + Perm os.FileMode `json:"perm"` + + fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix } -// an *os.File writer with locker. -type MuxWriter struct { - sync.Mutex - fd *os.File -} - -// write to os.File. -func (l *MuxWriter) Write(b []byte) (int, error) { - l.Lock() - defer l.Unlock() - return l.fd.Write(b) -} - -// set os.File in writer. -func (l *MuxWriter) SetFd(fd *os.File) { - if l.fd != nil { - l.fd.Close() - } - l.fd = fd -} - -// create a FileLogWriter returning as LoggerInterface. -func NewFileWriter() LoggerInterface { - w := &FileLogWriter{ +// newFileWriter create a FileLogWriter returning as LoggerInterface. +func newFileWriter() Logger { + w := &fileLogWriter{ Filename: "", - Maxlines: 1000000, - Maxsize: 1 << 28, //256 MB + MaxLines: 1000000, + MaxSize: 1 << 28, //256 MB Daily: true, - Maxdays: 7, + MaxDays: 7, Rotate: true, Level: LevelTrace, + Perm: 0660, } - // use MuxWriter instead direct use os.File for lock write when rotate - w.mw = new(MuxWriter) - // set MuxWriter as Logger's io.Writer - w.Logger = log.New(w.mw, "", log.Ldate|log.Ltime) return w } // Init file logger with json config. -// jsonconfig like: +// jsonConfig like: // { // "filename":"logs/beego.log", -// "maxlines":10000, +// "maxLines":10000, // "maxsize":1<<30, // "daily":true, -// "maxdays":15, -// "rotate":true +// "maxDays":15, +// "rotate":true, +// "perm":0600 // } -func (w *FileLogWriter) Init(jsonconfig string) error { - err := json.Unmarshal([]byte(jsonconfig), w) +func (w *fileLogWriter) Init(jsonConfig string) error { + err := json.Unmarshal([]byte(jsonConfig), w) if err != nil { return err } if len(w.Filename) == 0 { return errors.New("jsonconfig must have filename") } + w.suffix = filepath.Ext(w.Filename) + w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix) + if w.suffix == "" { + w.suffix = ".log" + } err = w.startLogger() return err } // start file logger. create log file and set to locker-inside file writer. -func (w *FileLogWriter) startLogger() error { - fd, err := w.createLogFile() +func (w *fileLogWriter) startLogger() error { + file, err := w.createLogFile() if err != nil { return err } - w.mw.SetFd(fd) + if w.fileWriter != nil { + w.fileWriter.Close() + } + w.fileWriter = file return w.initFd() } -func (w *FileLogWriter) docheck(size int) { - w.startLock.Lock() - defer w.startLock.Unlock() - if w.Rotate && ((w.Maxlines > 0 && w.maxlines_curlines >= w.Maxlines) || - (w.Maxsize > 0 && w.maxsize_cursize >= w.Maxsize) || - (w.Daily && time.Now().Day() != w.daily_opendate)) { - if err := w.DoRotate(); err != nil { - fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) - return - } - } - w.maxlines_curlines++ - w.maxsize_cursize += size +func (w *fileLogWriter) needRotate(size int, day int) bool { + return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) || + (w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) || + (w.Daily && day != w.dailyOpenDate) + } -// write logger message into file. -func (w *FileLogWriter) WriteMsg(msg string, level int) error { +// WriteMsg write logger message into file. +func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { if level > w.Level { return nil } - n := 24 + len(msg) // 24 stand for the length "2013/06/23 21:00:22 [T] " - w.docheck(n) - w.Logger.Println(msg) - return nil + h, d := formatTimeHeader(when) + msg = string(h) + msg + "\n" + if w.Rotate { + if w.needRotate(len(msg), d) { + w.Lock() + if w.needRotate(len(msg), d) { + if err := w.doRotate(when); err != nil { + fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) + } + } + w.Unlock() + } + } + + w.Lock() + _, err := w.fileWriter.Write([]byte(msg)) + if err == nil { + w.maxLinesCurLines++ + w.maxSizeCurSize += len(msg) + } + w.Unlock() + return err } -func (w *FileLogWriter) createLogFile() (*os.File, error) { +func (w *fileLogWriter) createLogFile() (*os.File, error) { // Open the log file - fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) + fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, w.Perm) return fd, err } -func (w *FileLogWriter) initFd() error { - fd := w.mw.fd - finfo, err := fd.Stat() +func (w *fileLogWriter) initFd() error { + fd := w.fileWriter + fInfo, err := fd.Stat() if err != nil { return fmt.Errorf("get stat err: %s\n", err) } - w.maxsize_cursize = int(finfo.Size()) - w.daily_opendate = time.Now().Day() - w.maxlines_curlines = 0 - if finfo.Size() > 0 { + w.maxSizeCurSize = int(fInfo.Size()) + w.dailyOpenDate = time.Now().Day() + w.maxLinesCurLines = 0 + if fInfo.Size() > 0 { count, err := w.lines() if err != nil { return err } - w.maxlines_curlines = count + w.maxLinesCurLines = count } return nil } -func (w *FileLogWriter) lines() (int, error) { +func (w *fileLogWriter) lines() (int, error) { fd, err := os.Open(w.Filename) if err != nil { return 0, err @@ -205,60 +202,62 @@ func (w *FileLogWriter) lines() (int, error) { } // DoRotate means it need to write file in new file. -// new file name like xx.log.2013-01-01.2 -func (w *FileLogWriter) DoRotate() error { +// new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size) +func (w *fileLogWriter) doRotate(logTime time.Time) error { _, err := os.Lstat(w.Filename) - if err == nil { // file exists - // Find the next available number - num := 1 - fname := "" + if err != nil { + return err + } + // file exists + // Find the next available number + num := 1 + fName := "" + if w.MaxLines > 0 || w.MaxSize > 0 { for ; err == nil && num <= 999; num++ { - fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num) - _, err = os.Lstat(fname) + fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix) + _, err = os.Lstat(fName) } - // return error if the last file checked still existed - if err == nil { - return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.Filename) - } - - // block Logger's io.Writer - w.mw.Lock() - defer w.mw.Unlock() - - fd := w.mw.fd - fd.Close() - - // close fd before rename - // Rename the file to its newfound home - err = os.Rename(w.Filename, fname) - if err != nil { - return fmt.Errorf("Rotate: %s\n", err) - } - - // re-start logger - err = w.startLogger() - if err != nil { - return fmt.Errorf("Rotate StartLogger: %s\n", err) - } - - go w.deleteOldLog() + } else { + fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix) + _, err = os.Lstat(fName) + } + // return error if the last file checked still existed + if err == nil { + return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.Filename) } + // close fileWriter before rename + w.fileWriter.Close() + + // Rename the file to its new found name + // even if occurs error,we MUST guarantee to restart new logger + renameErr := os.Rename(w.Filename, fName) + // re-start logger + startLoggerErr := w.startLogger() + go w.deleteOldLog() + + if startLoggerErr != nil { + return fmt.Errorf("Rotate StartLogger: %s\n", startLoggerErr) + } + if renameErr != nil { + return fmt.Errorf("Rotate: %s\n", renameErr) + } return nil + } -func (w *FileLogWriter) deleteOldLog() { +func (w *fileLogWriter) deleteOldLog() { dir := filepath.Dir(w.Filename) filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { defer func() { if r := recover(); r != nil { - returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r) - fmt.Println(returnErr) + fmt.Fprintf(os.Stderr, "Unable to delete old log '%s', error: %v\n", path, r) } }() - if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) { + if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.MaxDays) { + if strings.HasPrefix(filepath.Base(path), w.fileNameOnly) && + strings.HasSuffix(filepath.Base(path), w.suffix) { os.Remove(path) } } @@ -266,18 +265,18 @@ func (w *FileLogWriter) deleteOldLog() { }) } -// destroy file logger, close file writer. -func (w *FileLogWriter) Destroy() { - w.mw.fd.Close() +// Destroy close the file description, close file writer. +func (w *fileLogWriter) Destroy() { + w.fileWriter.Close() } -// flush file logger. +// Flush flush file logger. // there are no buffering messages in file logger in memory. // flush file means sync file from disk. -func (w *FileLogWriter) Flush() { - w.mw.fd.Sync() +func (w *fileLogWriter) Flush() { + w.fileWriter.Sync() } func init() { - Register("file", NewFileWriter) + Register("file", newFileWriter) } diff --git a/vendor/github.com/astaxie/beego/logs/log.go b/vendor/github.com/astaxie/beego/logs/log.go index cebbc737..a5982e45 100644 --- a/vendor/github.com/astaxie/beego/logs/log.go +++ b/vendor/github.com/astaxie/beego/logs/log.go @@ -12,6 +12,7 @@ // 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" @@ -34,9 +35,12 @@ package logs import ( "fmt" + "os" "path" "runtime" + "strconv" "sync" + "time" ) // RFC5424 log message levels. @@ -60,12 +64,12 @@ const ( LevelWarn = LevelWarning ) -type loggerType func() LoggerInterface +type loggerType func() Logger -// LoggerInterface defines the behavior of a log provider. -type LoggerInterface interface { +// Logger defines the behavior of a log provider. +type Logger interface { Init(config string) error - WriteMsg(msg string, level int) error + WriteMsg(when time.Time, msg string, level int) error Destroy() Flush() } @@ -93,68 +97,107 @@ type BeeLogger struct { enableFuncCallDepth bool loggerFuncCallDepth int asynchronous bool - msg chan *logMsg - outputs map[string]LoggerInterface + msgChan chan *logMsg + signalChan chan string + wg sync.WaitGroup + outputs []*nameLogger +} + +type nameLogger struct { + Logger + name string } type logMsg struct { level int msg string + when time.Time } +var logMsgPool *sync.Pool + // NewLogger returns a new BeeLogger. -// channellen means the number of messages in chan. +// channelLen means the number of messages in chan(used where asynchronous is true). // if the buffering chan is full, logger adapters write to file or other way. -func NewLogger(channellen int64) *BeeLogger { +func NewLogger(channelLen int64) *BeeLogger { bl := new(BeeLogger) bl.level = LevelDebug bl.loggerFuncCallDepth = 2 - bl.msg = make(chan *logMsg, channellen) - bl.outputs = make(map[string]LoggerInterface) + bl.msgChan = make(chan *logMsg, channelLen) + bl.signalChan = make(chan string, 1) return bl } +// Async set the log to asynchronous and start the goroutine func (bl *BeeLogger) Async() *BeeLogger { bl.asynchronous = true + logMsgPool = &sync.Pool{ + New: func() interface{} { + return &logMsg{} + }, + } + bl.wg.Add(1) go bl.startLogger() return bl } // SetLogger provides a given logger adapter into BeeLogger with config string. // config need to be correct JSON as string: {"interval":360}. -func (bl *BeeLogger) SetLogger(adaptername string, config string) error { +func (bl *BeeLogger) SetLogger(adapterName string, config string) error { bl.lock.Lock() defer bl.lock.Unlock() - if log, ok := adapters[adaptername]; ok { - lg := log() - err := lg.Init(config) - bl.outputs[adaptername] = lg - if err != nil { - fmt.Println("logs.BeeLogger.SetLogger: " + err.Error()) - return err + + for _, l := range bl.outputs { + if l.name == adapterName { + return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName) } - } else { - return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adaptername) } + + log, ok := adapters[adapterName] + if !ok { + return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName) + } + + lg := log() + err := lg.Init(config) + 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 } -// remove a logger adapter in BeeLogger. -func (bl *BeeLogger) DelLogger(adaptername string) error { +// DelLogger remove a logger adapter in BeeLogger. +func (bl *BeeLogger) DelLogger(adapterName string) error { bl.lock.Lock() defer bl.lock.Unlock() - if lg, ok := bl.outputs[adaptername]; ok { - lg.Destroy() - delete(bl.outputs, adaptername) - return nil - } else { - return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adaptername) + 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 +} + +func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) { + for _, l := range bl.outputs { + err := l.WriteMsg(when, msg, level) + if err != nil { + fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err) + } } } -func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { - lm := new(logMsg) - lm.level = loglevel +func (bl *BeeLogger) writeMsg(logLevel int, msg string) error { + when := time.Now() if bl.enableFuncCallDepth { _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) if !ok { @@ -162,43 +205,38 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { line = 0 } _, filename := path.Split(file) - lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg) - } else { - lm.msg = msg + msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "]" + msg } if bl.asynchronous { - bl.msg <- lm + lm := logMsgPool.Get().(*logMsg) + lm.level = logLevel + lm.msg = msg + lm.when = when + bl.msgChan <- lm } else { - for name, l := range bl.outputs { - err := l.WriteMsg(lm.msg, lm.level) - if err != nil { - fmt.Println("unable to WriteMsg to adapter:", name, err) - return err - } - } + bl.writeToLoggers(when, msg, logLevel) } return nil } -// Set log message level. -// +// SetLevel Set log message level. // If message level (such as LevelDebug) is higher than logger level (such as LevelWarning), // log providers will not even be sent the message. func (bl *BeeLogger) SetLevel(l int) { bl.level = l } -// set log funcCallDepth +// SetLogFuncCallDepth set log funcCallDepth func (bl *BeeLogger) SetLogFuncCallDepth(d int) { bl.loggerFuncCallDepth = d } -// get log funcCallDepth for wrapper +// GetLogFuncCallDepth return log funcCallDepth for wrapper func (bl *BeeLogger) GetLogFuncCallDepth() int { return bl.loggerFuncCallDepth } -// enable log funcCallDepth +// EnableFuncCallDepth enable log funcCallDepth func (bl *BeeLogger) EnableFuncCallDepth(b bool) { bl.enableFuncCallDepth = b } @@ -206,145 +244,179 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) { // start logger chan reading. // when chan is not empty, write logs. func (bl *BeeLogger) startLogger() { + gameOver := false for { select { - case bm := <-bl.msg: - for _, l := range bl.outputs { - err := l.WriteMsg(bm.msg, bm.level) - if err != nil { - fmt.Println("ERROR, unable to WriteMsg:", err) + case bm := <-bl.msgChan: + bl.writeToLoggers(bm.when, bm.msg, bm.level) + 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 } } } -// Log EMERGENCY level message. +// Emergency Log EMERGENCY level message. func (bl *BeeLogger) Emergency(format string, v ...interface{}) { if LevelEmergency > bl.level { return } msg := fmt.Sprintf("[M] "+format, v...) - bl.writerMsg(LevelEmergency, msg) + bl.writeMsg(LevelEmergency, msg) } -// Log ALERT level message. +// Alert Log ALERT level message. func (bl *BeeLogger) Alert(format string, v ...interface{}) { if LevelAlert > bl.level { return } msg := fmt.Sprintf("[A] "+format, v...) - bl.writerMsg(LevelAlert, msg) + bl.writeMsg(LevelAlert, msg) } -// Log CRITICAL level message. +// Critical Log CRITICAL level message. func (bl *BeeLogger) Critical(format string, v ...interface{}) { if LevelCritical > bl.level { return } msg := fmt.Sprintf("[C] "+format, v...) - bl.writerMsg(LevelCritical, msg) + bl.writeMsg(LevelCritical, msg) } -// Log ERROR level message. +// Error Log ERROR level message. func (bl *BeeLogger) Error(format string, v ...interface{}) { if LevelError > bl.level { return } msg := fmt.Sprintf("[E] "+format, v...) - bl.writerMsg(LevelError, msg) + bl.writeMsg(LevelError, msg) } -// Log WARNING level message. +// Warning Log WARNING level message. func (bl *BeeLogger) Warning(format string, v ...interface{}) { if LevelWarning > bl.level { return } msg := fmt.Sprintf("[W] "+format, v...) - bl.writerMsg(LevelWarning, msg) + bl.writeMsg(LevelWarning, msg) } -// Log NOTICE level message. +// Notice Log NOTICE level message. func (bl *BeeLogger) Notice(format string, v ...interface{}) { if LevelNotice > bl.level { return } msg := fmt.Sprintf("[N] "+format, v...) - bl.writerMsg(LevelNotice, msg) + bl.writeMsg(LevelNotice, msg) } -// Log INFORMATIONAL level message. +// Informational Log INFORMATIONAL level message. func (bl *BeeLogger) Informational(format string, v ...interface{}) { if LevelInformational > bl.level { return } msg := fmt.Sprintf("[I] "+format, v...) - bl.writerMsg(LevelInformational, msg) + bl.writeMsg(LevelInformational, msg) } -// Log DEBUG level message. +// Debug Log DEBUG level message. func (bl *BeeLogger) Debug(format string, v ...interface{}) { if LevelDebug > bl.level { return } msg := fmt.Sprintf("[D] "+format, v...) - bl.writerMsg(LevelDebug, msg) + bl.writeMsg(LevelDebug, msg) } -// Log WARN level message. +// Warn Log WARN level message. // compatibility alias for Warning() func (bl *BeeLogger) Warn(format string, v ...interface{}) { if LevelWarning > bl.level { return } msg := fmt.Sprintf("[W] "+format, v...) - bl.writerMsg(LevelWarning, msg) + bl.writeMsg(LevelWarning, msg) } -// Log INFO level message. +// Info Log INFO level message. // compatibility alias for Informational() func (bl *BeeLogger) Info(format string, v ...interface{}) { if LevelInformational > bl.level { return } msg := fmt.Sprintf("[I] "+format, v...) - bl.writerMsg(LevelInformational, msg) + bl.writeMsg(LevelInformational, msg) } -// Log TRACE level message. +// Trace Log TRACE level message. // compatibility alias for Debug() func (bl *BeeLogger) Trace(format string, v ...interface{}) { if LevelDebug > bl.level { return } msg := fmt.Sprintf("[D] "+format, v...) - bl.writerMsg(LevelDebug, msg) + bl.writeMsg(LevelDebug, msg) } -// flush all chan data. +// Flush flush all chan data. func (bl *BeeLogger) Flush() { - for _, l := range bl.outputs { - l.Flush() + if bl.asynchronous { + bl.signalChan <- "flush" + bl.wg.Wait() + bl.wg.Add(1) + return } + bl.flush() } -// close logger, flush all chan data and destroy all adapters in BeeLogger. +// 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() + } else { + bl.flush() + for _, l := range bl.outputs { + l.Destroy() + } + bl.outputs = nil + } + close(bl.msgChan) + 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() { for { - if len(bl.msg) > 0 { - bm := <-bl.msg - for _, l := range bl.outputs { - err := l.WriteMsg(bm.msg, bm.level) - if err != nil { - fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err) - } - } + if len(bl.msgChan) > 0 { + bm := <-bl.msgChan + bl.writeToLoggers(bm.when, bm.msg, bm.level) + logMsgPool.Put(bm) continue } break } for _, l := range bl.outputs { l.Flush() - l.Destroy() } } diff --git a/vendor/github.com/astaxie/beego/logs/logger.go b/vendor/github.com/astaxie/beego/logs/logger.go new file mode 100644 index 00000000..b25bfaef --- /dev/null +++ b/vendor/github.com/astaxie/beego/logs/logger.go @@ -0,0 +1,79 @@ +// 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 + +import ( + "io" + "sync" + "time" +) + +type logWriter struct { + sync.Mutex + writer io.Writer +} + +func newLogWriter(wr io.Writer) *logWriter { + return &logWriter{writer: wr} +} + +func (lg *logWriter) println(when time.Time, msg string) { + lg.Lock() + h, _ := formatTimeHeader(when) + lg.writer.Write(append(append(h, msg...), '\n')) + lg.Unlock() +} + +func formatTimeHeader(when time.Time) ([]byte, int) { + y, mo, d := when.Date() + h, mi, s := when.Clock() + //len(2006/01/02 15:03:04)==19 + var buf [20]byte + t := 3 + for y >= 10 { + p := y / 10 + buf[t] = byte('0' + y - p*10) + y = p + t-- + } + buf[0] = byte('0' + y) + buf[4] = '/' + if mo > 9 { + buf[5] = '1' + buf[6] = byte('0' + mo - 9) + } else { + buf[5] = '0' + buf[6] = byte('0' + mo) + } + buf[7] = '/' + t = d / 10 + buf[8] = byte('0' + t) + buf[9] = byte('0' + d - t*10) + buf[10] = ' ' + t = h / 10 + buf[11] = byte('0' + t) + buf[12] = byte('0' + h - t*10) + buf[13] = ':' + t = mi / 10 + buf[14] = byte('0' + t) + buf[15] = byte('0' + mi - t*10) + buf[16] = ':' + t = s / 10 + buf[17] = byte('0' + t) + buf[18] = byte('0' + s - t*10) + buf[19] = ' ' + + return buf[0:], d +} diff --git a/vendor/github.com/astaxie/beego/logs/multifile.go b/vendor/github.com/astaxie/beego/logs/multifile.go new file mode 100644 index 00000000..b82ba274 --- /dev/null +++ b/vendor/github.com/astaxie/beego/logs/multifile.go @@ -0,0 +1,116 @@ +// 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 + +import ( + "encoding/json" + "time" +) + +// A filesLogWriter manages several fileLogWriter +// filesLogWriter will write logs to the file in json configuration and write the same level log to correspond file +// means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log +// and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log +// the rotate attribute also acts like fileLogWriter +type multiFileLogWriter struct { + writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter + fullLogWriter *fileLogWriter + Separate []string `json:"separate"` +} + +var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} + +// Init file logger with json config. +// jsonConfig like: +// { +// "filename":"logs/beego.log", +// "maxLines":0, +// "maxsize":0, +// "daily":true, +// "maxDays":15, +// "rotate":true, +// "perm":0600, +// "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], +// } + +func (f *multiFileLogWriter) Init(config string) error { + writer := newFileWriter().(*fileLogWriter) + err := writer.Init(config) + if err != nil { + return err + } + f.fullLogWriter = writer + f.writers[LevelDebug+1] = writer + + //unmarshal "separate" field to f.Separate + json.Unmarshal([]byte(config), f) + + jsonMap := map[string]interface{}{} + json.Unmarshal([]byte(config), &jsonMap) + + for i := LevelEmergency; i < LevelDebug+1; i++ { + for _, v := range f.Separate { + if v == levelNames[i] { + jsonMap["filename"] = f.fullLogWriter.fileNameOnly + "." + levelNames[i] + f.fullLogWriter.suffix + jsonMap["level"] = i + bs, _ := json.Marshal(jsonMap) + writer = newFileWriter().(*fileLogWriter) + writer.Init(string(bs)) + f.writers[i] = writer + } + } + } + + return nil +} + +func (f *multiFileLogWriter) Destroy() { + for i := 0; i < len(f.writers); i++ { + if f.writers[i] != nil { + f.writers[i].Destroy() + } + } +} + +func (f *multiFileLogWriter) WriteMsg(when time.Time, msg string, level int) error { + if f.fullLogWriter != nil { + f.fullLogWriter.WriteMsg(when, msg, level) + } + for i := 0; i < len(f.writers)-1; i++ { + if f.writers[i] != nil { + if level == f.writers[i].Level { + f.writers[i].WriteMsg(when, msg, level) + } + } + } + return nil +} + +func (f *multiFileLogWriter) Flush() { + for i := 0; i < len(f.writers); i++ { + if f.writers[i] != nil { + f.writers[i].Flush() + } + } +} + +// newFilesWriter create a FileLogWriter returning as LoggerInterface. +func newFilesWriter() Logger { + return &multiFileLogWriter{} +} + +func init() { + Register("multifile", newFilesWriter) +} diff --git a/vendor/github.com/astaxie/beego/logs/smtp.go b/vendor/github.com/astaxie/beego/logs/smtp.go index 95123ebf..47f5a0c6 100644 --- a/vendor/github.com/astaxie/beego/logs/smtp.go +++ b/vendor/github.com/astaxie/beego/logs/smtp.go @@ -24,31 +24,26 @@ import ( "time" ) -const ( -// no usage -// subjectPhrase = "Diagnostic message from server" -) - -// smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. -type SmtpWriter struct { - Username string `json:"Username"` +// SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server. +type SMTPWriter struct { + Username string `json:"username"` Password string `json:"password"` - Host string `json:"Host"` + Host string `json:"host"` Subject string `json:"subject"` FromAddress string `json:"fromAddress"` RecipientAddresses []string `json:"sendTos"` Level int `json:"level"` } -// create smtp writer. -func NewSmtpWriter() LoggerInterface { - return &SmtpWriter{Level: LevelTrace} +// NewSMTPWriter create smtp writer. +func newSMTPWriter() Logger { + return &SMTPWriter{Level: LevelTrace} } -// init smtp writer with json config. +// Init smtp writer with json config. // config like: // { -// "Username":"example@gmail.com", +// "username":"example@gmail.com", // "password:"password", // "host":"smtp.gmail.com:465", // "subject":"email title", @@ -56,7 +51,7 @@ func NewSmtpWriter() LoggerInterface { // "sendTos":["email1","email2"], // "level":LevelError // } -func (s *SmtpWriter) Init(jsonconfig string) error { +func (s *SMTPWriter) Init(jsonconfig string) error { err := json.Unmarshal([]byte(jsonconfig), s) if err != nil { return err @@ -64,7 +59,7 @@ func (s *SmtpWriter) Init(jsonconfig string) error { return nil } -func (s *SmtpWriter) GetSmtpAuth(host string) smtp.Auth { +func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth { if len(strings.Trim(s.Username, " ")) == 0 && len(strings.Trim(s.Password, " ")) == 0 { return nil } @@ -76,7 +71,7 @@ func (s *SmtpWriter) GetSmtpAuth(host string) smtp.Auth { ) } -func (s *SmtpWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error { +func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error { client, err := smtp.Dial(hostAddressWithPort) if err != nil { return err @@ -129,9 +124,9 @@ func (s *SmtpWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd return nil } -// write message in smtp writer. +// WriteMsg write message in smtp writer. // it will send an email with subject and only this message. -func (s *SmtpWriter) WriteMsg(msg string, level int) error { +func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error { if level > s.Level { return nil } @@ -139,27 +134,27 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error { hp := strings.Split(s.Host, ":") // Set up authentication information. - auth := s.GetSmtpAuth(hp[0]) + auth := s.getSMTPAuth(hp[0]) // Connect to the server, authenticate, set the sender and recipient, // and send the email all in one step. - content_type := "Content-Type: text/plain" + "; charset=UTF-8" + contentType := "Content-Type: text/plain" + "; charset=UTF-8" mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + - ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) + ">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", when.Format("2006-01-02 15:04:05")) + msg) return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) } -// implementing method. empty. -func (s *SmtpWriter) Flush() { +// Flush implementing method. empty. +func (s *SMTPWriter) Flush() { return } -// implementing method. empty. -func (s *SmtpWriter) Destroy() { +// Destroy implementing method. empty. +func (s *SMTPWriter) Destroy() { return } func init() { - Register("smtp", NewSmtpWriter) + Register("smtp", newSMTPWriter) }