gf/g/os/glog/glog_logger.go

388 lines
9.8 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"
"errors"
"strings"
"runtime"
"strconv"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/util/gregex"
"gitee.com/johng/gf/g/os/gfilepool"
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/os/gmlock"
)
const (
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(),
level : gtype.NewInt(defaultLevel.Val()),
btSkip : gtype.NewInt(),
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(),
level : l.level.Clone(),
btSkip : l.btSkip.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) {
l.level.Set(l.level.Val()|LEVEL_DEBU)
}
func (l *Logger) SetBacktrace(enabled bool) {
l.btEnabled.Set(enabled)
}
// 设置BacktraceSkip
func (l *Logger) SetBacktraceSkip(skip int) {
l.btSkip.Set(skip)
}
// 可自定义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) getFileByPool() *gfilepool.File {
if path := l.path.Val(); path != "" {
fpath := path + gfile.Separator + time.Now().Format("2006-01-02.log")
if fp, err := gfilepool.OpenWithPool(fpath, gDEFAULT_FILE_POOL_FLAGS, 0666, 86400000); 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, "glog mkdir failed: " + err.Error())
return err
}
}
if !gfile.IsWritable(path) {
errstr := path + " is no writable for current user"
fmt.Fprintln(os.Stderr, errstr)
return errors.New(errstr)
}
l.path.Set(strings.TrimRight(path, gfile.Separator))
return nil
}
// 设置写日志时开启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.getFileByPool(); f != nil {
defer f.Close()
key := l.path.Val()
gmlock.Lock(key)
io.WriteString(f, str)
gmlock.Unlock(key)
}
} else {
io.WriteString(writer, str)
}
if l.alsoStdPrint.Val() {
io.WriteString(std, str)
}
}
// 核心打印数据方法(标准输出)
func (l *Logger) stdPrint(s string) {
l.print(os.Stdout, s)
}
// 核心打印数据方法(标准错误)
func (l *Logger) errPrint(s string) {
// 记录调用回溯信息
if l.btEnabled.Val() {
backtrace := l.GetBacktrace(2)
if s[len(s) - 1] == byte('\n') {
s = s + backtrace + ln
} else {
s = s + ln + backtrace + ln
}
}
l.print(os.Stderr, s)
}
// 直接打印回溯信息参数skip表示调用端往上多少级开始回溯
func (l *Logger) PrintBacktrace(skip...int) {
customSkip := 1
if len(skip) > 0 {
customSkip += skip[0]
}
l.Println(l.GetBacktrace(customSkip))
}
// 获取文件调用回溯字符串参数skip表示调用端往上多少级开始回溯
func (l *Logger) GetBacktrace(skip...int) string {
customSkip := 0
if len(skip) > 0 {
customSkip += skip[0]
}
backtrace := ""
index := 1
for i := 1; i < 10000; i++ {
if _, cfile, cline, ok := runtime.Caller(customSkip + i + l.btSkip.Val()); ok {
// 不打印出go源码路径
if !gregex.IsMatchString("^" + gfile.GoRootOfBuild(), cfile) {
backtrace += strconv.Itoa(index) + ".\t" + cfile + ":" + strconv.Itoa(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.Sprint(v...))
}
func (l *Logger) Printf(format string, v ...interface{}) {
l.stdPrint(fmt.Sprintf(format, v...))
}
func (l *Logger) Println(v ...interface{}) {
l.stdPrint(fmt.Sprint(v...) + ln)
}
func (l *Logger) Printfln(format string, v ...interface{}) {
l.stdPrint(fmt.Sprintf(format + ln, v...))
}
func (l *Logger) Fatal(v ...interface{}) {
l.errPrint(fmt.Sprint(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.Sprint(v...) + ln)
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.Sprint(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.Sprint(v...) + ln
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.Sprint(v...) + ln)
}
}
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.Sprint(v...) + ln)
}
}
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.Sprint(v...) + ln)
}
}
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.Sprint(v...) + ln)
}
}
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.Sprint(v...) + ln)
}
}
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.Sprint(v...) + ln)
}
}
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
}