Zap
Alternative logging through zap
Install / Use
/learn @gin-contrib/ZapREADME
zap
Alternative logging through zap. Thanks for Pull Request from @yezooz
Requirement
Require Go 1.19 or later.
Usage
Start using it
Download and install it:
go get github.com/gin-contrib/zap
Import it in your code:
import "github.com/gin-contrib/zap"
Example
See the example.
package main
import (
"fmt"
"time"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func main() {
r := gin.New()
logger, _ := zap.NewProduction()
// Add a ginzap middleware, which:
// - Logs all requests, like a combined access and error log.
// - Logs to stdout.
// - RFC3339 with UTC time format.
r.Use(ginzap.Ginzap(logger, time.RFC3339, true))
// Logs all panic to error log
// - stack means whether output the stack info.
r.Use(ginzap.RecoveryWithZap(logger, true))
// Example ping request.
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Example when panic happen.
r.GET("/panic", func(c *gin.Context) {
panic("An unexpected error happen!")
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}
Skip logging
When you want to skip logging for specific path, please use GinzapWithConfig
r.Use(GinzapWithConfig(utcLogger, &Config{
TimeFormat: time.RFC3339,
UTC: true,
SkipPaths: []string{"/no_log"},
}))
Custom Zap fields
example for custom log request body, response request ID or log Open Telemetry TraceID.
func main() {
r := gin.New()
logger, _ := zap.NewProduction()
r.Use(ginzap.GinzapWithConfig(logger, &ginzap.Config{
UTC: true,
TimeFormat: time.RFC3339,
Context: ginzap.Fn(func(c *gin.Context) []zapcore.Field {
fields := []zapcore.Field{}
// log request ID
if requestID := c.Writer.Header().Get("X-Request-Id"); requestID != "" {
fields = append(fields, zap.String("request_id", requestID))
}
// log trace and span ID
if trace.SpanFromContext(c.Request.Context()).SpanContext().IsValid() {
fields = append(fields, zap.String("trace_id", trace.SpanFromContext(c.Request.Context()).SpanContext().TraceID().String()))
fields = append(fields, zap.String("span_id", trace.SpanFromContext(c.Request.Context()).SpanContext().SpanID().String()))
}
// log request body
var body []byte
var buf bytes.Buffer
tee := io.TeeReader(c.Request.Body, &buf)
body, _ = io.ReadAll(tee)
c.Request.Body = io.NopCloser(&buf)
fields = append(fields, zap.String("body", string(body)))
return fields
}),
}))
// Example ping request.
r.GET("/ping", func(c *gin.Context) {
c.Writer.Header().Add("X-Request-Id", "1234-5678-9012")
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
r.POST("/ping", func(c *gin.Context) {
c.Writer.Header().Add("X-Request-Id", "9012-5678-1234")
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
if err := r.Run(":8080"); err != nil {
panic(err)
}
}
Custom skipper function
Example for custom skipper function
r.Use(GinzapWithConfig(logger, &Config{
TimeFormat: time.RFC3339,
UTC: true,
Skipper: func(c *gin.Context) bool {
return c.Request.URL.Path == "/ping" && c.Request.Method == "GET"
},
}))
Full example
package main
import (
"fmt"
"time"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func main() {
r := gin.New()
logger, _ := zap.NewProduction()
r.Use(ginzap.GinzapWithConfig(logger, &ginzap.Config{
UTC: true,
TimeFormat: time.RFC3339,
Skipper: func(c *gin.Context) bool {
return c.Request.URL.Path == "/ping" && c.Request.Method == "GET"
},
}))
// Example ping request.
r.GET("/ping", func(c *gin.Context) {
c.Writer.Header().Add("X-Request-Id", "1234-5678-9012")
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
r.POST("/ping", func(c *gin.Context) {
c.Writer.Header().Add("X-Request-Id", "9012-5678-1234")
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
if err := r.Run(":8080"); err != nil {
panic(err)
}
}
Custom SkipPathRegexps function
Example for custom SkipPathRegexps function
rxURL := regexp.MustCompile(`^/ping\s*`)
r.Use(ginzap.GinzapWithConfig(logger, &ginzap.Config{
UTC: true,
TimeFormat: time.RFC3339,
SkipPathRegexps: []*regexp.Regexp{rxURL},
}))
Full example
package main
import (
"fmt"
"regexp"
"time"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func main() {
r := gin.New()
logger, _ := zap.NewProduction()
rxURL := regexp.MustCompile(`^/ping\s*`)
r.Use(ginzap.GinzapWithConfig(logger, &ginzap.Config{
UTC: true,
TimeFormat: time.RFC3339,
SkipPathRegexps: []*regexp.Regexp{rxURL},
}))
// Example ping request.
r.GET("/ping1234", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
if err := r.Run(":8080"); err != nil {
panic(err)
}
}
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
