forked from traefik/traefik
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logs.go
200 lines (165 loc) · 6.63 KB
/
logs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package types
import (
"fmt"
"strings"
"github.com/containous/flaeg/parse"
)
const (
// AccessLogKeep is the keep string value
AccessLogKeep = "keep"
// AccessLogDrop is the drop string value
AccessLogDrop = "drop"
// AccessLogRedact is the redact string value
AccessLogRedact = "redact"
)
// TraefikLog holds the configuration settings for the traefik logger.
type TraefikLog struct {
FilePath string `json:"file,omitempty" description:"Traefik log file path. Stdout is used when omitted or empty"`
Format string `json:"format,omitempty" description:"Traefik log format: json | common"`
}
// AccessLog holds the configuration settings for the access logger (middlewares/accesslog).
type AccessLog struct {
FilePath string `json:"file,omitempty" description:"Access log file path. Stdout is used when omitted or empty" export:"true"`
Format string `json:"format,omitempty" description:"Access log format: json | common" export:"true"`
Filters *AccessLogFilters `json:"filters,omitempty" description:"Access log filters, used to keep only specific access logs" export:"true"`
Fields *AccessLogFields `json:"fields,omitempty" description:"AccessLogFields" export:"true"`
BufferingSize int64 `json:"bufferingSize,omitempty" description:"Number of access log lines to process in a buffered way. Default 0." export:"true"`
}
// AccessLogFilters holds filters configuration
type AccessLogFilters struct {
StatusCodes StatusCodes `json:"statusCodes,omitempty" description:"Keep access logs with status codes in the specified range" export:"true"`
RetryAttempts bool `json:"retryAttempts,omitempty" description:"Keep access logs when at least one retry happened" export:"true"`
MinDuration parse.Duration `json:"duration,omitempty" description:"Keep access logs when request took longer than the specified duration" export:"true"`
}
// FieldHeaders holds configuration for access log headers
type FieldHeaders struct {
DefaultMode string `json:"defaultMode,omitempty" description:"Default mode for fields: keep | drop | redact" export:"true"`
Names FieldHeaderNames `json:"names,omitempty" description:"Override mode for headers" export:"true"`
}
// StatusCodes holds status codes ranges to filter access log
type StatusCodes []string
// Set adds strings elem into the the parser
// it splits str on , and ;
func (s *StatusCodes) Set(str string) error {
fargs := func(c rune) bool {
return c == ',' || c == ';'
}
// get function
slice := strings.FieldsFunc(str, fargs)
*s = append(*s, slice...)
return nil
}
// Get StatusCodes
func (s *StatusCodes) Get() interface{} { return *s }
// String return slice in a string
func (s *StatusCodes) String() string { return fmt.Sprintf("%v", *s) }
// SetValue sets StatusCodes into the parser
func (s *StatusCodes) SetValue(val interface{}) {
*s = val.(StatusCodes)
}
// FieldNames holds maps of fields with specific mode
type FieldNames map[string]string
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (f *FieldNames) String() string {
return fmt.Sprintf("%+v", *f)
}
// Get return the FieldNames map
func (f *FieldNames) Get() interface{} {
return *f
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a space-separated list, so we split it.
func (f *FieldNames) Set(value string) error {
// When arguments are passed through YAML, escaped double quotes
// might be added to this string, and they would break the last
// key/value pair. This ensures the string is clean.
value = strings.Trim(value, "\"")
fields := strings.Fields(value)
for _, field := range fields {
n := strings.SplitN(field, "=", 2)
if len(n) == 2 {
(*f)[n[0]] = n[1]
}
}
return nil
}
// SetValue sets the FieldNames map with val
func (f *FieldNames) SetValue(val interface{}) {
*f = val.(FieldNames)
}
// FieldHeaderNames holds maps of fields with specific mode
type FieldHeaderNames map[string]string
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (f *FieldHeaderNames) String() string {
return fmt.Sprintf("%+v", *f)
}
// Get return the FieldHeaderNames map
func (f *FieldHeaderNames) Get() interface{} {
return *f
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a space-separated list, so we split it.
func (f *FieldHeaderNames) Set(value string) error {
// When arguments are passed through YAML, escaped double quotes
// might be added to this string, and they would break the last
// key/value pair. This ensures the string is clean.
value = strings.Trim(value, "\"")
fields := strings.Fields(value)
for _, field := range fields {
n := strings.SplitN(field, "=", 2)
(*f)[n[0]] = n[1]
}
return nil
}
// SetValue sets the FieldHeaderNames map with val
func (f *FieldHeaderNames) SetValue(val interface{}) {
*f = val.(FieldHeaderNames)
}
// AccessLogFields holds configuration for access log fields
type AccessLogFields struct {
DefaultMode string `json:"defaultMode,omitempty" description:"Default mode for fields: keep | drop" export:"true"`
Names FieldNames `json:"names,omitempty" description:"Override mode for fields" export:"true"`
Headers *FieldHeaders `json:"headers,omitempty" description:"Headers to keep, drop or redact" export:"true"`
}
// Keep check if the field need to be kept or dropped
func (f *AccessLogFields) Keep(field string) bool {
defaultKeep := true
if f != nil {
defaultKeep = checkFieldValue(f.DefaultMode, defaultKeep)
if v, ok := f.Names[field]; ok {
return checkFieldValue(v, defaultKeep)
}
}
return defaultKeep
}
// KeepHeader checks if the headers need to be kept, dropped or redacted and returns the status
func (f *AccessLogFields) KeepHeader(header string) string {
defaultValue := AccessLogKeep
if f != nil && f.Headers != nil {
defaultValue = checkFieldHeaderValue(f.Headers.DefaultMode, defaultValue)
if v, ok := f.Headers.Names[header]; ok {
return checkFieldHeaderValue(v, defaultValue)
}
}
return defaultValue
}
func checkFieldValue(value string, defaultKeep bool) bool {
switch value {
case AccessLogKeep:
return true
case AccessLogDrop:
return false
default:
return defaultKeep
}
}
func checkFieldHeaderValue(value string, defaultValue string) string {
if value == AccessLogKeep || value == AccessLogDrop || value == AccessLogRedact {
return value
}
return defaultValue
}