Logger
打印日志等操作的接收者是 *Logger
type Logger struct {
mu sync.Mutex // ensures atomic writes; protects the following fields
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
flag int // properties
out io.Writer // destination for output
buf []byte // for accumulating text to write
}
所以在打印日志前,需要构造一个Logger对象
log包自带一个默认的Logger,使用log.Println()
等打印日志操作时,实际上是使用了该Logger
var std = New(os.Stderr, "", LstdFlags)
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
每个Logger有自己的out,所以想将不同等级的log打印到不同地方,需要创建新的Logger使用
var (
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
func init() {
Info = log.New(ioutil.Discard, "Info:", log.Ldate|log.Ltime|log.Lmicroseconds|log.Llongfile)
Warning = log.New(os.Stdout, "Warning:", log.Ldate|log.Ltime|log.Lmicroseconds|log.Llongfile)
Error = log.New(os.Stderr, "Error:", log.Ldate|log.Ltime|log.Lmicroseconds|log.Llongfile)
}
Logger提供的方法简单而又清晰,主要分为设置和打印两种
设置Logger参数
在用log.New构造Logger对象时,对应的三个参数分别是日志输出位置、日志前缀、日志信息
当Logger构造好后,Logger也有对应的方法修改以上三个值
SetOutput
func (l *Logger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.out = w
}
修改日志信息的输出位置
SetPrefix
func (l *Logger) SetPrefix(prefix string) {
l.mu.Lock()
defer l.mu.Unlock()
l.prefix = prefix
}
修改日志信息前缀
SetFlags
func (l *Logger) SetFlags(flag int) {
l.mu.Lock()
defer l.mu.Unlock()
l.flag = flag
}
修改日志输出信息,时间、代码位置等
打印日志
打印日志内容
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
func (l *Logger) Printf(format string, v ...interface{}) {
l.Output(2, fmt.Sprintf(format, v...))
}
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
打印日志内容后退出程序(严重错误)
func (l *Logger) Fatal(v ...interface{}) {
l.Output(2, fmt.Sprint(v...))
os.Exit(1)
}
func (l *Logger) Fatalf(format string, v ...interface{}) {
l.Output(2, fmt.Sprintf(format, v...))
os.Exit(1)
}
func (l *Logger) Fatalln(v ...interface{}) {
l.Output(2, fmt.Sprintln(v...))
os.Exit(1)
}
打印日志内容后宕机
func (l *Logger) Panic(v ...interface{}) {
s := fmt.Sprint(v...)
l.Output(2, s)
panic(s)
}
func (l *Logger) Panicf(format string, v ...interface{}) {
s := fmt.Sprintf(format, v...)
l.Output(2, s)
panic(s)
}
func (l *Logger) Panicln(v ...interface{}) {
s := fmt.Sprintln(v...)
l.Output(2, s)
panic(s)
}
可以发现,打印日志最原始的方法是Output
func (l *Logger) Output(calldepth int, s string) error
Output是暴露出去的方法,所以在程序中也可以直接使用
calldepth可以恢复PC,打印日志时,如果flag设置了file,可以看到调用栈前面几层的位置
func main() {
log.SetFlags(log.Llongfile)
log.Output(0,"calldepth 0")
log.Output(1,"calldepth 1")
log.Output(2,"calldepth 2")
log.Output(3,"calldepth 3")
}
/* 结果
/usr/local/go/src/log/log.go:376: calldepth 0
~/go/src/awesomeProject/main.go:8: calldepth 1
/usr/local/go/src/runtime/proc.go:203: calldepth 2
/usr/local/go/src/runtime/asm_amd64.s:1373: calldepth 3
*/
使用Println等方法时,因为调用栈又多了一层,所以calldepth的值都为2