关于log glog logrus beego/logs
package main
import "log"
func main() {
log.Println("Content from log package!")
}
打印流程:
1、加锁;
2、buf从0开始(l.buf = l.buf[:0]),依次append prefix、Ldate、Ltime、日志内容到Logger实例buf中;
3、调用l.out.Write(l.buf),最后解锁;
package main
import (
"log"
"os"
)
func main() {
// 如果文件logs.txt不存在,会自动创建
file, err := os.OpenFile("logs.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
log.SetOutput(file)
log.Println("Content from log package!")
}
缺点
没有日志级别;
直接写文件,没有缓冲;
没有rotate;
字符可以直接与int相加
byte('0' + i - q*10)
go get github.com/golang/glog
package main
import (
"flag"
"github.com/golang/glog"
)
func main() {
// 解析传入的参数
flag.Parse()
// 退出前执行,清空缓存区,将日志写入文件
defer glog.Flush()
// 输出各个等级的日志
glog.Info("This is a info log")
// glog.Warning("This is a warning log")
// glog.Error("This is a error log")
// glog.Fatal("This is a fatal log")
}
输出到当前目录:
go run glogtest.go -log_dir="./"
生成软连接 glogtest.go -> glogtest.demondeMBP.demon.log.INFO.20220415-101633.8576。
每次跑会拿到当前时间戳生成新的文件,同时软连接指向最新生成的文件。
只打印到控制台错误流:
go run glogtest.go -logtostderr
- 加锁,从
freeList
获取一块buffer
-
buffer
里的tmp
数组写入元数据:Lmmdd hh:mm:ss.uuuuuu threadid file:line];
-
bytes.Buffer
的Write()
方法:buffer.Write(buffer.tmp[:30])
-
fmt.Fprintln(buffer, args...)
写入This is a info log
到内嵌的bytes.Buffer
mu
加锁;bytes.Buffer
的Bytes()
方法,拿到buffer
的字节数据:data := buffer.Bytes()
syncBuffer.Write(data) ==> syncBuffer.Writer.Write(data)
,最终调用的是内嵌的bufio.Writer
的Write()
方法先写入缓冲,至于何时写入文件,就由标准库bufio
- 加锁,放回
freeList
syncBuffer.file.Close()
syncBuffer.nbytes
1. mu
加锁;
2. 调用syncBuffer
内嵌的bufio.Writer
的Flush
()方法;
3. 调用syncBuffer.file.Sync()
方法;
4. mu
解锁;
1. 二级缓冲:块缓冲、bufio缓冲,适合写入频繁;
2. info(0)、warning(1)、error(2)、fatal(3)四个级别,相应的级别写进相应的文件;
3. 按文件大小分割,写入超过1024 * 1024 * 1800 1.8G 会重新创建文件;
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.WithFields(logrus.Fields{
"name": "dj",
"sime": 18,
}).Info("info msg")
}
entry2
,放回entry1
到pool
加锁,获取newEntry.Logger.ReportCaller
值,获取后解锁;
3. 加锁,存一份临时entry.Logger.Hooks
pool
里取一份bytes.Buffer
,并赋值newEntry.Buffer = buffer
写入Out
特点
1. 完全兼容标准log包;
2. debug、info、warn、error、fatal 、 panic 值依次减小;
3. 没有分割功能;
4. 一级缓冲:块缓冲用来写入格式化format后的数据,Out的写入得看具体实现;
package main
import(
"time"
log "github.com/sirupsen/logrus"
"github.com/lestrrat-go/file-rotatelogs"
)
func main() {
rl, _ := rotatelogs.New(
"./access_log.%Y-%m-%d %H:%M",
rotatelogs.WithRotationTime(24 * time.Hour), // 每天分割
rotatelogs.WithMaxAge(15 * 24 * time.Hour), // 保留最近15天
)
log.SetOutput(rl)
log.Printf("Hello, World!2")
for {
log.Println("now:", time.Now())
<- time.NewTicker(1 * time.Second).C
}
}
注意:file-rotatelogs内部也会加锁,配合logrus其实没必要再加一次锁。
package main
import (
"github.com/beego/beego/v2/core/logs"
)
func main() {
err := logs.SetLogger(logs.AdapterFile, `{"filename":"project.log","level":7,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`)
if err != nil {
panic(err)
}
logs.Info("hello beego")
}
LogMsg lm
bl.writeMsg(lm)
w.Format(lm)
w.Rlock()
func (w *fileLogWriter) needRotateHourly(hour int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Hourly && hour != w.hourlyOpenDate)
}
可以看到,小时与行数、字节大小分割判断交织在一起。
4.4 如果不需要按小时分割,再判断是否需要按天分割,判断条件为:
func (w *fileLogWriter) needRotateDaily(day int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Daily && day != w.dailyOpenDate)
}
可以看到,天数也与行数、字节大小分割判断交织在一起。
5. w.RUnlock()
w.Lock()
w.fileWriter.Write([]byte(msg))
w.Unlock()
w.RLock()
if w.needRotateHourly(h)
w.RUnlock()
w.Lock()
5. if w.needRotateHourly(h)
w.doRotate(lm.When)
w.fileWriter.Close()
err = os.Rename(w.Filename, fName)
fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
w.fileWriter = fd
// 启用异步
logs.Async()
// 可以设置缓冲 chan 的大小
logs.Async(1e3)
方法会设置BeeLogger
bl.asynchronous = true // 标志
bl.msgChan = make(chan *LogMsg, bl.msgChanLen) // 初始化通道
bl.wg.Add(1) // 同步组
go bl.startLogger() // 启动接收通道的goroutine
写日志流程:
1. LogMsg lm
bl.writeMsg(lm)
logM := logMsgPool.Get().(*LogMsg)
,把lm
里的属性值赋值给logM
bl.msgChan <- lm
func (bl *BeeLogger) startLogger() {
gameOver := false
for {
select {
case bm := <-bl.msgChan:
bl.writeToLoggers(bm)
logMsgPool.Put(bm)
case sg := <-bl.signalChan:
bl.flush()
if sg == "close" {
for _, l := range bl.outputs {
l.Destroy()
}
bl.outputs = nil
gameOver = true
}
bl.wg.Done()
}
if gameOver {
break
}
}
}
bl.writeToLoggers(bm)