| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | // Copyright 2015 Matthew Holt and The Caddy Authors | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | // You may obtain a copy of the License at | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and | 
					
						
							|  |  |  | // limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package logging | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2" | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | 	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	"go.uber.org/zap" | 
					
						
							|  |  |  | 	"go.uber.org/zap/buffer" | 
					
						
							|  |  |  | 	"go.uber.org/zap/zapcore" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	caddy.RegisterModule(ConsoleEncoder{}) | 
					
						
							|  |  |  | 	caddy.RegisterModule(JSONEncoder{}) | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | 	caddy.RegisterModule(SingleFieldEncoder{}) | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ConsoleEncoder encodes log entries that are mostly human-readable. | 
					
						
							|  |  |  | type ConsoleEncoder struct { | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	zapcore.Encoder `json:"-"` | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	LogEncoderConfig | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CaddyModule returns the Caddy module information. | 
					
						
							|  |  |  | func (ConsoleEncoder) CaddyModule() caddy.ModuleInfo { | 
					
						
							|  |  |  | 	return caddy.ModuleInfo{ | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 		ID:  "caddy.logging.encoders.console", | 
					
						
							|  |  |  | 		New: func() caddy.Module { return new(ConsoleEncoder) }, | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Provision sets up the encoder. | 
					
						
							|  |  |  | func (ce *ConsoleEncoder) Provision(_ caddy.Context) error { | 
					
						
							|  |  |  | 	ce.Encoder = zapcore.NewConsoleEncoder(ce.ZapcoreEncoderConfig()) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     console { | 
					
						
							|  |  |  | //         <common encoder config subdirectives...> | 
					
						
							|  |  |  | //     } | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // See the godoc on the LogEncoderConfig type for the syntax of | 
					
						
							|  |  |  | // subdirectives that are common to most/all encoders. | 
					
						
							|  |  |  | func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { | 
					
						
							|  |  |  | 	for d.Next() { | 
					
						
							|  |  |  | 		if d.NextArg() { | 
					
						
							|  |  |  | 			return d.ArgErr() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err := ce.LogEncoderConfig.UnmarshalCaddyfile(d) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | // JSONEncoder encodes entries as JSON. | 
					
						
							|  |  |  | type JSONEncoder struct { | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	zapcore.Encoder `json:"-"` | 
					
						
							|  |  |  | 	LogEncoderConfig | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CaddyModule returns the Caddy module information. | 
					
						
							|  |  |  | func (JSONEncoder) CaddyModule() caddy.ModuleInfo { | 
					
						
							|  |  |  | 	return caddy.ModuleInfo{ | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 		ID:  "caddy.logging.encoders.json", | 
					
						
							|  |  |  | 		New: func() caddy.Module { return new(JSONEncoder) }, | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Provision sets up the encoder. | 
					
						
							|  |  |  | func (je *JSONEncoder) Provision(_ caddy.Context) error { | 
					
						
							|  |  |  | 	je.Encoder = zapcore.NewJSONEncoder(je.ZapcoreEncoderConfig()) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     json { | 
					
						
							|  |  |  | //         <common encoder config subdirectives...> | 
					
						
							|  |  |  | //     } | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // See the godoc on the LogEncoderConfig type for the syntax of | 
					
						
							|  |  |  | // subdirectives that are common to most/all encoders. | 
					
						
							|  |  |  | func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { | 
					
						
							|  |  |  | 	for d.Next() { | 
					
						
							|  |  |  | 		if d.NextArg() { | 
					
						
							|  |  |  | 			return d.ArgErr() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err := je.LogEncoderConfig.UnmarshalCaddyfile(d) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SingleFieldEncoder writes a log entry that consists entirely | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | // of a single string field in the log entry. This is useful | 
					
						
							|  |  |  | // for custom, self-encoded log entries that consist of a | 
					
						
							|  |  |  | // single field in the structured log entry. | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | type SingleFieldEncoder struct { | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	zapcore.Encoder `json:"-"` | 
					
						
							|  |  |  | 	FieldName       string          `json:"field,omitempty"` | 
					
						
							|  |  |  | 	FallbackRaw     json.RawMessage `json:"fallback,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"` | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CaddyModule returns the Caddy module information. | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | func (SingleFieldEncoder) CaddyModule() caddy.ModuleInfo { | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	return caddy.ModuleInfo{ | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | 		ID:  "caddy.logging.encoders.single_field", | 
					
						
							|  |  |  | 		New: func() caddy.Module { return new(SingleFieldEncoder) }, | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Provision sets up the encoder. | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | func (se *SingleFieldEncoder) Provision(ctx caddy.Context) error { | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	if se.FallbackRaw != nil { | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 		val, err := ctx.LoadModule(se, "FallbackRaw") | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return fmt.Errorf("loading fallback encoder module: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		se.Encoder = val.(zapcore.Encoder) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if se.Encoder == nil { | 
					
						
							|  |  |  | 		se.Encoder = nopEncoder{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Clone wraps the underlying encoder's Clone. This is | 
					
						
							|  |  |  | // necessary because we implement our own EncodeEntry, | 
					
						
							|  |  |  | // and if we simply let the embedded encoder's Clone | 
					
						
							|  |  |  | // be promoted, it would return a clone of that, and | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | // we'd lose our SingleFieldEncoder's EncodeEntry. | 
					
						
							|  |  |  | func (se SingleFieldEncoder) Clone() zapcore.Encoder { | 
					
						
							|  |  |  | 	return SingleFieldEncoder{ | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 		Encoder:   se.Encoder.Clone(), | 
					
						
							|  |  |  | 		FieldName: se.FieldName, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // EncodeEntry partially implements the zapcore.Encoder interface. | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | func (se SingleFieldEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	for _, f := range fields { | 
					
						
							|  |  |  | 		if f.Key == se.FieldName { | 
					
						
							|  |  |  | 			buf := bufferpool.Get() | 
					
						
							|  |  |  | 			buf.AppendString(f.String) | 
					
						
							|  |  |  | 			if !strings.HasSuffix(f.String, "\n") { | 
					
						
							|  |  |  | 				buf.AppendByte('\n') | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return buf, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if se.Encoder == nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("no fallback encoder defined") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return se.Encoder.EncodeEntry(ent, fields) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | // UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     single_field <field_name> | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | func (se *SingleFieldEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { | 
					
						
							|  |  |  | 	for d.Next() { | 
					
						
							|  |  |  | 		var fieldName string | 
					
						
							|  |  |  | 		if !d.AllArgs(&fieldName) { | 
					
						
							|  |  |  | 			return d.ArgErr() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		se.FieldName = d.Val() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | // LogEncoderConfig holds configuration common to most encoders. | 
					
						
							|  |  |  | type LogEncoderConfig struct { | 
					
						
							|  |  |  | 	MessageKey     *string `json:"message_key,omitempty"` | 
					
						
							|  |  |  | 	LevelKey       *string `json:"level_key,omitempty"` | 
					
						
							|  |  |  | 	TimeKey        *string `json:"time_key,omitempty"` | 
					
						
							|  |  |  | 	NameKey        *string `json:"name_key,omitempty"` | 
					
						
							|  |  |  | 	CallerKey      *string `json:"caller_key,omitempty"` | 
					
						
							|  |  |  | 	StacktraceKey  *string `json:"stacktrace_key,omitempty"` | 
					
						
							|  |  |  | 	LineEnding     *string `json:"line_ending,omitempty"` | 
					
						
							|  |  |  | 	TimeFormat     string  `json:"time_format,omitempty"` | 
					
						
							|  |  |  | 	DurationFormat string  `json:"duration_format,omitempty"` | 
					
						
							|  |  |  | 	LevelFormat    string  `json:"level_format,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | // UnmarshalCaddyfile populates the struct from Caddyfile tokens. Syntax: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     { | 
					
						
							|  |  |  | //         message_key <key> | 
					
						
							|  |  |  | //         level_key   <key> | 
					
						
							|  |  |  | //         time_key    <key> | 
					
						
							|  |  |  | //         name_key    <key> | 
					
						
							|  |  |  | //         caller_key  <key> | 
					
						
							|  |  |  | //         stacktrace_key <key> | 
					
						
							|  |  |  | //         line_ending  <char> | 
					
						
							|  |  |  | //         time_format  <format> | 
					
						
							|  |  |  | //         level_format <format> | 
					
						
							|  |  |  | //     } | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { | 
					
						
							|  |  |  | 	for nesting := d.Nesting(); d.NextBlock(nesting); { | 
					
						
							|  |  |  | 		subdir := d.Val() | 
					
						
							|  |  |  | 		var arg string | 
					
						
							|  |  |  | 		if !d.AllArgs(&arg) { | 
					
						
							|  |  |  | 			return d.ArgErr() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		switch subdir { | 
					
						
							|  |  |  | 		case "message_key": | 
					
						
							|  |  |  | 			lec.MessageKey = &arg | 
					
						
							|  |  |  | 		case "level_key": | 
					
						
							|  |  |  | 			lec.LevelKey = &arg | 
					
						
							|  |  |  | 		case "time_key": | 
					
						
							|  |  |  | 			lec.TimeKey = &arg | 
					
						
							|  |  |  | 		case "name_key": | 
					
						
							|  |  |  | 			lec.NameKey = &arg | 
					
						
							|  |  |  | 		case "caller_key": | 
					
						
							|  |  |  | 			lec.CallerKey = &arg | 
					
						
							|  |  |  | 		case "stacktrace_key": | 
					
						
							|  |  |  | 			lec.StacktraceKey = &arg | 
					
						
							|  |  |  | 		case "line_ending": | 
					
						
							|  |  |  | 			lec.LineEnding = &arg | 
					
						
							|  |  |  | 		case "time_format": | 
					
						
							|  |  |  | 			lec.TimeFormat = arg | 
					
						
							|  |  |  | 		case "level_format": | 
					
						
							|  |  |  | 			lec.LevelFormat = arg | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return d.Errf("unrecognized subdirective %s", subdir) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | // ZapcoreEncoderConfig returns the equivalent zapcore.EncoderConfig. | 
					
						
							|  |  |  | // If lec is nil, zap.NewProductionEncoderConfig() is returned. | 
					
						
							|  |  |  | func (lec *LogEncoderConfig) ZapcoreEncoderConfig() zapcore.EncoderConfig { | 
					
						
							|  |  |  | 	cfg := zap.NewProductionEncoderConfig() | 
					
						
							|  |  |  | 	if lec == nil { | 
					
						
							|  |  |  | 		lec = new(LogEncoderConfig) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lec.MessageKey != nil { | 
					
						
							|  |  |  | 		cfg.MessageKey = *lec.MessageKey | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-04 16:15:43 -04:00
										 |  |  | 	if lec.LevelKey != nil { | 
					
						
							|  |  |  | 		cfg.LevelKey = *lec.LevelKey | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 	if lec.TimeKey != nil { | 
					
						
							|  |  |  | 		cfg.TimeKey = *lec.TimeKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lec.NameKey != nil { | 
					
						
							|  |  |  | 		cfg.NameKey = *lec.NameKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lec.CallerKey != nil { | 
					
						
							|  |  |  | 		cfg.CallerKey = *lec.CallerKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lec.StacktraceKey != nil { | 
					
						
							|  |  |  | 		cfg.StacktraceKey = *lec.StacktraceKey | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lec.LineEnding != nil { | 
					
						
							|  |  |  | 		cfg.LineEnding = *lec.LineEnding | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// time format | 
					
						
							|  |  |  | 	var timeFormatter zapcore.TimeEncoder | 
					
						
							|  |  |  | 	switch lec.TimeFormat { | 
					
						
							|  |  |  | 	case "", "unix_seconds_float": | 
					
						
							|  |  |  | 		timeFormatter = zapcore.EpochTimeEncoder | 
					
						
							|  |  |  | 	case "unix_milli_float": | 
					
						
							|  |  |  | 		timeFormatter = zapcore.EpochMillisTimeEncoder | 
					
						
							|  |  |  | 	case "unix_nano": | 
					
						
							|  |  |  | 		timeFormatter = zapcore.EpochNanosTimeEncoder | 
					
						
							|  |  |  | 	case "iso8601": | 
					
						
							|  |  |  | 		timeFormatter = zapcore.ISO8601TimeEncoder | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		timeFormat := lec.TimeFormat | 
					
						
							|  |  |  | 		switch lec.TimeFormat { | 
					
						
							|  |  |  | 		case "rfc3339": | 
					
						
							|  |  |  | 			timeFormat = time.RFC3339 | 
					
						
							|  |  |  | 		case "rfc3339_nano": | 
					
						
							|  |  |  | 			timeFormat = time.RFC3339Nano | 
					
						
							|  |  |  | 		case "wall": | 
					
						
							|  |  |  | 			timeFormat = "2006/01/02 15:04:05" | 
					
						
							|  |  |  | 		case "wall_milli": | 
					
						
							|  |  |  | 			timeFormat = "2006/01/02 15:04:05.000" | 
					
						
							|  |  |  | 		case "wall_nano": | 
					
						
							|  |  |  | 			timeFormat = "2006/01/02 15:04:05.000000000" | 
					
						
							| 
									
										
										
										
											2021-07-14 13:07:38 -04:00
										 |  |  | 		case "common_log": | 
					
						
							|  |  |  | 			timeFormat = "02/Jan/2006:15:04:05 -0700" | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		timeFormatter = func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) { | 
					
						
							|  |  |  | 			encoder.AppendString(ts.UTC().Format(timeFormat)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cfg.EncodeTime = timeFormatter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// duration format | 
					
						
							|  |  |  | 	var durFormatter zapcore.DurationEncoder | 
					
						
							|  |  |  | 	switch lec.DurationFormat { | 
					
						
							|  |  |  | 	case "", "seconds": | 
					
						
							|  |  |  | 		durFormatter = zapcore.SecondsDurationEncoder | 
					
						
							|  |  |  | 	case "nano": | 
					
						
							|  |  |  | 		durFormatter = zapcore.NanosDurationEncoder | 
					
						
							|  |  |  | 	case "string": | 
					
						
							|  |  |  | 		durFormatter = zapcore.StringDurationEncoder | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cfg.EncodeDuration = durFormatter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// level format | 
					
						
							|  |  |  | 	var levelFormatter zapcore.LevelEncoder | 
					
						
							|  |  |  | 	switch lec.LevelFormat { | 
					
						
							|  |  |  | 	case "", "lower": | 
					
						
							|  |  |  | 		levelFormatter = zapcore.LowercaseLevelEncoder | 
					
						
							|  |  |  | 	case "upper": | 
					
						
							|  |  |  | 		levelFormatter = zapcore.CapitalLevelEncoder | 
					
						
							|  |  |  | 	case "color": | 
					
						
							|  |  |  | 		levelFormatter = zapcore.CapitalColorLevelEncoder | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cfg.EncodeLevel = levelFormatter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var bufferpool = buffer.NewPool() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Interface guards | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	_ zapcore.Encoder = (*ConsoleEncoder)(nil) | 
					
						
							|  |  |  | 	_ zapcore.Encoder = (*JSONEncoder)(nil) | 
					
						
							| 
									
										
										
										
											2020-02-25 22:00:33 -07:00
										 |  |  | 	_ zapcore.Encoder = (*SingleFieldEncoder)(nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_ caddyfile.Unmarshaler = (*ConsoleEncoder)(nil) | 
					
						
							|  |  |  | 	_ caddyfile.Unmarshaler = (*JSONEncoder)(nil) | 
					
						
							|  |  |  | 	_ caddyfile.Unmarshaler = (*SingleFieldEncoder)(nil) | 
					
						
							| 
									
										
										
										
											2019-10-28 14:39:37 -06:00
										 |  |  | ) |