mirror of https://github.com/gogits/gogs.git
Unknwon
8 years ago
66 changed files with 198 additions and 1033 deletions
File diff suppressed because one or more lines are too long
@ -1,104 +0,0 @@ |
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package log |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"io" |
|
||||||
"log" |
|
||||||
"net" |
|
||||||
) |
|
||||||
|
|
||||||
// ConnWriter implements LoggerInterface.
|
|
||||||
// it writes messages in keep-live tcp connection.
|
|
||||||
type ConnWriter struct { |
|
||||||
lg *log.Logger |
|
||||||
innerWriter io.WriteCloser |
|
||||||
ReconnectOnMsg bool `json:"reconnectOnMsg"` |
|
||||||
Reconnect bool `json:"reconnect"` |
|
||||||
Net string `json:"net"` |
|
||||||
Addr string `json:"addr"` |
|
||||||
Level int `json:"level"` |
|
||||||
} |
|
||||||
|
|
||||||
// create new ConnWrite returning as LoggerInterface.
|
|
||||||
func NewConn() LoggerInterface { |
|
||||||
conn := new(ConnWriter) |
|
||||||
conn.Level = TRACE |
|
||||||
return conn |
|
||||||
} |
|
||||||
|
|
||||||
// init connection writer with json config.
|
|
||||||
// json config only need key "level".
|
|
||||||
func (cw *ConnWriter) Init(jsonconfig string) error { |
|
||||||
return json.Unmarshal([]byte(jsonconfig), cw) |
|
||||||
} |
|
||||||
|
|
||||||
// write message in connection.
|
|
||||||
// if connection is down, try to re-connect.
|
|
||||||
func (cw *ConnWriter) WriteMsg(msg string, skip, level int) error { |
|
||||||
if cw.Level > level { |
|
||||||
return nil |
|
||||||
} |
|
||||||
if cw.neddedConnectOnMsg() { |
|
||||||
if err := cw.connect(); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if cw.ReconnectOnMsg { |
|
||||||
defer cw.innerWriter.Close() |
|
||||||
} |
|
||||||
cw.lg.Println(msg) |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func (_ *ConnWriter) Flush() { |
|
||||||
} |
|
||||||
|
|
||||||
// destroy connection writer and close tcp listener.
|
|
||||||
func (cw *ConnWriter) Destroy() { |
|
||||||
if cw.innerWriter == nil { |
|
||||||
return |
|
||||||
} |
|
||||||
cw.innerWriter.Close() |
|
||||||
} |
|
||||||
|
|
||||||
func (cw *ConnWriter) connect() error { |
|
||||||
if cw.innerWriter != nil { |
|
||||||
cw.innerWriter.Close() |
|
||||||
cw.innerWriter = nil |
|
||||||
} |
|
||||||
|
|
||||||
conn, err := net.Dial(cw.Net, cw.Addr) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
if tcpConn, ok := conn.(*net.TCPConn); ok { |
|
||||||
tcpConn.SetKeepAlive(true) |
|
||||||
} |
|
||||||
|
|
||||||
cw.innerWriter = conn |
|
||||||
cw.lg = log.New(conn, "", log.Ldate|log.Ltime) |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func (cw *ConnWriter) neddedConnectOnMsg() bool { |
|
||||||
if cw.Reconnect { |
|
||||||
cw.Reconnect = false |
|
||||||
return true |
|
||||||
} |
|
||||||
|
|
||||||
if cw.innerWriter == nil { |
|
||||||
return true |
|
||||||
} |
|
||||||
|
|
||||||
return cw.ReconnectOnMsg |
|
||||||
} |
|
||||||
|
|
||||||
func init() { |
|
||||||
Register("conn", NewConn) |
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package log |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"log" |
|
||||||
"os" |
|
||||||
"runtime" |
|
||||||
) |
|
||||||
|
|
||||||
type Brush func(string) string |
|
||||||
|
|
||||||
func NewBrush(color string) Brush { |
|
||||||
pre := "\033[" |
|
||||||
reset := "\033[0m" |
|
||||||
return func(text string) string { |
|
||||||
return pre + color + "m" + text + reset |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var colors = []Brush{ |
|
||||||
NewBrush("1;36"), // Trace cyan
|
|
||||||
NewBrush("1;34"), // Debug blue
|
|
||||||
NewBrush("1;32"), // Info green
|
|
||||||
NewBrush("1;33"), // Warn yellow
|
|
||||||
NewBrush("1;31"), // Error red
|
|
||||||
NewBrush("1;35"), // Critical purple
|
|
||||||
NewBrush("1;31"), // Fatal red
|
|
||||||
} |
|
||||||
|
|
||||||
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
|
|
||||||
type ConsoleWriter struct { |
|
||||||
lg *log.Logger |
|
||||||
Level int `json:"level"` |
|
||||||
} |
|
||||||
|
|
||||||
// create ConsoleWriter returning as LoggerInterface.
|
|
||||||
func NewConsole() LoggerInterface { |
|
||||||
return &ConsoleWriter{ |
|
||||||
lg: log.New(os.Stdout, "", log.Ldate|log.Ltime), |
|
||||||
Level: TRACE, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (cw *ConsoleWriter) Init(config string) error { |
|
||||||
return json.Unmarshal([]byte(config), cw) |
|
||||||
} |
|
||||||
|
|
||||||
func (cw *ConsoleWriter) WriteMsg(msg string, skip, level int) error { |
|
||||||
if cw.Level > level { |
|
||||||
return nil |
|
||||||
} |
|
||||||
if runtime.GOOS == "windows" { |
|
||||||
cw.lg.Println(msg) |
|
||||||
} else { |
|
||||||
cw.lg.Println(colors[level](msg)) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func (_ *ConsoleWriter) Flush() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
func (_ *ConsoleWriter) Destroy() { |
|
||||||
} |
|
||||||
|
|
||||||
func init() { |
|
||||||
Register("console", NewConsole) |
|
||||||
} |
|
@ -1,243 +0,0 @@ |
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package log |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"errors" |
|
||||||
"fmt" |
|
||||||
"io/ioutil" |
|
||||||
"log" |
|
||||||
"os" |
|
||||||
"path/filepath" |
|
||||||
"strings" |
|
||||||
"sync" |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
// FileLogWriter implements LoggerInterface.
|
|
||||||
// It writes messages by lines limit, file size limit, or time frequency.
|
|
||||||
type FileLogWriter struct { |
|
||||||
*log.Logger |
|
||||||
mw *MuxWriter |
|
||||||
// The opened file
|
|
||||||
Filename string `json:"filename"` |
|
||||||
|
|
||||||
Maxlines int `json:"maxlines"` |
|
||||||
maxlines_curlines int |
|
||||||
|
|
||||||
// Rotate at size
|
|
||||||
Maxsize int `json:"maxsize"` |
|
||||||
maxsize_cursize int |
|
||||||
|
|
||||||
// Rotate daily
|
|
||||||
Daily bool `json:"daily"` |
|
||||||
Maxdays int64 `json:"maxdays"` |
|
||||||
daily_opendate 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 |
|
||||||
} |
|
||||||
|
|
||||||
// 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{ |
|
||||||
Filename: "", |
|
||||||
Maxlines: 1000000, |
|
||||||
Maxsize: 1 << 28, //256 MB
|
|
||||||
Daily: true, |
|
||||||
Maxdays: 7, |
|
||||||
Rotate: true, |
|
||||||
Level: TRACE, |
|
||||||
} |
|
||||||
// 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.
|
|
||||||
// config like:
|
|
||||||
// {
|
|
||||||
// "filename":"log/gogs.log",
|
|
||||||
// "maxlines":10000,
|
|
||||||
// "maxsize":1<<30,
|
|
||||||
// "daily":true,
|
|
||||||
// "maxdays":15,
|
|
||||||
// "rotate":true
|
|
||||||
// }
|
|
||||||
func (w *FileLogWriter) Init(config string) error { |
|
||||||
if err := json.Unmarshal([]byte(config), w); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
if len(w.Filename) == 0 { |
|
||||||
return errors.New("config must have filename") |
|
||||||
} |
|
||||||
return w.StartLogger() |
|
||||||
} |
|
||||||
|
|
||||||
// start file logger. create log file and set to locker-inside file writer.
|
|
||||||
func (w *FileLogWriter) StartLogger() error { |
|
||||||
fd, err := w.createLogFile() |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
w.mw.SetFd(fd) |
|
||||||
if err = w.initFd(); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
// write logger message into file.
|
|
||||||
func (w *FileLogWriter) WriteMsg(msg string, skip, 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 |
|
||||||
} |
|
||||||
|
|
||||||
func (w *FileLogWriter) createLogFile() (*os.File, error) { |
|
||||||
// Open the log file
|
|
||||||
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) |
|
||||||
} |
|
||||||
|
|
||||||
func (w *FileLogWriter) initFd() error { |
|
||||||
fd := w.mw.fd |
|
||||||
finfo, err := fd.Stat() |
|
||||||
if err != nil { |
|
||||||
return fmt.Errorf("get stat: %s\n", err) |
|
||||||
} |
|
||||||
w.maxsize_cursize = int(finfo.Size()) |
|
||||||
w.daily_opendate = time.Now().Day() |
|
||||||
if finfo.Size() > 0 { |
|
||||||
content, err := ioutil.ReadFile(w.Filename) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
w.maxlines_curlines = len(strings.Split(string(content), "\n")) |
|
||||||
} else { |
|
||||||
w.maxlines_curlines = 0 |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// 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 { |
|
||||||
_, err := os.Lstat(w.Filename) |
|
||||||
if err == nil { // file exists
|
|
||||||
// Find the next available number
|
|
||||||
num := 1 |
|
||||||
fname := "" |
|
||||||
for ; err == nil && num <= 999; num++ { |
|
||||||
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num) |
|
||||||
_, 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
|
|
||||||
if err = os.Rename(w.Filename, fname); err != nil { |
|
||||||
return fmt.Errorf("Rotate: %s\n", err) |
|
||||||
} |
|
||||||
|
|
||||||
// re-start logger
|
|
||||||
if err = w.StartLogger(); err != nil { |
|
||||||
return fmt.Errorf("Rotate StartLogger: %s\n", err) |
|
||||||
} |
|
||||||
|
|
||||||
go w.deleteOldLog() |
|
||||||
} |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
} |
|
||||||
}() |
|
||||||
|
|
||||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) { |
|
||||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) { |
|
||||||
os.Remove(path) |
|
||||||
} |
|
||||||
} |
|
||||||
return returnErr |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
// destroy file logger, close file writer.
|
|
||||||
func (w *FileLogWriter) Destroy() { |
|
||||||
w.mw.fd.Close() |
|
||||||
} |
|
||||||
|
|
||||||
// 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 init() { |
|
||||||
Register("file", NewFileWriter) |
|
||||||
} |
|
@ -1,312 +0,0 @@ |
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package log |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"os" |
|
||||||
"path" |
|
||||||
"path/filepath" |
|
||||||
"runtime" |
|
||||||
"strings" |
|
||||||
"sync" |
|
||||||
) |
|
||||||
|
|
||||||
var ( |
|
||||||
loggers []*Logger |
|
||||||
GitLogger *Logger |
|
||||||
) |
|
||||||
|
|
||||||
func NewLogger(bufLen int64, mode, config string) { |
|
||||||
logger := newLogger(bufLen) |
|
||||||
|
|
||||||
isExist := false |
|
||||||
for i, l := range loggers { |
|
||||||
if l.adapter == mode { |
|
||||||
isExist = true |
|
||||||
loggers[i] = logger |
|
||||||
} |
|
||||||
} |
|
||||||
if !isExist { |
|
||||||
loggers = append(loggers, logger) |
|
||||||
} |
|
||||||
if err := logger.SetLogger(mode, config); err != nil { |
|
||||||
Fatal(2, "Fail to set logger (%s): %v", mode, err) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// FIXME: use same log level as other loggers.
|
|
||||||
func NewGitLogger(logPath string) { |
|
||||||
os.MkdirAll(path.Dir(logPath), os.ModePerm) |
|
||||||
GitLogger = newLogger(0) |
|
||||||
GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath)) |
|
||||||
} |
|
||||||
|
|
||||||
func Trace(format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Trace(format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Debug(format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Debug(format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Info(format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Info(format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Warn(format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Warn(format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Error(skip int, format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Error(skip, format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Critical(skip int, format string, v ...interface{}) { |
|
||||||
for _, logger := range loggers { |
|
||||||
logger.Critical(skip, format, v...) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func Fatal(skip int, format string, v ...interface{}) { |
|
||||||
Error(skip, format, v...) |
|
||||||
for _, l := range loggers { |
|
||||||
l.Close() |
|
||||||
} |
|
||||||
os.Exit(1) |
|
||||||
} |
|
||||||
|
|
||||||
func Close() { |
|
||||||
for _, l := range loggers { |
|
||||||
l.Close() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// .___ __ _____
|
|
||||||
// | | _____/ |_ ____________/ ____\____ ____ ____
|
|
||||||
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
|
|
||||||
// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/
|
|
||||||
// |___|___| /__| \___ >__| |__| (____ /\___ >___ >
|
|
||||||
// \/ \/ \/ \/ \/
|
|
||||||
|
|
||||||
type LogLevel int |
|
||||||
|
|
||||||
const ( |
|
||||||
TRACE = iota |
|
||||||
DEBUG |
|
||||||
INFO |
|
||||||
WARN |
|
||||||
ERROR |
|
||||||
CRITICAL |
|
||||||
FATAL |
|
||||||
) |
|
||||||
|
|
||||||
// LoggerInterface represents behaviors of a logger provider.
|
|
||||||
type LoggerInterface interface { |
|
||||||
Init(config string) error |
|
||||||
WriteMsg(msg string, skip, level int) error |
|
||||||
Destroy() |
|
||||||
Flush() |
|
||||||
} |
|
||||||
|
|
||||||
type loggerType func() LoggerInterface |
|
||||||
|
|
||||||
var adapters = make(map[string]loggerType) |
|
||||||
|
|
||||||
// Register registers given logger provider to adapters.
|
|
||||||
func Register(name string, log loggerType) { |
|
||||||
if log == nil { |
|
||||||
panic("log: register provider is nil") |
|
||||||
} |
|
||||||
if _, dup := adapters[name]; dup { |
|
||||||
panic("log: register called twice for provider \"" + name + "\"") |
|
||||||
} |
|
||||||
adapters[name] = log |
|
||||||
} |
|
||||||
|
|
||||||
type logMsg struct { |
|
||||||
skip, level int |
|
||||||
msg string |
|
||||||
} |
|
||||||
|
|
||||||
// Logger is default logger in beego application.
|
|
||||||
// it can contain several providers and log message into all providers.
|
|
||||||
type Logger struct { |
|
||||||
adapter string |
|
||||||
lock sync.Mutex |
|
||||||
level int |
|
||||||
msg chan *logMsg |
|
||||||
outputs map[string]LoggerInterface |
|
||||||
quit chan bool |
|
||||||
} |
|
||||||
|
|
||||||
// newLogger initializes and returns a new logger.
|
|
||||||
func newLogger(buffer int64) *Logger { |
|
||||||
l := &Logger{ |
|
||||||
msg: make(chan *logMsg, buffer), |
|
||||||
outputs: make(map[string]LoggerInterface), |
|
||||||
quit: make(chan bool), |
|
||||||
} |
|
||||||
go l.StartLogger() |
|
||||||
return l |
|
||||||
} |
|
||||||
|
|
||||||
// SetLogger sets new logger instance with given logger adapter and config.
|
|
||||||
func (l *Logger) SetLogger(adapter string, config string) error { |
|
||||||
l.lock.Lock() |
|
||||||
defer l.lock.Unlock() |
|
||||||
if log, ok := adapters[adapter]; ok { |
|
||||||
lg := log() |
|
||||||
if err := lg.Init(config); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
l.outputs[adapter] = lg |
|
||||||
l.adapter = adapter |
|
||||||
} else { |
|
||||||
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)") |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// DelLogger removes a logger adapter instance.
|
|
||||||
func (l *Logger) DelLogger(adapter string) error { |
|
||||||
l.lock.Lock() |
|
||||||
defer l.lock.Unlock() |
|
||||||
if lg, ok := l.outputs[adapter]; ok { |
|
||||||
lg.Destroy() |
|
||||||
delete(l.outputs, adapter) |
|
||||||
} else { |
|
||||||
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)") |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) writerMsg(skip, level int, msg string) error { |
|
||||||
if l.level > level { |
|
||||||
return nil |
|
||||||
} |
|
||||||
lm := &logMsg{ |
|
||||||
skip: skip, |
|
||||||
level: level, |
|
||||||
} |
|
||||||
|
|
||||||
// Only error information needs locate position for debugging.
|
|
||||||
if lm.level >= ERROR { |
|
||||||
pc, file, line, ok := runtime.Caller(skip) |
|
||||||
if ok { |
|
||||||
// Get caller function name.
|
|
||||||
fn := runtime.FuncForPC(pc) |
|
||||||
var fnName string |
|
||||||
if fn == nil { |
|
||||||
fnName = "?()" |
|
||||||
} else { |
|
||||||
fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()" |
|
||||||
} |
|
||||||
|
|
||||||
fileName := file |
|
||||||
if len(fileName) > 20 { |
|
||||||
fileName = "..." + fileName[len(fileName)-20:] |
|
||||||
} |
|
||||||
lm.msg = fmt.Sprintf("[%s:%d %s] %s", fileName, line, fnName, msg) |
|
||||||
} else { |
|
||||||
lm.msg = msg |
|
||||||
} |
|
||||||
} else { |
|
||||||
lm.msg = msg |
|
||||||
} |
|
||||||
l.msg <- lm |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// StartLogger starts logger chan reading.
|
|
||||||
func (l *Logger) StartLogger() { |
|
||||||
for { |
|
||||||
select { |
|
||||||
case bm := <-l.msg: |
|
||||||
for _, l := range l.outputs { |
|
||||||
if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil { |
|
||||||
fmt.Println("ERROR, unable to WriteMsg:", err) |
|
||||||
} |
|
||||||
} |
|
||||||
case <-l.quit: |
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Flush flushs all chan data.
|
|
||||||
func (l *Logger) Flush() { |
|
||||||
for _, l := range l.outputs { |
|
||||||
l.Flush() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Close closes logger, flush all chan data and destroy all adapter instances.
|
|
||||||
func (l *Logger) Close() { |
|
||||||
l.quit <- true |
|
||||||
for { |
|
||||||
if len(l.msg) > 0 { |
|
||||||
bm := <-l.msg |
|
||||||
for _, l := range l.outputs { |
|
||||||
if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil { |
|
||||||
fmt.Println("ERROR, unable to WriteMsg:", err) |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
break |
|
||||||
} |
|
||||||
} |
|
||||||
for _, l := range l.outputs { |
|
||||||
l.Flush() |
|
||||||
l.Destroy() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Trace(format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[T] "+format, v...) |
|
||||||
l.writerMsg(0, TRACE, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Debug(format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[D] "+format, v...) |
|
||||||
l.writerMsg(0, DEBUG, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Info(format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[I] "+format, v...) |
|
||||||
l.writerMsg(0, INFO, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Warn(format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[W] "+format, v...) |
|
||||||
l.writerMsg(0, WARN, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Error(skip int, format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[E] "+format, v...) |
|
||||||
l.writerMsg(skip, ERROR, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Critical(skip int, format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[C] "+format, v...) |
|
||||||
l.writerMsg(skip, CRITICAL, msg) |
|
||||||
} |
|
||||||
|
|
||||||
func (l *Logger) Fatal(skip int, format string, v ...interface{}) { |
|
||||||
msg := fmt.Sprintf("[F] "+format, v...) |
|
||||||
l.writerMsg(skip, FATAL, msg) |
|
||||||
l.Close() |
|
||||||
os.Exit(1) |
|
||||||
} |
|
@ -1,87 +0,0 @@ |
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package log |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"fmt" |
|
||||||
"net/smtp" |
|
||||||
"strings" |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
const ( |
|
||||||
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"` |
|
||||||
Password string `json:"password"` |
|
||||||
Host string `json:"Host"` |
|
||||||
Subject string `json:"subject"` |
|
||||||
RecipientAddresses []string `json:"sendTos"` |
|
||||||
Level int `json:"level"` |
|
||||||
} |
|
||||||
|
|
||||||
// create smtp writer.
|
|
||||||
func NewSmtpWriter() LoggerInterface { |
|
||||||
return &SmtpWriter{Level: TRACE} |
|
||||||
} |
|
||||||
|
|
||||||
// init smtp writer with json config.
|
|
||||||
// config like:
|
|
||||||
// {
|
|
||||||
// "Username":"example@gmail.com",
|
|
||||||
// "password:"password",
|
|
||||||
// "host":"smtp.gmail.com:465",
|
|
||||||
// "subject":"email title",
|
|
||||||
// "sendTos":["email1","email2"],
|
|
||||||
// "level":LevelError
|
|
||||||
// }
|
|
||||||
func (sw *SmtpWriter) Init(jsonconfig string) error { |
|
||||||
return json.Unmarshal([]byte(jsonconfig), sw) |
|
||||||
} |
|
||||||
|
|
||||||
// write message in smtp writer.
|
|
||||||
// it will send an email with subject and only this message.
|
|
||||||
func (s *SmtpWriter) WriteMsg(msg string, skip, level int) error { |
|
||||||
if level < s.Level { |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
hp := strings.Split(s.Host, ":") |
|
||||||
|
|
||||||
// Set up authentication information.
|
|
||||||
auth := smtp.PlainAuth( |
|
||||||
"", |
|
||||||
s.Username, |
|
||||||
s.Password, |
|
||||||
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" |
|
||||||
mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.Username + "<" + s.Username + |
|
||||||
">\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) |
|
||||||
|
|
||||||
return smtp.SendMail( |
|
||||||
s.Host, |
|
||||||
auth, |
|
||||||
s.Username, |
|
||||||
s.RecipientAddresses, |
|
||||||
mailmsg, |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
func (_ *SmtpWriter) Flush() { |
|
||||||
} |
|
||||||
|
|
||||||
func (_ *SmtpWriter) Destroy() { |
|
||||||
} |
|
||||||
|
|
||||||
func init() { |
|
||||||
Register("smtp", NewSmtpWriter) |
|
||||||
} |
|
Loading…
Reference in new issue