mirror of
https://gitee.com/johng/gf
synced 2026-07-07 06:15:15 +08:00
改进glog的backtrace skip功能,g模块增加错误日志信息提示
This commit is contained in:
@ -75,7 +75,7 @@ func (db *Db) printSql(v *Sql) {
|
||||
)
|
||||
if v.Error != nil {
|
||||
s += "\nError: " + v.Error.Error()
|
||||
glog.Backtrace(true).Error(s)
|
||||
glog.Backtrace(true, 2).Error(s)
|
||||
} else {
|
||||
glog.Debug(s)
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ import (
|
||||
"gitee.com/johng/gf/g/os/gview"
|
||||
"gitee.com/johng/gf/g/os/gcfg"
|
||||
"gitee.com/johng/gf/g/util/gregex"
|
||||
"gitee.com/johng/gf/g/os/glog"
|
||||
"fmt"
|
||||
)
|
||||
const (
|
||||
gIS_DATABASE_CONFIG_CACHED = "gf.core.component.database.cached"
|
||||
@ -55,10 +57,11 @@ func Config() *gcfg.Config {
|
||||
func Database(name...string) *gdb.Db {
|
||||
config := gins.Config()
|
||||
if config == nil {
|
||||
glog.Error("Config component init failed")
|
||||
return nil
|
||||
}
|
||||
// 数据库配置是否已经设置
|
||||
if gcache.Get(gIS_DATABASE_CONFIG_CACHED) == nil {
|
||||
gcache.GetOrSetFuncLock(gIS_DATABASE_CONFIG_CACHED, func() interface{} {
|
||||
if m := config.GetMap("database"); m != nil {
|
||||
c := gdb.Config{}
|
||||
for group, v := range m {
|
||||
@ -109,16 +112,20 @@ func Database(name...string) *gdb.Db {
|
||||
c[group] = cg
|
||||
}
|
||||
gdb.SetConfig(c)
|
||||
gcache.Set(gIS_DATABASE_CONFIG_CACHED, struct{}{}, 0)
|
||||
// 使用gfsnotify进行文件监控,当配置文件有任何变化时,清空数据库配置缓存
|
||||
gfsnotify.Add(Config().GetFilePath(), func(event *gfsnotify.Event) {
|
||||
gcache.Remove(gIS_DATABASE_CONFIG_CACHED)
|
||||
})
|
||||
return struct{}{}
|
||||
} else {
|
||||
glog.Error(fmt.Sprintf(`incomplete configuration for database: "database" node not found in config file "%s"`, config.GetFilePath()))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, 0)
|
||||
if db, err := gdb.New(name...); err == nil {
|
||||
return db
|
||||
} else {
|
||||
glog.Error(err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +175,7 @@ func GetServer(name...interface{}) (*Server) {
|
||||
closeQueue : gqueue.New(),
|
||||
logger : glog.New(),
|
||||
}
|
||||
// 日志的标准输出默认关闭,但是错误信息会特殊处理
|
||||
s.logger.SetStdPrint(false)
|
||||
for _, v := range strings.Split(gHTTP_METHODS, ",") {
|
||||
s.methodsMap[v] = struct{}{}
|
||||
|
||||
@ -29,24 +29,33 @@ func (s *Server) handleAccessLog(r *Request) {
|
||||
)
|
||||
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime - r.EnterTime)/1000)
|
||||
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
|
||||
s.logger.Cat("access").Println(content)
|
||||
s.logger.Cat("access").Backtrace(false, 2).Println(content)
|
||||
}
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
func (s *Server) handleErrorLog(error interface{}, r *Request) {
|
||||
r.Response.WriteStatus(http.StatusInternalServerError)
|
||||
|
||||
// 错误输出默认是开启的
|
||||
if !s.IsErrorLogEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
// 自定义错误处理
|
||||
if v := s.GetLogHandler(); v != nil {
|
||||
v(r, error)
|
||||
return
|
||||
}
|
||||
|
||||
// 错误日志信息
|
||||
content := fmt.Sprintf(`%v, "%s %s %s %s"`, error, r.Method, r.Host, r.URL.String(), r.Proto)
|
||||
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime - r.EnterTime)/1000)
|
||||
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
|
||||
s.logger.Cat("error").Error(content)
|
||||
|
||||
if s.logger.GetPath() == "" {
|
||||
// 错误信息特殊处理,在未开启日志文件保存时强制强制输出到终端
|
||||
s.logger.Cat("error").Backtrace(true, 2).StdPrint(true).Error(content)
|
||||
} else {
|
||||
s.logger.Cat("error").Backtrace(true, 2).Error(content)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,17 +64,17 @@ func SetStdPrint(open bool) {
|
||||
|
||||
// 获取日志目录绝对路径
|
||||
func GetPath() string {
|
||||
return logger.path.Val()
|
||||
return logger.GetPath()
|
||||
}
|
||||
|
||||
// 打印文件调用回溯信息
|
||||
func PrintBacktrace() {
|
||||
logger.PrintBacktrace()
|
||||
func PrintBacktrace(skip...int) {
|
||||
logger.PrintBacktrace(skip...)
|
||||
}
|
||||
|
||||
// 获取文件调用回溯信息
|
||||
func GetBacktrace() string {
|
||||
return logger.GetBacktrace()
|
||||
func GetBacktrace(skip...int) string {
|
||||
return logger.GetBacktrace(skip...)
|
||||
}
|
||||
|
||||
// 设置下一次输出的分类,支持多级分类设置
|
||||
@ -93,8 +93,8 @@ func Level(level int) *Logger {
|
||||
}
|
||||
|
||||
// 设置文件调用回溯信息
|
||||
func Backtrace(enabled bool) *Logger {
|
||||
return logger.Backtrace(enabled)
|
||||
func Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger.Backtrace(enabled, skip...)
|
||||
}
|
||||
|
||||
// 是否允许在设置输出文件时同时也输出到终端
|
||||
|
||||
@ -30,6 +30,7 @@ type Logger struct {
|
||||
path *gtype.String // 日志写入的目录路径
|
||||
file *gtype.String // 日志文件名称格式
|
||||
level *gtype.Int // 日志输出等级
|
||||
btSkip *gtype.Int // 错误产生时的backtrace回调信息skip条数
|
||||
btEnabled *gtype.Bool // 是否当打印错误时同时开启backtrace打印
|
||||
alsoStdPrint *gtype.Bool // 控制台打印开关,当输出到文件/自定义输出时也同时打印到终端
|
||||
}
|
||||
@ -56,6 +57,7 @@ func New() *Logger {
|
||||
path : gtype.NewString(),
|
||||
file : gtype.NewString(gDEFAULT_FILE_FORMAT),
|
||||
level : gtype.NewInt(defaultLevel.Val()),
|
||||
btSkip : gtype.NewInt(),
|
||||
btEnabled : gtype.NewBool(true),
|
||||
alsoStdPrint : gtype.NewBool(true),
|
||||
}
|
||||
@ -69,6 +71,7 @@ func (l *Logger) Clone() *Logger {
|
||||
path : l.path.Clone(),
|
||||
file : l.file.Clone(),
|
||||
level : l.level.Clone(),
|
||||
btSkip : l.btSkip.Clone(),
|
||||
btEnabled : l.btEnabled.Clone(),
|
||||
alsoStdPrint : l.alsoStdPrint.Clone(),
|
||||
}
|
||||
@ -97,6 +100,11 @@ 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()
|
||||
@ -142,6 +150,11 @@ func (l *Logger) SetPath(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取设置的日志目录路径
|
||||
func (l *Logger) GetPath() string {
|
||||
return l.path.Val()
|
||||
}
|
||||
|
||||
// 日志文件名称
|
||||
func (l *Logger) SetFile(file string) {
|
||||
l.file.Set(file)
|
||||
@ -204,21 +217,34 @@ func (l *Logger) errPrint(s string) {
|
||||
l.print(os.Stderr, s)
|
||||
}
|
||||
|
||||
// 直接打印回溯信息
|
||||
func (l *Logger) PrintBacktrace() {
|
||||
l.Println(l.GetBacktrace())
|
||||
// 直接打印回溯信息,参数skip表示调用端往上多少级开始回溯
|
||||
func (l *Logger) PrintBacktrace(skip...int) {
|
||||
l.Println(l.GetBacktrace(skip...))
|
||||
}
|
||||
|
||||
// 获取文件调用回溯字符串
|
||||
func (l *Logger) GetBacktrace() string {
|
||||
// 获取文件调用回溯字符串,参数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++ {
|
||||
from := 0
|
||||
// 首先定位业务文件开始位置
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, cfile, _, ok := runtime.Caller(i); ok {
|
||||
if !gregex.IsMatchString("/g/os/glog/glog.+$", cfile) {
|
||||
from = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 从业务文件开始位置根据自定义的skip开始backtrace
|
||||
for i := from + customSkip + l.btSkip.Val(); 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) {
|
||||
// 不打印出go源码路径及glog包文件路径,日志打印必须从业务源码文件开始,且从glog包文件开始检索
|
||||
if !gregex.IsMatchString("^" + gfile.GoRootOfBuild(), cfile) && !gregex.IsMatchString(`<autogenerated>`, cfile) {
|
||||
backtrace += fmt.Sprintf(`%d. %s:%d%s`, index, cfile, cline, ln)
|
||||
index++
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ func (l *Logger) Level(level int) *Logger {
|
||||
}
|
||||
|
||||
// 设置文件调用回溯信息
|
||||
func (l *Logger) Backtrace(enabled bool) *Logger {
|
||||
func (l *Logger) Backtrace(enabled bool, skip...int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
logger = l.Clone()
|
||||
@ -62,6 +62,9 @@ func (l *Logger) Backtrace(enabled bool) *Logger {
|
||||
logger = l
|
||||
}
|
||||
logger.SetBacktrace(enabled)
|
||||
if len(skip) > 0 {
|
||||
logger.SetBacktraceSkip(skip[0])
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user