 d2ea21d0d8
			
		
	
	
	
	
	d2ea21d0d8* use certmagic for more extensible/robust ACME cert handling * accept TOS based on config option Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv>
		
			
				
	
	
		
			262 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			262 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // Copyright (c) 2016 Uber Technologies, Inc.
 | |
| //
 | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| // of this software and associated documentation files (the "Software"), to deal
 | |
| // in the Software without restriction, including without limitation the rights
 | |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| // copies of the Software, and to permit persons to whom the Software is
 | |
| // furnished to do so, subject to the following conditions:
 | |
| //
 | |
| // The above copyright notice and this permission notice shall be included in
 | |
| // all copies or substantial portions of the Software.
 | |
| //
 | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
| // THE SOFTWARE.
 | |
| 
 | |
| package zap
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| 	"time"
 | |
| 
 | |
| 	"go.uber.org/zap/zapcore"
 | |
| )
 | |
| 
 | |
| // SamplingConfig sets a sampling strategy for the logger. Sampling caps the
 | |
| // global CPU and I/O load that logging puts on your process while attempting
 | |
| // to preserve a representative subset of your logs.
 | |
| //
 | |
| // If specified, the Sampler will invoke the Hook after each decision.
 | |
| //
 | |
| // Values configured here are per-second. See zapcore.NewSamplerWithOptions for
 | |
| // details.
 | |
| type SamplingConfig struct {
 | |
| 	Initial    int                                           `json:"initial" yaml:"initial"`
 | |
| 	Thereafter int                                           `json:"thereafter" yaml:"thereafter"`
 | |
| 	Hook       func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
 | |
| }
 | |
| 
 | |
| // Config offers a declarative way to construct a logger. It doesn't do
 | |
| // anything that can't be done with New, Options, and the various
 | |
| // zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
 | |
| // toggle common options.
 | |
| //
 | |
| // Note that Config intentionally supports only the most common options. More
 | |
| // unusual logging setups (logging to network connections or message queues,
 | |
| // splitting output between multiple files, etc.) are possible, but require
 | |
| // direct use of the zapcore package. For sample code, see the package-level
 | |
| // BasicConfiguration and AdvancedConfiguration examples.
 | |
| //
 | |
| // For an example showing runtime log level changes, see the documentation for
 | |
| // AtomicLevel.
 | |
| type Config struct {
 | |
| 	// Level is the minimum enabled logging level. Note that this is a dynamic
 | |
| 	// level, so calling Config.Level.SetLevel will atomically change the log
 | |
| 	// level of all loggers descended from this config.
 | |
| 	Level AtomicLevel `json:"level" yaml:"level"`
 | |
| 	// Development puts the logger in development mode, which changes the
 | |
| 	// behavior of DPanicLevel and takes stacktraces more liberally.
 | |
| 	Development bool `json:"development" yaml:"development"`
 | |
| 	// DisableCaller stops annotating logs with the calling function's file
 | |
| 	// name and line number. By default, all logs are annotated.
 | |
| 	DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
 | |
| 	// DisableStacktrace completely disables automatic stacktrace capturing. By
 | |
| 	// default, stacktraces are captured for WarnLevel and above logs in
 | |
| 	// development and ErrorLevel and above in production.
 | |
| 	DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
 | |
| 	// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
 | |
| 	Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
 | |
| 	// Encoding sets the logger's encoding. Valid values are "json" and
 | |
| 	// "console", as well as any third-party encodings registered via
 | |
| 	// RegisterEncoder.
 | |
| 	Encoding string `json:"encoding" yaml:"encoding"`
 | |
| 	// EncoderConfig sets options for the chosen encoder. See
 | |
| 	// zapcore.EncoderConfig for details.
 | |
| 	EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
 | |
| 	// OutputPaths is a list of URLs or file paths to write logging output to.
 | |
| 	// See Open for details.
 | |
| 	OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
 | |
| 	// ErrorOutputPaths is a list of URLs to write internal logger errors to.
 | |
| 	// The default is standard error.
 | |
| 	//
 | |
| 	// Note that this setting only affects internal errors; for sample code that
 | |
| 	// sends error-level logs to a different location from info- and debug-level
 | |
| 	// logs, see the package-level AdvancedConfiguration example.
 | |
| 	ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
 | |
| 	// InitialFields is a collection of fields to add to the root logger.
 | |
| 	InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
 | |
| }
 | |
| 
 | |
| // NewProductionEncoderConfig returns an opinionated EncoderConfig for
 | |
| // production environments.
 | |
| func NewProductionEncoderConfig() zapcore.EncoderConfig {
 | |
| 	return zapcore.EncoderConfig{
 | |
| 		TimeKey:        "ts",
 | |
| 		LevelKey:       "level",
 | |
| 		NameKey:        "logger",
 | |
| 		CallerKey:      "caller",
 | |
| 		MessageKey:     "msg",
 | |
| 		StacktraceKey:  "stacktrace",
 | |
| 		LineEnding:     zapcore.DefaultLineEnding,
 | |
| 		EncodeLevel:    zapcore.LowercaseLevelEncoder,
 | |
| 		EncodeTime:     zapcore.EpochTimeEncoder,
 | |
| 		EncodeDuration: zapcore.SecondsDurationEncoder,
 | |
| 		EncodeCaller:   zapcore.ShortCallerEncoder,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewProductionConfig is a reasonable production logging configuration.
 | |
| // Logging is enabled at InfoLevel and above.
 | |
| //
 | |
| // It uses a JSON encoder, writes to standard error, and enables sampling.
 | |
| // Stacktraces are automatically included on logs of ErrorLevel and above.
 | |
| func NewProductionConfig() Config {
 | |
| 	return Config{
 | |
| 		Level:       NewAtomicLevelAt(InfoLevel),
 | |
| 		Development: false,
 | |
| 		Sampling: &SamplingConfig{
 | |
| 			Initial:    100,
 | |
| 			Thereafter: 100,
 | |
| 		},
 | |
| 		Encoding:         "json",
 | |
| 		EncoderConfig:    NewProductionEncoderConfig(),
 | |
| 		OutputPaths:      []string{"stderr"},
 | |
| 		ErrorOutputPaths: []string{"stderr"},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
 | |
| // development environments.
 | |
| func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
 | |
| 	return zapcore.EncoderConfig{
 | |
| 		// Keys can be anything except the empty string.
 | |
| 		TimeKey:        "T",
 | |
| 		LevelKey:       "L",
 | |
| 		NameKey:        "N",
 | |
| 		CallerKey:      "C",
 | |
| 		MessageKey:     "M",
 | |
| 		StacktraceKey:  "S",
 | |
| 		LineEnding:     zapcore.DefaultLineEnding,
 | |
| 		EncodeLevel:    zapcore.CapitalLevelEncoder,
 | |
| 		EncodeTime:     zapcore.ISO8601TimeEncoder,
 | |
| 		EncodeDuration: zapcore.StringDurationEncoder,
 | |
| 		EncodeCaller:   zapcore.ShortCallerEncoder,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewDevelopmentConfig is a reasonable development logging configuration.
 | |
| // Logging is enabled at DebugLevel and above.
 | |
| //
 | |
| // It enables development mode (which makes DPanicLevel logs panic), uses a
 | |
| // console encoder, writes to standard error, and disables sampling.
 | |
| // Stacktraces are automatically included on logs of WarnLevel and above.
 | |
| func NewDevelopmentConfig() Config {
 | |
| 	return Config{
 | |
| 		Level:            NewAtomicLevelAt(DebugLevel),
 | |
| 		Development:      true,
 | |
| 		Encoding:         "console",
 | |
| 		EncoderConfig:    NewDevelopmentEncoderConfig(),
 | |
| 		OutputPaths:      []string{"stderr"},
 | |
| 		ErrorOutputPaths: []string{"stderr"},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Build constructs a logger from the Config and Options.
 | |
| func (cfg Config) Build(opts ...Option) (*Logger, error) {
 | |
| 	enc, err := cfg.buildEncoder()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	sink, errSink, err := cfg.openSinks()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if cfg.Level == (AtomicLevel{}) {
 | |
| 		return nil, fmt.Errorf("missing Level")
 | |
| 	}
 | |
| 
 | |
| 	log := New(
 | |
| 		zapcore.NewCore(enc, sink, cfg.Level),
 | |
| 		cfg.buildOptions(errSink)...,
 | |
| 	)
 | |
| 	if len(opts) > 0 {
 | |
| 		log = log.WithOptions(opts...)
 | |
| 	}
 | |
| 	return log, nil
 | |
| }
 | |
| 
 | |
| func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
 | |
| 	opts := []Option{ErrorOutput(errSink)}
 | |
| 
 | |
| 	if cfg.Development {
 | |
| 		opts = append(opts, Development())
 | |
| 	}
 | |
| 
 | |
| 	if !cfg.DisableCaller {
 | |
| 		opts = append(opts, AddCaller())
 | |
| 	}
 | |
| 
 | |
| 	stackLevel := ErrorLevel
 | |
| 	if cfg.Development {
 | |
| 		stackLevel = WarnLevel
 | |
| 	}
 | |
| 	if !cfg.DisableStacktrace {
 | |
| 		opts = append(opts, AddStacktrace(stackLevel))
 | |
| 	}
 | |
| 
 | |
| 	if scfg := cfg.Sampling; scfg != nil {
 | |
| 		opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
 | |
| 			var samplerOpts []zapcore.SamplerOption
 | |
| 			if scfg.Hook != nil {
 | |
| 				samplerOpts = append(samplerOpts, zapcore.SamplerHook(scfg.Hook))
 | |
| 			}
 | |
| 			return zapcore.NewSamplerWithOptions(
 | |
| 				core,
 | |
| 				time.Second,
 | |
| 				cfg.Sampling.Initial,
 | |
| 				cfg.Sampling.Thereafter,
 | |
| 				samplerOpts...,
 | |
| 			)
 | |
| 		}))
 | |
| 	}
 | |
| 
 | |
| 	if len(cfg.InitialFields) > 0 {
 | |
| 		fs := make([]Field, 0, len(cfg.InitialFields))
 | |
| 		keys := make([]string, 0, len(cfg.InitialFields))
 | |
| 		for k := range cfg.InitialFields {
 | |
| 			keys = append(keys, k)
 | |
| 		}
 | |
| 		sort.Strings(keys)
 | |
| 		for _, k := range keys {
 | |
| 			fs = append(fs, Any(k, cfg.InitialFields[k]))
 | |
| 		}
 | |
| 		opts = append(opts, Fields(fs...))
 | |
| 	}
 | |
| 
 | |
| 	return opts
 | |
| }
 | |
| 
 | |
| func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
 | |
| 	sink, closeOut, err := Open(cfg.OutputPaths...)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	errSink, _, err := Open(cfg.ErrorOutputPaths...)
 | |
| 	if err != nil {
 | |
| 		closeOut()
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	return sink, errSink, nil
 | |
| }
 | |
| 
 | |
| func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
 | |
| 	return newEncoder(cfg.Encoding, cfg.EncoderConfig)
 | |
| }
 |