You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	provide a basic agent healthcheck
This commit is contained in:
		| @@ -1,7 +1,9 @@ | ||||
| # docker build --rm -t drone/drone . | ||||
| # docker build --rm -f Dockerfile.agent -t drone/agent . | ||||
|  | ||||
| FROM centurylink/ca-certs | ||||
| ENV GODEBUG=netdns=go | ||||
| ADD release/drone-agent /bin/ | ||||
|  | ||||
| ENTRYPOINT ["/bin/drone-agent"] | ||||
|  | ||||
| HEALTHCHECK CMD ["/bin/drone-agent", "ping"] | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| # docker build --rm -t drone/drone . | ||||
|  | ||||
| FROM centurylink/ca-certs | ||||
| ENV GODEBUG=netdns=go | ||||
| ENV DRONE_PLATFORM=linux/arm | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| # docker build --rm -t drone/drone . | ||||
|  | ||||
| FROM centurylink/ca-certs | ||||
| ENV GODEBUG=netdns=go | ||||
| ENV DRONE_PLATFORM=linux/arm64 | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| @@ -46,6 +47,19 @@ func loop(c *cli.Context) error { | ||||
| 		zerolog.SetGlobalLevel(zerolog.WarnLevel) | ||||
| 	} | ||||
|  | ||||
| 	if c.Bool("pretty") { | ||||
| 		log.Logger = log.Output( | ||||
| 			zerolog.ConsoleWriter{ | ||||
| 				Out:     os.Stderr, | ||||
| 				NoColor: c.BoolT("nocolor"), | ||||
| 			}, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	if c.BoolT("healthcheck") { | ||||
| 		go http.ListenAndServe(":3000", nil) | ||||
| 	} | ||||
|  | ||||
| 	// TODO pass version information to grpc server | ||||
| 	// TODO authenticate to grpc server | ||||
|  | ||||
|   | ||||
							
								
								
									
										51
									
								
								cmd/drone-agent/health.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								cmd/drone-agent/health.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/drone/drone/version" | ||||
| 	"github.com/urfave/cli" | ||||
| ) | ||||
|  | ||||
| // the file implements some basic healthcheck logic based on the | ||||
| // following specification: | ||||
| //   https://github.com/mozilla-services/Dockerflow | ||||
|  | ||||
| func init() { | ||||
| 	http.HandleFunc("/__heartbeat__", handleHeartbeat) | ||||
| 	http.HandleFunc("/__version__", handleVersion) | ||||
| } | ||||
|  | ||||
| func handleHeartbeat(w http.ResponseWriter, r *http.Request) { | ||||
| 	w.WriteHeader(200) | ||||
| } | ||||
|  | ||||
| func handleVersion(w http.ResponseWriter, r *http.Request) { | ||||
| 	w.WriteHeader(200) | ||||
| 	w.Header().Add("Content-Type", "text/json") | ||||
| 	json.NewEncoder(w).Encode(versionResp{ | ||||
| 		Source:  "https://github.com/drone/drone", | ||||
| 		Version: version.Version.String(), | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type versionResp struct { | ||||
| 	Version string `json:"version"` | ||||
| 	Source  string `json:"source"` | ||||
| } | ||||
|  | ||||
| // handles pinging the endpoint and returns an error if the | ||||
| // agent is in an unhealthy state. | ||||
| func pinger(c *cli.Context) error { | ||||
| 	resp, err := http.Get("http://localhost:3000/__heartbeat__") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return fmt.Errorf("agent returned non-200 status code") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -16,6 +16,13 @@ func main() { | ||||
| 	app.Version = version.Version.String() | ||||
| 	app.Usage = "drone agent" | ||||
| 	app.Action = loop | ||||
| 	app.Commands = []cli.Command{ | ||||
| 		{ | ||||
| 			Name:   "ping", | ||||
| 			Usage:  "ping the agent", | ||||
| 			Action: pinger, | ||||
| 		}, | ||||
| 	} | ||||
| 	app.Flags = []cli.Flag{ | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_SERVER", | ||||
| @@ -39,6 +46,16 @@ func main() { | ||||
| 			Name:   "debug", | ||||
| 			Usage:  "start the agent in debug mode", | ||||
| 		}, | ||||
| 		cli.BoolFlag{ | ||||
| 			EnvVar: "DRONE_DEBUG_PRETTY", | ||||
| 			Name:   "pretty", | ||||
| 			Usage:  "enable pretty-printed debug output", | ||||
| 		}, | ||||
| 		cli.BoolTFlag{ | ||||
| 			EnvVar: "DRONE_DEBUG_NOCOLOR", | ||||
| 			Name:   "nocolor", | ||||
| 			Usage:  "disable colored debug output", | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_HOSTNAME,HOSTNAME", | ||||
| 			Name:   "hostname", | ||||
| @@ -50,14 +67,19 @@ func main() { | ||||
| 		}, | ||||
| 		cli.StringFlag{ | ||||
| 			EnvVar: "DRONE_FILTER", | ||||
| 			Name:   "drone-filter", | ||||
| 			Usage:  "A filter expression used to restrict builds by label", | ||||
| 			Name:   "filter", | ||||
| 			Usage:  "filter expression used to restrict builds by label", | ||||
| 		}, | ||||
| 		cli.IntFlag{ | ||||
| 			EnvVar: "DRONE_MAX_PROCS", | ||||
| 			Name:   "max-procs", | ||||
| 			Value:  1, | ||||
| 		}, | ||||
| 		cli.BoolTFlag{ | ||||
| 			EnvVar: "DRONE_HEALTHCHECK", | ||||
| 			Name:   "healthcheck", | ||||
| 			Usage:  "enables the healthcheck endpoint", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if err := app.Run(os.Args); err != nil { | ||||
|   | ||||
							
								
								
									
										58
									
								
								vendor/github.com/rs/zerolog/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/rs/zerolog/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,16 +8,20 @@ Zerolog's API is designed to provide both a great developer experience and stunn | ||||
|  | ||||
| The uber's [zap](https://godoc.org/go.uber.org/zap) library pioneered this approach. Zerolog is taking this concept to the next level with simpler to use API and even better performance. | ||||
|  | ||||
| To keep the code base and the API simple, zerolog focuses on JSON logging only. As [suggested on reddit](https://www.reddit.com/r/golang/comments/6c9k7n/zerolog_is_now_faster_than_zap/), you may use tools like [humanlog](https://github.com/aybabtme/humanlog) to pretty print JSON on the console during development. | ||||
| To keep the code base and the API simple, zerolog focuses on JSON logging only. Pretty logging on the console is made possible using the provided (but inefficient) `zerolog.ConsoleWriter`. | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| * Blazing fast | ||||
| * Low to zero allocation | ||||
| * Level logging | ||||
| * Sampling | ||||
| * Contextual fields | ||||
| * `context.Context` integration | ||||
| * `net/http` helpers | ||||
| * Pretty logging for development | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| @@ -27,6 +31,13 @@ import "github.com/rs/zerolog/log" | ||||
|  | ||||
| ### A global logger can be use for simple logging | ||||
|  | ||||
| ```go | ||||
| log.Print("hello world") | ||||
|  | ||||
| // Output: {"level":"debug","time":1494567715,"message":"hello world"} | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ```go | ||||
| log.Info().Msg("hello world") | ||||
|  | ||||
| @@ -96,6 +107,18 @@ if e := log.Debug(); e.Enabled() { | ||||
| // Output: {"level":"info","time":1494567715,"message":"routed message"} | ||||
| ``` | ||||
|  | ||||
| ### Pretty logging | ||||
|  | ||||
| ```go | ||||
| if isConsole { | ||||
|     log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) | ||||
| } | ||||
|  | ||||
| log.Info().Str("foo", "bar").Msg("Hello world") | ||||
|  | ||||
| // Output: 1494567715 |INFO| Hello world foo=bar | ||||
| ``` | ||||
|  | ||||
| ### Sub dictionary | ||||
|  | ||||
| ```go | ||||
| @@ -138,12 +161,31 @@ log.Logger = log.With().Str("foo", "bar").Logger() | ||||
| ### Log Sampling | ||||
|  | ||||
| ```go | ||||
| sampled := log.Sample(10) | ||||
| sampled := log.Sample(&zerolog.BasicSampler{N: 10}) | ||||
| sampled.Info().Msg("will be logged every 10 messages") | ||||
|  | ||||
| // Output: {"time":1494567715,"sample":10,"message":"will be logged every 10 messages"} | ||||
| // Output: {"time":1494567715,"level":"info","message":"will be logged every 10 messages"} | ||||
| ``` | ||||
|  | ||||
| More advanced sampling: | ||||
|  | ||||
| ```go | ||||
| // Will let 5 debug messages per period of 1 second. | ||||
| // Over 5 debug message, 1 every 100 debug messages are logged. | ||||
| // Other levels are not sampled. | ||||
| sampled := log.Sample(zerolog.LevelSampler{ | ||||
|     DebugSampler: &zerolog.BurstSampler{ | ||||
|         Burst: 5, | ||||
|         Period: 1*time.Second, | ||||
|         NextSampler: &zerolog.BasicSampler{N: 100}, | ||||
|     }, | ||||
| }) | ||||
| sampled.Debug().Msg("hello world") | ||||
|  | ||||
| // Output: {"time":1494567715,"level":"debug","message":"hello world"} | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ### Pass a sub-logger by context | ||||
|  | ||||
| ```go | ||||
| @@ -233,7 +275,6 @@ Some settings can be changed and will by applied to all loggers: | ||||
| * `zerolog.LevelFieldName`: Can be set to customize level field name. | ||||
| * `zerolog.MessageFieldName`: Can be set to customize message field name. | ||||
| * `zerolog.ErrorFieldName`: Can be set to customize `Err` field name. | ||||
| * `zerolog.SampleFieldName`: Can be set to customize the field name added when sampling is enabled. | ||||
| * `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with an empty string, times are formated as UNIX timestamp. | ||||
| 	// DurationFieldUnit defines the unit for time.Duration type fields added | ||||
| 	// using the Dur method. | ||||
| @@ -259,7 +300,7 @@ Some settings can be changed and will by applied to all loggers: | ||||
| * `Dict`: Adds a sub-key/value as a field of the event. | ||||
| * `Interface`: Uses reflection to marshal the type. | ||||
|  | ||||
| ## Performance | ||||
| ## Benchmarks | ||||
|  | ||||
| All operations are allocation free (those numbers *include* JSON encoding): | ||||
|  | ||||
| @@ -271,7 +312,12 @@ BenchmarkContextFields-8   30000000	    44.9 ns/op	   0 B/op       0 allocs/op | ||||
| BenchmarkLogFields-8       10000000	   184 ns/op	   0 B/op       0 allocs/op | ||||
| ``` | ||||
|  | ||||
| Using Uber's zap [comparison benchmark](https://github.com/uber-go/zap#performance): | ||||
| There are a few Go logging benchmarks and comparisons that include zerolog. | ||||
|  | ||||
| - [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) | ||||
| - [uber-common/zap](https://github.com/uber-go/zap#performance) | ||||
|  | ||||
| Using Uber's zap comparison benchmark: | ||||
|  | ||||
| Log a message and 10 fields: | ||||
|  | ||||
|   | ||||
							
								
								
									
										117
									
								
								vendor/github.com/rs/zerolog/console.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/github.com/rs/zerolog/console.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| package zerolog | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	cReset    = 0 | ||||
| 	cBold     = 1 | ||||
| 	cRed      = 31 | ||||
| 	cGreen    = 32 | ||||
| 	cYellow   = 33 | ||||
| 	cBlue     = 34 | ||||
| 	cMagenta  = 35 | ||||
| 	cCyan     = 36 | ||||
| 	cGray     = 37 | ||||
| 	cDarkGray = 90 | ||||
| ) | ||||
|  | ||||
| var consoleBufPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		return bytes.NewBuffer(make([]byte, 0, 100)) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // ConsoleWriter reads a JSON object per write operation and output an | ||||
| // optionally colored human readable version on the Out writer. | ||||
| type ConsoleWriter struct { | ||||
| 	Out     io.Writer | ||||
| 	NoColor bool | ||||
| } | ||||
|  | ||||
| func (w ConsoleWriter) Write(p []byte) (n int, err error) { | ||||
| 	var event map[string]interface{} | ||||
| 	err = json.Unmarshal(p, &event) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	buf := consoleBufPool.Get().(*bytes.Buffer) | ||||
| 	defer consoleBufPool.Put(buf) | ||||
| 	lvlColor := cReset | ||||
| 	level := "????" | ||||
| 	if l, ok := event[LevelFieldName].(string); ok { | ||||
| 		if !w.NoColor { | ||||
| 			lvlColor = levelColor(l) | ||||
| 		} | ||||
| 		level = strings.ToUpper(l)[0:4] | ||||
| 	} | ||||
| 	fmt.Fprintf(buf, "%s |%s| %s", | ||||
| 		colorize(event[TimestampFieldName], cDarkGray, !w.NoColor), | ||||
| 		colorize(level, lvlColor, !w.NoColor), | ||||
| 		colorize(event[MessageFieldName], cReset, !w.NoColor)) | ||||
| 	fields := make([]string, 0, len(event)) | ||||
| 	for field := range event { | ||||
| 		switch field { | ||||
| 		case LevelFieldName, TimestampFieldName, MessageFieldName: | ||||
| 			continue | ||||
| 		} | ||||
| 		fields = append(fields, field) | ||||
| 	} | ||||
| 	sort.Strings(fields) | ||||
| 	for _, field := range fields { | ||||
| 		fmt.Fprintf(buf, " %s=", colorize(field, cCyan, !w.NoColor)) | ||||
| 		switch value := event[field].(type) { | ||||
| 		case string: | ||||
| 			if needsQuote(value) { | ||||
| 				buf.WriteString(strconv.Quote(value)) | ||||
| 			} else { | ||||
| 				buf.WriteString(value) | ||||
| 			} | ||||
| 		default: | ||||
| 			fmt.Fprint(buf, value) | ||||
| 		} | ||||
| 	} | ||||
| 	buf.WriteByte('\n') | ||||
| 	buf.WriteTo(w.Out) | ||||
| 	n = len(p) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func colorize(s interface{}, color int, enabled bool) string { | ||||
| 	if !enabled { | ||||
| 		return fmt.Sprintf("%v", s) | ||||
| 	} | ||||
| 	return fmt.Sprintf("\x1b[%dm%v\x1b[0m", color, s) | ||||
| } | ||||
|  | ||||
| func levelColor(level string) int { | ||||
| 	switch level { | ||||
| 	case "debug": | ||||
| 		return cMagenta | ||||
| 	case "info": | ||||
| 		return cGreen | ||||
| 	case "warn": | ||||
| 		return cYellow | ||||
| 	case "error", "fatal", "panic": | ||||
| 		return cRed | ||||
| 	default: | ||||
| 		return cReset | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func needsQuote(s string) bool { | ||||
| 	for i := range s { | ||||
| 		if s[i] < 0x20 || s[i] > 0x7e || s[i] == ' ' || s[i] == '\\' || s[i] == '"' { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										25
									
								
								vendor/github.com/rs/zerolog/ctx.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/rs/zerolog/ctx.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,25 +5,42 @@ import ( | ||||
| 	"io/ioutil" | ||||
| ) | ||||
|  | ||||
| var disabledLogger = New(ioutil.Discard).Level(Disabled) | ||||
| var disabledLogger *Logger | ||||
|  | ||||
| func init() { | ||||
| 	l := New(ioutil.Discard).Level(Disabled) | ||||
| 	disabledLogger = &l | ||||
| } | ||||
|  | ||||
| type ctxKey struct{} | ||||
|  | ||||
| // WithContext returns a copy of ctx with l associated. | ||||
| // WithContext returns a copy of ctx with l associated. If an instance of Logger | ||||
| // is already in the context, the pointer to this logger is updated with l. | ||||
| // | ||||
| // For instance, to add a field to an existing logger in the context, use this | ||||
| // notation: | ||||
| // | ||||
| //     ctx := r.Context() | ||||
| //     l := zerolog.Ctx(ctx) | ||||
| //     ctx = l.With().Str("foo", "bar").WithContext(ctx) | ||||
| func (l Logger) WithContext(ctx context.Context) context.Context { | ||||
| 	if lp, ok := ctx.Value(ctxKey{}).(*Logger); ok { | ||||
| 		// Update existing pointer. | ||||
| 		*lp = l | ||||
| 		return ctx | ||||
| 	} | ||||
| 	if l.level == Disabled { | ||||
| 		// Do not store disabled logger. | ||||
| 		return ctx | ||||
| 	} | ||||
| 	return context.WithValue(ctx, ctxKey{}, &l) | ||||
| } | ||||
|  | ||||
| // Ctx returns the Logger associated with the ctx. If no logger | ||||
| // is associated, a disabled logger is returned. | ||||
| func Ctx(ctx context.Context) Logger { | ||||
| func Ctx(ctx context.Context) *Logger { | ||||
| 	if l, ok := ctx.Value(ctxKey{}).(*Logger); ok { | ||||
| 		return *l | ||||
| 		return l | ||||
| 	} | ||||
| 	return disabledLogger | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/rs/zerolog/globals.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/rs/zerolog/globals.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,9 +16,6 @@ var ( | ||||
| 	// ErrorFieldName is the field name used for error fields. | ||||
| 	ErrorFieldName = "error" | ||||
|  | ||||
| 	// SampleFieldName is the name of the field used to report sampling. | ||||
| 	SampleFieldName = "sample" | ||||
|  | ||||
| 	// TimeFieldFormat defines the time format of the Time field type. | ||||
| 	// If set to an empty string, the time is formatted as an UNIX timestamp | ||||
| 	// as integer. | ||||
|   | ||||
							
								
								
									
										98
									
								
								vendor/github.com/rs/zerolog/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/rs/zerolog/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -62,17 +62,17 @@ | ||||
| // | ||||
| // Sample logs: | ||||
| // | ||||
| //     sampled := log.Sample(10) | ||||
| //     sampled := log.Sample(&zerolog.BasicSampler{N: 10}) | ||||
| //     sampled.Info().Msg("will be logged every 10 messages") | ||||
| // | ||||
| package zerolog | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"github.com/rs/zerolog/internal/json" | ||||
| ) | ||||
| @@ -115,15 +115,6 @@ func (l Level) String() string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	// Often samples log every 10 events. | ||||
| 	Often = 10 | ||||
| 	// Sometimes samples log every 100 events. | ||||
| 	Sometimes = 100 | ||||
| 	// Rarely samples log every 1000 events. | ||||
| 	Rarely = 1000 | ||||
| ) | ||||
|  | ||||
| var disabledEvent = newEvent(levelWriterAdapter{ioutil.Discard}, 0, false) | ||||
|  | ||||
| // A Logger represents an active logging object that generates lines | ||||
| @@ -134,8 +125,7 @@ var disabledEvent = newEvent(levelWriterAdapter{ioutil.Discard}, 0, false) | ||||
| type Logger struct { | ||||
| 	w       LevelWriter | ||||
| 	level   Level | ||||
| 	sample  uint32 | ||||
| 	counter *uint32 | ||||
| 	sampler Sampler | ||||
| 	context []byte | ||||
| } | ||||
|  | ||||
| @@ -162,6 +152,16 @@ func Nop() Logger { | ||||
| 	return New(nil).Level(Disabled) | ||||
| } | ||||
|  | ||||
| // Output duplicates the current logger and sets w as its output. | ||||
| func (l Logger) Output(w io.Writer) Logger { | ||||
| 	l2 := New(w) | ||||
| 	l2.level = l.level | ||||
| 	l2.sampler = l.sampler | ||||
| 	l2.context = make([]byte, len(l.context), cap(l.context)) | ||||
| 	copy(l2.context, l.context) | ||||
| 	return l2 | ||||
| } | ||||
|  | ||||
| // With creates a child logger with the field added to its context. | ||||
| func (l Logger) With() Context { | ||||
| 	context := l.context | ||||
| @@ -175,34 +175,30 @@ func (l Logger) With() Context { | ||||
| 	return Context{l} | ||||
| } | ||||
|  | ||||
| // Level creates a child logger with the minimum accepted level set to level. | ||||
| func (l Logger) Level(lvl Level) Logger { | ||||
| 	return Logger{ | ||||
| 		w:       l.w, | ||||
| 		level:   lvl, | ||||
| 		sample:  l.sample, | ||||
| 		counter: l.counter, | ||||
| 		context: l.context, | ||||
| // UpdateContext updates the internal logger's context. | ||||
| // | ||||
| // Use this method with caution. If unsure, prefer the With method. | ||||
| func (l *Logger) UpdateContext(update func(c Context) Context) { | ||||
| 	if l == disabledLogger { | ||||
| 		return | ||||
| 	} | ||||
| 	if cap(l.context) == 0 { | ||||
| 		l.context = make([]byte, 1, 500) // first byte is timestamp flag | ||||
| 	} | ||||
| 	c := update(Context{*l}) | ||||
| 	l.context = c.l.context | ||||
| } | ||||
|  | ||||
| // Sample returns a logger that only let one message out of every to pass thru. | ||||
| func (l Logger) Sample(every int) Logger { | ||||
| 	if every == 0 { | ||||
| 		// Create a child with no sampling. | ||||
| 		return Logger{ | ||||
| 			w:       l.w, | ||||
| 			level:   l.level, | ||||
| 			context: l.context, | ||||
| 		} | ||||
| 	} | ||||
| 	return Logger{ | ||||
| 		w:       l.w, | ||||
| 		level:   l.level, | ||||
| 		sample:  uint32(every), | ||||
| 		counter: new(uint32), | ||||
| 		context: l.context, | ||||
| 	} | ||||
| // Level creates a child logger with the minimum accepted level set to level. | ||||
| func (l Logger) Level(lvl Level) Logger { | ||||
| 	l.level = lvl | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Sample returns a logger with the s sampler. | ||||
| func (l Logger) Sample(s Sampler) Logger { | ||||
| 	l.sampler = s | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Debug starts a new message with debug level. | ||||
| @@ -283,6 +279,22 @@ func (l Logger) Log() *Event { | ||||
| 	return l.newEvent(PanicLevel, false, nil) | ||||
| } | ||||
|  | ||||
| // Print sends a log event using debug level and no extra field. | ||||
| // Arguments are handled in the manner of fmt.Print. | ||||
| func (l Logger) Print(v ...interface{}) { | ||||
| 	if e := l.Debug(); e.Enabled() { | ||||
| 		e.Msg(fmt.Sprint(v...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Printf sends a log event using debug level and no extra field. | ||||
| // Arguments are handled in the manner of fmt.Printf. | ||||
| func (l Logger) Printf(format string, v ...interface{}) { | ||||
| 	if e := l.Debug(); e.Enabled() { | ||||
| 		e.Msg(fmt.Sprintf(format, v...)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Write implements the io.Writer interface. This is useful to set as a writer | ||||
| // for the standard library log. | ||||
| func (l Logger) Write(p []byte) (n int, err error) { | ||||
| @@ -304,7 +316,7 @@ func (l Logger) newEvent(level Level, addLevelField bool, done func(string)) *Ev | ||||
| 	if addLevelField { | ||||
| 		lvl = level | ||||
| 	} | ||||
| 	e := newEvent(l.w, lvl, enabled) | ||||
| 	e := newEvent(l.w, lvl, true) | ||||
| 	e.done = done | ||||
| 	if l.context != nil && len(l.context) > 0 && l.context[0] > 0 { | ||||
| 		// first byte of context is ts flag | ||||
| @@ -313,9 +325,6 @@ func (l Logger) newEvent(level Level, addLevelField bool, done func(string)) *Ev | ||||
| 	if addLevelField { | ||||
| 		e.Str(LevelFieldName, level.String()) | ||||
| 	} | ||||
| 	if l.sample > 0 && SampleFieldName != "" { | ||||
| 		e.Uint32(SampleFieldName, l.sample) | ||||
| 	} | ||||
| 	if l.context != nil && len(l.context) > 1 { | ||||
| 		if len(e.buf) > 1 { | ||||
| 			e.buf = append(e.buf, ',') | ||||
| @@ -330,9 +339,8 @@ func (l Logger) should(lvl Level) bool { | ||||
| 	if lvl < l.level || lvl < globalLevel() { | ||||
| 		return false | ||||
| 	} | ||||
| 	if l.sample > 0 && l.counter != nil && !samplingDisabled() { | ||||
| 		c := atomic.AddUint32(l.counter, 1) | ||||
| 		return c%l.sample == 0 | ||||
| 	if l.sampler != nil && !samplingDisabled() { | ||||
| 		return l.sampler.Sample(lvl) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/github.com/rs/zerolog/log/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/rs/zerolog/log/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ package log | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/rs/zerolog" | ||||
| @@ -11,6 +12,11 @@ import ( | ||||
| // Logger is the global logger. | ||||
| var Logger = zerolog.New(os.Stderr).With().Timestamp().Logger() | ||||
|  | ||||
| // Output duplicates the global logger and sets w as its output. | ||||
| func Output(w io.Writer) zerolog.Logger { | ||||
| 	return Logger.Output(w) | ||||
| } | ||||
|  | ||||
| // With creates a child logger with the field added to its context. | ||||
| func With() zerolog.Context { | ||||
| 	return Logger.With() | ||||
| @@ -21,9 +27,9 @@ func Level(level zerolog.Level) zerolog.Logger { | ||||
| 	return Logger.Level(level) | ||||
| } | ||||
|  | ||||
| // Sample returns a logger that only let one message out of every to pass thru. | ||||
| func Sample(every int) zerolog.Logger { | ||||
| 	return Logger.Sample(every) | ||||
| // Sample returns a logger with the s sampler. | ||||
| func Sample(s zerolog.Sampler) zerolog.Logger { | ||||
| 	return Logger.Sample(s) | ||||
| } | ||||
|  | ||||
| // Debug starts a new message with debug level. | ||||
| @@ -78,8 +84,20 @@ func Log() *zerolog.Event { | ||||
| 	return Logger.Log() | ||||
| } | ||||
|  | ||||
| // Print sends a log event using debug level and no extra field. | ||||
| // Arguments are handled in the manner of fmt.Print. | ||||
| func Print(v ...interface{}) { | ||||
| 	Logger.Print(v...) | ||||
| } | ||||
|  | ||||
| // Printf sends a log event using debug level and no extra field. | ||||
| // Arguments are handled in the manner of fmt.Printf. | ||||
| func Printf(format string, v ...interface{}) { | ||||
| 	Logger.Printf(format, v...) | ||||
| } | ||||
|  | ||||
| // Ctx returns the Logger associated with the ctx. If no logger | ||||
| // is associated, a disabled logger is returned. | ||||
| func Ctx(ctx context.Context) zerolog.Logger { | ||||
| func Ctx(ctx context.Context) *zerolog.Logger { | ||||
| 	return zerolog.Ctx(ctx) | ||||
| } | ||||
|   | ||||
							
								
								
									
										126
									
								
								vendor/github.com/rs/zerolog/sampler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								vendor/github.com/rs/zerolog/sampler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| package zerolog | ||||
|  | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Often samples log every ~ 10 events. | ||||
| 	Often = RandomSampler(10) | ||||
| 	// Sometimes samples log every ~ 100 events. | ||||
| 	Sometimes = RandomSampler(100) | ||||
| 	// Rarely samples log every ~ 1000 events. | ||||
| 	Rarely = RandomSampler(1000) | ||||
| ) | ||||
|  | ||||
| // Sampler defines an interface to a log sampler. | ||||
| type Sampler interface { | ||||
| 	// Sample returns true if the event should be part of the sample, false if | ||||
| 	// the event should be dropped. | ||||
| 	Sample(lvl Level) bool | ||||
| } | ||||
|  | ||||
| // RandomSampler use a PRNG to randomly sample an event out of N events, | ||||
| // regardless of their level. | ||||
| type RandomSampler uint32 | ||||
|  | ||||
| // Sample implements the Sampler interface. | ||||
| func (s RandomSampler) Sample(lvl Level) bool { | ||||
| 	if s <= 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	if rand.Intn(int(s)) != 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // BasicSampler is a sampler that will send every Nth events, regardless of | ||||
| // there level. | ||||
| type BasicSampler struct { | ||||
| 	N       uint32 | ||||
| 	counter uint32 | ||||
| } | ||||
|  | ||||
| // Sample implements the Sampler interface. | ||||
| func (s *BasicSampler) Sample(lvl Level) bool { | ||||
| 	c := atomic.AddUint32(&s.counter, 1) | ||||
| 	return c%s.N == 0 | ||||
| } | ||||
|  | ||||
| // BurstSampler lets Burst events pass per Period then pass the decision to | ||||
| // NextSampler. If Sampler is not set, all subsequent events are rejected. | ||||
| type BurstSampler struct { | ||||
| 	// Burst is the maximum number of event per period allowed before calling | ||||
| 	// NextSampler. | ||||
| 	Burst uint32 | ||||
| 	// Period defines the burst period. If 0, NextSampler is always called. | ||||
| 	Period time.Duration | ||||
| 	// NextSampler is the sampler used after the burst is reached. If nil, | ||||
| 	// events are always rejected after the burst. | ||||
| 	NextSampler Sampler | ||||
|  | ||||
| 	counter uint32 | ||||
| 	resetAt int64 | ||||
| } | ||||
|  | ||||
| // Sample implements the Sampler interface. | ||||
| func (s *BurstSampler) Sample(lvl Level) bool { | ||||
| 	if s.Burst > 9 && s.Period > 0 { | ||||
| 		if s.inc() <= s.Burst { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	if s.NextSampler == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return s.NextSampler.Sample(lvl) | ||||
| } | ||||
|  | ||||
| func (s *BurstSampler) inc() uint32 { | ||||
| 	now := time.Now().UnixNano() | ||||
| 	resetAt := atomic.LoadInt64(&s.resetAt) | ||||
| 	var c uint32 | ||||
| 	if now > resetAt { | ||||
| 		c = 1 | ||||
| 		atomic.StoreUint32(&s.counter, c) | ||||
| 		newResetAt := now + s.Period.Nanoseconds() | ||||
| 		reset := atomic.CompareAndSwapInt64(&s.resetAt, resetAt, newResetAt) | ||||
| 		if !reset { | ||||
| 			// Lost the race with another goroutine trying to reset. | ||||
| 			c = atomic.AddUint32(&s.counter, 1) | ||||
| 		} | ||||
| 	} else { | ||||
| 		c = atomic.AddUint32(&s.counter, 1) | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // LevelSampler applies a different sampler for each level. | ||||
| type LevelSampler struct { | ||||
| 	DebugSampler, InfoSampler, WarnSampler, ErrorSampler Sampler | ||||
| } | ||||
|  | ||||
| func (s LevelSampler) Sample(lvl Level) bool { | ||||
| 	switch lvl { | ||||
| 	case DebugLevel: | ||||
| 		if s.DebugSampler != nil { | ||||
| 			return s.DebugSampler.Sample(lvl) | ||||
| 		} | ||||
| 	case InfoLevel: | ||||
| 		if s.InfoSampler != nil { | ||||
| 			return s.InfoSampler.Sample(lvl) | ||||
| 		} | ||||
| 	case WarnLevel: | ||||
| 		if s.WarnSampler != nil { | ||||
| 			return s.WarnSampler.Sample(lvl) | ||||
| 		} | ||||
| 	case ErrorLevel: | ||||
| 		if s.ErrorSampler != nil { | ||||
| 			return s.ErrorSampler.Sample(lvl) | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
							
								
								
									
										8
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							| @@ -762,10 +762,10 @@ | ||||
| 			"revisionTime": "2017-04-24T20:45:52Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "fGBeb3o1grSXGUNAjwptkBWfch0=", | ||||
| 			"checksumSHA1": "3Ie7HG2k47G/gwz8prjymTMLEms=", | ||||
| 			"path": "github.com/rs/zerolog", | ||||
| 			"revision": "89ff8dbc5f047ae9957523b07e627891079f7967", | ||||
| 			"revisionTime": "2017-07-27T06:42:12Z" | ||||
| 			"revision": "9d194eb6f50e8718a6d6f8f1e1f0bf3ddf4065f1", | ||||
| 			"revisionTime": "2017-09-11T21:52:32Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "AREhk6LKIp2I/4Njd756bqU6JSQ=", | ||||
| @@ -774,7 +774,7 @@ | ||||
| 			"revisionTime": "2017-07-27T06:42:12Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "kolarHDX6fkauW+1KWx1SFqSF2o=", | ||||
| 			"checksumSHA1": "VFgakVFNczJTf9gtUeIpkgcFRf0=", | ||||
| 			"path": "github.com/rs/zerolog/log", | ||||
| 			"revision": "89ff8dbc5f047ae9957523b07e627891079f7967", | ||||
| 			"revisionTime": "2017-07-27T06:42:12Z" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user