New UI merge in progress

This commit is contained in:
Unknwon 2014-07-26 00:24:27 -04:00
parent 0a739cf9ac
commit 8dd07c0ddd
199 changed files with 15030 additions and 9325 deletions

73
modules/log/console.go Normal file
View file

@ -0,0 +1,73 @@
// 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) Destroy() {
}
func (_ *ConsoleWriter) Flush() {
}
func init() {
Register("console", NewConsole)
}

237
modules/log/file.go Normal file
View file

@ -0,0 +1,237 @@
// 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) error {
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 nil
})
}
// 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)
}

View file

@ -2,32 +2,29 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Package log is a wrapper of logs for short calling name.
package log
import (
"fmt"
"os"
"path"
"github.com/gogits/logs"
"path/filepath"
"runtime"
"strings"
"sync"
)
var (
loggers []*logs.BeeLogger
GitLogger *logs.BeeLogger
loggers []*Logger
GitLogger *Logger
)
func init() {
NewLogger(0, "console", `{"level": 0}`)
}
func NewLogger(bufLen int64, mode, config string) {
logger := logs.NewLogger(bufLen)
logger := newLogger(bufLen)
isExist := false
for _, l := range loggers {
if l.Adapter == mode {
if l.adapter == mode {
isExist = true
l = logger
}
@ -35,15 +32,14 @@ func NewLogger(bufLen int64, mode, config string) {
if !isExist {
loggers = append(loggers, logger)
}
logger.SetLogFuncCallDepth(3)
if err := logger.SetLogger(mode, config); err != nil {
Fatal("Fail to set logger(%s): %v", mode, err)
Fatal(1, "Fail to set logger(%s): %v", mode, err)
}
}
func NewGitLogger(logPath string) {
os.MkdirAll(path.Dir(logPath), os.ModePerm)
GitLogger = logs.NewLogger(0)
GitLogger = newLogger(0)
GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath))
}
@ -65,28 +61,237 @@ func Info(format string, v ...interface{}) {
}
}
func Error(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Error(format, v...)
}
}
func Warn(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Warn(format, v...)
}
}
func Critical(format string, v ...interface{}) {
func Error(skip int, format string, v ...interface{}) {
for _, logger := range loggers {
logger.Critical(format, v...)
logger.Error(skip, format, v...)
}
}
func Fatal(format string, v ...interface{}) {
Error(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(2)
os.Exit(1)
}
// .___ _______________________________________________________ _________ ___________
// | |\ \__ ___/\_ _____/\______ \_ _____/ _ \ \_ ___ \\_ _____/
// | |/ | \| | | __)_ | _/| __)/ /_\ \/ \ \/ | __)_
// | / | \ | | \ | | \| \/ | \ \____| \
// |___\____|__ /____| /_______ / |____|_ /\___ /\____|__ /\______ /_______ /
// \/ \/ \/ \/ \/ \/ \/
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 instanse 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()), ".") + "()"
}
lm.msg = fmt.Sprintf("[%s:%d %s] %s", filepath.Base(file), 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 {
l.WriteMsg(bm.msg, bm.skip, bm.level)
}
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 {
l.WriteMsg(bm.msg, bm.skip, bm.level)
}
} 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)
}