Upgrade OpenTelemetry dependencies
This commit upgrades the packages under go.opentelemetry.io/. Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
This commit is contained in:
		
							
								
								
									
										29
									
								
								vendor/github.com/go-logr/logr/.golangci.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/go-logr/logr/.golangci.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| run: | ||||
|   timeout: 1m | ||||
|   tests: true | ||||
|  | ||||
| linters: | ||||
|   disable-all: true | ||||
|   enable: | ||||
|     - asciicheck | ||||
|     - deadcode | ||||
|     - errcheck | ||||
|     - forcetypeassert | ||||
|     - gocritic | ||||
|     - gofmt | ||||
|     - goimports | ||||
|     - gosimple | ||||
|     - govet | ||||
|     - ineffassign | ||||
|     - misspell | ||||
|     - revive | ||||
|     - staticcheck | ||||
|     - structcheck | ||||
|     - typecheck | ||||
|     - unused | ||||
|     - varcheck | ||||
|  | ||||
| issues: | ||||
|   exclude-use-default: false | ||||
|   max-issues-per-linter: 0 | ||||
|   max-same-issues: 10 | ||||
							
								
								
									
										6
									
								
								vendor/github.com/go-logr/logr/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/go-logr/logr/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| # CHANGELOG | ||||
|  | ||||
| ## v1.0.0-rc1 | ||||
|  | ||||
| This is the first logged release.  Major changes (including breaking changes) | ||||
| have occurred since earlier tags. | ||||
							
								
								
									
										17
									
								
								vendor/github.com/go-logr/logr/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/go-logr/logr/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Contributing | ||||
|  | ||||
| Logr is open to pull-requests, provided they fit within the intended scope of | ||||
| the project.  Specifically, this library aims to be VERY small and minimalist, | ||||
| with no external dependencies. | ||||
|  | ||||
| ## Compatibility | ||||
|  | ||||
| This project intends to follow [semantic versioning](http://semver.org) and | ||||
| is very strict about compatibility.  Any proposed changes MUST follow those | ||||
| rules. | ||||
|  | ||||
| ## Performance | ||||
|  | ||||
| As a logging library, logr must be as light-weight as possible.  Any proposed | ||||
| code change must include results of running the [benchmark](./benchmark) | ||||
| before and after the change. | ||||
							
								
								
									
										209
									
								
								vendor/github.com/go-logr/logr/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										209
									
								
								vendor/github.com/go-logr/logr/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,112 +1,182 @@ | ||||
| # A more minimal logging API for Go | ||||
| # A minimal logging API for Go | ||||
|  | ||||
| [](https://pkg.go.dev/github.com/go-logr/logr) | ||||
|  | ||||
| logr offers an(other) opinion on how Go programs and libraries can do logging | ||||
| without becoming coupled to a particular logging implementation.  This is not | ||||
| an implementation of logging - it is an API.  In fact it is two APIs with two | ||||
| different sets of users. | ||||
|  | ||||
| The `Logger` type is intended for application and library authors.  It provides | ||||
| a relatively small API which can be used everywhere you want to emit logs.  It | ||||
| defers the actual act of writing logs (to files, to stdout, or whatever) to the | ||||
| `LogSink` interface. | ||||
|  | ||||
| The `LogSink` interface is intended for logging library implementers.  It is a | ||||
| pure interface which can be implemented by logging frameworks to provide the actual logging | ||||
| functionality. | ||||
|  | ||||
| This decoupling allows application and library developers to write code in | ||||
| terms of `logr.Logger` (which has very low dependency fan-out) while the | ||||
| implementation of logging is managed "up stack" (e.g. in or near `main()`.) | ||||
| Application developers can then switch out implementations as necessary. | ||||
|  | ||||
| Many people assert that libraries should not be logging, and as such efforts | ||||
| like this are pointless.  Those people are welcome to convince the authors of | ||||
| the tens-of-thousands of libraries that *DO* write logs that they are all | ||||
| wrong.  In the meantime, logr takes a more practical approach. | ||||
|  | ||||
| ## Typical usage | ||||
|  | ||||
| Somewhere, early in an application's life, it will make a decision about which | ||||
| logging library (implementation) it actually wants to use.  Something like: | ||||
|  | ||||
| ``` | ||||
|     func main() { | ||||
|         // ... other setup code ... | ||||
|  | ||||
|         // Create the "root" logger.  We have chosen the "logimpl" implementation, | ||||
|         // which takes some initial parameters and returns a logr.Logger. | ||||
|         logger := logimpl.New(param1, param2) | ||||
|  | ||||
|         // ... other setup code ... | ||||
| ``` | ||||
|  | ||||
| Most apps will call into other libraries, create structures to govern the flow, | ||||
| etc.  The `logr.Logger` object can be passed to these other libraries, stored | ||||
| in structs, or even used as a package-global variable, if needed.  For example: | ||||
|  | ||||
| ``` | ||||
|     app := createTheAppObject(logger) | ||||
|     app.Run() | ||||
| ``` | ||||
|  | ||||
| Outside of this early setup, no other packages need to know about the choice of | ||||
| implementation.  They write logs in terms of the `logr.Logger` that they | ||||
| received: | ||||
|  | ||||
| ``` | ||||
|     type appObject struct { | ||||
|         // ... other fields ... | ||||
|         logger logr.Logger | ||||
|         // ... other fields ... | ||||
|     } | ||||
|  | ||||
|     func (app *appObject) Run() { | ||||
|         app.logger.Info("starting up", "timestamp", time.Now()) | ||||
|  | ||||
|         // ... app code ... | ||||
| ``` | ||||
|  | ||||
| ## Background | ||||
|  | ||||
| If the Go standard library had defined an interface for logging, this project | ||||
| probably would not be needed.  Alas, here we are. | ||||
|  | ||||
| ### Inspiration | ||||
|  | ||||
| Before you consider this package, please read [this blog post by the | ||||
| inimitable Dave Cheney][warning-makes-no-sense].  I really appreciate what | ||||
| he has to say, and it largely aligns with my own experiences.  Too many | ||||
| choices of levels means inconsistent logs. | ||||
| inimitable Dave Cheney][warning-makes-no-sense].  We really appreciate what | ||||
| he has to say, and it largely aligns with our own experiences. | ||||
|  | ||||
| This package offers a purely abstract interface, based on these ideas but with | ||||
| a few twists.  Code can depend on just this interface and have the actual | ||||
| logging implementation be injected from callers.  Ideally only `main()` knows | ||||
| what logging implementation is being used. | ||||
|  | ||||
| # Differences from Dave's ideas | ||||
| ### Differences from Dave's ideas | ||||
|  | ||||
| The main differences are: | ||||
|  | ||||
| 1) Dave basically proposes doing away with the notion of a logging API in favor | ||||
| of `fmt.Printf()`.  I disagree, especially when you consider things like output | ||||
| locations, timestamps, file and line decorations, and structured logging.  I | ||||
| restrict the API to just 2 types of logs: info and error. | ||||
| 1. Dave basically proposes doing away with the notion of a logging API in favor | ||||
| of `fmt.Printf()`.  We disagree, especially when you consider things like output | ||||
| locations, timestamps, file and line decorations, and structured logging.  This | ||||
| package restricts the logging API to just 2 types of logs: info and error. | ||||
|  | ||||
| Info logs are things you want to tell the user which are not errors.  Error | ||||
| logs are, well, errors.  If your code receives an `error` from a subordinate | ||||
| function call and is logging that `error` *and not returning it*, use error | ||||
| logs. | ||||
|  | ||||
| 2) Verbosity-levels on info logs.  This gives developers a chance to indicate | ||||
| 2. Verbosity-levels on info logs.  This gives developers a chance to indicate | ||||
| arbitrary grades of importance for info logs, without assigning names with | ||||
| semantic meaning such as "warning", "trace", and "debug".  Superficially this | ||||
| semantic meaning such as "warning", "trace", and "debug."  Superficially this | ||||
| may feel very similar, but the primary difference is the lack of semantics. | ||||
| Because verbosity is a numerical value, it's safe to assume that an app running | ||||
| with higher verbosity means more (and less important) logs will be generated. | ||||
|  | ||||
| This is a BETA grade API. | ||||
| ## Implementations (non-exhaustive) | ||||
|  | ||||
| There are implementations for the following logging libraries: | ||||
|  | ||||
| - **a function** (can bridge to non-structured libraries): [funcr](https://github.com/go-logr/logr/tree/master/funcr) | ||||
| - **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr) | ||||
| - **k8s.io/klog**: [klogr](https://git.k8s.io/klog/klogr) | ||||
| - **k8s.io/klog** (for Kubernetes): [klogr](https://git.k8s.io/klog/klogr) | ||||
| - **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr) | ||||
| - **log** (the Go standard library logger): | ||||
|   [stdr](https://github.com/go-logr/stdr) | ||||
| - **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr) | ||||
| - **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr) | ||||
| - **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend) | ||||
| - **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr) | ||||
| - **github.com/rs/zerolog**: [zerologr](https://github.com/go-logr/zerologr) | ||||
|  | ||||
| # FAQ | ||||
| ## FAQ | ||||
|  | ||||
| ## Conceptual | ||||
| ### Conceptual | ||||
|  | ||||
| ## Why structured logging? | ||||
| #### Why structured logging? | ||||
|  | ||||
| - **Structured logs are more easily queriable**: Since you've got | ||||
| - **Structured logs are more easily queryable**: Since you've got | ||||
|   key-value pairs, it's much easier to query your structured logs for | ||||
|   particular values by filtering on the contents of a particular key -- | ||||
|   think searching request logs for error codes, Kubernetes reconcilers for | ||||
|   the name and namespace of the reconciled object, etc | ||||
|   the name and namespace of the reconciled object, etc. | ||||
|  | ||||
| - **Structured logging makes it easier to have cross-referencable logs**: | ||||
| - **Structured logging makes it easier to have cross-referenceable logs**: | ||||
|   Similarly to searchability, if you maintain conventions around your | ||||
|   keys, it becomes easy to gather all log lines related to a particular | ||||
|   concept. | ||||
|   | ||||
|  | ||||
| - **Structured logs allow better dimensions of filtering**: if you have | ||||
|   structure to your logs, you've got more precise control over how much | ||||
|   information is logged -- you might choose in a particular configuration | ||||
|   to log certain keys but not others, only log lines where a certain key | ||||
|   matches a certain value, etc, instead of just having v-levels and names | ||||
|   matches a certain value, etc., instead of just having v-levels and names | ||||
|   to key off of. | ||||
|  | ||||
| - **Structured logs better represent structured data**: sometimes, the | ||||
|   data that you want to log is inherently structured (think tuple-link | ||||
|   objects).  Structured logs allow you to preserve that structure when | ||||
|   objects.)  Structured logs allow you to preserve that structure when | ||||
|   outputting. | ||||
|  | ||||
| ## Why V-levels? | ||||
| #### Why V-levels? | ||||
|  | ||||
| **V-levels give operators an easy way to control the chattiness of log | ||||
| operations**.  V-levels provide a way for a given package to distinguish | ||||
| the relative importance or verbosity of a given log message.  Then, if | ||||
| a particular logger or package is logging too many messages, the user | ||||
| of the package can simply change the v-levels for that library.  | ||||
| of the package can simply change the v-levels for that library. | ||||
|  | ||||
| ## Why not more named levels, like Warning? | ||||
| #### Why not named levels, like Info/Warning/Error? | ||||
|  | ||||
| Read [Dave Cheney's post][warning-makes-no-sense].  Then read [Differences | ||||
| from Dave's ideas](#differences-from-daves-ideas). | ||||
|  | ||||
| ## Why not allow format strings, too? | ||||
| #### Why not allow format strings, too? | ||||
|  | ||||
| **Format strings negate many of the benefits of structured logs**: | ||||
|  | ||||
| - They're not easily searchable without resorting to fuzzy searching, | ||||
|   regular expressions, etc | ||||
|   regular expressions, etc. | ||||
|  | ||||
| - They don't store structured data well, since contents are flattened into | ||||
|   a string | ||||
|   a string. | ||||
|  | ||||
| - They're not cross-referencable | ||||
| - They're not cross-referenceable. | ||||
|  | ||||
| - They don't compress easily, since the message is not constant | ||||
| - They don't compress easily, since the message is not constant. | ||||
|  | ||||
| (unless you turn positional parameters into key-value pairs with numerical | ||||
| (Unless you turn positional parameters into key-value pairs with numerical | ||||
| keys, at which point you've gotten key-value logging with meaningless | ||||
| keys) | ||||
| keys.) | ||||
|  | ||||
| ## Practical | ||||
| ### Practical | ||||
|  | ||||
| ## Why key-value pairs, and not a map? | ||||
| #### Why key-value pairs, and not a map? | ||||
|  | ||||
| Key-value pairs are *much* easier to optimize, especially around | ||||
| allocations.  Zap (a structured logger that inspired logr's interface) has | ||||
| @@ -117,26 +187,26 @@ While the interface ends up being a little less obvious, you get | ||||
| potentially better performance, plus avoid making users type | ||||
| `map[string]string{}` every time they want to log. | ||||
|  | ||||
| ## What if my V-levels differ between libraries? | ||||
| #### What if my V-levels differ between libraries? | ||||
|  | ||||
| That's fine.  Control your V-levels on a per-logger basis, and use the | ||||
| `WithName` function to pass different loggers to different libraries. | ||||
| `WithName` method to pass different loggers to different libraries. | ||||
|  | ||||
| Generally, you should take care to ensure that you have relatively | ||||
| consistent V-levels within a given logger, however, as this makes deciding | ||||
| on what verbosity of logs to request easier. | ||||
|  | ||||
| ## But I *really* want to use a format string! | ||||
| #### But I really want to use a format string! | ||||
|  | ||||
| That's not actually a question.  Assuming your question is "how do | ||||
| I convert my mental model of logging with format strings to logging with | ||||
| constant messages": | ||||
|  | ||||
| 1. figure out what the error actually is, as you'd write in a TL;DR style, | ||||
|    and use that as a message | ||||
| 1. Figure out what the error actually is, as you'd write in a TL;DR style, | ||||
|    and use that as a message. | ||||
|  | ||||
| 2. For every place you'd write a format specifier, look to the word before | ||||
|    it, and add that as a key value pair | ||||
|    it, and add that as a key value pair. | ||||
|  | ||||
| For instance, consider the following examples (all taken from spots in the | ||||
| Kubernetes codebase): | ||||
| @@ -150,34 +220,59 @@ Kubernetes codebase): | ||||
|   response when requesting url", "attempt", retries, "after | ||||
|   seconds", seconds, "url", url)` | ||||
|  | ||||
| If you *really* must use a format string, place it as a key value, and | ||||
| call `fmt.Sprintf` yourself -- for instance, `log.Printf("unable to | ||||
| If you *really* must use a format string, use it in a key's value, and | ||||
| call `fmt.Sprintf` yourself.  For instance: `log.Printf("unable to | ||||
| reflect over type %T")` becomes `logger.Info("unable to reflect over | ||||
| type", "type", fmt.Sprintf("%T"))`.  In general though, the cases where | ||||
| this is necessary should be few and far between. | ||||
|  | ||||
| ## How do I choose my V-levels? | ||||
| #### How do I choose my V-levels? | ||||
|  | ||||
| This is basically the only hard constraint: increase V-levels to denote | ||||
| more verbose or more debug-y logs. | ||||
|  | ||||
| Otherwise, you can start out with `0` as "you always want to see this", | ||||
| `1` as "common logging that you might *possibly* want to turn off", and | ||||
| `10` as "I would like to performance-test your log collection stack". | ||||
| `10` as "I would like to performance-test your log collection stack." | ||||
|  | ||||
| Then gradually choose levels in between as you need them, working your way | ||||
| down from 10 (for debug and trace style logs) and up from 1 (for chattier | ||||
| info-type logs). | ||||
| info-type logs.) | ||||
|  | ||||
| ## How do I choose my keys | ||||
| #### How do I choose my keys? | ||||
|  | ||||
| - make your keys human-readable | ||||
| - constant keys are generally a good idea | ||||
| - be consistent across your codebase | ||||
| - keys should naturally match parts of the message string | ||||
| Keys are fairly flexible, and can hold more or less any string | ||||
| value. For best compatibility with implementations and consistency | ||||
| with existing code in other projects, there are a few conventions you | ||||
| should consider. | ||||
|  | ||||
| - Make your keys human-readable. | ||||
| - Constant keys are generally a good idea. | ||||
| - Be consistent across your codebase. | ||||
| - Keys should naturally match parts of the message string. | ||||
| - Use lower case for simple keys and | ||||
|   [lowerCamelCase](https://en.wiktionary.org/wiki/lowerCamelCase) for | ||||
|   more complex ones. Kubernetes is one example of a project that has | ||||
|   [adopted that | ||||
|   convention](https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments). | ||||
|  | ||||
| While key names are mostly unrestricted (and spaces are acceptable), | ||||
| it's generally a good idea to stick to printable ascii characters, or at | ||||
| least match the general character set of your log lines. | ||||
|  | ||||
| #### Why should keys be constant values? | ||||
|  | ||||
| The point of structured logging is to make later log processing easier.  Your | ||||
| keys are, effectively, the schema of each log message.  If you use different | ||||
| keys across instances of the same log line, you will make your structured logs | ||||
| much harder to use.  `Sprintf()` is for values, not for keys! | ||||
|  | ||||
| #### Why is this not a pure interface? | ||||
|  | ||||
| The Logger type is implemented as a struct in order to allow the Go compiler to | ||||
| optimize things like high-V `Info` logs that are not triggered.  Not all of | ||||
| these implementations are implemented yet, but this structure was suggested as | ||||
| a way to ensure they *can* be implemented.  All of the real work is behind the | ||||
| `LogSink` interface. | ||||
|  | ||||
| [warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging | ||||
|   | ||||
							
								
								
									
										37
									
								
								vendor/github.com/go-logr/logr/discard.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/go-logr/logr/discard.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,36 +16,39 @@ limitations under the License. | ||||
|  | ||||
| package logr | ||||
|  | ||||
| // Discard returns a valid Logger that discards all messages logged to it. | ||||
| // It can be used whenever the caller is not interested in the logs. | ||||
| // Discard returns a Logger that discards all messages logged to it.  It can be | ||||
| // used whenever the caller is not interested in the logs.  Logger instances | ||||
| // produced by this function always compare as equal. | ||||
| func Discard() Logger { | ||||
| 	return DiscardLogger{} | ||||
| 	return Logger{ | ||||
| 		level: 0, | ||||
| 		sink:  discardLogSink{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DiscardLogger is a Logger that discards all messages. | ||||
| type DiscardLogger struct{} | ||||
| // discardLogSink is a LogSink that discards all messages. | ||||
| type discardLogSink struct{} | ||||
|  | ||||
| func (l DiscardLogger) Enabled() bool { | ||||
| // Verify that it actually implements the interface | ||||
| var _ LogSink = discardLogSink{} | ||||
|  | ||||
| func (l discardLogSink) Init(RuntimeInfo) { | ||||
| } | ||||
|  | ||||
| func (l discardLogSink) Enabled(int) bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (l DiscardLogger) Info(msg string, keysAndValues ...interface{}) { | ||||
| func (l discardLogSink) Info(int, string, ...interface{}) { | ||||
| } | ||||
|  | ||||
| func (l DiscardLogger) Error(err error, msg string, keysAndValues ...interface{}) { | ||||
| func (l discardLogSink) Error(error, string, ...interface{}) { | ||||
| } | ||||
|  | ||||
| func (l DiscardLogger) V(level int) Logger { | ||||
| func (l discardLogSink) WithValues(...interface{}) LogSink { | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| func (l DiscardLogger) WithValues(keysAndValues ...interface{}) Logger { | ||||
| func (l discardLogSink) WithName(string) LogSink { | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| func (l DiscardLogger) WithName(name string) Logger { | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Verify that it actually implements the interface | ||||
| var _ Logger = DiscardLogger{} | ||||
|   | ||||
							
								
								
									
										759
									
								
								vendor/github.com/go-logr/logr/funcr/funcr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										759
									
								
								vendor/github.com/go-logr/logr/funcr/funcr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,759 @@ | ||||
| /* | ||||
| Copyright 2021 The logr 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 funcr implements formatting of structured log messages and | ||||
| // optionally captures the call site and timestamp. | ||||
| // | ||||
| // The simplest way to use it is via its implementation of a | ||||
| // github.com/go-logr/logr.LogSink with output through an arbitrary | ||||
| // "write" function.  See New and NewJSON for details. | ||||
| // | ||||
| // Custom LogSinks | ||||
| // | ||||
| // For users who need more control, a funcr.Formatter can be embedded inside | ||||
| // your own custom LogSink implementation. This is useful when the LogSink | ||||
| // needs to implement additional methods, for example. | ||||
| // | ||||
| // Formatting | ||||
| // | ||||
| // This will respect logr.Marshaler, fmt.Stringer, and error interfaces for | ||||
| // values which are being logged.  When rendering a struct, funcr will use Go's | ||||
| // standard JSON tags (all except "string"). | ||||
| package funcr | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/go-logr/logr" | ||||
| ) | ||||
|  | ||||
| // New returns a logr.Logger which is implemented by an arbitrary function. | ||||
| func New(fn func(prefix, args string), opts Options) logr.Logger { | ||||
| 	return logr.New(newSink(fn, NewFormatter(opts))) | ||||
| } | ||||
|  | ||||
| // NewJSON returns a logr.Logger which is implemented by an arbitrary function | ||||
| // and produces JSON output. | ||||
| func NewJSON(fn func(obj string), opts Options) logr.Logger { | ||||
| 	fnWrapper := func(_, obj string) { | ||||
| 		fn(obj) | ||||
| 	} | ||||
| 	return logr.New(newSink(fnWrapper, NewFormatterJSON(opts))) | ||||
| } | ||||
|  | ||||
| // Underlier exposes access to the underlying logging function. Since | ||||
| // callers only have a logr.Logger, they have to know which | ||||
| // implementation is in use, so this interface is less of an | ||||
| // abstraction and more of a way to test type conversion. | ||||
| type Underlier interface { | ||||
| 	GetUnderlying() func(prefix, args string) | ||||
| } | ||||
|  | ||||
| func newSink(fn func(prefix, args string), formatter Formatter) logr.LogSink { | ||||
| 	l := &fnlogger{ | ||||
| 		Formatter: formatter, | ||||
| 		write:     fn, | ||||
| 	} | ||||
| 	// For skipping fnlogger.Info and fnlogger.Error. | ||||
| 	l.Formatter.AddCallDepth(1) | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Options carries parameters which influence the way logs are generated. | ||||
| type Options struct { | ||||
| 	// LogCaller tells funcr to add a "caller" key to some or all log lines. | ||||
| 	// This has some overhead, so some users might not want it. | ||||
| 	LogCaller MessageClass | ||||
|  | ||||
| 	// LogCallerFunc tells funcr to also log the calling function name.  This | ||||
| 	// has no effect if caller logging is not enabled (see Options.LogCaller). | ||||
| 	LogCallerFunc bool | ||||
|  | ||||
| 	// LogTimestamp tells funcr to add a "ts" key to log lines.  This has some | ||||
| 	// overhead, so some users might not want it. | ||||
| 	LogTimestamp bool | ||||
|  | ||||
| 	// TimestampFormat tells funcr how to render timestamps when LogTimestamp | ||||
| 	// is enabled.  If not specified, a default format will be used.  For more | ||||
| 	// details, see docs for Go's time.Layout. | ||||
| 	TimestampFormat string | ||||
|  | ||||
| 	// Verbosity tells funcr which V logs to produce.  Higher values enable | ||||
| 	// more logs.  Info logs at or below this level will be written, while logs | ||||
| 	// above this level will be discarded. | ||||
| 	Verbosity int | ||||
|  | ||||
| 	// RenderBuiltinsHook allows users to mutate the list of key-value pairs | ||||
| 	// while a log line is being rendered.  The kvList argument follows logr | ||||
| 	// conventions - each pair of slice elements is comprised of a string key | ||||
| 	// and an arbitrary value (verified and sanitized before calling this | ||||
| 	// hook).  The value returned must follow the same conventions.  This hook | ||||
| 	// can be used to audit or modify logged data.  For example, you might want | ||||
| 	// to prefix all of funcr's built-in keys with some string.  This hook is | ||||
| 	// only called for built-in (provided by funcr itself) key-value pairs. | ||||
| 	// Equivalent hooks are offered for key-value pairs saved via | ||||
| 	// logr.Logger.WithValues or Formatter.AddValues (see RenderValuesHook) and | ||||
| 	// for user-provided pairs (see RenderArgsHook). | ||||
| 	RenderBuiltinsHook func(kvList []interface{}) []interface{} | ||||
|  | ||||
| 	// RenderValuesHook is the same as RenderBuiltinsHook, except that it is | ||||
| 	// only called for key-value pairs saved via logr.Logger.WithValues.  See | ||||
| 	// RenderBuiltinsHook for more details. | ||||
| 	RenderValuesHook func(kvList []interface{}) []interface{} | ||||
|  | ||||
| 	// RenderArgsHook is the same as RenderBuiltinsHook, except that it is only | ||||
| 	// called for key-value pairs passed directly to Info and Error.  See | ||||
| 	// RenderBuiltinsHook for more details. | ||||
| 	RenderArgsHook func(kvList []interface{}) []interface{} | ||||
|  | ||||
| 	// MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct | ||||
| 	// that contains a struct, etc.) it may log.  Every time it finds a struct, | ||||
| 	// slice, array, or map the depth is increased by one.  When the maximum is | ||||
| 	// reached, the value will be converted to a string indicating that the max | ||||
| 	// depth has been exceeded.  If this field is not specified, a default | ||||
| 	// value will be used. | ||||
| 	MaxLogDepth int | ||||
| } | ||||
|  | ||||
| // MessageClass indicates which category or categories of messages to consider. | ||||
| type MessageClass int | ||||
|  | ||||
| const ( | ||||
| 	// None ignores all message classes. | ||||
| 	None MessageClass = iota | ||||
| 	// All considers all message classes. | ||||
| 	All | ||||
| 	// Info only considers info messages. | ||||
| 	Info | ||||
| 	// Error only considers error messages. | ||||
| 	Error | ||||
| ) | ||||
|  | ||||
| // fnlogger inherits some of its LogSink implementation from Formatter | ||||
| // and just needs to add some glue code. | ||||
| type fnlogger struct { | ||||
| 	Formatter | ||||
| 	write func(prefix, args string) | ||||
| } | ||||
|  | ||||
| func (l fnlogger) WithName(name string) logr.LogSink { | ||||
| 	l.Formatter.AddName(name) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| func (l fnlogger) WithValues(kvList ...interface{}) logr.LogSink { | ||||
| 	l.Formatter.AddValues(kvList) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| func (l fnlogger) WithCallDepth(depth int) logr.LogSink { | ||||
| 	l.Formatter.AddCallDepth(depth) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| func (l fnlogger) Info(level int, msg string, kvList ...interface{}) { | ||||
| 	prefix, args := l.FormatInfo(level, msg, kvList) | ||||
| 	l.write(prefix, args) | ||||
| } | ||||
|  | ||||
| func (l fnlogger) Error(err error, msg string, kvList ...interface{}) { | ||||
| 	prefix, args := l.FormatError(err, msg, kvList) | ||||
| 	l.write(prefix, args) | ||||
| } | ||||
|  | ||||
| func (l fnlogger) GetUnderlying() func(prefix, args string) { | ||||
| 	return l.write | ||||
| } | ||||
|  | ||||
| // Assert conformance to the interfaces. | ||||
| var _ logr.LogSink = &fnlogger{} | ||||
| var _ logr.CallDepthLogSink = &fnlogger{} | ||||
| var _ Underlier = &fnlogger{} | ||||
|  | ||||
| // NewFormatter constructs a Formatter which emits a JSON-like key=value format. | ||||
| func NewFormatter(opts Options) Formatter { | ||||
| 	return newFormatter(opts, outputKeyValue) | ||||
| } | ||||
|  | ||||
| // NewFormatterJSON constructs a Formatter which emits strict JSON. | ||||
| func NewFormatterJSON(opts Options) Formatter { | ||||
| 	return newFormatter(opts, outputJSON) | ||||
| } | ||||
|  | ||||
| // Defaults for Options. | ||||
| const defaultTimestampFormat = "2006-01-02 15:04:05.000000" | ||||
| const defaultMaxLogDepth = 16 | ||||
|  | ||||
| func newFormatter(opts Options, outfmt outputFormat) Formatter { | ||||
| 	if opts.TimestampFormat == "" { | ||||
| 		opts.TimestampFormat = defaultTimestampFormat | ||||
| 	} | ||||
| 	if opts.MaxLogDepth == 0 { | ||||
| 		opts.MaxLogDepth = defaultMaxLogDepth | ||||
| 	} | ||||
| 	f := Formatter{ | ||||
| 		outputFormat: outfmt, | ||||
| 		prefix:       "", | ||||
| 		values:       nil, | ||||
| 		depth:        0, | ||||
| 		opts:         opts, | ||||
| 	} | ||||
| 	return f | ||||
| } | ||||
|  | ||||
| // Formatter is an opaque struct which can be embedded in a LogSink | ||||
| // implementation. It should be constructed with NewFormatter. Some of | ||||
| // its methods directly implement logr.LogSink. | ||||
| type Formatter struct { | ||||
| 	outputFormat outputFormat | ||||
| 	prefix       string | ||||
| 	values       []interface{} | ||||
| 	valuesStr    string | ||||
| 	depth        int | ||||
| 	opts         Options | ||||
| } | ||||
|  | ||||
| // outputFormat indicates which outputFormat to use. | ||||
| type outputFormat int | ||||
|  | ||||
| const ( | ||||
| 	// outputKeyValue emits a JSON-like key=value format, but not strict JSON. | ||||
| 	outputKeyValue outputFormat = iota | ||||
| 	// outputJSON emits strict JSON. | ||||
| 	outputJSON | ||||
| ) | ||||
|  | ||||
| // PseudoStruct is a list of key-value pairs that gets logged as a struct. | ||||
| type PseudoStruct []interface{} | ||||
|  | ||||
| // render produces a log line, ready to use. | ||||
| func (f Formatter) render(builtins, args []interface{}) string { | ||||
| 	// Empirically bytes.Buffer is faster than strings.Builder for this. | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, 1024)) | ||||
| 	if f.outputFormat == outputJSON { | ||||
| 		buf.WriteByte('{') | ||||
| 	} | ||||
| 	vals := builtins | ||||
| 	if hook := f.opts.RenderBuiltinsHook; hook != nil { | ||||
| 		vals = hook(f.sanitize(vals)) | ||||
| 	} | ||||
| 	f.flatten(buf, vals, false, false) // keys are ours, no need to escape | ||||
| 	continuing := len(builtins) > 0 | ||||
| 	if len(f.valuesStr) > 0 { | ||||
| 		if continuing { | ||||
| 			if f.outputFormat == outputJSON { | ||||
| 				buf.WriteByte(',') | ||||
| 			} else { | ||||
| 				buf.WriteByte(' ') | ||||
| 			} | ||||
| 		} | ||||
| 		continuing = true | ||||
| 		buf.WriteString(f.valuesStr) | ||||
| 	} | ||||
| 	vals = args | ||||
| 	if hook := f.opts.RenderArgsHook; hook != nil { | ||||
| 		vals = hook(f.sanitize(vals)) | ||||
| 	} | ||||
| 	f.flatten(buf, vals, continuing, true) // escape user-provided keys | ||||
| 	if f.outputFormat == outputJSON { | ||||
| 		buf.WriteByte('}') | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| // flatten renders a list of key-value pairs into a buffer.  If continuing is | ||||
| // true, it assumes that the buffer has previous values and will emit a | ||||
| // separator (which depends on the output format) before the first pair it | ||||
| // writes.  If escapeKeys is true, the keys are assumed to have | ||||
| // non-JSON-compatible characters in them and must be evaluated for escapes. | ||||
| // | ||||
| // This function returns a potentially modified version of kvList, which | ||||
| // ensures that there is a value for every key (adding a value if needed) and | ||||
| // that each key is a string (substituting a key if needed). | ||||
| func (f Formatter) flatten(buf *bytes.Buffer, kvList []interface{}, continuing bool, escapeKeys bool) []interface{} { | ||||
| 	// This logic overlaps with sanitize() but saves one type-cast per key, | ||||
| 	// which can be measurable. | ||||
| 	if len(kvList)%2 != 0 { | ||||
| 		kvList = append(kvList, noValue) | ||||
| 	} | ||||
| 	for i := 0; i < len(kvList); i += 2 { | ||||
| 		k, ok := kvList[i].(string) | ||||
| 		if !ok { | ||||
| 			k = f.nonStringKey(kvList[i]) | ||||
| 			kvList[i] = k | ||||
| 		} | ||||
| 		v := kvList[i+1] | ||||
|  | ||||
| 		if i > 0 || continuing { | ||||
| 			if f.outputFormat == outputJSON { | ||||
| 				buf.WriteByte(',') | ||||
| 			} else { | ||||
| 				// In theory the format could be something we don't understand.  In | ||||
| 				// practice, we control it, so it won't be. | ||||
| 				buf.WriteByte(' ') | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if escapeKeys { | ||||
| 			buf.WriteString(prettyString(k)) | ||||
| 		} else { | ||||
| 			// this is faster | ||||
| 			buf.WriteByte('"') | ||||
| 			buf.WriteString(k) | ||||
| 			buf.WriteByte('"') | ||||
| 		} | ||||
| 		if f.outputFormat == outputJSON { | ||||
| 			buf.WriteByte(':') | ||||
| 		} else { | ||||
| 			buf.WriteByte('=') | ||||
| 		} | ||||
| 		buf.WriteString(f.pretty(v)) | ||||
| 	} | ||||
| 	return kvList | ||||
| } | ||||
|  | ||||
| func (f Formatter) pretty(value interface{}) string { | ||||
| 	return f.prettyWithFlags(value, 0, 0) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	flagRawStruct = 0x1 // do not print braces on structs | ||||
| ) | ||||
|  | ||||
| // TODO: This is not fast. Most of the overhead goes here. | ||||
| func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) string { | ||||
| 	if depth > f.opts.MaxLogDepth { | ||||
| 		return `"<max-log-depth-exceeded>"` | ||||
| 	} | ||||
|  | ||||
| 	// Handle types that take full control of logging. | ||||
| 	if v, ok := value.(logr.Marshaler); ok { | ||||
| 		// Replace the value with what the type wants to get logged. | ||||
| 		// That then gets handled below via reflection. | ||||
| 		value = v.MarshalLog() | ||||
| 	} | ||||
|  | ||||
| 	// Handle types that want to format themselves. | ||||
| 	switch v := value.(type) { | ||||
| 	case fmt.Stringer: | ||||
| 		value = v.String() | ||||
| 	case error: | ||||
| 		value = v.Error() | ||||
| 	} | ||||
|  | ||||
| 	// Handling the most common types without reflect is a small perf win. | ||||
| 	switch v := value.(type) { | ||||
| 	case bool: | ||||
| 		return strconv.FormatBool(v) | ||||
| 	case string: | ||||
| 		return prettyString(v) | ||||
| 	case int: | ||||
| 		return strconv.FormatInt(int64(v), 10) | ||||
| 	case int8: | ||||
| 		return strconv.FormatInt(int64(v), 10) | ||||
| 	case int16: | ||||
| 		return strconv.FormatInt(int64(v), 10) | ||||
| 	case int32: | ||||
| 		return strconv.FormatInt(int64(v), 10) | ||||
| 	case int64: | ||||
| 		return strconv.FormatInt(int64(v), 10) | ||||
| 	case uint: | ||||
| 		return strconv.FormatUint(uint64(v), 10) | ||||
| 	case uint8: | ||||
| 		return strconv.FormatUint(uint64(v), 10) | ||||
| 	case uint16: | ||||
| 		return strconv.FormatUint(uint64(v), 10) | ||||
| 	case uint32: | ||||
| 		return strconv.FormatUint(uint64(v), 10) | ||||
| 	case uint64: | ||||
| 		return strconv.FormatUint(v, 10) | ||||
| 	case uintptr: | ||||
| 		return strconv.FormatUint(uint64(v), 10) | ||||
| 	case float32: | ||||
| 		return strconv.FormatFloat(float64(v), 'f', -1, 32) | ||||
| 	case float64: | ||||
| 		return strconv.FormatFloat(v, 'f', -1, 64) | ||||
| 	case complex64: | ||||
| 		return `"` + strconv.FormatComplex(complex128(v), 'f', -1, 64) + `"` | ||||
| 	case complex128: | ||||
| 		return `"` + strconv.FormatComplex(v, 'f', -1, 128) + `"` | ||||
| 	case PseudoStruct: | ||||
| 		buf := bytes.NewBuffer(make([]byte, 0, 1024)) | ||||
| 		v = f.sanitize(v) | ||||
| 		if flags&flagRawStruct == 0 { | ||||
| 			buf.WriteByte('{') | ||||
| 		} | ||||
| 		for i := 0; i < len(v); i += 2 { | ||||
| 			if i > 0 { | ||||
| 				buf.WriteByte(',') | ||||
| 			} | ||||
| 			// arbitrary keys might need escaping | ||||
| 			buf.WriteString(prettyString(v[i].(string))) | ||||
| 			buf.WriteByte(':') | ||||
| 			buf.WriteString(f.prettyWithFlags(v[i+1], 0, depth+1)) | ||||
| 		} | ||||
| 		if flags&flagRawStruct == 0 { | ||||
| 			buf.WriteByte('}') | ||||
| 		} | ||||
| 		return buf.String() | ||||
| 	} | ||||
|  | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, 256)) | ||||
| 	t := reflect.TypeOf(value) | ||||
| 	if t == nil { | ||||
| 		return "null" | ||||
| 	} | ||||
| 	v := reflect.ValueOf(value) | ||||
| 	switch t.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		return strconv.FormatBool(v.Bool()) | ||||
| 	case reflect.String: | ||||
| 		return prettyString(v.String()) | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		return strconv.FormatInt(int64(v.Int()), 10) | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||
| 		return strconv.FormatUint(uint64(v.Uint()), 10) | ||||
| 	case reflect.Float32: | ||||
| 		return strconv.FormatFloat(float64(v.Float()), 'f', -1, 32) | ||||
| 	case reflect.Float64: | ||||
| 		return strconv.FormatFloat(v.Float(), 'f', -1, 64) | ||||
| 	case reflect.Complex64: | ||||
| 		return `"` + strconv.FormatComplex(complex128(v.Complex()), 'f', -1, 64) + `"` | ||||
| 	case reflect.Complex128: | ||||
| 		return `"` + strconv.FormatComplex(v.Complex(), 'f', -1, 128) + `"` | ||||
| 	case reflect.Struct: | ||||
| 		if flags&flagRawStruct == 0 { | ||||
| 			buf.WriteByte('{') | ||||
| 		} | ||||
| 		for i := 0; i < t.NumField(); i++ { | ||||
| 			fld := t.Field(i) | ||||
| 			if fld.PkgPath != "" { | ||||
| 				// reflect says this field is only defined for non-exported fields. | ||||
| 				continue | ||||
| 			} | ||||
| 			if !v.Field(i).CanInterface() { | ||||
| 				// reflect isn't clear exactly what this means, but we can't use it. | ||||
| 				continue | ||||
| 			} | ||||
| 			name := "" | ||||
| 			omitempty := false | ||||
| 			if tag, found := fld.Tag.Lookup("json"); found { | ||||
| 				if tag == "-" { | ||||
| 					continue | ||||
| 				} | ||||
| 				if comma := strings.Index(tag, ","); comma != -1 { | ||||
| 					if n := tag[:comma]; n != "" { | ||||
| 						name = n | ||||
| 					} | ||||
| 					rest := tag[comma:] | ||||
| 					if strings.Contains(rest, ",omitempty,") || strings.HasSuffix(rest, ",omitempty") { | ||||
| 						omitempty = true | ||||
| 					} | ||||
| 				} else { | ||||
| 					name = tag | ||||
| 				} | ||||
| 			} | ||||
| 			if omitempty && isEmpty(v.Field(i)) { | ||||
| 				continue | ||||
| 			} | ||||
| 			if i > 0 { | ||||
| 				buf.WriteByte(',') | ||||
| 			} | ||||
| 			if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" { | ||||
| 				buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1)) | ||||
| 				continue | ||||
| 			} | ||||
| 			if name == "" { | ||||
| 				name = fld.Name | ||||
| 			} | ||||
| 			// field names can't contain characters which need escaping | ||||
| 			buf.WriteByte('"') | ||||
| 			buf.WriteString(name) | ||||
| 			buf.WriteByte('"') | ||||
| 			buf.WriteByte(':') | ||||
| 			buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), 0, depth+1)) | ||||
| 		} | ||||
| 		if flags&flagRawStruct == 0 { | ||||
| 			buf.WriteByte('}') | ||||
| 		} | ||||
| 		return buf.String() | ||||
| 	case reflect.Slice, reflect.Array: | ||||
| 		buf.WriteByte('[') | ||||
| 		for i := 0; i < v.Len(); i++ { | ||||
| 			if i > 0 { | ||||
| 				buf.WriteByte(',') | ||||
| 			} | ||||
| 			e := v.Index(i) | ||||
| 			buf.WriteString(f.prettyWithFlags(e.Interface(), 0, depth+1)) | ||||
| 		} | ||||
| 		buf.WriteByte(']') | ||||
| 		return buf.String() | ||||
| 	case reflect.Map: | ||||
| 		buf.WriteByte('{') | ||||
| 		// This does not sort the map keys, for best perf. | ||||
| 		it := v.MapRange() | ||||
| 		i := 0 | ||||
| 		for it.Next() { | ||||
| 			if i > 0 { | ||||
| 				buf.WriteByte(',') | ||||
| 			} | ||||
| 			// If a map key supports TextMarshaler, use it. | ||||
| 			keystr := "" | ||||
| 			if m, ok := it.Key().Interface().(encoding.TextMarshaler); ok { | ||||
| 				txt, err := m.MarshalText() | ||||
| 				if err != nil { | ||||
| 					keystr = fmt.Sprintf("<error-MarshalText: %s>", err.Error()) | ||||
| 				} else { | ||||
| 					keystr = string(txt) | ||||
| 				} | ||||
| 				keystr = prettyString(keystr) | ||||
| 			} else { | ||||
| 				// prettyWithFlags will produce already-escaped values | ||||
| 				keystr = f.prettyWithFlags(it.Key().Interface(), 0, depth+1) | ||||
| 				if t.Key().Kind() != reflect.String { | ||||
| 					// JSON only does string keys.  Unlike Go's standard JSON, we'll | ||||
| 					// convert just about anything to a string. | ||||
| 					keystr = prettyString(keystr) | ||||
| 				} | ||||
| 			} | ||||
| 			buf.WriteString(keystr) | ||||
| 			buf.WriteByte(':') | ||||
| 			buf.WriteString(f.prettyWithFlags(it.Value().Interface(), 0, depth+1)) | ||||
| 			i++ | ||||
| 		} | ||||
| 		buf.WriteByte('}') | ||||
| 		return buf.String() | ||||
| 	case reflect.Ptr, reflect.Interface: | ||||
| 		if v.IsNil() { | ||||
| 			return "null" | ||||
| 		} | ||||
| 		return f.prettyWithFlags(v.Elem().Interface(), 0, depth) | ||||
| 	} | ||||
| 	return fmt.Sprintf(`"<unhandled-%s>"`, t.Kind().String()) | ||||
| } | ||||
|  | ||||
| func prettyString(s string) string { | ||||
| 	// Avoid escaping (which does allocations) if we can. | ||||
| 	if needsEscape(s) { | ||||
| 		return strconv.Quote(s) | ||||
| 	} | ||||
| 	b := bytes.NewBuffer(make([]byte, 0, 1024)) | ||||
| 	b.WriteByte('"') | ||||
| 	b.WriteString(s) | ||||
| 	b.WriteByte('"') | ||||
| 	return b.String() | ||||
| } | ||||
|  | ||||
| // needsEscape determines whether the input string needs to be escaped or not, | ||||
| // without doing any allocations. | ||||
| func needsEscape(s string) bool { | ||||
| 	for _, r := range s { | ||||
| 		if !strconv.IsPrint(r) || r == '\\' || r == '"' { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func isEmpty(v reflect.Value) bool { | ||||
| 	switch v.Kind() { | ||||
| 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String: | ||||
| 		return v.Len() == 0 | ||||
| 	case reflect.Bool: | ||||
| 		return !v.Bool() | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		return v.Int() == 0 | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||||
| 		return v.Uint() == 0 | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		return v.Float() == 0 | ||||
| 	case reflect.Complex64, reflect.Complex128: | ||||
| 		return v.Complex() == 0 | ||||
| 	case reflect.Interface, reflect.Ptr: | ||||
| 		return v.IsNil() | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Caller represents the original call site for a log line, after considering | ||||
| // logr.Logger.WithCallDepth and logr.Logger.WithCallStackHelper.  The File and | ||||
| // Line fields will always be provided, while the Func field is optional. | ||||
| // Users can set the render hook fields in Options to examine logged key-value | ||||
| // pairs, one of which will be {"caller", Caller} if the Options.LogCaller | ||||
| // field is enabled for the given MessageClass. | ||||
| type Caller struct { | ||||
| 	// File is the basename of the file for this call site. | ||||
| 	File string `json:"file"` | ||||
| 	// Line is the line number in the file for this call site. | ||||
| 	Line int `json:"line"` | ||||
| 	// Func is the function name for this call site, or empty if | ||||
| 	// Options.LogCallerFunc is not enabled. | ||||
| 	Func string `json:"function,omitempty"` | ||||
| } | ||||
|  | ||||
| func (f Formatter) caller() Caller { | ||||
| 	// +1 for this frame, +1 for Info/Error. | ||||
| 	pc, file, line, ok := runtime.Caller(f.depth + 2) | ||||
| 	if !ok { | ||||
| 		return Caller{"<unknown>", 0, ""} | ||||
| 	} | ||||
| 	fn := "" | ||||
| 	if f.opts.LogCallerFunc { | ||||
| 		if fp := runtime.FuncForPC(pc); fp != nil { | ||||
| 			fn = fp.Name() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return Caller{filepath.Base(file), line, fn} | ||||
| } | ||||
|  | ||||
| const noValue = "<no-value>" | ||||
|  | ||||
| func (f Formatter) nonStringKey(v interface{}) string { | ||||
| 	return fmt.Sprintf("<non-string-key: %s>", f.snippet(v)) | ||||
| } | ||||
|  | ||||
| // snippet produces a short snippet string of an arbitrary value. | ||||
| func (f Formatter) snippet(v interface{}) string { | ||||
| 	const snipLen = 16 | ||||
|  | ||||
| 	snip := f.pretty(v) | ||||
| 	if len(snip) > snipLen { | ||||
| 		snip = snip[:snipLen] | ||||
| 	} | ||||
| 	return snip | ||||
| } | ||||
|  | ||||
| // sanitize ensures that a list of key-value pairs has a value for every key | ||||
| // (adding a value if needed) and that each key is a string (substituting a key | ||||
| // if needed). | ||||
| func (f Formatter) sanitize(kvList []interface{}) []interface{} { | ||||
| 	if len(kvList)%2 != 0 { | ||||
| 		kvList = append(kvList, noValue) | ||||
| 	} | ||||
| 	for i := 0; i < len(kvList); i += 2 { | ||||
| 		_, ok := kvList[i].(string) | ||||
| 		if !ok { | ||||
| 			kvList[i] = f.nonStringKey(kvList[i]) | ||||
| 		} | ||||
| 	} | ||||
| 	return kvList | ||||
| } | ||||
|  | ||||
| // Init configures this Formatter from runtime info, such as the call depth | ||||
| // imposed by logr itself. | ||||
| // Note that this receiver is a pointer, so depth can be saved. | ||||
| func (f *Formatter) Init(info logr.RuntimeInfo) { | ||||
| 	f.depth += info.CallDepth | ||||
| } | ||||
|  | ||||
| // Enabled checks whether an info message at the given level should be logged. | ||||
| func (f Formatter) Enabled(level int) bool { | ||||
| 	return level <= f.opts.Verbosity | ||||
| } | ||||
|  | ||||
| // GetDepth returns the current depth of this Formatter.  This is useful for | ||||
| // implementations which do their own caller attribution. | ||||
| func (f Formatter) GetDepth() int { | ||||
| 	return f.depth | ||||
| } | ||||
|  | ||||
| // FormatInfo renders an Info log message into strings.  The prefix will be | ||||
| // empty when no names were set (via AddNames), or when the output is | ||||
| // configured for JSON. | ||||
| func (f Formatter) FormatInfo(level int, msg string, kvList []interface{}) (prefix, argsStr string) { | ||||
| 	args := make([]interface{}, 0, 64) // using a constant here impacts perf | ||||
| 	prefix = f.prefix | ||||
| 	if f.outputFormat == outputJSON { | ||||
| 		args = append(args, "logger", prefix) | ||||
| 		prefix = "" | ||||
| 	} | ||||
| 	if f.opts.LogTimestamp { | ||||
| 		args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat)) | ||||
| 	} | ||||
| 	if policy := f.opts.LogCaller; policy == All || policy == Info { | ||||
| 		args = append(args, "caller", f.caller()) | ||||
| 	} | ||||
| 	args = append(args, "level", level, "msg", msg) | ||||
| 	return prefix, f.render(args, kvList) | ||||
| } | ||||
|  | ||||
| // FormatError renders an Error log message into strings.  The prefix will be | ||||
| // empty when no names were set (via AddNames),  or when the output is | ||||
| // configured for JSON. | ||||
| func (f Formatter) FormatError(err error, msg string, kvList []interface{}) (prefix, argsStr string) { | ||||
| 	args := make([]interface{}, 0, 64) // using a constant here impacts perf | ||||
| 	prefix = f.prefix | ||||
| 	if f.outputFormat == outputJSON { | ||||
| 		args = append(args, "logger", prefix) | ||||
| 		prefix = "" | ||||
| 	} | ||||
| 	if f.opts.LogTimestamp { | ||||
| 		args = append(args, "ts", time.Now().Format(f.opts.TimestampFormat)) | ||||
| 	} | ||||
| 	if policy := f.opts.LogCaller; policy == All || policy == Error { | ||||
| 		args = append(args, "caller", f.caller()) | ||||
| 	} | ||||
| 	args = append(args, "msg", msg) | ||||
| 	var loggableErr interface{} | ||||
| 	if err != nil { | ||||
| 		loggableErr = err.Error() | ||||
| 	} | ||||
| 	args = append(args, "error", loggableErr) | ||||
| 	return f.prefix, f.render(args, kvList) | ||||
| } | ||||
|  | ||||
| // AddName appends the specified name.  funcr uses '/' characters to separate | ||||
| // name elements.  Callers should not pass '/' in the provided name string, but | ||||
| // this library does not actually enforce that. | ||||
| func (f *Formatter) AddName(name string) { | ||||
| 	if len(f.prefix) > 0 { | ||||
| 		f.prefix += "/" | ||||
| 	} | ||||
| 	f.prefix += name | ||||
| } | ||||
|  | ||||
| // AddValues adds key-value pairs to the set of saved values to be logged with | ||||
| // each log line. | ||||
| func (f *Formatter) AddValues(kvList []interface{}) { | ||||
| 	// Three slice args forces a copy. | ||||
| 	n := len(f.values) | ||||
| 	f.values = append(f.values[:n:n], kvList...) | ||||
|  | ||||
| 	vals := f.values | ||||
| 	if hook := f.opts.RenderValuesHook; hook != nil { | ||||
| 		vals = hook(f.sanitize(vals)) | ||||
| 	} | ||||
|  | ||||
| 	// Pre-render values, so we don't have to do it on each Info/Error call. | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, 1024)) | ||||
| 	f.flatten(buf, vals, false, true) // escape user-provided keys | ||||
| 	f.valuesStr = buf.String() | ||||
| } | ||||
|  | ||||
| // AddCallDepth increases the number of stack-frames to skip when attributing | ||||
| // the log line to a file and line. | ||||
| func (f *Formatter) AddCallDepth(depth int) { | ||||
| 	f.depth += depth | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/go-logr/logr/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-logr/logr/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | ||||
| module github.com/go-logr/logr | ||||
|  | ||||
| go 1.14 | ||||
| go 1.16 | ||||
|   | ||||
							
								
								
									
										549
									
								
								vendor/github.com/go-logr/logr/logr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										549
									
								
								vendor/github.com/go-logr/logr/logr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,83 +16,104 @@ limitations under the License. | ||||
|  | ||||
| // This design derives from Dave Cheney's blog: | ||||
| //     http://dave.cheney.net/2015/11/05/lets-talk-about-logging | ||||
| // | ||||
| // This is a BETA grade API.  Until there is a significant 2nd implementation, | ||||
| // I don't really know how it will change. | ||||
|  | ||||
| // Package logr defines abstract interfaces for logging.  Packages can depend on | ||||
| // these interfaces and callers can implement logging in whatever way is | ||||
| // appropriate. | ||||
| // Package logr defines a general-purpose logging API and abstract interfaces | ||||
| // to back that API.  Packages in the Go ecosystem can depend on this package, | ||||
| // while callers can implement logging with whatever backend is appropriate. | ||||
| // | ||||
| // Usage | ||||
| // | ||||
| // Logging is done using a Logger.  Loggers can have name prefixes and named | ||||
| // values attached, so that all log messages logged with that Logger have some | ||||
| // base context associated. | ||||
| // Logging is done using a Logger instance.  Logger is a concrete type with | ||||
| // methods, which defers the actual logging to a LogSink interface.  The main | ||||
| // methods of Logger are Info() and Error().  Arguments to Info() and Error() | ||||
| // are key/value pairs rather than printf-style formatted strings, emphasizing | ||||
| // "structured logging". | ||||
| // | ||||
| // The term "key" is used to refer to the name associated with a particular | ||||
| // value, to disambiguate it from the general Logger name. | ||||
| // With Go's standard log package, we might write: | ||||
| //   log.Printf("setting target value %s", targetValue) | ||||
| // | ||||
| // For instance, suppose we're trying to reconcile the state of an object, and | ||||
| // we want to log that we've made some decision. | ||||
| // With logr's structured logging, we'd write: | ||||
| //   logger.Info("setting target", "value", targetValue) | ||||
| // | ||||
| // With the traditional log package, we might write: | ||||
| // Errors are much the same.  Instead of: | ||||
| //   log.Printf("failed to open the pod bay door for user %s: %v", user, err) | ||||
| // | ||||
| // We'd write: | ||||
| //   logger.Error(err, "failed to open the pod bay door", "user", user) | ||||
| // | ||||
| // Info() and Error() are very similar, but they are separate methods so that | ||||
| // LogSink implementations can choose to do things like attach additional | ||||
| // information (such as stack traces) on calls to Error(). Error() messages are | ||||
| // always logged, regardless of the current verbosity.  If there is no error | ||||
| // instance available, passing nil is valid. | ||||
| // | ||||
| // Verbosity | ||||
| // | ||||
| // Often we want to log information only when the application in "verbose | ||||
| // mode".  To write log lines that are more verbose, Logger has a V() method. | ||||
| // The higher the V-level of a log line, the less critical it is considered. | ||||
| // Log-lines with V-levels that are not enabled (as per the LogSink) will not | ||||
| // be written.  Level V(0) is the default, and logger.V(0).Info() has the same | ||||
| // meaning as logger.Info().  Negative V-levels have the same meaning as V(0). | ||||
| // Error messages do not have a verbosity level and are always logged. | ||||
| // | ||||
| // Where we might have written: | ||||
| //   if flVerbose >= 2 { | ||||
| //       log.Printf("an unusual thing happened") | ||||
| //   } | ||||
| // | ||||
| // We can write: | ||||
| //   logger.V(2).Info("an unusual thing happened") | ||||
| // | ||||
| // Logger Names | ||||
| // | ||||
| // Logger instances can have name strings so that all messages logged through | ||||
| // that instance have additional context.  For example, you might want to add | ||||
| // a subsystem name: | ||||
| // | ||||
| //   logger.WithName("compactor").Info("started", "time", time.Now()) | ||||
| // | ||||
| // The WithName() method returns a new Logger, which can be passed to | ||||
| // constructors or other functions for further use.  Repeated use of WithName() | ||||
| // will accumulate name "segments".  These name segments will be joined in some | ||||
| // way by the LogSink implementation.  It is strongly recommended that name | ||||
| // segments contain simple identifiers (letters, digits, and hyphen), and do | ||||
| // not contain characters that could muddle the log output or confuse the | ||||
| // joining operation (e.g. whitespace, commas, periods, slashes, brackets, | ||||
| // quotes, etc). | ||||
| // | ||||
| // Saved Values | ||||
| // | ||||
| // Logger instances can store any number of key/value pairs, which will be | ||||
| // logged alongside all messages logged through that instance.  For example, | ||||
| // you might want to create a Logger instance per managed object: | ||||
| // | ||||
| // With the standard log package, we might write: | ||||
| //   log.Printf("decided to set field foo to value %q for object %s/%s", | ||||
| //       targetValue, object.Namespace, object.Name) | ||||
| // | ||||
| // With logr's structured logging, we'd write: | ||||
| //   // elsewhere in the file, set up the logger to log with the prefix of | ||||
| //   // "reconcilers", and the named value target-type=Foo, for extra context. | ||||
| //   log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo") | ||||
| // With logr we'd write: | ||||
| //   // Elsewhere: set up the logger to log the object name. | ||||
| //   obj.logger = mainLogger.WithValues( | ||||
| //       "name", obj.name, "namespace", obj.namespace) | ||||
| // | ||||
| //   // later on... | ||||
| //   log.Info("setting foo on object", "value", targetValue, "object", object) | ||||
| //   obj.logger.Info("setting foo", "value", targetValue) | ||||
| // | ||||
| // Depending on our logging implementation, we could then make logging decisions | ||||
| // based on field values (like only logging such events for objects in a certain | ||||
| // namespace), or copy the structured information into a structured log store. | ||||
| // Best Practices | ||||
| // | ||||
| // For logging errors, Logger has a method called Error.  Suppose we wanted to | ||||
| // log an error while reconciling.  With the traditional log package, we might | ||||
| // write: | ||||
| //   log.Errorf("unable to reconcile object %s/%s: %v", object.Namespace, object.Name, err) | ||||
| // | ||||
| // With logr, we'd instead write: | ||||
| //   // assuming the above setup for log | ||||
| //   log.Error(err, "unable to reconcile object", "object", object) | ||||
| // | ||||
| // This functions similarly to: | ||||
| //   log.Info("unable to reconcile object", "error", err, "object", object) | ||||
| // | ||||
| // However, it ensures that a standard key for the error value ("error") is used | ||||
| // across all error logging.  Furthermore, certain implementations may choose to | ||||
| // attach additional information (such as stack traces) on calls to Error, so | ||||
| // it's preferred to use Error to log errors. | ||||
| // | ||||
| // Parts of a log line | ||||
| // | ||||
| // Each log message from a Logger has four types of context: | ||||
| // logger name, log verbosity, log message, and the named values. | ||||
| // | ||||
| // The Logger name consists of a series of name "segments" added by successive | ||||
| // calls to WithName.  These name segments will be joined in some way by the | ||||
| // underlying implementation.  It is strongly recommended that name segments | ||||
| // contain simple identifiers (letters, digits, and hyphen), and do not contain | ||||
| // characters that could muddle the log output or confuse the joining operation | ||||
| // (e.g.  whitespace, commas, periods, slashes, brackets, quotes, etc). | ||||
| // | ||||
| // Log verbosity represents how little a log matters.  Level zero, the default, | ||||
| // matters most.  Increasing levels matter less and less.  Try to avoid lots of | ||||
| // different verbosity levels, and instead provide useful keys, logger names, | ||||
| // and log messages for users to filter on.  It's illegal to pass a log level | ||||
| // below zero. | ||||
| // Logger has very few hard rules, with the goal that LogSink implementations | ||||
| // might have a lot of freedom to differentiate.  There are, however, some | ||||
| // things to consider. | ||||
| // | ||||
| // The log message consists of a constant message attached to the log line. | ||||
| // This should generally be a simple description of what's occurring, and should | ||||
| // never be a format string. | ||||
| // never be a format string.  Variable information can then be attached using | ||||
| // named values. | ||||
| // | ||||
| // Variable information can then be attached using named values (key/value | ||||
| // pairs).  Keys are arbitrary strings, while values may be any Go value. | ||||
| // Keys are arbitrary strings, but should generally be constant values.  Values | ||||
| // may be any Go value, but how the value is formatted is determined by the | ||||
| // LogSink implementation. | ||||
| // | ||||
| // Key Naming Conventions | ||||
| // | ||||
| @@ -102,6 +123,7 @@ limitations under the License. | ||||
| //   * be constant (not dependent on input data) | ||||
| //   * contain only printable characters | ||||
| //   * not contain whitespace or punctuation | ||||
| //   * use lower case for simple keys and lowerCamelCase for more complex ones | ||||
| // | ||||
| // These guidelines help ensure that log data is processed properly regardless | ||||
| // of the log implementation.  For example, log implementations will try to | ||||
| @@ -110,21 +132,22 @@ limitations under the License. | ||||
| // While users are generally free to use key names of their choice, it's | ||||
| // generally best to avoid using the following keys, as they're frequently used | ||||
| // by implementations: | ||||
| // | ||||
| //   * `"caller"`: the calling information (file/line) of a particular log line. | ||||
| //   * `"error"`: the underlying error value in the `Error` method. | ||||
| //   * `"level"`: the log level. | ||||
| //   * `"logger"`: the name of the associated logger. | ||||
| //   * `"msg"`: the log message. | ||||
| //   * `"stacktrace"`: the stack trace associated with a particular log line or | ||||
| //                     error (often from the `Error` message). | ||||
| //   * `"ts"`: the timestamp for a log line. | ||||
| //   * "caller": the calling information (file/line) of a particular log line | ||||
| //   * "error": the underlying error value in the `Error` method | ||||
| //   * "level": the log level | ||||
| //   * "logger": the name of the associated logger | ||||
| //   * "msg": the log message | ||||
| //   * "stacktrace": the stack trace associated with a particular log line or | ||||
| //                   error (often from the `Error` message) | ||||
| //   * "ts": the timestamp for a log line | ||||
| // | ||||
| // Implementations are encouraged to make use of these keys to represent the | ||||
| // above concepts, when necessary (for example, in a pure-JSON output form, it | ||||
| // would be necessary to represent at least message and timestamp as ordinary | ||||
| // named values). | ||||
| // | ||||
| // Break Glass | ||||
| // | ||||
| // Implementations may choose to give callers access to the underlying | ||||
| // logging implementation.  The recommended pattern for this is: | ||||
| //   // Underlier exposes access to the underlying logging implementation. | ||||
| @@ -134,81 +157,222 @@ limitations under the License. | ||||
| //   type Underlier interface { | ||||
| //       GetUnderlying() <underlying-type> | ||||
| //   } | ||||
| // | ||||
| // Logger grants access to the sink to enable type assertions like this: | ||||
| //   func DoSomethingWithImpl(log logr.Logger) { | ||||
| //       if underlier, ok := log.GetSink()(impl.Underlier) { | ||||
| //          implLogger := underlier.GetUnderlying() | ||||
| //          ... | ||||
| //       } | ||||
| //   } | ||||
| // | ||||
| // Custom `With*` functions can be implemented by copying the complete | ||||
| // Logger struct and replacing the sink in the copy: | ||||
| //   // WithFooBar changes the foobar parameter in the log sink and returns a | ||||
| //   // new logger with that modified sink.  It does nothing for loggers where | ||||
| //   // the sink doesn't support that parameter. | ||||
| //   func WithFoobar(log logr.Logger, foobar int) logr.Logger { | ||||
| //      if foobarLogSink, ok := log.GetSink()(FoobarSink); ok { | ||||
| //         log = log.WithSink(foobarLogSink.WithFooBar(foobar)) | ||||
| //      } | ||||
| //      return log | ||||
| //   } | ||||
| // | ||||
| // Don't use New to construct a new Logger with a LogSink retrieved from an | ||||
| // existing Logger. Source code attribution might not work correctly and | ||||
| // unexported fields in Logger get lost. | ||||
| // | ||||
| // Beware that the same LogSink instance may be shared by different logger | ||||
| // instances. Calling functions that modify the LogSink will affect all of | ||||
| // those. | ||||
| package logr | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| ) | ||||
|  | ||||
| // TODO: consider adding back in format strings if they're really needed | ||||
| // TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects) | ||||
| // TODO: consider other bits of glog functionality like Flush, OutputStats | ||||
|  | ||||
| // Logger represents the ability to log messages, both errors and not. | ||||
| type Logger interface { | ||||
| 	// Enabled tests whether this Logger is enabled.  For example, commandline | ||||
| 	// flags might be used to set the logging verbosity and disable some info | ||||
| 	// logs. | ||||
| 	Enabled() bool | ||||
|  | ||||
| 	// Info logs a non-error message with the given key/value pairs as context. | ||||
| 	// | ||||
| 	// The msg argument should be used to add some constant description to | ||||
| 	// the log line.  The key/value pairs can then be used to add additional | ||||
| 	// variable information.  The key/value pairs should alternate string | ||||
| 	// keys and arbitrary values. | ||||
| 	Info(msg string, keysAndValues ...interface{}) | ||||
|  | ||||
| 	// Error logs an error, with the given message and key/value pairs as context. | ||||
| 	// It functions similarly to calling Info with the "error" named value, but may | ||||
| 	// have unique behavior, and should be preferred for logging errors (see the | ||||
| 	// package documentations for more information). | ||||
| 	// | ||||
| 	// The msg field should be used to add context to any underlying error, | ||||
| 	// while the err field should be used to attach the actual error that | ||||
| 	// triggered this log line, if present. | ||||
| 	Error(err error, msg string, keysAndValues ...interface{}) | ||||
|  | ||||
| 	// V returns an Logger value for a specific verbosity level, relative to | ||||
| 	// this Logger.  In other words, V values are additive.  V higher verbosity | ||||
| 	// level means a log message is less important.  It's illegal to pass a log | ||||
| 	// level less than zero. | ||||
| 	V(level int) Logger | ||||
|  | ||||
| 	// WithValues adds some key-value pairs of context to a logger. | ||||
| 	// See Info for documentation on how key/value pairs work. | ||||
| 	WithValues(keysAndValues ...interface{}) Logger | ||||
|  | ||||
| 	// WithName adds a new element to the logger's name. | ||||
| 	// Successive calls with WithName continue to append | ||||
| 	// suffixes to the logger's name.  It's strongly recommended | ||||
| 	// that name segments contain only letters, digits, and hyphens | ||||
| 	// (see the package documentation for more information). | ||||
| 	WithName(name string) Logger | ||||
| // New returns a new Logger instance.  This is primarily used by libraries | ||||
| // implementing LogSink, rather than end users. | ||||
| func New(sink LogSink) Logger { | ||||
| 	logger := Logger{} | ||||
| 	logger.setSink(sink) | ||||
| 	sink.Init(runtimeInfo) | ||||
| 	return logger | ||||
| } | ||||
|  | ||||
| // InfoLogger provides compatibility with code that relies on the v0.1.0 | ||||
| // interface. | ||||
| // | ||||
| // Deprecated: InfoLogger is an artifact of early versions of this API.  New | ||||
| // users should never use it and existing users should use Logger instead. This | ||||
| // will be removed in a future release. | ||||
| type InfoLogger = Logger | ||||
| // setSink stores the sink and updates any related fields. It mutates the | ||||
| // logger and thus is only safe to use for loggers that are not currently being | ||||
| // used concurrently. | ||||
| func (l *Logger) setSink(sink LogSink) { | ||||
| 	l.sink = sink | ||||
| } | ||||
|  | ||||
| // GetSink returns the stored sink. | ||||
| func (l Logger) GetSink() LogSink { | ||||
| 	return l.sink | ||||
| } | ||||
|  | ||||
| // WithSink returns a copy of the logger with the new sink. | ||||
| func (l Logger) WithSink(sink LogSink) Logger { | ||||
| 	l.setSink(sink) | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Logger is an interface to an abstract logging implementation.  This is a | ||||
| // concrete type for performance reasons, but all the real work is passed on to | ||||
| // a LogSink.  Implementations of LogSink should provide their own constructors | ||||
| // that return Logger, not LogSink. | ||||
| // | ||||
| // The underlying sink can be accessed through GetSink and be modified through | ||||
| // WithSink. This enables the implementation of custom extensions (see "Break | ||||
| // Glass" in the package documentation). Normally the sink should be used only | ||||
| // indirectly. | ||||
| type Logger struct { | ||||
| 	sink  LogSink | ||||
| 	level int | ||||
| } | ||||
|  | ||||
| // Enabled tests whether this Logger is enabled.  For example, commandline | ||||
| // flags might be used to set the logging verbosity and disable some info logs. | ||||
| func (l Logger) Enabled() bool { | ||||
| 	return l.sink.Enabled(l.level) | ||||
| } | ||||
|  | ||||
| // Info logs a non-error message with the given key/value pairs as context. | ||||
| // | ||||
| // The msg argument should be used to add some constant description to the log | ||||
| // line.  The key/value pairs can then be used to add additional variable | ||||
| // information.  The key/value pairs must alternate string keys and arbitrary | ||||
| // values. | ||||
| func (l Logger) Info(msg string, keysAndValues ...interface{}) { | ||||
| 	if l.Enabled() { | ||||
| 		if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { | ||||
| 			withHelper.GetCallStackHelper()() | ||||
| 		} | ||||
| 		l.sink.Info(l.level, msg, keysAndValues...) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Error logs an error, with the given message and key/value pairs as context. | ||||
| // It functions similarly to Info, but may have unique behavior, and should be | ||||
| // preferred for logging errors (see the package documentations for more | ||||
| // information). The log message will always be emitted, regardless of | ||||
| // verbosity level. | ||||
| // | ||||
| // The msg argument should be used to add context to any underlying error, | ||||
| // while the err argument should be used to attach the actual error that | ||||
| // triggered this log line, if present. The err parameter is optional | ||||
| // and nil may be passed instead of an error instance. | ||||
| func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) { | ||||
| 	if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { | ||||
| 		withHelper.GetCallStackHelper()() | ||||
| 	} | ||||
| 	l.sink.Error(err, msg, keysAndValues...) | ||||
| } | ||||
|  | ||||
| // V returns a new Logger instance for a specific verbosity level, relative to | ||||
| // this Logger.  In other words, V-levels are additive.  A higher verbosity | ||||
| // level means a log message is less important.  Negative V-levels are treated | ||||
| // as 0. | ||||
| func (l Logger) V(level int) Logger { | ||||
| 	if level < 0 { | ||||
| 		level = 0 | ||||
| 	} | ||||
| 	l.level += level | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // WithValues returns a new Logger instance with additional key/value pairs. | ||||
| // See Info for documentation on how key/value pairs work. | ||||
| func (l Logger) WithValues(keysAndValues ...interface{}) Logger { | ||||
| 	l.setSink(l.sink.WithValues(keysAndValues...)) | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // WithName returns a new Logger instance with the specified name element added | ||||
| // to the Logger's name.  Successive calls with WithName append additional | ||||
| // suffixes to the Logger's name.  It's strongly recommended that name segments | ||||
| // contain only letters, digits, and hyphens (see the package documentation for | ||||
| // more information). | ||||
| func (l Logger) WithName(name string) Logger { | ||||
| 	l.setSink(l.sink.WithName(name)) | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // WithCallDepth returns a Logger instance that offsets the call stack by the | ||||
| // specified number of frames when logging call site information, if possible. | ||||
| // This is useful for users who have helper functions between the "real" call | ||||
| // site and the actual calls to Logger methods.  If depth is 0 the attribution | ||||
| // should be to the direct caller of this function.  If depth is 1 the | ||||
| // attribution should skip 1 call frame, and so on.  Successive calls to this | ||||
| // are additive. | ||||
| // | ||||
| // If the underlying log implementation supports a WithCallDepth(int) method, | ||||
| // it will be called and the result returned.  If the implementation does not | ||||
| // support CallDepthLogSink, the original Logger will be returned. | ||||
| // | ||||
| // To skip one level, WithCallStackHelper() should be used instead of | ||||
| // WithCallDepth(1) because it works with implementions that support the | ||||
| // CallDepthLogSink and/or CallStackHelperLogSink interfaces. | ||||
| func (l Logger) WithCallDepth(depth int) Logger { | ||||
| 	if withCallDepth, ok := l.sink.(CallDepthLogSink); ok { | ||||
| 		l.setSink(withCallDepth.WithCallDepth(depth)) | ||||
| 	} | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // WithCallStackHelper returns a new Logger instance that skips the direct | ||||
| // caller when logging call site information, if possible.  This is useful for | ||||
| // users who have helper functions between the "real" call site and the actual | ||||
| // calls to Logger methods and want to support loggers which depend on marking | ||||
| // each individual helper function, like loggers based on testing.T. | ||||
| // | ||||
| // In addition to using that new logger instance, callers also must call the | ||||
| // returned function. | ||||
| // | ||||
| // If the underlying log implementation supports a WithCallDepth(int) method, | ||||
| // WithCallDepth(1) will be called to produce a new logger. If it supports a | ||||
| // WithCallStackHelper() method, that will be also called. If the | ||||
| // implementation does not support either of these, the original Logger will be | ||||
| // returned. | ||||
| func (l Logger) WithCallStackHelper() (func(), Logger) { | ||||
| 	var helper func() | ||||
| 	if withCallDepth, ok := l.sink.(CallDepthLogSink); ok { | ||||
| 		l.setSink(withCallDepth.WithCallDepth(1)) | ||||
| 	} | ||||
| 	if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { | ||||
| 		helper = withHelper.GetCallStackHelper() | ||||
| 	} else { | ||||
| 		helper = func() {} | ||||
| 	} | ||||
| 	return helper, l | ||||
| } | ||||
|  | ||||
| // contextKey is how we find Loggers in a context.Context. | ||||
| type contextKey struct{} | ||||
|  | ||||
| // FromContext returns a Logger constructed from ctx or nil if no | ||||
| // logger details are found. | ||||
| func FromContext(ctx context.Context) Logger { | ||||
| // FromContext returns a Logger from ctx or an error if no Logger is found. | ||||
| func FromContext(ctx context.Context) (Logger, error) { | ||||
| 	if v, ok := ctx.Value(contextKey{}).(Logger); ok { | ||||
| 		return v | ||||
| 		return v, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| 	return Logger{}, notFoundError{} | ||||
| } | ||||
|  | ||||
| // FromContextOrDiscard returns a Logger constructed from ctx or a Logger | ||||
| // that discards all messages if no logger details are found. | ||||
| // notFoundError exists to carry an IsNotFound method. | ||||
| type notFoundError struct{} | ||||
|  | ||||
| func (notFoundError) Error() string { | ||||
| 	return "no logr.Logger was present" | ||||
| } | ||||
|  | ||||
| func (notFoundError) IsNotFound() bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // FromContextOrDiscard returns a Logger from ctx.  If no Logger is found, this | ||||
| // returns a Logger that discards all log messages. | ||||
| func FromContextOrDiscard(ctx context.Context) Logger { | ||||
| 	if v, ok := ctx.Value(contextKey{}).(Logger); ok { | ||||
| 		return v | ||||
| @@ -217,12 +381,59 @@ func FromContextOrDiscard(ctx context.Context) Logger { | ||||
| 	return Discard() | ||||
| } | ||||
|  | ||||
| // NewContext returns a new context derived from ctx that embeds the Logger. | ||||
| func NewContext(ctx context.Context, l Logger) context.Context { | ||||
| 	return context.WithValue(ctx, contextKey{}, l) | ||||
| // NewContext returns a new Context, derived from ctx, which carries the | ||||
| // provided Logger. | ||||
| func NewContext(ctx context.Context, logger Logger) context.Context { | ||||
| 	return context.WithValue(ctx, contextKey{}, logger) | ||||
| } | ||||
|  | ||||
| // CallDepthLogger represents a Logger that knows how to climb the call stack | ||||
| // RuntimeInfo holds information that the logr "core" library knows which | ||||
| // LogSinks might want to know. | ||||
| type RuntimeInfo struct { | ||||
| 	// CallDepth is the number of call frames the logr library adds between the | ||||
| 	// end-user and the LogSink.  LogSink implementations which choose to print | ||||
| 	// the original logging site (e.g. file & line) should climb this many | ||||
| 	// additional frames to find it. | ||||
| 	CallDepth int | ||||
| } | ||||
|  | ||||
| // runtimeInfo is a static global.  It must not be changed at run time. | ||||
| var runtimeInfo = RuntimeInfo{ | ||||
| 	CallDepth: 1, | ||||
| } | ||||
|  | ||||
| // LogSink represents a logging implementation.  End-users will generally not | ||||
| // interact with this type. | ||||
| type LogSink interface { | ||||
| 	// Init receives optional information about the logr library for LogSink | ||||
| 	// implementations that need it. | ||||
| 	Init(info RuntimeInfo) | ||||
|  | ||||
| 	// Enabled tests whether this LogSink is enabled at the specified V-level. | ||||
| 	// For example, commandline flags might be used to set the logging | ||||
| 	// verbosity and disable some info logs. | ||||
| 	Enabled(level int) bool | ||||
|  | ||||
| 	// Info logs a non-error message with the given key/value pairs as context. | ||||
| 	// The level argument is provided for optional logging.  This method will | ||||
| 	// only be called when Enabled(level) is true. See Logger.Info for more | ||||
| 	// details. | ||||
| 	Info(level int, msg string, keysAndValues ...interface{}) | ||||
|  | ||||
| 	// Error logs an error, with the given message and key/value pairs as | ||||
| 	// context.  See Logger.Error for more details. | ||||
| 	Error(err error, msg string, keysAndValues ...interface{}) | ||||
|  | ||||
| 	// WithValues returns a new LogSink with additional key/value pairs.  See | ||||
| 	// Logger.WithValues for more details. | ||||
| 	WithValues(keysAndValues ...interface{}) LogSink | ||||
|  | ||||
| 	// WithName returns a new LogSink with the specified name appended.  See | ||||
| 	// Logger.WithName for more details. | ||||
| 	WithName(name string) LogSink | ||||
| } | ||||
|  | ||||
| // CallDepthLogSink represents a Logger that knows how to climb the call stack | ||||
| // to identify the original call site and can offset the depth by a specified | ||||
| // number of frames.  This is useful for users who have helper functions | ||||
| // between the "real" call site and the actual calls to Logger methods. | ||||
| @@ -232,35 +443,59 @@ func NewContext(ctx context.Context, l Logger) context.Context { | ||||
| // | ||||
| // This is an optional interface and implementations are not required to | ||||
| // support it. | ||||
| type CallDepthLogger interface { | ||||
| 	Logger | ||||
|  | ||||
| 	// WithCallDepth returns a Logger that will offset the call stack by the | ||||
| 	// specified number of frames when logging call site information.  If depth | ||||
| 	// is 0 the attribution should be to the direct caller of this method.  If | ||||
| 	// depth is 1 the attribution should skip 1 call frame, and so on. | ||||
| type CallDepthLogSink interface { | ||||
| 	// WithCallDepth returns a LogSink that will offset the call | ||||
| 	// stack by the specified number of frames when logging call | ||||
| 	// site information. | ||||
| 	// | ||||
| 	// If depth is 0, the LogSink should skip exactly the number | ||||
| 	// of call frames defined in RuntimeInfo.CallDepth when Info | ||||
| 	// or Error are called, i.e. the attribution should be to the | ||||
| 	// direct caller of Logger.Info or Logger.Error. | ||||
| 	// | ||||
| 	// If depth is 1 the attribution should skip 1 call frame, and so on. | ||||
| 	// Successive calls to this are additive. | ||||
| 	WithCallDepth(depth int) Logger | ||||
| 	WithCallDepth(depth int) LogSink | ||||
| } | ||||
|  | ||||
| // WithCallDepth returns a Logger that will offset the call stack by the | ||||
| // specified number of frames when logging call site information, if possible. | ||||
| // This is useful for users who have helper functions between the "real" call | ||||
| // site and the actual calls to Logger methods.  If depth is 0 the attribution | ||||
| // should be to the direct caller of this function.  If depth is 1 the | ||||
| // attribution should skip 1 call frame, and so on.  Successive calls to this | ||||
| // are additive. | ||||
| // CallStackHelperLogSink represents a Logger that knows how to climb | ||||
| // the call stack to identify the original call site and can skip | ||||
| // intermediate helper functions if they mark themselves as | ||||
| // helper. Go's testing package uses that approach. | ||||
| // | ||||
| // If the underlying log implementation supports the CallDepthLogger interface, | ||||
| // the WithCallDepth method will be called and the result returned.  If the | ||||
| // implementation does not support CallDepthLogger, the original Logger will be | ||||
| // returned. | ||||
| // This is useful for users who have helper functions between the | ||||
| // "real" call site and the actual calls to Logger methods. | ||||
| // Implementations that log information about the call site (such as | ||||
| // file, function, or line) would otherwise log information about the | ||||
| // intermediate helper functions. | ||||
| // | ||||
| // Callers which care about whether this was supported or not should test for | ||||
| // CallDepthLogger support themselves. | ||||
| func WithCallDepth(logger Logger, depth int) Logger { | ||||
| 	if decorator, ok := logger.(CallDepthLogger); ok { | ||||
| 		return decorator.WithCallDepth(depth) | ||||
| 	} | ||||
| 	return logger | ||||
| // This is an optional interface and implementations are not required | ||||
| // to support it. Implementations that choose to support this must not | ||||
| // simply implement it as WithCallDepth(1), because | ||||
| // Logger.WithCallStackHelper will call both methods if they are | ||||
| // present. This should only be implemented for LogSinks that actually | ||||
| // need it, as with testing.T. | ||||
| type CallStackHelperLogSink interface { | ||||
| 	// GetCallStackHelper returns a function that must be called | ||||
| 	// to mark the direct caller as helper function when logging | ||||
| 	// call site information. | ||||
| 	GetCallStackHelper() func() | ||||
| } | ||||
|  | ||||
| // Marshaler is an optional interface that logged values may choose to | ||||
| // implement. Loggers with structured output, such as JSON, should | ||||
| // log the object return by the MarshalLog method instead of the | ||||
| // original value. | ||||
| type Marshaler interface { | ||||
| 	// MarshalLog can be used to: | ||||
| 	//   - ensure that structs are not logged as strings when the original | ||||
| 	//     value has a String method: return a different type without a | ||||
| 	//     String method | ||||
| 	//   - select which fields of a complex type should get logged: | ||||
| 	//     return a simpler struct with fewer fields | ||||
| 	//   - log unexported fields: return a different struct | ||||
| 	//     with exported fields | ||||
| 	// | ||||
| 	// It may return any value of any type. | ||||
| 	MarshalLog() interface{} | ||||
| } | ||||
|   | ||||
							
								
								
									
										201
									
								
								vendor/github.com/go-logr/stdr/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/go-logr/stdr/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright [yyyy] [name of copyright owner] | ||||
|  | ||||
|    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. | ||||
							
								
								
									
										6
									
								
								vendor/github.com/go-logr/stdr/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/go-logr/stdr/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| # Minimal Go logging using logr and Go's standard library | ||||
|  | ||||
| [](https://pkg.go.dev/github.com/go-logr/stdr) | ||||
|  | ||||
| This package implements the [logr interface](https://github.com/go-logr/logr) | ||||
| in terms of Go's standard log package(https://pkg.go.dev/log). | ||||
							
								
								
									
										5
									
								
								vendor/github.com/go-logr/stdr/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/go-logr/stdr/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| module github.com/go-logr/stdr | ||||
|  | ||||
| go 1.16 | ||||
|  | ||||
| require github.com/go-logr/logr v1.2.2 | ||||
							
								
								
									
										2
									
								
								vendor/github.com/go-logr/stdr/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-logr/stdr/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= | ||||
| github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= | ||||
							
								
								
									
										170
									
								
								vendor/github.com/go-logr/stdr/stdr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								vendor/github.com/go-logr/stdr/stdr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| /* | ||||
| Copyright 2019 The logr 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 stdr implements github.com/go-logr/logr.Logger in terms of | ||||
| // Go's standard log package. | ||||
| package stdr | ||||
|  | ||||
| import ( | ||||
| 	"log" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/go-logr/logr" | ||||
| 	"github.com/go-logr/logr/funcr" | ||||
| ) | ||||
|  | ||||
| // The global verbosity level.  See SetVerbosity(). | ||||
| var globalVerbosity int | ||||
|  | ||||
| // SetVerbosity sets the global level against which all info logs will be | ||||
| // compared.  If this is greater than or equal to the "V" of the logger, the | ||||
| // message will be logged.  A higher value here means more logs will be written. | ||||
| // The previous verbosity value is returned.  This is not concurrent-safe - | ||||
| // callers must be sure to call it from only one goroutine. | ||||
| func SetVerbosity(v int) int { | ||||
| 	old := globalVerbosity | ||||
| 	globalVerbosity = v | ||||
| 	return old | ||||
| } | ||||
|  | ||||
| // New returns a logr.Logger which is implemented by Go's standard log package, | ||||
| // or something like it.  If std is nil, this will use a default logger | ||||
| // instead. | ||||
| // | ||||
| // Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile))) | ||||
| func New(std StdLogger) logr.Logger { | ||||
| 	return NewWithOptions(std, Options{}) | ||||
| } | ||||
|  | ||||
| // NewWithOptions returns a logr.Logger which is implemented by Go's standard | ||||
| // log package, or something like it.  See New for details. | ||||
| func NewWithOptions(std StdLogger, opts Options) logr.Logger { | ||||
| 	if std == nil { | ||||
| 		// Go's log.Default() is only available in 1.16 and higher. | ||||
| 		std = log.New(os.Stderr, "", log.LstdFlags) | ||||
| 	} | ||||
|  | ||||
| 	if opts.Depth < 0 { | ||||
| 		opts.Depth = 0 | ||||
| 	} | ||||
|  | ||||
| 	fopts := funcr.Options{ | ||||
| 		LogCaller: funcr.MessageClass(opts.LogCaller), | ||||
| 	} | ||||
|  | ||||
| 	sl := &logger{ | ||||
| 		Formatter: funcr.NewFormatter(fopts), | ||||
| 		std:       std, | ||||
| 	} | ||||
|  | ||||
| 	// For skipping our own logger.Info/Error. | ||||
| 	sl.Formatter.AddCallDepth(1 + opts.Depth) | ||||
|  | ||||
| 	return logr.New(sl) | ||||
| } | ||||
|  | ||||
| // Options carries parameters which influence the way logs are generated. | ||||
| type Options struct { | ||||
| 	// Depth biases the assumed number of call frames to the "true" caller. | ||||
| 	// This is useful when the calling code calls a function which then calls | ||||
| 	// stdr (e.g. a logging shim to another API).  Values less than zero will | ||||
| 	// be treated as zero. | ||||
| 	Depth int | ||||
|  | ||||
| 	// LogCaller tells stdr to add a "caller" key to some or all log lines. | ||||
| 	// Go's log package has options to log this natively, too. | ||||
| 	LogCaller MessageClass | ||||
|  | ||||
| 	// TODO: add an option to log the date/time | ||||
| } | ||||
|  | ||||
| // MessageClass indicates which category or categories of messages to consider. | ||||
| type MessageClass int | ||||
|  | ||||
| const ( | ||||
| 	// None ignores all message classes. | ||||
| 	None MessageClass = iota | ||||
| 	// All considers all message classes. | ||||
| 	All | ||||
| 	// Info only considers info messages. | ||||
| 	Info | ||||
| 	// Error only considers error messages. | ||||
| 	Error | ||||
| ) | ||||
|  | ||||
| // StdLogger is the subset of the Go stdlib log.Logger API that is needed for | ||||
| // this adapter. | ||||
| type StdLogger interface { | ||||
| 	// Output is the same as log.Output and log.Logger.Output. | ||||
| 	Output(calldepth int, logline string) error | ||||
| } | ||||
|  | ||||
| type logger struct { | ||||
| 	funcr.Formatter | ||||
| 	std StdLogger | ||||
| } | ||||
|  | ||||
| var _ logr.LogSink = &logger{} | ||||
| var _ logr.CallDepthLogSink = &logger{} | ||||
|  | ||||
| func (l logger) Enabled(level int) bool { | ||||
| 	return globalVerbosity >= level | ||||
| } | ||||
|  | ||||
| func (l logger) Info(level int, msg string, kvList ...interface{}) { | ||||
| 	prefix, args := l.FormatInfo(level, msg, kvList) | ||||
| 	if prefix != "" { | ||||
| 		args = prefix + ": " + args | ||||
| 	} | ||||
| 	_ = l.std.Output(l.Formatter.GetDepth()+1, args) | ||||
| } | ||||
|  | ||||
| func (l logger) Error(err error, msg string, kvList ...interface{}) { | ||||
| 	prefix, args := l.FormatError(err, msg, kvList) | ||||
| 	if prefix != "" { | ||||
| 		args = prefix + ": " + args | ||||
| 	} | ||||
| 	_ = l.std.Output(l.Formatter.GetDepth()+1, args) | ||||
| } | ||||
|  | ||||
| func (l logger) WithName(name string) logr.LogSink { | ||||
| 	l.Formatter.AddName(name) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| func (l logger) WithValues(kvList ...interface{}) logr.LogSink { | ||||
| 	l.Formatter.AddValues(kvList) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| func (l logger) WithCallDepth(depth int) logr.LogSink { | ||||
| 	l.Formatter.AddCallDepth(depth) | ||||
| 	return &l | ||||
| } | ||||
|  | ||||
| // Underlier exposes access to the underlying logging implementation.  Since | ||||
| // callers only have a logr.Logger, they have to know which implementation is | ||||
| // in use, so this interface is less of an abstraction and more of way to test | ||||
| // type conversion. | ||||
| type Underlier interface { | ||||
| 	GetUnderlying() StdLogger | ||||
| } | ||||
|  | ||||
| // GetUnderlying returns the StdLogger underneath this logger.  Since StdLogger | ||||
| // is itself an interface, the result may or may not be a Go log.Logger. | ||||
| func (l logger) GetUnderlying() StdLogger { | ||||
| 	return l.std | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Kazuyoshi Kato
					Kazuyoshi Kato