1
1
package middlewares
2
2
3
3
import (
4
- "fmt"
5
- "io"
4
+ "net/netip"
6
5
"strings"
7
- "time"
8
6
7
+ "github.com/OpenListTeam/OpenList/v4/internal/conf"
9
8
"github.com/gin-gonic/gin"
10
9
log "github.com/sirupsen/logrus"
11
10
)
12
11
13
- // FilteredLoggerConfig defines the configuration for the filtered logger
14
- type FilteredLoggerConfig struct {
15
- // SkipPaths is a list of URL paths to skip logging
16
- SkipPaths []string
17
- // SkipMethods is a list of HTTP methods to skip logging
18
- SkipMethods []string
19
- // SkipPathPrefixes is a list of URL path prefixes to skip logging
20
- SkipPathPrefixes []string
21
- // Output is the writer where logs will be written
22
- Output io.Writer
12
+ type filter struct {
13
+ CIDR * netip.Prefix `json:"cidr,omitempty"`
14
+ Path * string `json:"path,omitempty"`
15
+ Method * string `json:"method,omitempty"`
23
16
}
24
17
25
- // FilteredLoggerWithConfig returns a gin.HandlerFunc (middleware) that logs requests
26
- // but skips logging for specified paths, methods, or path prefixes
27
- func FilteredLoggerWithConfig (config FilteredLoggerConfig ) gin.HandlerFunc {
28
- if config .Output == nil {
29
- config .Output = log .StandardLogger ().Out
30
- }
18
+ var filterList []* filter
31
19
32
- return gin .LoggerWithConfig (gin.LoggerConfig {
33
- Output : config .Output ,
34
- SkipPaths : config .SkipPaths ,
35
- Formatter : func (param gin.LogFormatterParams ) string {
36
- // Skip logging for health check endpoints
37
- if shouldSkipLogging (param .Path , param .Method , config ) {
38
- return ""
20
+ func initFilterList () {
21
+ for _ , s := range conf .Conf .Log .Filter .Filters {
22
+ f := new (filter )
23
+
24
+ if s .CIDR != "" {
25
+ cidr , err := netip .ParsePrefix (s .CIDR )
26
+ if err != nil {
27
+ log .Errorf ("failed to parse CIDR %s: %v" , s .CIDR , err )
28
+ continue
39
29
}
30
+ f .CIDR = & cidr
31
+ }
40
32
41
- // Use a custom log format similar to Gin's default
42
- return defaultLogFormatter (param )
43
- },
44
- })
45
- }
33
+ if s .Path != "" {
34
+ f .Path = & s .Path
35
+ }
46
36
37
+ if s .Method != "" {
38
+ f .Method = & s .Method
39
+ }
47
40
48
- // shouldSkipLogging determines if a request should be skipped from logging
49
- func shouldSkipLogging (path , method string , config FilteredLoggerConfig ) bool {
50
- // Check if path should be skipped
51
- for _ , skipPath := range config .SkipPaths {
52
- if path == skipPath {
53
- return true
41
+ if f .CIDR == nil && f .Path == nil && f .Method == nil {
42
+ log .Warnf ("filter %s is empty, skipping" , s )
43
+ continue
54
44
}
45
+
46
+ filterList = append (filterList , f )
47
+ log .Debugf ("added filter: %+v" , f )
55
48
}
56
49
57
- // Check if method should be skipped
58
- for _ , skipMethod := range config .SkipMethods {
59
- if method == skipMethod {
60
- return true
50
+ log .Infof ("Loaded %d log filters." , len (filterList ))
51
+ }
52
+
53
+ func skiperDecider (c * gin.Context ) bool {
54
+ // every filter need metch all condithon as filter match
55
+ // so if any condithon not metch, skip this filter
56
+ // all filters misatch, log this request
57
+
58
+ for _ , f := range filterList {
59
+ if f .CIDR != nil {
60
+ cip := netip .MustParseAddr (c .ClientIP ())
61
+ if ! f .CIDR .Contains (cip ) {
62
+ continue
63
+ }
61
64
}
62
- }
63
65
64
- // Check if path prefix should be skipped
65
- for _ , skipPrefix := range config .SkipPathPrefixes {
66
- if strings .HasPrefix (path , skipPrefix ) {
67
- return true
66
+ if f .Path != nil {
67
+ if (* f .Path )[0 ] == '/' {
68
+ // match path as prefix/exact path
69
+ if ! strings .HasPrefix (c .Request .URL .Path , * f .Path ) {
70
+ continue
71
+ }
72
+ } else {
73
+ // match path as relative path
74
+ if ! strings .Contains (c .Request .URL .Path , "/" + * f .Path ) {
75
+ continue
76
+ }
77
+ }
78
+ }
79
+
80
+ if f .Method != nil {
81
+ if * f .Method != c .Request .Method {
82
+ continue
83
+ }
68
84
}
69
- }
70
85
71
- // Special case: Skip PROPFIND requests (common in WebDAV)
72
- if method == "PROPFIND" {
73
86
return true
74
87
}
75
88
76
89
return false
77
90
}
78
91
79
- // defaultLogFormatter provides a default log format similar to Gin's built-in formatter
80
- func defaultLogFormatter (param gin.LogFormatterParams ) string {
81
- var statusColor , methodColor , resetColor string
82
- if param .IsOutputColor () {
83
- statusColor = param .StatusCodeColor ()
84
- methodColor = param .MethodColor ()
85
- resetColor = param .ResetColor ()
86
- }
87
-
88
- if param .Latency > time .Minute {
89
- param .Latency = param .Latency .Truncate (time .Second )
90
- }
92
+ func FilteredLogger () gin.HandlerFunc {
93
+ initFilterList ()
91
94
92
- return fmt .Sprintf ("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n %s" ,
93
- param .TimeStamp .Format ("2006/01/02 - 15:04:05" ),
94
- statusColor , param .StatusCode , resetColor ,
95
- param .Latency ,
96
- param .ClientIP ,
97
- methodColor , param .Method , resetColor ,
98
- param .Path ,
99
- param .ErrorMessage ,
100
- )
101
- }
95
+ return gin .LoggerWithConfig (gin.LoggerConfig {
96
+ Output : log .StandardLogger ().Out ,
97
+ Skip : skiperDecider ,
98
+ })
99
+ }
0 commit comments