gf/g/os/glog/glog_logger.go
2018-10-10 15:24:30 +08:00

407 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// @author john, zseeker
package glog
import (
"os"
"io"
"time"
"fmt"
"strings"
"runtime"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/util/gregex"
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/os/gmlock"
"gitee.com/johng/gf/g/os/gfpool"
"sync"
"gitee.com/johng/gf/g/os/gtime"
)
type Logger struct {
mu sync.RWMutex
pr *Logger // 父级Logger
io io.Writer // 日志内容写入的IO接口
path *gtype.String // 日志写入的目录路径
file *gtype.String // 日志文件名称格式
level *gtype.Int // 日志输出等级
btEnabled *gtype.Bool // 是否当打印错误时同时开启backtrace打印
alsoStdPrint *gtype.Bool // 控制台打印开关,当输出到文件/自定义输出时也同时打印到终端
}
const (
gDEFAULT_FILE_FORMAT = `{Y-m-d}.log`
gDEFAULT_FILE_POOL_FLAGS = os.O_CREATE|os.O_WRONLY|os.O_APPEND
)
// 默认的日志换行符
var ln = "\n"
// 初始化日志换行符
func init() {
if runtime.GOOS == "windows" {
ln = "\r\n"
}
}
// 新建自定义的日志操作对象
func New() *Logger {
return &Logger {
io : nil,
path : gtype.NewString(),
file : gtype.NewString(gDEFAULT_FILE_FORMAT),
level : gtype.NewInt(defaultLevel.Val()),
btEnabled : gtype.NewBool(true),
alsoStdPrint : gtype.NewBool(true),
}
}
// Logger深拷贝
func (l *Logger) Clone() *Logger {
return &Logger {
pr : l,
io : l.GetIO(),
path : l.path.Clone(),
file : l.file.Clone(),
level : l.level.Clone(),
btEnabled : l.btEnabled.Clone(),
alsoStdPrint : l.alsoStdPrint.Clone(),
}
}
// 设置日志记录等级
func (l *Logger) SetLevel(level int) {
l.level.Set(level)
}
// 获取日志记录等级
func (l *Logger) GetLevel() int {
return l.level.Val()
}
// 快捷方法打开或关闭DEBU日志信息
func (l *Logger) SetDebug(debug bool) {
if debug {
l.level.Set(l.level.Val() | LEVEL_DEBU)
} else {
l.level.Set(l.level.Val() & ^LEVEL_DEBU)
}
}
func (l *Logger) SetBacktrace(enabled bool) {
l.btEnabled.Set(enabled)
}
// 可自定义IO接口IO可以是文件输出、标准输出、网络输出
func (l *Logger) SetIO(w io.Writer) {
l.mu.Lock()
l.io = w
l.mu.Unlock()
}
// 返回自定义的IO默认为nil
func (l *Logger) GetIO() io.Writer {
l.mu.RLock()
r := l.io
l.mu.RUnlock()
return r
}
// 获取默认的文件IO
func (l *Logger) getFilePointer() *gfpool.File {
if path := l.path.Val(); path != "" {
// 文件名称中使用"{}"包含的内容使用gtime格式化
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.file.Val(), func(s string) string {
return gtime.Now().Format(strings.Trim(s, "{}"))
})
fpath := path + gfile.Separator + file
if fp, err := gfpool.Open(fpath, gDEFAULT_FILE_POOL_FLAGS, 0666); err == nil {
return fp
} else {
fmt.Fprintln(os.Stderr, err)
}
}
return nil
}
// 设置日志文件的存储目录路径
func (l *Logger) SetPath(path string) error {
// 如果目录不存在,则递归创建
if !gfile.Exists(path) {
if err := gfile.Mkdir(path); err != nil {
fmt.Fprintln(os.Stderr, fmt.Sprintf(`glog mkdir "%s" failed: %s`, path, err.Error()))
return err
}
}
l.path.Set(strings.TrimRight(path, gfile.Separator))
return nil
}
// 日志文件名称
func (l *Logger) SetFile(file string) {
l.file.Set(file)
}
// 设置写日志时开启or关闭控制台打印默认是关闭的
func (l *Logger) SetStdPrint(enabled bool) {
l.alsoStdPrint.Set(enabled)
}
// 这里的写锁保证统一时刻只会写入一行日志,防止串日志的情况
func (l *Logger) print(std io.Writer, s string) {
// 优先使用自定义的IO输出
str := l.format(s)
writer := l.GetIO()
if writer == nil {
// 如果设置的IO为空那么其次判断是否有文件输出设置
// 内部使用了内存锁保证在glog中对同一个日志文件的并发写入不会串日志
if f := l.getFilePointer(); f != nil {
defer f.Close()
key := l.path.Val()
gmlock.Lock(key)
_, err := io.WriteString(f, str)
gmlock.Unlock(key)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
}
} else {
if _, err := io.WriteString(writer, str); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
}
if l.alsoStdPrint.Val() {
if _, err := io.WriteString(std, str); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
}
}
// 核心打印数据方法(标准输出)
func (l *Logger) stdPrint(s string) {
l.print(os.Stdout, s)
}
// 核心打印数据方法(标准错误)
func (l *Logger) errPrint(s string) {
// 记录调用回溯信息
if l.btEnabled.Val() {
tracestr := l.GetBacktrace()
if tracestr != "" {
backtrace := "Backtrace:" + ln + tracestr
if s[len(s) - 1] == byte('\n') {
s = s + backtrace + ln
} else {
s = s + ln + backtrace + ln
}
}
}
l.print(os.Stderr, s)
}
// 直接打印回溯信息
func (l *Logger) PrintBacktrace() {
l.Println(l.GetBacktrace())
}
// 获取文件调用回溯字符串
func (l *Logger) GetBacktrace() string {
backtrace := ""
index := 1
for i := 1; i < 10000; i++ {
if _, cfile, cline, ok := runtime.Caller(i); ok {
// 不打印出go源码路径及glog包文件路径
if !gregex.IsMatchString("/g/os/glog/glog.+$", cfile) &&
!gregex.IsMatchString("^" + gfile.GoRootOfBuild(), cfile) &&
!gregex.IsMatchString(`<autogenerated>`, cfile) {
backtrace += fmt.Sprintf(`%d. %s:%d%s`, index, cfile, cline, ln)
index++
}
} else {
break
}
}
return backtrace
}
func (l *Logger) format(s string) string {
return time.Now().Format("2006-01-02 15:04:05.000 ") + s
}
func (l *Logger) Print(v ...interface{}) {
l.stdPrint(fmt.Sprintln(v...))
}
func (l *Logger) Printf(format string, v ...interface{}) {
l.stdPrint(fmt.Sprintf(format, v...))
}
func (l *Logger) Println(v ...interface{}) {
l.stdPrint(fmt.Sprintln(v...))
}
func (l *Logger) Printfln(format string, v ...interface{}) {
l.stdPrint(fmt.Sprintf(format + ln, v...))
}
func (l *Logger) Fatal(v ...interface{}) {
l.errPrint(fmt.Sprintln(v...))
os.Exit(1)
}
func (l *Logger) Fatalf(format string, v ...interface{}) {
l.errPrint(fmt.Sprintf(format, v...))
os.Exit(1)
}
func (l *Logger) Fatalln(v ...interface{}) {
l.errPrint(fmt.Sprintln(v...))
os.Exit(1)
}
func (l *Logger) Fatalfln(format string, v ...interface{}) {
l.errPrint(fmt.Sprintf(format + ln, v...))
os.Exit(1)
}
func (l *Logger) Panic(v ...interface{}) {
s := fmt.Sprintln(v...)
l.errPrint(s)
panic(s)
}
func (l *Logger) Panicf(format string, v ...interface{}) {
s := fmt.Sprintf(format, v...)
l.errPrint(s)
panic(s)
}
func (l *Logger) Panicln(v ...interface{}) {
s := fmt.Sprintln(v...)
l.errPrint(s)
panic(s)
}
func (l *Logger) Panicfln(format string, v ...interface{}) {
s := fmt.Sprintf(format + ln, v...)
l.errPrint(s)
panic(s)
}
func (l *Logger) Info(v ...interface{}) {
if l.checkLevel(LEVEL_INFO) {
l.stdPrint("[INFO] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Infof(format string, v ...interface{}) {
if l.checkLevel(LEVEL_INFO) {
l.stdPrint("[INFO] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Infofln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_INFO) {
l.stdPrint("[INFO] " + fmt.Sprintf(format, v...) + ln)
}
}
func (l *Logger) Debug(v ...interface{}) {
if l.checkLevel(LEVEL_DEBU) {
l.stdPrint("[DEBU] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Debugf(format string, v ...interface{}) {
if l.checkLevel(LEVEL_DEBU) {
l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Debugfln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_DEBU) {
l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...) + ln)
}
}
func (l *Logger) Notice(v ...interface{}) {
if l.checkLevel(LEVEL_NOTI) {
l.errPrint("[NOTI] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Noticef(format string, v ...interface{}) {
if l.checkLevel(LEVEL_NOTI) {
l.errPrint("[NOTI] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Noticefln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_NOTI) {
l.errPrint("[NOTI] " + fmt.Sprintf(format, v...) + ln)
}
}
func (l *Logger) Warning(v ...interface{}) {
if l.checkLevel(LEVEL_WARN) {
l.errPrint("[WARN] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Warningf(format string, v ...interface{}) {
if l.checkLevel(LEVEL_WARN) {
l.errPrint("[WARN] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Warningfln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_WARN) {
l.errPrint("[WARN] " + fmt.Sprintf(format, v...) + ln)
}
}
func (l *Logger) Error(v ...interface{}) {
if l.checkLevel(LEVEL_ERRO) {
l.errPrint("[ERRO] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Errorf(format string, v ...interface{}) {
if l.checkLevel(LEVEL_ERRO) {
l.errPrint("[ERRO] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Errorfln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_ERRO) {
l.errPrint("[ERRO] " + fmt.Sprintf(format, v...) + ln)
}
}
func (l *Logger) Critical(v ...interface{}) {
if l.checkLevel(LEVEL_CRIT) {
l.errPrint("[CRIT] " + fmt.Sprintln(v...))
}
}
func (l *Logger) Criticalf(format string, v ...interface{}) {
if l.checkLevel(LEVEL_CRIT) {
l.errPrint("[CRIT] " + fmt.Sprintf(format, v...))
}
}
func (l *Logger) Criticalfln(format string, v ...interface{}) {
if l.checkLevel(LEVEL_CRIT) {
l.errPrint("[CRIT] " + fmt.Sprintf(format, v...) + ln)
}
}
// 判断给定level是否满足
func (l *Logger) checkLevel(level int) bool {
return l.level.Val() & level > 0
}