golang日志库之log
查看基本使用:
package main import ( "log" ) type User struct { Name string Age int } func main() { u := User{ Name: "dj", Age: 18, } log.Printf("%s login, age:%d", u.Name, u.Age) log.Panicf("Oh, system error when %s login", u.Name) log.Fatalf("Danger! hacker %s login", u.Name) }
log
默认输出到标准错误(stderr
),每条日志前会自动加上日期和时间。如果日志不是以换行符结尾的,那么log
会自动加上换行符。即每条日志会在新行中输出。
log
提供了三组函数:
Print/Printf/Println
:正常输出日志;Panic/Panicf/Panicln
:输出日志后,以拼装好的字符串为参数调用panic
;Fatal/Fatalf/Fatalln
:输出日志后,调用os.Exit(1)
退出程序。
命名比较容易辨别,带f
后缀的有格式化功能,带ln
后缀的会在日志后增加一个换行符。
注意,上面的程序中由于调用log.Panicf
会panic
,所以log.Fatalf
并不会调用。
前缀:
调用log.SetPrefix为每条日志文本前增加一个前缀。例如,在上面的程序中设置Login:前缀:
package main import ( "log" ) type User struct { Name string Age int } func main() { u := User{ Name: "dj", Age: 18, } log.SetPrefix("Login: ") log.Printf("%s login, age:%d", u.Name, u.Age) }
选项flag:
设置选项可在每条输出的文本前增加一些额外信息,如日期时间、文件名等。
log
库提供了 6 个选项:
const ( Ldate = 1 << iota Ltime Lmicroseconds Llongfile Lshortfile LUTC )
Ldate
:输出当地时区的日期,如2020/02/07
;Ltime
:输出当地时区的时间,如11:45:45
;Lmicroseconds
:输出的时间精确到微秒,设置了该选项就不用设置Ltime
了。如11:45:45.123123
;Llongfile
:输出长文件名+行号,含包名,如github.com/darjun/go-daily-lib/log/flag/main.go:50
;Lshortfile
:输出短文件名+行号,不含包名,如main.go:50
;LUTC
:如果设置了Ldate
或Ltime
,将输出 UTC 时间,而非当地时区。
package main import ( "log" ) type User struct { Name string Age int } func main() { u := User{ Name: "dj", Age: 18, } log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds) log.Printf("%s login, age:%d", u.Name, u.Age) }
调用log.Flags()
可以获取当前设置的选项。
log
库还定义了一个Lstdflag
,为Ldate | Ltime
,这就是我们默认的选项。
const ( LstdFlags = Ldate | Ltime )
log.New
接受三个参数:
io.Writer
:日志都会写到这个Writer
中;prefix
:前缀,也可以后面调用logger.SetPrefix
设置;flag
:选项,也可以后面调用logger.SetFlag
设置。
注意到,第一个参数为io.Writer
,我们可以使用io.MultiWriter
实现多目的地输出。下面我们将日志同时输出到标准输出、bytes.Buffer
和文件中:
package main import ( "bytes" "io" "log" "os" ) type User struct { Name string Age int } func main() { u := User{ Name: "dj", Age: 18, } writer1 := &bytes.Buffer{} writer2 := os.Stdout writer3, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE, 0755) if err != nil { log.Fatalf("create file log.txt failed: %v", err) } logger := log.New(io.MultiWriter(writer1, writer2, writer3), "", log.Lshortfile|log.LstdFlags) logger.Printf("%s login, age:%d", u.Name, u.Age) }
自定义日志包:
logfer/logger.go
package logger
import (
"io"
"log"
"os"
)
const (
flag = log.Ldate | log.Ltime | log.Lshortfile
preDebug = "[DEBUG]"
preInfo = "[INFO]"
preWarn = "[WARN]"
preError = "[ERROR]"
)
var (
logFile io.Writer
debugLogger *log.Logger
infoLogger *log.Logger
warnLogger *log.Logger
errorLogger *log.Logger
defaultLogFile = "web.log"
)
func init(){
var err error
logFile, err = os.OpenFile(defaultLogFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
defaultLogFile = "./web.log"
logFile, err = os.OpenFile(defaultLogFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
log.Fatalf("create log file err %+v", err)
}
}
debugLogger = log.New(logFile, preDebug, flag)
infoLogger = log.New(logFile, preInfo, flag)
warnLogger = log.New(logFile, preWarn, flag)
errorLogger = log.New(logFile, preError, flag)
}
func Debugf(format string, v ...interface{}){
debugLogger.Printf(format, v...)
}
func Infof(format string, v ...interface{}){
infoLogger.Printf(format, v...)
}
func Warnf(format string, v ...interface{}){
warnLogger.Printf(format, v...)
}
func Errorf(format string, v ...interface{}){
errorLogger.Printf(format, v...)
}
func SetOutputPath(path string) {
var err error
logFile, err = os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
log.Fatalf("create log file err %+v", err)
}
debugLogger = log.New(logFile, preDebug, flag)
infoLogger = log.New(logFile, preInfo, flag)
warnLogger = log.New(logFile, preWarn, flag)
errorLogger = log.New(logFile, preError, flag)
}
使用方式:
errStr := "this is a error" logger.Debugf("hello, %s", errStr) logger.Infof("hello, %s", errStr) logger.Warnf("hello, %s", errStr) logger.Errorf("hello, %s", errStr)