Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 04:15 UTC
log: Make sink logs encodable (#5441)
* log: make `sink` encodable * deduplicate logger fields * extract common fields into `BaseLog` and embed it into `SinkLog` * amend godoc on `BaseLog` and `SinkLog` * minor style change --------- Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Mohammed Al Sahaf committed
Mar 28, 2023 at 00:41 UTC
1aef807c71b1ea8e70e664765e0010734aee468c
5 files changed
+106
-112
caddyconfig/httpcaddyfile/httptype.go
+3
-1
@@ -241,7 +241,9 @@ func (st ServerType) Setup(inputServerBlocks []caddyfile.ServerBlock,
241
if _, ok := options["debug"]; ok {
242
customLogs = append(customLogs, namedCustomLog{
243
name: caddy.DefaultLoggerName,
244
- log: &caddy.CustomLog{Level: zap.DebugLevel.CapitalString()},
244
+ log: &caddy.CustomLog{
245
+ BaseLog: caddy.BaseLog{Level: zap.DebugLevel.CapitalString()},
246
+ },
247
})
248
}
249
}
logging.go
+98
-108
@@ -62,7 +62,7 @@ type Logging struct {
62
// in dependencies that are not designed specifically for use
63
// in Caddy. Because it is global and unstructured, the sink
64
// lacks most advanced features and customizations.
65
- Sink *StandardLibLog `json:"sink,omitempty"`
65
+ Sink *SinkLog `json:"sink,omitempty"`
66
67
// Logs are your logs, keyed by an arbitrary name of your
68
// choosing. The default log can be customized by defining
@@ -259,55 +259,11 @@ func (wdest writerDestructor) Destruct() error {
259
return wdest.Close()
260
}
261
262
-// StandardLibLog configures the default Go standard library
263
-// global logger in the log package. This is necessary because
264
-// module dependencies which are not built specifically for
265
-// Caddy will use the standard logger. This is also known as
266
-// the "sink" logger.
267
-type StandardLibLog struct {
262
+// BaseLog contains the common logging parameters for logging.
263
+type BaseLog struct {
264
// The module that writes out log entries for the sink.
265
WriterRaw json.RawMessage `json:"writer,omitempty" caddy:"namespace=caddy.logging.writers inline_key=output"`
266
271
- writer io.WriteCloser
272
-}
273
-
274
-func (sll *StandardLibLog) provision(ctx Context, logging *Logging) error {
275
- if sll.WriterRaw != nil {
276
- mod, err := ctx.LoadModule(sll, "WriterRaw")
277
- if err != nil {
278
- return fmt.Errorf("loading sink log writer module: %v", err)
279
- }
280
- wo := mod.(WriterOpener)
281
-
282
- var isNew bool
283
- sll.writer, isNew, err = logging.openWriter(wo)
284
- if err != nil {
285
- return fmt.Errorf("opening sink log writer %#v: %v", mod, err)
286
- }
287
-
288
- if isNew {
289
- log.Printf("[INFO] Redirecting sink to: %s", wo)
290
- log.SetOutput(sll.writer)
291
- log.Printf("[INFO] Redirected sink to here (%s)", wo)
292
- }
293
- }
294
-
295
- return nil
296
-}
297
-
298
-// CustomLog represents a custom logger configuration.
299
-//
300
-// By default, a log will emit all log entries. Some entries
301
-// will be skipped if sampling is enabled. Further, the Include
302
-// and Exclude parameters define which loggers (by name) are
303
-// allowed or rejected from emitting in this log. If both Include
304
-// and Exclude are populated, their values must be mutually
305
-// exclusive, and longer namespaces have priority. If neither
306
-// are populated, all logs are emitted.
307
-type CustomLog struct {
308
- // The writer defines where log entries are emitted.
309
- WriterRaw json.RawMessage `json:"writer,omitempty" caddy:"namespace=caddy.logging.writers inline_key=output"`
310
-
267
// The encoder is how the log entries are formatted or encoded.
268
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
269
@@ -321,16 +277,6 @@ type CustomLog struct {
277
// servers.
278
Sampling *LogSampling `json:"sampling,omitempty"`
279
324
- // Include defines the names of loggers to emit in this
325
- // log. For example, to include only logs emitted by the
326
- // admin API, you would include "admin.api".
327
- Include []string `json:"include,omitempty"`
328
-
329
- // Exclude defines the names of loggers that should be
330
- // skipped by this log. For example, to exclude only
331
- // HTTP access logs, you would exclude "http.log.access".
332
- Exclude []string `json:"exclude,omitempty"`
333
-
280
writerOpener WriterOpener
281
writer io.WriteCloser
282
encoder zapcore.Encoder
@@ -338,8 +284,23 @@ type CustomLog struct {
284
core zapcore.Core
285
}
286
341
-func (cl *CustomLog) provision(ctx Context, logging *Logging) error {
342
- // Replace placeholder for log level
287
+func (cl *BaseLog) provisionCommon(ctx Context, logging *Logging) error {
288
+ if cl.WriterRaw != nil {
289
+ mod, err := ctx.LoadModule(cl, "WriterRaw")
290
+ if err != nil {
291
+ return fmt.Errorf("loading log writer module: %v", err)
292
+ }
293
+ cl.writerOpener = mod.(WriterOpener)
294
+ }
295
+ if cl.writerOpener == nil {
296
+ cl.writerOpener = StderrWriter{}
297
+ }
298
+ var err error
299
+ cl.writer, _, err = logging.openWriter(cl.writerOpener)
300
+ if err != nil {
301
+ return fmt.Errorf("opening log writer using %#v: %v", cl.writerOpener, err)
302
+ }
303
+
304
repl := NewReplacer()
305
level, err := repl.ReplaceOrErr(cl.Level, true, true)
306
if err != nil {
@@ -365,52 +326,6 @@ func (cl *CustomLog) provision(ctx Context, logging *Logging) error {
326
return fmt.Errorf("unrecognized log level: %s", cl.Level)
327
}
328
368
- // If both Include and Exclude lists are populated, then each item must
369
- // be a superspace or subspace of an item in the other list, because
370
- // populating both lists means that any given item is either a rule
371
- // or an exception to another rule. But if the item is not a super-
372
- // or sub-space of any item in the other list, it is neither a rule
373
- // nor an exception, and is a contradiction. Ensure, too, that the
374
- // sets do not intersect, which is also a contradiction.
375
- if len(cl.Include) > 0 && len(cl.Exclude) > 0 {
376
- // prevent intersections
377
- for _, allow := range cl.Include {
378
- for _, deny := range cl.Exclude {
379
- if allow == deny {
380
- return fmt.Errorf("include and exclude must not intersect, but found %s in both lists", allow)
381
- }
382
- }
383
- }
384
-
385
- // ensure namespaces are nested
386
- outer:
387
- for _, allow := range cl.Include {
388
- for _, deny := range cl.Exclude {
389
- if strings.HasPrefix(allow+".", deny+".") ||
390
- strings.HasPrefix(deny+".", allow+".") {
391
- continue outer
392
- }
393
- }
394
- return fmt.Errorf("when both include and exclude are populated, each element must be a superspace or subspace of one in the other list; check '%s' in include", allow)
395
- }
396
- }
397
-
398
- if cl.WriterRaw != nil {
399
- mod, err := ctx.LoadModule(cl, "WriterRaw")
400
- if err != nil {
401
- return fmt.Errorf("loading log writer module: %v", err)
402
- }
403
- cl.writerOpener = mod.(WriterOpener)
404
- }
405
- if cl.writerOpener == nil {
406
- cl.writerOpener = StderrWriter{}
407
- }
408
-
409
- cl.writer, _, err = logging.openWriter(cl.writerOpener)
410
- if err != nil {
411
- return fmt.Errorf("opening log writer using %#v: %v", cl.writerOpener, err)
412
- }
413
-
329
if cl.EncoderRaw != nil {
330
mod, err := ctx.LoadModule(cl, "EncoderRaw")
331
if err != nil {
@@ -428,13 +343,11 @@ func (cl *CustomLog) provision(ctx Context, logging *Logging) error {
343
}
344
cl.encoder = newDefaultProductionLogEncoder(colorize)
345
}
431
-
346
cl.buildCore()
433
-
347
return nil
348
}
349
437
-func (cl *CustomLog) buildCore() {
350
+func (cl *BaseLog) buildCore() {
351
// logs which only discard their output don't need
352
// to perform encoding or any other processing steps
353
// at all, so just shorcut to a nop core instead
@@ -463,6 +376,83 @@ func (cl *CustomLog) buildCore() {
376
cl.core = c
377
}
378
379
+// SinkLog configures the default Go standard library
380
+// global logger in the log package. This is necessary because
381
+// module dependencies which are not built specifically for
382
+// Caddy will use the standard logger. This is also known as
383
+// the "sink" logger.
384
+type SinkLog struct {
385
+ BaseLog
386
+}
387
+
388
+func (sll *SinkLog) provision(ctx Context, logging *Logging) error {
389
+ if err := sll.provisionCommon(ctx, logging); err != nil {
390
+ return err
391
+ }
392
+ ctx.cleanupFuncs = append(ctx.cleanupFuncs, zap.RedirectStdLog(zap.New(sll.core)))
393
+ return nil
394
+}
395
+
396
+// CustomLog represents a custom logger configuration.
397
+//
398
+// By default, a log will emit all log entries. Some entries
399
+// will be skipped if sampling is enabled. Further, the Include
400
+// and Exclude parameters define which loggers (by name) are
401
+// allowed or rejected from emitting in this log. If both Include
402
+// and Exclude are populated, their values must be mutually
403
+// exclusive, and longer namespaces have priority. If neither
404
+// are populated, all logs are emitted.
405
+type CustomLog struct {
406
+ BaseLog
407
+
408
+ // Include defines the names of loggers to emit in this
409
+ // log. For example, to include only logs emitted by the
410
+ // admin API, you would include "admin.api".
411
+ Include []string `json:"include,omitempty"`
412
+
413
+ // Exclude defines the names of loggers that should be
414
+ // skipped by this log. For example, to exclude only
415
+ // HTTP access logs, you would exclude "http.log.access".
416
+ Exclude []string `json:"exclude,omitempty"`
417
+}
418
+
419
+func (cl *CustomLog) provision(ctx Context, logging *Logging) error {
420
+ if err := cl.provisionCommon(ctx, logging); err != nil {
421
+ return err
422
+ }
423
+
424
+ // If both Include and Exclude lists are populated, then each item must
425
+ // be a superspace or subspace of an item in the other list, because
426
+ // populating both lists means that any given item is either a rule
427
+ // or an exception to another rule. But if the item is not a super-
428
+ // or sub-space of any item in the other list, it is neither a rule
429
+ // nor an exception, and is a contradiction. Ensure, too, that the
430
+ // sets do not intersect, which is also a contradiction.
431
+ if len(cl.Include) > 0 && len(cl.Exclude) > 0 {
432
+ // prevent intersections
433
+ for _, allow := range cl.Include {
434
+ for _, deny := range cl.Exclude {
435
+ if allow == deny {
436
+ return fmt.Errorf("include and exclude must not intersect, but found %s in both lists", allow)
437
+ }
438
+ }
439
+ }
440
+
441
+ // ensure namespaces are nested
442
+ outer:
443
+ for _, allow := range cl.Include {
444
+ for _, deny := range cl.Exclude {
445
+ if strings.HasPrefix(allow+".", deny+".") ||
446
+ strings.HasPrefix(deny+".", allow+".") {
447
+ continue outer
448
+ }
449
+ }
450
+ return fmt.Errorf("when both include and exclude are populated, each element must be a superspace or subspace of one in the other list; check '%s' in include", allow)
451
+ }
452
+ }
453
+ return nil
454
+}
455
+
456
func (cl *CustomLog) matchesModule(moduleID string) bool {
457
return cl.loggerAllowed(moduleID, true)
458
}
modules/caddyhttp/fileserver/command.go
+3
-1
@@ -134,7 +134,9 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) {
134
if debug {
135
cfg.Logging = &caddy.Logging{
136
Logs: map[string]*caddy.CustomLog{
137
- "default": {Level: zap.DebugLevel.CapitalString()},
137
+ "default": {
138
+ BaseLog: caddy.BaseLog{Level: zap.DebugLevel.CapitalString()},
139
+ },
140
},
141
}
142
}
modules/caddyhttp/reverseproxy/command.go
+1
-1
@@ -280,7 +280,7 @@ func cmdReverseProxy(fs caddycmd.Flags) (int, error) {
280
if debug {
281
cfg.Logging = &caddy.Logging{
282
Logs: map[string]*caddy.CustomLog{
283
- "default": {Level: zap.DebugLevel.CapitalString()},
283
+ "default": {BaseLog: caddy.BaseLog{Level: zap.DebugLevel.CapitalString()}},
284
},
285
}
286
}
modules/caddyhttp/staticresp.go
+1
-1
@@ -407,7 +407,7 @@ func cmdRespond(fl caddycmd.Flags) (int, error) {
407
if debug {
408
cfg.Logging = &caddy.Logging{
409
Logs: map[string]*caddy.CustomLog{
410
- "default": {Level: zap.DebugLevel.CapitalString()},
410
+ "default": {BaseLog: caddy.BaseLog{Level: zap.DebugLevel.CapitalString()}},
411
},
412
}
413
}