feat: adding filters
This commit is contained in:
@@ -78,6 +78,46 @@ router.Run(":1234")
|
|||||||
// time=2023-04-10T14:00:0.000000Z level=INFO msg="Incoming request" status=200 method=GET path=/pong ip=127.0.0.1 latency=25.5µs user-agent=curl/7.77.0 time=2023-04-10T14:00:00.000Z
|
// time=2023-04-10T14:00:0.000000Z level=INFO msg="Incoming request" status=200 method=GET path=/pong ip=127.0.0.1 latency=25.5µs user-agent=curl/7.77.0 time=2023-04-10T14:00:00.000Z
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
sloggin "github.com/samber/slog-gin"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||||
|
|
||||||
|
router := gin.New()
|
||||||
|
router.Use(
|
||||||
|
sloggin.NewWithFilters(
|
||||||
|
logger,
|
||||||
|
sloggin.Accept(func (c *gin.Context) bool {
|
||||||
|
return xxx
|
||||||
|
}),
|
||||||
|
sloggin.IgnoreStatus(401, 404),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Available filters:
|
||||||
|
- Accept / Ignore
|
||||||
|
- AcceptMethod / IgnoreMethod
|
||||||
|
- AcceptStatus / IgnoreStatus
|
||||||
|
- AcceptStatusGreaterThan / IgnoreStatusLessThan
|
||||||
|
- AcceptStatusGreaterThanOrEqual / IgnoreStatusLessThanOrEqual
|
||||||
|
- AcceptPath / IgnorePath
|
||||||
|
- AcceptPathContains / IgnorePathContains
|
||||||
|
- AcceptPathPrefix / IgnorePathPrefix
|
||||||
|
- AcceptPathSuffix / IgnorePathSuffix
|
||||||
|
- AcceptPathMatch / IgnorePathMatch
|
||||||
|
- AcceptHost / IgnoreHost
|
||||||
|
- AcceptHostContains / IgnoreHostContains
|
||||||
|
- AcceptHostPrefix / IgnoreHostPrefix
|
||||||
|
- AcceptHostSuffix / IgnoreHostSuffix
|
||||||
|
- AcceptHostMatch / IgnoreHostMatch
|
||||||
|
|
||||||
### Using custom time formatters
|
### Using custom time formatters
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|||||||
+334
@@ -0,0 +1,334 @@
|
|||||||
|
package sloggin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter func(ctx *gin.Context) bool
|
||||||
|
|
||||||
|
// Basic
|
||||||
|
func Accept(filter Filter) Filter { return filter }
|
||||||
|
func Ignore(filter Filter) Filter { return filter }
|
||||||
|
|
||||||
|
// Method
|
||||||
|
func AcceptMethod(methods ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
reqMethod := strings.ToLower(c.Request.Method)
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
if strings.ToLower(method) == reqMethod {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreMethod(methods ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
reqMethod := strings.ToLower(c.Request.Method)
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
if strings.ToLower(method) == reqMethod {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status
|
||||||
|
func AcceptStatus(statuses ...int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, status := range statuses {
|
||||||
|
if status == c.Writer.Status() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreStatus(statuses ...int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, status := range statuses {
|
||||||
|
if status == c.Writer.Status() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptStatusGreaterThan(status int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
return c.Writer.Status() > status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreStatusLessThan(status int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
return c.Writer.Status() < status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptStatusGreaterThanOrEqual(status int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
return c.Writer.Status() >= status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreStatusLessThanOrEqual(status int) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
return c.Writer.Status() <= status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path
|
||||||
|
func AcceptPath(urls ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, url := range urls {
|
||||||
|
if c.Request.URL.Path == url {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnorePath(urls ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, url := range urls {
|
||||||
|
if c.Request.URL.Path == url {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptPathContains(parts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, part := range parts {
|
||||||
|
if strings.Contains(c.Request.URL.Path, part) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnorePathContains(parts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, part := range parts {
|
||||||
|
if strings.Contains(c.Request.URL.Path, part) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptPathPrefix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Path, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnorePathPrefix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Path, prefix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptPathSuffix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Path, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnorePathSuffix(suffixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, suffix := range suffixs {
|
||||||
|
if strings.HasSuffix(c.Request.URL.Path, suffix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptPathMatch(regs ...regexp.Regexp) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, reg := range regs {
|
||||||
|
if reg.Match([]byte(c.Request.URL.Path)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnorePathMatch(regs ...regexp.Regexp) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, reg := range regs {
|
||||||
|
if reg.Match([]byte(c.Request.URL.Path)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host
|
||||||
|
func AcceptHost(hosts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, host := range hosts {
|
||||||
|
if c.Request.URL.Host == host {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreHost(hosts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, host := range hosts {
|
||||||
|
if c.Request.URL.Host == host {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptHostContains(parts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, part := range parts {
|
||||||
|
if strings.Contains(c.Request.URL.Host, part) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreHostContains(parts ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, part := range parts {
|
||||||
|
if strings.Contains(c.Request.URL.Host, part) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptHostPrefix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Host, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreHostPrefix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Host, prefix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptHostSuffix(prefixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, prefix := range prefixs {
|
||||||
|
if strings.HasPrefix(c.Request.URL.Host, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreHostSuffix(suffixs ...string) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, suffix := range suffixs {
|
||||||
|
if strings.HasSuffix(c.Request.URL.Host, suffix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptHostMatch(regs ...regexp.Regexp) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, reg := range regs {
|
||||||
|
if reg.Match([]byte(c.Request.URL.Host)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IgnoreHostMatch(regs ...regexp.Regexp) Filter {
|
||||||
|
return func(c *gin.Context) bool {
|
||||||
|
for _, reg := range regs {
|
||||||
|
if reg.Match([]byte(c.Request.URL.Host)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ type Config struct {
|
|||||||
ServerErrorLevel slog.Level
|
ServerErrorLevel slog.Level
|
||||||
|
|
||||||
WithRequestID bool
|
WithRequestID bool
|
||||||
|
|
||||||
|
Filters []Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a gin.HandlerFunc (middleware) that logs requests using slog.
|
// New returns a gin.HandlerFunc (middleware) that logs requests using slog.
|
||||||
@@ -32,6 +34,24 @@ func New(logger *slog.Logger) gin.HandlerFunc {
|
|||||||
ServerErrorLevel: slog.LevelError,
|
ServerErrorLevel: slog.LevelError,
|
||||||
|
|
||||||
WithRequestID: true,
|
WithRequestID: true,
|
||||||
|
|
||||||
|
Filters: []Filter{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithFilters returns a gin.HandlerFunc (middleware) that logs requests using slog.
|
||||||
|
//
|
||||||
|
// Requests with errors are logged using slog.Error().
|
||||||
|
// Requests without errors are logged using slog.Info().
|
||||||
|
func NewWithFilters(logger *slog.Logger, filters ...Filter) gin.HandlerFunc {
|
||||||
|
return NewWithConfig(logger, Config{
|
||||||
|
DefaultLevel: slog.LevelInfo,
|
||||||
|
ClientErrorLevel: slog.LevelWarn,
|
||||||
|
ServerErrorLevel: slog.LevelError,
|
||||||
|
|
||||||
|
WithRequestID: true,
|
||||||
|
|
||||||
|
Filters: filters,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +86,12 @@ func NewWithConfig(logger *slog.Logger, config Config) gin.HandlerFunc {
|
|||||||
attributes = append(attributes, slog.String("request-id", requestID))
|
attributes = append(attributes, slog.String("request-id", requestID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, filter := range config.Filters {
|
||||||
|
if !filter(c) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case c.Writer.Status() >= http.StatusBadRequest && c.Writer.Status() < http.StatusInternalServerError:
|
case c.Writer.Status() >= http.StatusBadRequest && c.Writer.Status() < http.StatusInternalServerError:
|
||||||
logger.LogAttrs(context.Background(), config.ClientErrorLevel, c.Errors.String(), attributes...)
|
logger.LogAttrs(context.Background(), config.ClientErrorLevel, c.Errors.String(), attributes...)
|
||||||
|
|||||||
Reference in New Issue
Block a user