Change logging to be json comaptible
This commit is contained in:
@@ -19,6 +19,9 @@ type Claims struct {
|
||||
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
log := StructuredLog(c).With().
|
||||
Str("event", "auth_middleware").
|
||||
Logger()
|
||||
|
||||
var tokenString string
|
||||
|
||||
@@ -39,6 +42,7 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
if tokenString == "" {
|
||||
log.Warn().Str("reason", "no_token").Msg("Auth failed - no token provided")
|
||||
abortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
@@ -51,13 +55,26 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
return jwtSecret, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
if err != nil {
|
||||
log.Warn().
|
||||
Str("reason", "token_parse_error").
|
||||
Err(err).
|
||||
Msg("Auth failed - token parse error")
|
||||
abortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
log.Warn().Str("reason", "invalid_token").Msg("Auth failed - invalid token")
|
||||
abortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("user_id", claims.UserID)
|
||||
c.Set("role", claims.Role)
|
||||
c.Set("username", claims.UserID)
|
||||
|
||||
log.Debug().Str("user_id", claims.UserID).Str("role", claims.Role).Msg("Auth successful")
|
||||
|
||||
c.Next()
|
||||
}
|
||||
@@ -76,26 +93,37 @@ func abortUnauthorized(c *gin.Context) {
|
||||
|
||||
func RequireRole(roles ...string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
log := StructuredLog(c).With().
|
||||
Str("event", "role_check").
|
||||
Logger()
|
||||
|
||||
roleValue, exists := c.Get("role")
|
||||
if !exists {
|
||||
log.Warn().Str("reason", "no_role").Msg("Role check failed - no role in context")
|
||||
abortForbidden(c)
|
||||
return
|
||||
}
|
||||
|
||||
userRole, ok := roleValue.(string)
|
||||
if !ok {
|
||||
log.Warn().Str("reason", "invalid_role_type").Msg("Role check failed - invalid role type")
|
||||
abortForbidden(c)
|
||||
return
|
||||
}
|
||||
|
||||
for _, allowed := range roles {
|
||||
if userRole == allowed {
|
||||
log.Debug().Str("required_roles", strings.Join(roles, ",")).Str("user_role", userRole).Msg("Role check passed")
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Warn().
|
||||
Str("required_roles", strings.Join(roles, ",")).
|
||||
Str("user_role", userRole).
|
||||
Msg("Role check failed - insufficient permissions")
|
||||
|
||||
abortForbidden(c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,87 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"ResendIt/internal/logger"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// StructuredLogger returns a gin middleware that logs HTTP requests in JSON format
|
||||
func StructuredLogger() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
query := c.Request.URL.RawQuery
|
||||
method := c.Request.Method
|
||||
|
||||
c.Next()
|
||||
|
||||
latency := time.Since(start)
|
||||
status := c.Writer.Status()
|
||||
clientIP := c.ClientIP()
|
||||
userAgent := c.Request.UserAgent()
|
||||
requestID := c.GetString("request_id")
|
||||
|
||||
evt := logger.Log.Info().
|
||||
Str("type", "http_request").
|
||||
Str("method", method).
|
||||
Str("path", path).
|
||||
Str("query", query).
|
||||
Int("status", status).
|
||||
Dur("latency_ms", latency).
|
||||
Str("client_ip", clientIP).
|
||||
Str("user_agent", userAgent).
|
||||
Str("request_id", requestID)
|
||||
|
||||
if len(c.Errors) > 0 {
|
||||
evt = evt.Str("error", c.Errors.ByType(gin.ErrorTypePrivate).String())
|
||||
}
|
||||
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
evt = evt.Str("user_id", userID.(string))
|
||||
}
|
||||
if username, exists := c.Get("username"); exists {
|
||||
evt = evt.Str("username", username.(string))
|
||||
}
|
||||
|
||||
evt.Msg("")
|
||||
}
|
||||
}
|
||||
|
||||
// RequestIDMiddleware adds a unique request ID to each request
|
||||
func RequestIDMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := c.GetHeader("X-Request-ID")
|
||||
if requestID == "" {
|
||||
requestID = generateRequestID()
|
||||
}
|
||||
c.Set("request_id", requestID)
|
||||
c.Header("X-Request-ID", requestID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func generateRequestID() string {
|
||||
// Simple request ID generation - could use uuid package for more entropy
|
||||
return strconv.FormatInt(time.Now().UnixNano(), 36)
|
||||
}
|
||||
|
||||
// StructuredLog returns a child logger with HTTP context for use in handlers
|
||||
func StructuredLog(c *gin.Context) zerolog.Logger {
|
||||
log := logger.Log.With().
|
||||
Str("type", "app_log").
|
||||
Str("request_id", c.GetString("request_id"))
|
||||
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
log = log.Str("user_id", userID.(string))
|
||||
}
|
||||
if username, exists := c.Get("username"); exists {
|
||||
log = log.Str("username", username.(string))
|
||||
}
|
||||
|
||||
return log.Logger()
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ func RateLimitByIPDynamic(maxFn func() int, per time.Duration, burstFn func() in
|
||||
}
|
||||
|
||||
return func(c *gin.Context) {
|
||||
log := StructuredLog(c).With().
|
||||
Str("event", "rate_limit_check").
|
||||
Logger()
|
||||
|
||||
// Kinda a shitty fix
|
||||
if c.FullPath() == "/api/files/upload/chunk" || c.FullPath() == "/api/files/upload/init" || c.FullPath() == "/api/files/upload/complete" {
|
||||
@@ -136,6 +139,12 @@ func RateLimitByIPDynamic(maxFn func() int, per time.Duration, burstFn func() in
|
||||
client := getClient(ip, now, max, burst)
|
||||
|
||||
if !client.bucket.allow() {
|
||||
log.Warn().
|
||||
Str("ip", ip).
|
||||
Int("max", max).
|
||||
Int("burst", burst).
|
||||
Msg("Rate limit exceeded")
|
||||
|
||||
c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{
|
||||
"error": "rate limit exceeded",
|
||||
})
|
||||
@@ -144,4 +153,4 @@ func RateLimitByIPDynamic(maxFn func() int, per time.Duration, burstFn func() in
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user