@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 309 lines 8.3 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package logging
16
17 import (
18 "time"
19
20 "go.uber.org/zap"
21 "go.uber.org/zap/buffer"
22 "go.uber.org/zap/zapcore"
23
24 "github.com/caddyserver/caddy/v2"
25 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
26 )
27
28 func init() {
29 caddy.RegisterModule(ConsoleEncoder{})
30 caddy.RegisterModule(JSONEncoder{})
31 }
32
33 // ConsoleEncoder encodes log entries that are mostly human-readable.
34 type ConsoleEncoder struct {
35 zapcore.Encoder `json:"-"`
36 LogEncoderConfig
37 }
38
39 // CaddyModule returns the Caddy module information.
40 func (ConsoleEncoder) CaddyModule() caddy.ModuleInfo {
41 return caddy.ModuleInfo{
42 ID: "caddy.logging.encoders.console",
43 New: func() caddy.Module { return new(ConsoleEncoder) },
44 }
45 }
46
47 // Provision sets up the encoder.
48 func (ce *ConsoleEncoder) Provision(_ caddy.Context) error {
49 if ce.LevelFormat == "" {
50 ce.LevelFormat = "color"
51 }
52 if ce.TimeFormat == "" {
53 ce.TimeFormat = "wall_milli"
54 }
55 ce.Encoder = zapcore.NewConsoleEncoder(ce.ZapcoreEncoderConfig())
56 return nil
57 }
58
59 // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
60 //
61 // console {
62 // <common encoder config subdirectives...>
63 // }
64 //
65 // See the godoc on the LogEncoderConfig type for the syntax of
66 // subdirectives that are common to most/all encoders.
67 func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
68 d.Next() // consume encoder name
69 if d.NextArg() {
70 return d.ArgErr()
71 }
72 err := ce.LogEncoderConfig.UnmarshalCaddyfile(d)
73 if err != nil {
74 return err
75 }
76 return nil
77 }
78
79 // JSONEncoder encodes entries as JSON.
80 type JSONEncoder struct {
81 zapcore.Encoder `json:"-"`
82 LogEncoderConfig
83 }
84
85 // CaddyModule returns the Caddy module information.
86 func (JSONEncoder) CaddyModule() caddy.ModuleInfo {
87 return caddy.ModuleInfo{
88 ID: "caddy.logging.encoders.json",
89 New: func() caddy.Module { return new(JSONEncoder) },
90 }
91 }
92
93 // Provision sets up the encoder.
94 func (je *JSONEncoder) Provision(_ caddy.Context) error {
95 je.Encoder = zapcore.NewJSONEncoder(je.ZapcoreEncoderConfig())
96 return nil
97 }
98
99 // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
100 //
101 // json {
102 // <common encoder config subdirectives...>
103 // }
104 //
105 // See the godoc on the LogEncoderConfig type for the syntax of
106 // subdirectives that are common to most/all encoders.
107 func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
108 d.Next() // consume encoder name
109 if d.NextArg() {
110 return d.ArgErr()
111 }
112 err := je.LogEncoderConfig.UnmarshalCaddyfile(d)
113 if err != nil {
114 return err
115 }
116 return nil
117 }
118
119 // LogEncoderConfig holds configuration common to most encoders.
120 type LogEncoderConfig struct {
121 MessageKey *string `json:"message_key,omitempty"`
122 LevelKey *string `json:"level_key,omitempty"`
123 TimeKey *string `json:"time_key,omitempty"`
124 NameKey *string `json:"name_key,omitempty"`
125 CallerKey *string `json:"caller_key,omitempty"`
126 StacktraceKey *string `json:"stacktrace_key,omitempty"`
127 LineEnding *string `json:"line_ending,omitempty"`
128
129 // Recognized values are: unix_seconds_float, unix_milli_float, unix_nano, iso8601, rfc3339, rfc3339_nano, wall, wall_milli, wall_nano, common_log.
130 // The value may also be custom format per the Go `time` package layout specification, as described [here](https://pkg.go.dev/time#pkg-constants).
131 TimeFormat string `json:"time_format,omitempty"`
132 TimeLocal bool `json:"time_local,omitempty"`
133
134 // Recognized values are: s/second/seconds, ns/nano/nanos, ms/milli/millis, string.
135 // Empty and unrecognized value default to seconds.
136 DurationFormat string `json:"duration_format,omitempty"`
137
138 // Recognized values are: lower, upper, color.
139 // Empty and unrecognized value default to lower.
140 LevelFormat string `json:"level_format,omitempty"`
141 }
142
143 // UnmarshalCaddyfile populates the struct from Caddyfile tokens. Syntax:
144 //
145 // {
146 // message_key <key>
147 // level_key <key>
148 // time_key <key>
149 // name_key <key>
150 // caller_key <key>
151 // stacktrace_key <key>
152 // line_ending <char>
153 // time_format <format>
154 // time_local
155 // duration_format <format>
156 // level_format <format>
157 // }
158 func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
159 for d.NextBlock(0) {
160 subdir := d.Val()
161 switch subdir {
162 case "time_local":
163 lec.TimeLocal = true
164 if d.NextArg() {
165 return d.ArgErr()
166 }
167 continue
168 }
169 var arg string
170 if !d.AllArgs(&arg) {
171 return d.ArgErr()
172 }
173 switch subdir {
174 case "message_key":
175 lec.MessageKey = &arg
176 case "level_key":
177 lec.LevelKey = &arg
178 case "time_key":
179 lec.TimeKey = &arg
180 case "name_key":
181 lec.NameKey = &arg
182 case "caller_key":
183 lec.CallerKey = &arg
184 case "stacktrace_key":
185 lec.StacktraceKey = &arg
186 case "line_ending":
187 lec.LineEnding = &arg
188 case "time_format":
189 lec.TimeFormat = arg
190 case "duration_format":
191 lec.DurationFormat = arg
192 case "level_format":
193 lec.LevelFormat = arg
194 default:
195 return d.Errf("unrecognized subdirective %s", subdir)
196 }
197 }
198 return nil
199 }
200
201 // ZapcoreEncoderConfig returns the equivalent zapcore.EncoderConfig.
202 // If lec is nil, zap.NewProductionEncoderConfig() is returned.
203 func (lec *LogEncoderConfig) ZapcoreEncoderConfig() zapcore.EncoderConfig {
204 cfg := zap.NewProductionEncoderConfig()
205 if lec == nil {
206 lec = new(LogEncoderConfig)
207 }
208 if lec.MessageKey != nil {
209 cfg.MessageKey = *lec.MessageKey
210 }
211 if lec.LevelKey != nil {
212 cfg.LevelKey = *lec.LevelKey
213 }
214 if lec.TimeKey != nil {
215 cfg.TimeKey = *lec.TimeKey
216 }
217 if lec.NameKey != nil {
218 cfg.NameKey = *lec.NameKey
219 }
220 if lec.CallerKey != nil {
221 cfg.CallerKey = *lec.CallerKey
222 }
223 if lec.StacktraceKey != nil {
224 cfg.StacktraceKey = *lec.StacktraceKey
225 }
226 if lec.LineEnding != nil {
227 cfg.LineEnding = *lec.LineEnding
228 }
229
230 // time format
231 var timeFormatter zapcore.TimeEncoder
232 switch lec.TimeFormat {
233 case "", "unix_seconds_float":
234 timeFormatter = zapcore.EpochTimeEncoder
235 case "unix_milli_float":
236 timeFormatter = zapcore.EpochMillisTimeEncoder
237 case "unix_nano":
238 timeFormatter = zapcore.EpochNanosTimeEncoder
239 case "iso8601":
240 timeFormatter = zapcore.ISO8601TimeEncoder
241 default:
242 timeFormat := lec.TimeFormat
243 switch lec.TimeFormat {
244 case "rfc3339":
245 timeFormat = time.RFC3339
246 case "rfc3339_nano":
247 timeFormat = time.RFC3339Nano
248 case "wall":
249 timeFormat = "2006/01/02 15:04:05"
250 case "wall_milli":
251 timeFormat = "2006/01/02 15:04:05.000"
252 case "wall_nano":
253 timeFormat = "2006/01/02 15:04:05.000000000"
254 case "common_log":
255 timeFormat = "02/Jan/2006:15:04:05 -0700"
256 }
257 timeFormatter = func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) {
258 var time time.Time
259 if lec.TimeLocal {
260 time = ts.Local()
261 } else {
262 time = ts.UTC()
263 }
264 encoder.AppendString(time.Format(timeFormat))
265 }
266 }
267 cfg.EncodeTime = timeFormatter
268
269 // duration format
270 var durFormatter zapcore.DurationEncoder
271 switch lec.DurationFormat {
272 case "s", "second", "seconds":
273 durFormatter = zapcore.SecondsDurationEncoder
274 case "ns", "nano", "nanos":
275 durFormatter = zapcore.NanosDurationEncoder
276 case "ms", "milli", "millis":
277 durFormatter = zapcore.MillisDurationEncoder
278 case "string":
279 durFormatter = zapcore.StringDurationEncoder
280 default:
281 durFormatter = zapcore.SecondsDurationEncoder
282 }
283 cfg.EncodeDuration = durFormatter
284
285 // level format
286 var levelFormatter zapcore.LevelEncoder
287 switch lec.LevelFormat {
288 case "", "lower":
289 levelFormatter = zapcore.LowercaseLevelEncoder
290 case "upper":
291 levelFormatter = zapcore.CapitalLevelEncoder
292 case "color":
293 levelFormatter = zapcore.CapitalColorLevelEncoder
294 }
295 cfg.EncodeLevel = levelFormatter
296
297 return cfg
298 }
299
300 var bufferpool = buffer.NewPool()
301
302 // Interface guards
303 var (
304 _ zapcore.Encoder = (*ConsoleEncoder)(nil)
305 _ zapcore.Encoder = (*JSONEncoder)(nil)
306
307 _ caddyfile.Unmarshaler = (*ConsoleEncoder)(nil)
308 _ caddyfile.Unmarshaler = (*JSONEncoder)(nil)
309 )