Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Gray-Ice

个人博客兼个人网站

先上Github地址: lumberjack

本篇博文中的示例为logrus + lumberjack。

因为没有找到很好的中文示例,我只能读文档了。所以本篇文章中的内容不会很高级,但会将其github上README文档中的内容简略写出。有时你可能会发现我完全是在翻译文档,请不要感到意外。

注意

这个包是v2.0版本的lumberjack,因此应该用 gopkg.in导入。[博主注: 不是很明白这里有什么因果关系]

1
import "gopkg.in/natefinch/lumberjack.v2"

Lumberjack故意把自己设计成日志基础的一部分,它不是一个集全面于一体的解决方案,相反,它是在日志底层可插拔的组件,它可以简单的控制日志写入的文件。 [博主: 有机翻那味儿了]

Lumberjack在任何使用io.Writer作为写入的日志库中都表现良好,包括标准库中的log包。

Lumberjack假设只有一个进程在写入到输出文件,在同一台机器上多进程使用相同的lumberjack配置将会造成lumberjack出现不当的行为。[博主注: 因为不加锁的多进程/线程对同一文件进行读写是不安全的]

示例

标准库中的log包只需要在应用启动时调用SetOutput函数就可以使用lumberjack。

代码:

1
2
3
4
5
6
7
log.SetOutput(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, //days
Compress: true, // disabled by default
})

logger类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
type Logger struct {
// Filename is the file to write logs to. Backup log files will be retained
// in the same directory. It uses <processname>-lumberjack.log in
// os.TempDir() if empty.
// Filename是日志将要写入的文件的名字。备份的日志文件将会保留在同级目录中。(后面的我没太懂什么意思,就不翻译了)
Filename string `json:"filename" yaml:"filename"`

// MaxSize is the maximum size in megabytes of the log file before it gets
// rotated. It defaults to 100 megabytes.
// MaxSize是日志文件轮转前的最大尺寸,单位是MB。它默认是100MB。
MaxSize int `json:"maxsize" yaml:"maxsize"`

// MaxAge is the maximum number of days to retain old log files based on the
// timestamp encoded in their filename. Note that a day is defined as 24
// hours and may not exactly correspond to calendar days due to daylight
// savings, leap seconds, etc. The default is not to remove old log files
// based on age.
// MaxAge是保留旧文件的最大日期,它基于编码在文件名中的时间戳来实现。注意,一天的定义是24小时,并且由于夏令时,闰秒等原因,可能与日历不对应默认是不移除旧的日志文件。
MaxAge int `json:"maxage" yaml:"maxage"`

// MaxBackups is the maximum number of old log files to retain. The default
// is to retain all old log files (though MaxAge may still cause them to get
// deleted.)
// MaxBackups是最大保存的日志文件数量。默认是保存所有的旧日志。(但MaxAge仍然会使旧文件被删除)
MaxBackups int `json:"maxbackups" yaml:"maxbackups"`

// LocalTime determines if the time used for formatting the timestamps in
// backup files is the computer's local time. The default is to use UTC
// time.
// LocalTime决定了备份日志时的时间戳的格式是否是本机的本地时间。默认是UTC时间。
LocalTime bool `json:"localtime" yaml:"localtime"`

// Compress determines if the rotated log files should be compressed
// using gzip. The default is not to perform compression.
// Compress决定了旧日志是否需要用gzip压缩。默认是不执行压缩。
Compress bool `json:"compress" yaml:"compress"`
// contains filtered or unexported fields
// 过滤过的或未导出的字段
}

Logger是一个写入指定文件名的io.WriteCloser类型。

Logger会打开日志文件,如果是第一次打开(即文件此时不存在),则会创建文件。如果文件已经存在并且文件大小小于MaxSize规定的MB,lumberjack将会打开文件并且向这个文件中添加内容。如果文件已经存在了并且文件大小>=MaxSize MB,这个文件会立即被重命名,lumberjack会添加当前时间的时间戳在文件名的扩展名之前(如果没有扩展名 时间戳将会添加在文件名之后),然后一个新的文件会以原来文件的文件名被创建。[博主注: 就是传入Logger的Filename]

当一次写入会造成当前文件的大小超过MaxSize MB时,当前的文件将会被关闭,重命名,然后一个新的日志文件将会被以原来的文件名被创建。因此,传入Logger的文件名将总是”当前”文件名。

麻了,README中关于文件名的解释的太多了,我眼睛看酸了,不翻译了。剩下的内容看原文吧:

1
Backups use the log file name given to Logger, in the form name-timestamp.ext where name is the filename without the extension, timestamp is the time at which the log was rotated formatted with the time.Time format of 2006-01-02T15-04-05.000 and the extension is the original extension. For example, if your Logger.Filename is /var/log/foo/server.log, a backup created at 6:30pm on Nov 11 2016 would use the filename /var/log/foo/server-2016-11-04T18-30-00.000.log

清除旧文件

当一个新的日志文件被创建时,旧的日志文件就有可能被删除。根据时间戳,最近创建的文件将会被保留,保留的文件的数量等于MaxBackups,如果MaxBackups为0,则全部都会被保留。根据时间戳,所有比MaxAge规定的天数旧的文件都会被删除,不管是否达到了MaxBackups规定的最大保留数。注意,时间戳中编码的时间是轮转时间,可能与文件最后一次写入的时间有所不同。

如果MaxAge和MaxBackups都为0,那么旧文件将不会被删除。

func (*Logger) Close

1
func (l *Logger) Close() error

Close实现了io.Closer,它会关掉当前的日志文件。

func (*Logger) Rotate

1
func (l *Logger) Rotate() error

Rotate会使Logger关闭当前存在的日志文件并且立即创建一个新的日志文件。这个函数在想要在轮转规则之外发起日志轮转时是相当有用的,例如响应SIGHUP。在轮转之后,它会根据正常的轮转规则清除旧文件。

示例

这个示例演示了如何在响应SIGHUP时轮转。

1
2
3
4
5
6
7
8
9
10
11
l := &lumberjack.Logger{}
log.SetOutput(l)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP)

go func() {
for {
<-c
l.Rotate()
}
}()

func (*Logger) Write

1
func (l *Logger) Write(p []byte) (n int, err error)

Write实现了io.Writer。如果一次写入将会造成日志文件大于MaxSize,那么这个文件将会被关闭,并以文件名中包含当前时间时间戳的方式重命名,之后将会以原来的文件名创建一个新的文件。如果一次写入的字节大于MaxSize,那么这个函数将会返回错误。

logrus+lumberjack示例

我翻译了这么长的文档,就为了等这一刻。我给logrus的logger添加了一个钩子,这个钩子会在使用Info级别输出时使用SetOutput函数将lumberjack的logger传入logrus的logger,之后logrus的logger就会调用这个lumberjack的logger的Write方法。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// main.go
package main

import (
"github.com/sirupsen/logrus"
"gray-ice.com/test/hooks"
)

func main() {
// 新建logger
logger := logrus.New()

// 设置logger为JSON格式
logger.SetFormatter(&logrus.JSONFormatter{})

// 添加钩子
logger.AddHook(&hooks.InfoHook{})

// 循环打印
for i := 0; i < 100*10000; i++ {
logger.Info("Info output!")
logger.Warn("Warn output!")
}
}

​ “gray-ice.com/test/hooks”的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// gray-ice.com/test/hooks/hooks.go
package hooks

import (
"github.com/sirupsen/logrus"
lj "gopkg.in/natefinch/lumberjack.v2"
)

var info_logger = &lj.Logger{
Filename: "./log/info.log",
MaxSize: 100,
MaxAge: 1,
Compress: false,
}

// 定义Info钩子
type InfoHook struct{}

// 实现Levels方法
func (h *InfoHook) Levels() []logrus.Level {
return []logrus.Level{logrus.InfoLevel}
}

// 实现Fire方法
func (h *InfoHook) Fire(e *logrus.Entry) error {
// 设置输出为Logger
e.Logger.SetOutput(info_logger)
return nil
}

运行程序后,log文件夹中多出了两个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~/codeSet/goCode/test » cd log

~/codeSet/goCode/test/log » ls
info-2022-01-19T07-26-54.717.log info.log

~/codeSet/goCode/test/log » stat info-2022-01-19T07-26-54.717.log
File: info-2022-01-19T07-26-54.717.log
Size: 104857558 Blocks: 204800 IO Block: 4096 regular file
Device: 810h/2064d Inode: 204243 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ zero) Gid: ( 1000/ zero)
Access: 2022-01-19 15:26:42.556896700 +0800
Modify: 2022-01-19 15:26:54.706896700 +0800
Change: 2022-01-19 15:26:54.706896700 +0800
Birth: -

评论



愿火焰指引你