Go 語言之 zap 日志庫簡單使用
默認的 Go log
log:https://pkg.go.dev/log
package main
import (
"log"
"os"
)
func init() {
log.SetPrefix("LOG: ") // 設定前綴
f, err := os.OpenFile("./log.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatalf("open log file failed with error: %v", err)
}
log.SetOutput(f) // 設定輸出
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile)
// const (
// Ldate = 1 << iota // 1 << 0 = 000000001 = 1
// Ltime // 1 << 1 = 000000010 = 2
// Lmicroseconds // 1 << 2 = 000000100 = 4
// Llongfile // 1 << 3 = 000001000 = 8
// Lshortfile // 1 << 4 = 000010000 = 16
// ...
// )
}
func main() {
log.Println("1234")
// log.Fatalln("1234")
// log.Panicln("1234")
// log.Panic("1234")
// log.Panicf("1234, %d", 5678)
}
log 包是一個簡單的日志包,
Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined 'standard' Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message. Every log message is output on a separate line: if the message being printed does not end in a newline, the logger will add one. The Fatal functions call os.Exit(1) after writing the log message. The Panic functions call panic after writing the log message.
uber-go zap
log:https://pkg.go.dev/log
github zap:https://github.com/uber-go/zap
pkg zap:https://pkg.go.dev/go.uber.org/zap#section-readme
Blazing fast, structured, leveled logging in Go.
安裝
go get -u go.uber.org/zap
在性能良好但不是關鍵的背景關系中,使用 SugaredLogger,它比其他結構化日志包快4-10倍,包括結構化和 printf 風格的 API,
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
當性能和型別安全至關重要時,請使用Logger,它甚至比SugaredLogger 更快,分配也少得多,但它只支持結構化日志記錄,
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
zap檔案:https://pkg.go.dev/go.uber.org/zap#section-readme
Logger 簡單使用
package main
import (
"go.uber.org/zap"
"net/http"
)
// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger
func main() {
// 初始化
InitLogger()
// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
// 在程式退出之前,把緩沖區里的日志刷到磁盤上
defer logger.Sync()
simpleHttpGet("www.baidu.com")
simpleHttpGet("http://www.baidu.com")
}
func InitLogger() {
// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
// It's a shortcut for NewProductionConfig().Build(...Option).
logger, _ = zap.NewProduction()
}
func simpleHttpGet(url string) {
// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
// 301 (Moved Permanently)
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
// 308 (Permanent Redirect)
// Get is a wrapper around DefaultClient.Get.
// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
resp, err := http.Get(url)
if err != nil {
// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
logger.Error(
"Error fetching url..",
zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
zap.Error(err)) // // Error is shorthand for the common idiom NamedError("error", err).
} else {
// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
logger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
運行
Code/go/zap_demo via ?? v1.20.3 via ?? base took 11.0s
? go run main.go
{"level":"error","ts":1686929392.121357,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.google.com","error":"Get \"www.google.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"error","ts":1686929422.123222,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"http://www.google.com","error":"Get \"http://www.google.com\": dial tcp 103.252.115.59:80: i/o timeout","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:22\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
Code/go/zap_demo via ?? v1.20.3 via ?? base took 30.3s
? go run main.go
{"level":"error","ts":1686929534.4672909,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.baidu.com","error":"Get \"www.baidu.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686929535.561184,"caller":"zap_demo/main.go:47","msg":"Success..","statusCode":"200 OK","url":"http://www.baidu.com"}
Code/go/zap_demo via ?? v1.20.3 via ?? base
?
原始碼
// Level reports the minimum enabled level for this logger.
//
// For NopLoggers, this is [zapcore.InvalidLevel].
func (log *Logger) Level() zapcore.Level {
return zapcore.LevelOf(log.core)
}
// Check returns a CheckedEntry if logging a message at the specified level
// is enabled. It's a completely optional optimization; in high-performance
// applications, Check can help avoid allocating a slice to hold fields.
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
return log.check(lvl, msg)
}
// Log logs a message at the specified level. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Log(lvl zapcore.Level, msg string, fields ...Field) {
if ce := log.check(lvl, msg); ce != nil {
ce.Write(fields...)
}
}
// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Debug(msg string, fields ...Field) {
if ce := log.check(DebugLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Info(msg string, fields ...Field) {
if ce := log.check(InfoLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Warn(msg string, fields ...Field) {
if ce := log.check(WarnLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Error(msg string, fields ...Field) {
if ce := log.check(ErrorLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func (log *Logger) DPanic(msg string, fields ...Field) {
if ce := log.check(DPanicLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func (log *Logger) Panic(msg string, fields ...Field) {
if ce := log.check(PanicLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (log *Logger) Fatal(msg string, fields ...Field) {
if ce := log.check(FatalLevel, msg); ce != nil {
ce.Write(fields...)
}
}
每個zapcore.Field其實就是一組鍵值對引數,
// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field
輸出的是 JSON 格式的日志
SugaredLogger 簡單使用
NewProduction
package main
import (
"go.uber.org/zap"
"net/http"
)
// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger
var sugarLogger *zap.SugaredLogger
func main() {
// 初始化
InitLogger()
// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
// 在程式退出之前,把緩沖區里的日志刷到磁盤上
defer logger.Sync()
simpleHttpGet("www.baidu.com")
simpleHttpGet("http://www.baidu.com")
}
func InitLogger() {
// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
// It's a shortcut for NewProductionConfig().Build(...Option).
logger, _ = zap.NewProduction()
sugarLogger = logger.Sugar()
}
func simpleHttpGet(url string) {
// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
// 301 (Moved Permanently)
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
// 308 (Permanent Redirect)
// Get is a wrapper around DefaultClient.Get.
// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
resp, err := http.Get(url)
if err != nil {
// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
//logger.Error(
sugarLogger.Error(
"Error fetching url..",
zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
zap.Error(err)) // // Error is shorthand for the common idiom NamedError("error", err).
} else {
// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
//logger.Info("Success..",
sugarLogger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
運行
Code/go/zap_demo via ?? v1.20.3 via ?? base
? go run main.go
{"level":"error","ts":1686930454.798492,"caller":"zap_demo/main.go:47","msg":"Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0 Get \"www.baidu.com\": unsupported protocol scheme \"\"}","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:47\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:23\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686930454.83406,"caller":"zap_demo/main.go:54","msg":"Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}"}
Code/go/zap_demo via ?? v1.20.3 via ?? base
?
NewDevelopment
package main
import (
"go.uber.org/zap"
"net/http"
)
// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger
// SugaredLogger將基本的Logger功能封裝在一個較慢但不那么冗長的API中,任何Logger都可以通過其Sugar方法轉換為sugardlogger,
//與Logger不同,SugaredLogger并不堅持結構化日志記錄,對于每個日志級別,它公開了四個方法:
// - methods named after the log level for log.Print-style logging
// - methods ending in "w" for loosely-typed structured logging
// - methods ending in "f" for log.Printf-style logging
// - methods ending in "ln" for log.Println-style logging
// For example, the methods for InfoLevel are:
//
// Info(...any) Print-style logging
// Infow(...any) Structured logging (read as "info with")
// Infof(string, ...any) Printf-style logging
// Infoln(...any) Println-style logging
var sugarLogger *zap.SugaredLogger
func main() {
// 初始化
InitLogger()
// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
// 在程式退出之前,把緩沖區里的日志刷到磁盤上
defer logger.Sync()
simpleHttpGet("www.baidu.com")
simpleHttpGet("http://www.baidu.com")
}
func InitLogger() {
// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
// It's a shortcut for NewProductionConfig().Build(...Option).
//logger, _ = zap.NewProduction()
// NewDevelopment構建一個開發日志,它以一種人性化的格式將DebugLevel及以上的日志寫入標準錯誤,
logger, _ = zap.NewDevelopment()
// Sugar封裝了Logger,以提供更符合人體工程學的API,但速度略慢,糖化一個Logger的成本非常低,
// 因此一個應用程式同時使用Logger和sugaredlogger是合理的,在性能敏感代碼的邊界上在它們之間進行轉換,
sugarLogger = logger.Sugar()
}
func simpleHttpGet(url string) {
// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
// 301 (Moved Permanently)
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
// 308 (Permanent Redirect)
// Get is a wrapper around DefaultClient.Get.
// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
resp, err := http.Get(url)
if err != nil {
// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
//logger.Error(
// 錯誤使用fmt,以Sprint方式構造和記錄訊息,
sugarLogger.Error(
"Error fetching url..",
zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
zap.Error(err)) // // Error is shorthand for the common idiom NamedError("error", err).
} else {
// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
//logger.Info("Success..",
// Info使用fmt,以Sprint方式構造和記錄訊息,
sugarLogger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
運行
Code/go/zap_demo via ?? v1.20.3 via ?? base
? go run main.go
2023-06-16T23:52:00.384+0800 ERROR zap_demo/main.go:48 Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0 Get "www.baidu.com": unsupported protocol scheme ""}
main.simpleHttpGet
/Users/qiaopengjun/Code/go/zap_demo/main.go:48
main.main
/Users/qiaopengjun/Code/go/zap_demo/main.go:23
runtime.main
/usr/local/go/src/runtime/proc.go:250
2023-06-16T23:52:00.439+0800 INFO zap_demo/main.go:55 Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}
Code/go/zap_demo via ?? v1.20.3 via ?? base
?
本文來自博客園,作者:尋月隱君,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17487169.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555438.html
標籤:其他
上一篇:Scala面向物件
下一篇:返回列表
