@marcel91200 / caddy Mirror · read-only / commits / 1aef807c
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 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 }