Jelajahi Sumber

update package beego/logs

fatedier 8 tahun lalu
induk
melakukan
740691b080

+ 2 - 2
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",

+ 22 - 21
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

+ 43 - 37
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() {
 
 }
 

+ 126 - 127
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"`
-}
 
-// an *os.File writer with locker.
-type MuxWriter struct {
-	sync.Mutex
-	fd *os.File
-}
+	Perm os.FileMode `json:"perm"`
 
-// write to os.File.
-func (l *MuxWriter) Write(b []byte) (int, error) {
-	l.Lock()
-	defer l.Unlock()
-	return l.fd.Write(b)
+	fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix
 }
 
-// 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()
+	} 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 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)
-		}
+	// close fileWriter before rename
+	w.fileWriter.Close()
 
-		// re-start logger
-		err = w.startLogger()
-		if err != nil {
-			return fmt.Errorf("Rotate StartLogger: %s\n", err)
-		}
+	// 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()
 
-		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)
 }

+ 159 - 87
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()
 	}
 }

+ 79 - 0
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
+}

+ 116 - 0
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)
+}

+ 22 - 27
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)
 }