内容简介:golang的log包已经提供了比较完善的功能,我们只是做了一些简单的封装主要就是构造了第一步就是在终端输出,其实就是写到终端里
介绍
golang的log包已经提供了比较完善的功能,我们只是做了一些简单的封装
主要就是构造了 Writer
,这个 writer
每次调用 Write()
的时候,执行了两步
第一步就是在终端输出,其实就是写到终端里
第二部就是写入到我们的日志文件。写入到日志文件的时候,有个大小判断,超过预定的大小后,就会进行分割和压缩
golang原生日志系统
log包简单实用
func main() {
log.Println("this is my first log")
}
进入到log包中,看 Println()
函数
// Println calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Println.
func Println(v ...interface{}) {
std.Output(2, fmt.Sprintln(v...))
}
再网上追溯
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout") var std = New(os.Stderr, "", LstdFlags)
// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
这里的 Logger
就是一切的重点了
// A Logger represents an active logging object that generates lines of
// output to an io.Writer. Each logging operation makes a single call to
// the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
mu sync.Mutex // ensures atomic writes; protects the following fields
prefix string // prefix to write at beginning of each line
flag int // properties
out io.Writer // destination for output
buf []byte // for accumulating text to write
}
我们再看 Output
函数
func (l *Logger) Output(calldepth int, s string) error {
...
...
_, err := l.out.Write(l.buf)
return err
}
其实就是把日志写入到一个文件中。只是终端有默认的文件而已。
构建我们自己的Logger
上面的例子,当我们没有创建 Logger
时,系统会使用默认的 Logger
,也就是 Stdout
.
接下来,我们构建一个自己的 Logger
,让日志输出到我们自己指定的文件中
func main() {
//logFile,_ := os.Open("./test.log") /
logFile, _ := os.OpenFile("test.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
logger := log.New(logFile, "TEST", log.Lshortfile|log.Ldate|log.Ltime)
for i := 0; i < 10; i++ {
logger.Printf("this is my %v test log",i)
}
}
注意两点
-
open(filename)默认是以只读方式打开,那我们就不能写入了
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
-
os.O_APPEND以追加模式test.log
TEST2019/01/10 14:25:35 test01.go:13: this is my 0 test log TEST2019/01/10 14:25:35 test01.go:13: this is my 1 test log TEST2019/01/10 14:25:35 test01.go:13: this is my 2 test log TEST2019/01/10 14:25:35 test01.go:13: this is my 3 test log TEST2019/01/10 14:25:35 test01.go:13: this is my 4 test log ...
开始造轮子
第一步就是在终端输出,其实就是写到终端里
第二部就是写入到我们的日志文件。写入到日志文件的时候,有个大小判断,超过预定的大小后,就会进行分割和压缩
接下来展示一下目录结构
mlog 定义了我们日志系统,还有日志子系统
log.go 日志系统接口实现和子系统的创建
interface.go 日志系统接口
rotator
rotator.go 日志写入文件、日志分割、日志压缩
log.go 项目的日志配置文件,创建日志系统及子系统
config.go 项目的配置文件,加载日志等级,用配置的日志文件初始化rotator
main.go 项目入口文件
分析
首先在 log.go
文件中,初始化后台日志系统,还有日志子系统。
var (
backendLog = mlog.NewBackend(logWriter{}) //往终端中写入日志
logRotator *rotator.Rotator // 往文件中写入日志
Mainlog = backendLog.Logger("HCD") //日志子系统
TESTlog = backendLog.Logger("TEST") // 日志子系统
)
然后我们会在 config.go
会初始化 logRatator
,设置日志等级
initLogRotator("./test.log") // 这里已经设置了日志输出文件
setLogLevels(DebugLevel)
当我们调用子日志系统打印日志
Mainlog.Infof("this si my log %v",i)
判断日志级别后,调用Backend打印日志,BackendLog统一管理各个子日志系统的日志
func (l *slog) Infof(format string, args ...interface{}) {
lvl := l.Level()
if lvl <= LevelInfo {
l.b.printf("INF", l.tag, format, args...)
}
}
然后我们再看Backend.printf()函数
b.mu.Lock()
b.w.Write(*bytebuf)
b.mu.Unlock()
b.w.Write(*bytebuf)
,这个 w.Write()
是我们实现io.Writer接口的Write函数。
他内部有两个Write()
type logWriter struct{}
func (logWriter) Write(p []byte)(n int,err error){
os.Stdout.Write(p) //标准输出,就是我们看到的前台显示
logRotator.Write(p) // rotator的输出,就是文件记录中的操作
return len(p),nil
}
backendLog = mlog.NewBackend(logWriter{})
我们再分析logWriter的Write方法
os.Stdout.Write(p)
这个是系统的标准数据,暂时不讨论
logRotator.Write(p)
func (r *Rotator) Write(p []byte) (n int, err error) {
// 写入文件
n, _ = r.out.Write(p)
r.size += int64(n)
// 日志拆分,压缩
if r.size >= r.threshold && len(p) > 0 && p[len(p)-1] == '\n' {
err := r.rotate()
if err != nil {
return 0, err
}
r.size = 0
}
return n, nil
}
具体的日志压缩,可以看源码
以上所述就是小编给大家介绍的《造轮子-golang日志系统》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web开发敏捷之道
Sam Ruby、Dave Thomas、David Heineme Hansson / 慕尼黑Isar工作组、骆古道 / 机械工业出版社 / 2012-3-15 / 59.00元
本书第1版曾荣获Jolt大奖“最佳技术图书”奖。在前3版的内容架构基础上,第4版增加了关于Rails中新特性和最佳实践的内容。本书从逐步创建一个真正的应用程序开始,然后介绍Rails的内置功能。全书分为3部分,第一部分介绍Rails的安装、应用程序验证、Rails框架的体系结构,以及Ruby语言的知识;第二部分用迭代方式创建应用程序,然后依据敏捷开发模式搭建测试案例,最终用Capistrano完成......一起来看看 《Web开发敏捷之道》 这本书的介绍吧!