文章目录
go-zero的日志处理学习
开始
-
读取配置文件
// MustSetup sets up logging with given config c. It exits on error. func MustSetup(c LogConf) { Must(SetUp(c)) }
使用SetUp 来进行判断那种类型的日志记录方式:
- console
- volume ——映射,用于 k8s 服务启动
- file —— 裸机运行,记录日志为文件
使用 Must 进行包裹 error 进行error 判断及逻辑处理
避免了 if error != nil 在方法里面。
-
(看过一篇文件,写到过,这个种写法,但是我不知道叫什么,有知道的可以告诉我一声)读取配置
// 定义 logOptions struct { gzipEnabled bool logStackCooldownMills int keepDays int } // LogOption defines the method to customize the logging. LogOption func(options *logOptions)
var opts []LogOption 1 var err error if len(c.Path) == 0 { return ErrLogPathNotSet } opts = append(opts, WithCooldownMillis(c.StackCooldownMillis)) 2 if c.Compress { opts = append(opts, WithGzip()) 3 } if c.KeepDays > 0 { opts = append(opts, WithKeepDays(c.KeepDays)) 4 }
func handleOptions(opts []LogOption) { 5 for _, opt := range opts { opt(&options) } }
获取文件的配置的优雅写法:
- 通过定义发现LogOptions 是一个结构体
- 而 LogOption 是类型定义,那个func函数
- 增加配置,写到数组里面
- 通过方法handleOptions 方法,遍历数组,使用地址 options 覆盖源配置的默认配置。
setupWithConsole 控制台启动
once.Do(func() {
atomic.StoreUint32(&initialized, 1)
writeConsole = true
setupLogLevel(c)
infoLog = newLogWriter(log.New(os.Stdout, "", flags))
errorLog = newLogWriter(log.New(os.Stderr, "", flags))
severeLog = newLogWriter(log.New(os.Stderr, "", flags))
slowLog = newLogWriter(log.New(os.Stderr, "", flags))
stackLog = newLessWriter(errorLog, options.logStackCooldownMills)
statLog = infoLog
})
全局唯一实例化,使用
once.Do
进行方法初始化。并且通过atomic 存储初始化 initialized 状态
看到go-zero 文档,他将 日志 分为 5 种,分别为 info ,error, servere , slow, stack
而上述的newLogWriter 是 使用log.Logger 进行 包装构造的。
func newLogWriter(logger *log.Logger) logWriter {
return logWriter{
logger: logger,
}
}
setupWithFiles
var opts []LogOption
var err error
if len(c.Path) == 0 {
return ErrLogPathNotSet
}
opts = append(opts, WithCooldownMillis(c.StackCooldownMillis))
if c.Compress {
opts = append(opts, WithGzip())
}
if c.KeepDays > 0 {
opts = append(opts, WithKeepDays(c.KeepDays))
}
// 上面将进行配置读取
accessFile := path.Join(c.Path, accessFilename)
errorFile := path.Join(c.Path, errorFilename)
severeFile := path.Join(c.Path, severeFilename)
slowFile := path.Join(c.Path, slowFilename)
statFile := path.Join(c.Path, statFilename)
// log文件 写入的文件名称
// 全局执行一次的方法
once.Do(func() {
atomic.StoreUint32(&initialized, 1)
handleOptions(opts)
setupLogLevel(c)
if infoLog, err = createOutput(accessFile); err != nil {
return
}
if errorLog, err = createOutput(errorFile); err != nil {
return
}
if severeLog, err = createOutput(severeFile); err != nil {
return
}
if slowLog, err = createOutput(slowFile); err != nil {
return
}
if statLog, err = createOutput(statFile); err != nil {
return
}
stackLog = newLessWriter(errorLog, options.logStackCooldownMills)
})
return err
setupWithVolume 在 setupWithFiles 的保存文件的基础上,增加了 主机名称和服务名称
func setupWithVolume(c LogConf) error {
if len(c.ServiceName) == 0 {
return ErrLogServiceNameNotSet
}
c.Path = path.Join(c.Path, c.ServiceName, sysx.Hostname())
return setupWithFiles(c)
}
是在写文件的基础上,增加了 主机名称和服务名称
记录
Error 日志打印
// Error writes v into error log.
func Error(v ...interface{}) {
ErrorCaller(1, v...)
}
// ErrorCaller writes v with context into error log.
func ErrorCaller(callDepth int, v ...interface{}) {
errorTextSync(fmt.Sprint(v...), callDepth+callerInnerDepth)
}
// ErrorCallerf writes v with context in format into error log.
func ErrorCallerf(callDepth int, format string, v ...interface{}) {
errorTextSync(fmt.Sprintf(format, v...), callDepth+callerInnerDepth)
}
// Errorf writes v with format into error log.
func Errorf(format string, v ...interface{}) {
ErrorCallerf(1, format, v...)
}
// ErrorStack writes v along with call stack into error log.
func ErrorStack(v ...interface{}) {
// there is newline in stack string
stackSync(fmt.Sprint(v...))
}
// ErrorStackf writes v along with call stack in format into error log.
func ErrorStackf(format string, v ...interface{}) {
// there is newline in stack string
stackSync(fmt.Sprintf(format, v...))
}
// Errorv writes v into error log with json content.
// No call stack attached, because not elegant to pack the messages.
func Errorv(v interface{}) {
errorAnySync(v)
}
首先是继承接口
上述覆写了多种方法,用于使用,函数名称描述函数用途,
info 和 servere 同理
停止
func Close() error {
if writeConsole {
return nil
}
if atomic.LoadUint32(&initialized) == 0 {
return ErrLogNotInitialized
}
atomic.StoreUint32(&initialized, 0)
if infoLog != nil {
if err := infoLog.Close(); err != nil {
return err
}
}
if errorLog != nil {
if err := errorLog.Close(); err != nil {
return err
}
}
if severeLog != nil {
if err := severeLog.Close(); err != nil {
return err
}
}
if slowLog != nil {
if err := slowLog.Close(); err != nil {
return err
}
}
if statLog != nil {
if err := statLog.Close(); err != nil {
return err
}
}
return nil
}
全局使用原子化变量进行状态判断,
停止,只需要关闭文件写入就可以了。