Gin Integration
Capture errors, panics, and request context from Gin applications.
Installation
go get github.com/KodyDennon/statly-goSetup
package main
import (
"github.com/gin-gonic/gin"
statly "github.com/KodyDennon/statly-go"
statlygin "github.com/KodyDennon/statly-go/integrations/gin"
)
func main() {
// Initialize SDK first
statly.Init(statly.Options{
DSN: "https://[email protected]/your-org",
Environment: "production",
})
defer statly.Close()
r := gin.New()
// Add Statly middleware
r.Use(statlygin.Recovery(statlygin.Options{}))
r.Use(statlygin.Logger())
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello"})
})
r.Run(":8080")
}Middleware
Recovery
Panic recovery middleware that captures panics as events.
func Recovery(options Options) gin.HandlerFunc
type Options struct {
Repanic bool // Re-panic after capture (default: true)
WaitForDelivery bool // Wait for event to be sent
Timeout time.Duration // Delivery timeout
}What's captured:
- Panic value and stack trace
- HTTP request context (method, URL, headers)
- Client IP address
- Request duration
Example:
r.Use(statlygin.Recovery(statlygin.Options{
Repanic: true, // Re-panic to let Gin handle response
WaitForDelivery: true, // Wait for event to send before panicking
Timeout: 2 * time.Second,
}))Logger
Request logging middleware that adds breadcrumbs.
func Logger() gin.HandlerFuncWhat's captured:
- Request breadcrumb (method, URL, start time)
- Response breadcrumb (status code, duration)
- 4xx/5xx responses are marked with error level
Example:
r.Use(statlygin.Logger())ErrorHandler
Captures errors added with c.Error().
func ErrorHandler() gin.HandlerFuncExample:
r.Use(statlygin.ErrorHandler())
r.GET("/data", func(c *gin.Context) {
data, err := fetchData()
if err != nil {
c.Error(err) // Will be captured by ErrorHandler
c.JSON(500, gin.H{"error": "Failed to fetch data"})
return
}
c.JSON(200, data)
})What's Captured
Request Context
For each error, the middleware captures:
- HTTP method, URL, path, full path
- Query string and path parameters
- Headers (sensitive ones filtered)
- Client IP via
c.ClientIP() - Host
Automatic Sanitization
Headers filtered:
AuthorizationCookie
Tags
Automatically set:
http.method: Request methodhttp.url: Request URLtransaction: Route path (e.g.,/users/:id)
With Authentication
Set user context from your auth middleware:
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
user := getCurrentUser(c)
if user != nil {
statly.SetUser(statly.User{
ID: user.ID,
Email: user.Email,
})
}
c.Next()
}
}
r.Use(statlygin.Recovery(statlygin.Options{}))
r.Use(AuthMiddleware())Manual Capture
Capture errors manually with context:
r.POST("/orders", func(c *gin.Context) {
var order OrderRequest
if err := c.ShouldBindJSON(&order); err != nil {
c.JSON(400, gin.H{"error": "Invalid request"})
return
}
result, err := processOrder(order)
if err != nil {
statly.CaptureExceptionWithContext(err, map[string]interface{}{
"order_total": order.Total,
"user_id": c.GetString("user_id"),
})
c.JSON(500, gin.H{"error": "Order processing failed"})
return
}
c.JSON(200, result)
})Full Example
package main
import (
"github.com/gin-gonic/gin"
statly "github.com/KodyDennon/statly-go"
statlygin "github.com/KodyDennon/statly-go/integrations/gin"
)
func main() {
statly.Init(statly.Options{
DSN: "https://[email protected]/your-org",
Environment: "production",
})
defer statly.Close()
r := gin.New()
// Statly middleware
r.Use(statlygin.Recovery(statlygin.Options{
Repanic: true,
WaitForDelivery: true,
}))
r.Use(statlygin.Logger())
r.Use(statlygin.ErrorHandler())
// Auth middleware
r.Use(func(c *gin.Context) {
if user := authenticate(c); user != nil {
statly.SetUser(statly.User{
ID: user.ID,
Email: user.Email,
})
}
c.Next()
})
// Routes
r.GET("/api/users", listUsers)
r.POST("/api/orders", createOrder)
r.Run(":8080")
}
func createOrder(c *gin.Context) {
statly.AddBreadcrumb(statly.Breadcrumb{
Message: "Creating order",
Category: "order",
})
var order Order
if err := c.ShouldBindJSON(&order); err != nil {
c.Error(err)
c.JSON(400, gin.H{"error": "Invalid order"})
return
}
result, err := processOrder(order)
if err != nil {
statly.CaptureException(err)
c.JSON(500, gin.H{"error": "Processing failed"})
return
}
c.JSON(200, result)
}