diff --git a/go.mod b/go.mod index 2f62a00c9c0..217f033ae86 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 knative.dev/hack v0.0.0-20201201234937-fddbf732e450 - knative.dev/pkg v0.0.0-20201130192436-e5346d90e980 + knative.dev/pkg v0.0.0-20201207225040-7e918163fc4f knative.dev/reconciler-test v0.0.0-20201124190335-83a44efcdfef sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 411d324e497..b054deb2818 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,8 @@ github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= @@ -1105,12 +1107,11 @@ k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9 h1:OgYL1cATsWTS6kztSOuQqhmYfcn6ZdpPAQQ6TKCx00I= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= -knative.dev/hack v0.0.0-20201120192952-353db687ec5b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/hack v0.0.0-20201201234937-fddbf732e450 h1:IyitWF7OzfunCgE4b9ZsJAeIRoQ6JOyqDrz/19X4iS4= knative.dev/hack v0.0.0-20201201234937-fddbf732e450/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed/go.mod h1:nxlh3CUvx6WBPr1WKD96AHxFZPD2UKRDo9RUp8ILTyQ= -knative.dev/pkg v0.0.0-20201130192436-e5346d90e980 h1:44zakwrFjbivCM/YR+ni70e9u1ELtwA7VF1HSmUcj+g= -knative.dev/pkg v0.0.0-20201130192436-e5346d90e980/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug= +knative.dev/pkg v0.0.0-20201207225040-7e918163fc4f h1:X8hnoZl7EkFUk8gWZlxrHFHt49vjE7XV0XOpV0ucgpg= +knative.dev/pkg v0.0.0-20201207225040-7e918163fc4f/go.mod h1:Jtbz2/1gB8EZgZA4VvabTxM+AcDt2WL2P0RaFnKcOX8= knative.dev/reconciler-test v0.0.0-20201124190335-83a44efcdfef h1:8PttDFSsac32mq6Va+uPOyOR5CfX8JQT9g+MnHNyJ94= knative.dev/reconciler-test v0.0.0-20201124190335-83a44efcdfef/go.mod h1:YSs1y1rgnjs8w39/drLIOQbWvZUQwqApvd+EizO8UsA= pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= diff --git a/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE b/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE new file mode 100644 index 00000000000..7db45677551 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) Blendle + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/blendle/zapdriver/.gitignore b/vendor/github.com/blendle/zapdriver/.gitignore new file mode 100644 index 00000000000..48b8bf9072d --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/.gitignore @@ -0,0 +1 @@ +vendor/ diff --git a/vendor/github.com/blendle/zapdriver/LICENSE b/vendor/github.com/blendle/zapdriver/LICENSE new file mode 100644 index 00000000000..7db45677551 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) Blendle + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/blendle/zapdriver/README.md b/vendor/github.com/blendle/zapdriver/README.md new file mode 100644 index 00000000000..8044c5523a8 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/README.md @@ -0,0 +1,347 @@ +# :zap: Zapdriver + +Blazing fast, [Zap][zap]-based [Stackdriver][stackdriver] logging. + +[zap]: https://github.com/uber-go/zap +[stackdriver]: https://cloud.google.com/stackdriver/ + +## Usage + +This package provides three building blocks to support the full array of +structured logging capabilities of Stackdriver: + +* [Special purpose logging fields](#special-purpose-logging-fields) +* [Pre-configured Stackdriver-optimized encoder](#pre-configured-stackdriver-optimized-encoder) +* [Custom Stackdriver Zap core](#custom-stackdriver-zap-core) +* [Using Error Reporting](#using-error-reporting) + +The above components can be used separately, but to start, you can create a new +Zap logger with all of the above included: + +```golang +logger, err := zapdriver.NewProduction() // with sampling +logger, err := zapdriver.NewDevelopment() // with `development` set to `true` +``` + +The above functions give back a pointer to a `zap.Logger` object, so you can use +[Zap][zap] like you've always done, except that it now logs in the proper +[Stackdriver][stackdriver] format. + +You can also create a configuration struct, and build your logger from there: + +```golang +config := zapdriver.NewProductionConfig() +config := zapdriver.NewDevelopmentConfig() +``` + +Or, get the Zapdriver encoder, and build your own configuration struct from +that: + +```golang +encoder := zapdriver.NewProductionEncoderConfig() +encoder := zapdriver.NewDevelopmentEncoderConfig() +``` + +Read on to learn more about the available Stackdriver-specific log fields, and +how to use the above-mentioned components. + +### Special purpose logging fields + +You can use the following fields to add extra information to your log entries. +These fields are parsed by Stackdriver to make it easier to query your logs or +to use the log details in the Stackdriver monitoring interface. + +* [`HTTP`](#http) +* [`Label`](#label) +* [`SourceLocation`](#sourcelocation) +* [`Operation`](#operation) +* [`TraceContext`](#tracecontext) + +#### HTTP + +You can log HTTP request/response cycles using the following field: + +```golang +HTTP(req *HTTPPayload) zap.Field +``` + +You can either manually build the request payload: + +```golang +req := &HTTPPayload{ + RequestMethod: "GET", + RequestURL: "/", + Status: 200, +} +``` + +Or, you can auto generate the struct, based on the available request and +response objects: + +```golang +NewHTTP(req *http.Request, res *http.Response) *HTTPPayload +``` + +You are free to pass in `nil` for either the request or response object, if one +of them is unavailable to you at the point of logging. Any field depending on +one or the other will be omitted if `nil` is passed in. + +Note that there are some fields that are not populated by either the request or +response object, and need to be set manually: + +* `ServerIP string` +* `Latency string` +* `CacheLookup bool` +* `CacheHit bool` +* `CacheValidatedWithOriginServer bool` +* `CacheFillBytes string` + +If you have no need for those fields, the quickest way to get started is like +so: + +```golang +logger.Info("Request Received.", zapdriver.HTTP(zapdriver.NewHTTP(req, res))) +``` + +#### Label + +You can add a "label" to your payload as follows: + +```golang +Label(key, value string) zap.Field +``` + +Note that underwater, this sets the key to `labels.`. You need to be using +the `zapdriver.Core` core for this to be converted to the proper format for +Stackdriver to recognize the labels. + +See "Custom Stackdriver Zap core" for more details. + +If you have a reason not to use the provided Core, you can still wrap labels in +the right `labels` namespace by using the available function: + +```golang +Labels(fields ...zap.Field) zap.Field +``` + +Like so: + +```golang +logger.Info( + "Did something.", + zapdriver.Labels( + zapdriver.Label("hello", "world"), + zapdriver.Label("hi", "universe"), + ), +) +``` + +Again, wrapping the `Label` calls in `Labels` is not required if you use the +supplied Zap Core. + +#### SourceLocation + +You can add a source code location to your log lines to be picked up by +Stackdriver. + +Note that you can set this manually, or use `zapdriver.Core` to automatically +add this. If you set it manually, _and_ use `zapdriver.Core`, the manual call +stack will be preserved over the automated one. + +```golang +SourceLocation(pc uintptr, file string, line int, ok bool) zap.Field +``` + +Note that the function signature equals that of the return values of +`runtime.Caller()`. This allows you to catch the stack frame at one location, +while logging it at a different location, like so: + +```golang +pc, file, line, ok := runtime.Caller(0) + +// do other stuff... + +logger.Error("Something happened!", zapdriver.SourceLocation(pc, file, line, ok)) +``` + +If you use `zapdriver.Core`, the above use-case is the only use-case where you +would want to manually set the source location. In all other situations, you can +simply omit this field, and it will be added automatically, using the stack +frame at the location where the log line is triggered. + +If you don't use `zapdriver.Core`, and still want to add the source location at +the frame of the triggered log line, you'd do it like this: + +```golang +logger.Error("Something happened!", zapdriver.SourceLocation(runtime.Caller(0))) +``` + +#### Operation + +The `Operation` log field allows you to group log lines into a single +"operation" performed by the application: + +```golang +Operation(id, producer string, first, last bool) zap.Field +``` + +For a pair of logs that belong to the same operation, you should use the same +`id` between them. The `producer` is an arbitrary identifier that should be +globally unique amongst all the logs of all your applications (meaning it should +probably be the unique name of the current application). You should set `first` +to true for the first log in the operation, and `last` to true for the final log +of the operation. + +```golang +logger.Info("Started.", zapdriver.Operation("3g4d3g", "my-app", true, false)) +logger.Debug("Progressing.", zapdriver.Operation("3g4d3g", "my-app", false, false)) +logger.Info("Done.", zapdriver.Operation("3g4d3g", "my-app", false, true)) +``` + +Instead of defining the "start" and "end" booleans, you can also use these three +convenience functions: + +```golang +OperationStart(id, producer string) zap.Field +OperationCont(id, producer string) zap.Field +OperationEnd(id, producer string) zap.Field +``` + +#### TraceContext + +You can add trace context information to your log lines to be picked up by +Stackdriver. + +```golang +TraceContext(trace string, spanId string, sampled bool, projectName string) []zap.Field +``` + +Like so: + +```golang +logger.Error("Something happened!", zapdriver.TraceContext("105445aa7843bc8bf206b120001000", "0", true, "my-project-name")...) +``` + +### Pre-configured Stackdriver-optimized encoder + +The Stackdriver encoder maps all Zap log levels to the appropriate +[Stackdriver-supported levels][levels]: + +> DEBUG (100) Debug or trace information. +> +> INFO (200) Routine information, such as ongoing status or performance. +> +> WARNING (400) Warning events might cause problems. +> +> ERROR (500) Error events are likely to cause problems. +> +> CRITICAL (600) Critical events cause more severe problems or outages. +> +> ALERT (700) A person must take an action immediately. +> +> EMERGENCY (800) One or more systems are unusable. + +[levels]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity + +It also sets some of the default keys to use [the right names][names], such as +`timestamp`, `severity`, and `message`. + +[names]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry + +You can use this encoder if you want to build your Zap logger configuration +manually: + +```golang +zapdriver.NewProductionEncoderConfig() +``` + +For parity-sake, there's also `zapdriver.NewDevelopmentEncoderConfig()`, but it +returns the exact same encoder right now. + +### Custom Stackdriver Zap core + +A custom Zap core is included in this package to support some special use-cases. + +First of all, if you use `zapdriver.NewProduction()` (or `NewDevelopment`) , you +already have this core enabled, so everything _just works_ ™. + +There are two use-cases which require this core: + +1. If you use `zapdriver.Label("hello", "world")`, it will initially end up in + your log with the key `labels.hello` and value `world`. Now if you have two + labels, you could also have `labels.hi` with value `universe`. This works as- + is, but for this to be correctly parsed by Stackdriver as true "labels", you + need to use the Zapdriver core, so that both of these fields get rewritten, + to use the namespace `labels`, and use the keys `hello` and `hi` within that + namespace. This is done automatically. + +2. If you don't want to use `zapdriver.SourceLocation()` on every log call, you + can use this core for the source location to be automatically added to + each log entry. + +When building a logger, you can inject the Zapdriver core as follows: + +```golang +config := &zap.Config{} +logger, err := config.Build(zapdriver.WrapCore()) +``` + +### Using Error Reporting + +To report errors using StackDriver's Error Reporting tool, a log line needs to follow a separate log format described in the [Error Reporting][errorreporting] documentation. + +[errorreporting]: https://cloud.google.com/error-reporting/docs/formatting-error-messages + +The simplest way to do this is by using `NewProductionWithCore`: + +```golang +logger, err := zapdriver.NewProductionWithCore(zapdriver.WrapCore( + zapdriver.ReportAllErrors(true), + zapdriver.ServiceName("my service"), +)) +``` + +For parity-sake, there's also `zapdriver.NewDevelopmentWithCore()` + +If you are building a custom logger, you can use `WrapCore()` to configure the driver core: + +```golang +config := &zap.Config{} +logger, err := config.Build(zapdriver.WrapCore( + zapdriver.ReportAllErrors(true), + zapdriver.ServiceName("my service"), +)) +``` + +Configuring this way, every error log entry will be reported to Stackdriver's Error Reporting tool. + +#### Reporting errors manually + +If you do not want every error to be reported, you can attach `ErrorReport()` to log call manually: + +```golang +logger.Error("An error to be reported!", zapdriver.ErrorReport(runtime.Caller(0))) +// Or get Caller details +pc, file, line, ok := runtime.Caller(0) +// do other stuff... and log elsewhere +logger.Error("Another error to be reported!", zapdriver.ErrorReport(pc, file, line, ok)) +``` + +Please keep in mind that ErrorReport needs a ServiceContext attached to the log +entry. If you did not configure this using `WrapCore`, error reports will +get attached using service name as `unknown`. To prevent this from happeneing, +either configure your core or attach service context before (or when) using +the logger: + +```golang +logger.Error( + "An error to be reported!", + zapdriver.ErrorReport(runtime.Caller(0)), + zapdriver.ServiceContext("my service"), +) + +// Or permanently attach it to your logger +logger = logger.With(zapdriver.ServiceContext("my service")) +// and then use it +logger.Error("An error to be reported!", zapdriver.ErrorReport(runtime.Caller(0))) +``` diff --git a/vendor/github.com/blendle/zapdriver/config.go b/vendor/github.com/blendle/zapdriver/config.go new file mode 100644 index 00000000000..fe901ce3b1e --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/config.go @@ -0,0 +1,55 @@ +package zapdriver + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// NewProductionEncoderConfig returns an opinionated EncoderConfig for +// production environments. +func NewProductionEncoderConfig() zapcore.EncoderConfig { + return encoderConfig +} + +// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for +// development environments. +func NewDevelopmentEncoderConfig() zapcore.EncoderConfig { + return encoderConfig +} + +// NewProductionConfig is a reasonable production logging configuration. +// Logging is enabled at InfoLevel and above. +// +// It uses a JSON encoder, writes to standard error, and enables sampling. +// Stacktraces are automatically included on logs of ErrorLevel and above. +func NewProductionConfig() zap.Config { + return zap.Config{ + Level: zap.NewAtomicLevelAt(zap.InfoLevel), + Development: false, + Sampling: &zap.SamplingConfig{ + Initial: 100, + Thereafter: 100, + }, + Encoding: "json", + EncoderConfig: NewProductionEncoderConfig(), + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + } +} + +// NewDevelopmentConfig is a reasonable development logging configuration. +// Logging is enabled at DebugLevel and above. +// +// It enables development mode (which makes DPanicLevel logs panic), uses a +// console encoder, writes to standard error, and disables sampling. +// Stacktraces are automatically included on logs of WarnLevel and above. +func NewDevelopmentConfig() zap.Config { + return zap.Config{ + Level: zap.NewAtomicLevelAt(zap.DebugLevel), + Development: true, + Encoding: "json", + EncoderConfig: NewDevelopmentEncoderConfig(), + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + } +} diff --git a/vendor/github.com/blendle/zapdriver/core.go b/vendor/github.com/blendle/zapdriver/core.go new file mode 100644 index 00000000000..bcb7660f70b --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/core.go @@ -0,0 +1,243 @@ +package zapdriver + +import ( + "strings" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// driverConfig is used to configure core. +type driverConfig struct { + // Report all logs with level error or above to stackdriver using + // `ErrorReport()` when set to true + ReportAllErrors bool + + // ServiceName is added as `ServiceContext()` to all logs when set + ServiceName string +} + +// Core is a zapdriver specific core wrapped around the default zap core. It +// allows to merge all defined labels +type core struct { + zapcore.Core + + // permLabels is a collection of labels that have been added to the logger + // through the use of `With()`. These labels should never be cleared after + // logging a single entry, unlike `tempLabel`. + permLabels *labels + + // tempLabels keeps a record of all the labels that need to be applied to the + // current log entry. Zap serializes log fields at different parts of the + // stack, one such location is when calling `core.With` and the other one is + // when calling `core.Write`. This makes it impossible to (for example) take + // all `labels.xxx` fields, and wrap them in the `labels` namespace in one go. + // + // Instead, we have to filter out these labels at both locations, and then add + // them back in the proper format right before we call `Write` on the original + // Zap core. + tempLabels *labels + + // Configuration for the zapdriver core + config driverConfig +} + +// zapdriver core option to report all logs with level error or above to stackdriver +// using `ErrorReport()` when set to true +func ReportAllErrors(report bool) func(*core) { + return func(c *core) { + c.config.ReportAllErrors = report + } +} + +// zapdriver core option to add `ServiceContext()` to all logs with `name` as +// service name +func ServiceName(name string) func(*core) { + return func(c *core) { + c.config.ServiceName = name + } +} + +// WrapCore returns a `zap.Option` that wraps the default core with the +// zapdriver one. +func WrapCore(options ...func(*core)) zap.Option { + return zap.WrapCore(func(c zapcore.Core) zapcore.Core { + newcore := &core{ + Core: c, + permLabels: newLabels(), + tempLabels: newLabels(), + } + for _, option := range options { + option(newcore) + } + return newcore + }) +} + +// With adds structured context to the Core. +func (c *core) With(fields []zap.Field) zapcore.Core { + var lbls *labels + lbls, fields = c.extractLabels(fields) + + lbls.mutex.RLock() + c.permLabels.mutex.Lock() + for k, v := range lbls.store { + c.permLabels.store[k] = v + } + c.permLabels.mutex.Unlock() + lbls.mutex.RUnlock() + + return &core{ + Core: c.Core.With(fields), + permLabels: c.permLabels, + tempLabels: newLabels(), + config: c.config, + } +} + +// Check determines whether the supplied Entry should be logged (using the +// embedded LevelEnabler and possibly some extra logic). If the entry +// should be logged, the Core adds itself to the CheckedEntry and returns +// the result. +// +// Callers must use Check before calling Write. +func (c *core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { + if c.Enabled(ent.Level) { + return ce.AddCore(ent, c) + } + + return ce +} + +func (c *core) Write(ent zapcore.Entry, fields []zapcore.Field) error { + var lbls *labels + lbls, fields = c.extractLabels(fields) + + lbls.mutex.RLock() + c.tempLabels.mutex.Lock() + for k, v := range lbls.store { + c.tempLabels.store[k] = v + } + c.tempLabels.mutex.Unlock() + lbls.mutex.RUnlock() + + fields = append(fields, labelsField(c.allLabels())) + fields = c.withSourceLocation(ent, fields) + if c.config.ServiceName != "" { + fields = c.withServiceContext(c.config.ServiceName, fields) + } + if c.config.ReportAllErrors && zapcore.ErrorLevel.Enabled(ent.Level) { + fields = c.withErrorReport(ent, fields) + if c.config.ServiceName == "" { + // A service name was not set but error report needs it + // So attempt to add a generic service name + fields = c.withServiceContext("unknown", fields) + } + } + + c.tempLabels.reset() + + return c.Core.Write(ent, fields) +} + +// Sync flushes buffered logs (if any). +func (c *core) Sync() error { + return c.Core.Sync() +} + +func (c *core) allLabels() *labels { + lbls := newLabels() + + lbls.mutex.Lock() + c.permLabels.mutex.RLock() + for k, v := range c.permLabels.store { + lbls.store[k] = v + } + c.permLabels.mutex.RUnlock() + + c.tempLabels.mutex.RLock() + for k, v := range c.tempLabels.store { + lbls.store[k] = v + } + c.tempLabels.mutex.RUnlock() + lbls.mutex.Unlock() + + return lbls +} + +func (c *core) extractLabels(fields []zapcore.Field) (*labels, []zapcore.Field) { + lbls := newLabels() + out := []zapcore.Field{} + + lbls.mutex.Lock() + for i := range fields { + if !isLabelField(fields[i]) { + out = append(out, fields[i]) + continue + } + + lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String + } + lbls.mutex.Unlock() + + return lbls, out +} + +func (c *core) withLabels(fields []zapcore.Field) []zapcore.Field { + lbls := newLabels() + out := []zapcore.Field{} + + lbls.mutex.Lock() + for i := range fields { + if isLabelField(fields[i]) { + lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String + continue + } + + out = append(out, fields[i]) + } + lbls.mutex.Unlock() + + return append(out, labelsField(lbls)) +} + +func (c *core) withSourceLocation(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field { + // If the source location was manually set, don't overwrite it + for i := range fields { + if fields[i].Key == sourceKey { + return fields + } + } + + if !ent.Caller.Defined { + return fields + } + + return append(fields, SourceLocation(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true)) +} + +func (c *core) withServiceContext(name string, fields []zapcore.Field) []zapcore.Field { + // If the service context was manually set, don't overwrite it + for i := range fields { + if fields[i].Key == serviceContextKey { + return fields + } + } + + return append(fields, ServiceContext(name)) +} + +func (c *core) withErrorReport(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field { + // If the error report was manually set, don't overwrite it + for i := range fields { + if fields[i].Key == contextKey { + return fields + } + } + + if !ent.Caller.Defined { + return fields + } + + return append(fields, ErrorReport(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true)) +} diff --git a/vendor/github.com/blendle/zapdriver/encoder.go b/vendor/github.com/blendle/zapdriver/encoder.go new file mode 100644 index 00000000000..eec571fb8ec --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/encoder.go @@ -0,0 +1,59 @@ +package zapdriver + +import ( + "time" + + "go.uber.org/zap/zapcore" +) + +// logLevelSeverity maps the Zap log levels to the correct level names as +// defined by Stackdriver. +// +// DEFAULT (0) The log entry has no assigned severity level. +// DEBUG (100) Debug or trace information. +// INFO (200) Routine information, such as ongoing status or performance. +// NOTICE (300) Normal but significant events, such as start up, shut down, or a configuration change. +// WARNING (400) Warning events might cause problems. +// ERROR (500) Error events are likely to cause problems. +// CRITICAL (600) Critical events cause more severe problems or outages. +// ALERT (700) A person must take an action immediately. +// EMERGENCY (800) One or more systems are unusable. +// +// See: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity +var logLevelSeverity = map[zapcore.Level]string{ + zapcore.DebugLevel: "DEBUG", + zapcore.InfoLevel: "INFO", + zapcore.WarnLevel: "WARNING", + zapcore.ErrorLevel: "ERROR", + zapcore.DPanicLevel: "CRITICAL", + zapcore.PanicLevel: "ALERT", + zapcore.FatalLevel: "EMERGENCY", +} + +// encoderConfig is the default encoder configuration, slightly tweaked to use +// the correct fields for Stackdriver to parse them. +var encoderConfig = zapcore.EncoderConfig{ + TimeKey: "timestamp", + LevelKey: "severity", + NameKey: "logger", + CallerKey: "caller", + MessageKey: "message", + StacktraceKey: "stacktrace", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: EncodeLevel, + EncodeTime: RFC3339NanoTimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, +} + +// EncodeLevel maps the internal Zap log level to the appropriate Stackdriver +// level. +func EncodeLevel(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(logLevelSeverity[l]) +} + +// RFC3339NanoTimeEncoder serializes a time.Time to an RFC3339Nano-formatted +// string with nanoseconds precision. +func RFC3339NanoTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format(time.RFC3339Nano)) +} diff --git a/vendor/github.com/blendle/zapdriver/go.mod b/vendor/github.com/blendle/zapdriver/go.mod new file mode 100644 index 00000000000..aecbd4f1203 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/go.mod @@ -0,0 +1,12 @@ +module github.com/blendle/zapdriver + +go 1.12 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pkg/errors v0.8.1 // indirect + github.com/stretchr/testify v1.3.0 + go.uber.org/atomic v1.4.0 // indirect + go.uber.org/multierr v1.1.0 // indirect + go.uber.org/zap v1.10.0 +) diff --git a/vendor/github.com/blendle/zapdriver/go.sum b/vendor/github.com/blendle/zapdriver/go.sum new file mode 100644 index 00000000000..237b5d2e278 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= diff --git a/vendor/github.com/blendle/zapdriver/http.go b/vendor/github.com/blendle/zapdriver/http.go new file mode 100644 index 00000000000..441e585902b --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/http.go @@ -0,0 +1,160 @@ +package zapdriver + +// "Broker: Request timed out" +// https://console.cloud.google.com/logs/viewer?project=bnl-blendle&minLogLevel= +// 0&expandAll=false×tamp=2018-05-23T22:21:56.142000000Z&customFacets=&limi +// tCustomFacetWidth=true&dateRangeEnd=2018-05-23T22:21:52.545Z&interval=PT1H&re +// source=container%2Fcluster_name%2Fblendle-2%2Fnamespace_id%2Fstream- +// composition-analytic-events- +// backfill&scrollTimestamp=2018-05-23T05:29:33.000000000Z&logName=projects +// %2Fbnl-blendle%2Flogs%2Fstream-composition-analytic-events- +// pipe-1&dateRangeUnbound=backwardInTime + +import ( + "bytes" + "io" + "net/http" + "strconv" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// HTTP adds the correct Stackdriver "HTTP" field. +// +// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#HttpRequest +func HTTP(req *HTTPPayload) zap.Field { + return zap.Object("httpRequest", req) +} + +// HTTPPayload is the complete payload that can be interpreted by +// Stackdriver as a HTTP request. +type HTTPPayload struct { + // The request method. Examples: "GET", "HEAD", "PUT", "POST". + RequestMethod string `json:"requestMethod"` + + // The scheme (http, https), the host name, the path and the query portion of + // the URL that was requested. + // + // Example: "http://example.com/some/info?color=red". + RequestURL string `json:"requestUrl"` + + // The size of the HTTP request message in bytes, including the request + // headers and the request body. + RequestSize string `json:"requestSize"` + + // The response code indicating the status of response. + // + // Examples: 200, 404. + Status int `json:"status"` + + // The size of the HTTP response message sent back to the client, in bytes, + // including the response headers and the response body. + ResponseSize string `json:"responseSize"` + + // The user agent sent by the client. + // + // Example: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705)". + UserAgent string `json:"userAgent"` + + // The IP address (IPv4 or IPv6) of the client that issued the HTTP request. + // + // Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329". + RemoteIP string `json:"remoteIp"` + + // The IP address (IPv4 or IPv6) of the origin server that the request was + // sent to. + ServerIP string `json:"serverIp"` + + // The referrer URL of the request, as defined in HTTP/1.1 Header Field + // Definitions. + Referer string `json:"referer"` + + // The request processing latency on the server, from the time the request was + // received until the response was sent. + // + // A duration in seconds with up to nine fractional digits, terminated by 's'. + // + // Example: "3.5s". + Latency string `json:"latency"` + + // Whether or not a cache lookup was attempted. + CacheLookup bool `json:"cacheLookup"` + + // Whether or not an entity was served from cache (with or without + // validation). + CacheHit bool `json:"cacheHit"` + + // Whether or not the response was validated with the origin server before + // being served from cache. This field is only meaningful if cacheHit is True. + CacheValidatedWithOriginServer bool `json:"cacheValidatedWithOriginServer"` + + // The number of HTTP response bytes inserted into cache. Set only when a + // cache fill was attempted. + CacheFillBytes string `json:"cacheFillBytes"` + + // Protocol used for the request. + // + // Examples: "HTTP/1.1", "HTTP/2", "websocket" + Protocol string `json:"protocol"` +} + +// NewHTTP returns a new HTTPPayload struct, based on the passed +// in http.Request and http.Response objects. +func NewHTTP(req *http.Request, res *http.Response) *HTTPPayload { + if req == nil { + req = &http.Request{} + } + + if res == nil { + res = &http.Response{} + } + + sdreq := &HTTPPayload{ + RequestMethod: req.Method, + Status: res.StatusCode, + UserAgent: req.UserAgent(), + RemoteIP: req.RemoteAddr, + Referer: req.Referer(), + Protocol: req.Proto, + } + + if req.URL != nil { + sdreq.RequestURL = req.URL.String() + } + + buf := &bytes.Buffer{} + if req.Body != nil { + n, _ := io.Copy(buf, req.Body) // nolint: gas + sdreq.RequestSize = strconv.FormatInt(n, 10) + } + + if res.Body != nil { + buf.Reset() + n, _ := io.Copy(buf, res.Body) // nolint: gas + sdreq.ResponseSize = strconv.FormatInt(n, 10) + } + + return sdreq +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (req HTTPPayload) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("requestMethod", req.RequestMethod) + enc.AddString("requestUrl", req.RequestURL) + enc.AddString("requestSize", req.RequestSize) + enc.AddInt("status", req.Status) + enc.AddString("responseSize", req.ResponseSize) + enc.AddString("userAgent", req.UserAgent) + enc.AddString("remoteIp", req.RemoteIP) + enc.AddString("serverIp", req.ServerIP) + enc.AddString("referer", req.Referer) + enc.AddString("latency", req.Latency) + enc.AddBool("cacheLookup", req.CacheLookup) + enc.AddBool("cacheHit", req.CacheHit) + enc.AddBool("cacheValidatedWithOriginServer", req.CacheValidatedWithOriginServer) + enc.AddString("cacheFillBytes", req.CacheFillBytes) + enc.AddString("protocol", req.Protocol) + + return nil +} diff --git a/vendor/github.com/blendle/zapdriver/label.go b/vendor/github.com/blendle/zapdriver/label.go new file mode 100644 index 00000000000..7238642096d --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/label.go @@ -0,0 +1,77 @@ +package zapdriver + +import ( + "strings" + "sync" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const labelsKey = "logging.googleapis.com/labels" + +// Label adds an optional label to the payload. +// +// Labels are a set of user-defined (key, value) data that provides additional +// information about the log entry. +// +// Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }. +func Label(key, value string) zap.Field { + return zap.String("labels."+key, value) +} + +// Labels takes Zap fields, filters the ones that have their key start with the +// string `labels.` and their value type set to StringType. It then wraps those +// key/value pairs in a top-level `labels` namespace. +func Labels(fields ...zap.Field) zap.Field { + lbls := newLabels() + + lbls.mutex.Lock() + for i := range fields { + if isLabelField(fields[i]) { + lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String + } + } + lbls.mutex.Unlock() + + return labelsField(lbls) +} + +func isLabelField(field zap.Field) bool { + return strings.HasPrefix(field.Key, "labels.") && field.Type == zapcore.StringType +} + +func labelsField(l *labels) zap.Field { + return zap.Object(labelsKey, l) +} + +type labels struct { + store map[string]string + mutex *sync.RWMutex +} + +func newLabels() *labels { + return &labels{store: map[string]string{}, mutex: &sync.RWMutex{}} +} + +func (l *labels) Add(key, value string) { + l.mutex.Lock() + l.store[key] = value + l.mutex.Unlock() +} + +func (l *labels) reset() { + l.mutex.Lock() + l.store = map[string]string{} + l.mutex.Unlock() +} + +func (l labels) MarshalLogObject(enc zapcore.ObjectEncoder) error { + l.mutex.RLock() + for k, v := range l.store { + enc.AddString(k, v) + } + l.mutex.RUnlock() + + return nil +} diff --git a/vendor/github.com/blendle/zapdriver/logger.go b/vendor/github.com/blendle/zapdriver/logger.go new file mode 100644 index 00000000000..59c10993e90 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/logger.go @@ -0,0 +1,39 @@ +package zapdriver + +import ( + "go.uber.org/zap" +) + +// NewProduction builds a sensible production Logger that writes InfoLevel and +// above logs to standard error as JSON. +// +// It's a shortcut for NewProductionConfig().Build(...Option). +func NewProduction(options ...zap.Option) (*zap.Logger, error) { + options = append(options, WrapCore()) + + return NewProductionConfig().Build(options...) +} + +// NewProductionWithCore is same as NewProduction but accepts a custom configured core +func NewProductionWithCore(core zap.Option, options ...zap.Option) (*zap.Logger, error) { + options = append(options, core) + + return NewProductionConfig().Build(options...) +} + +// NewDevelopment builds a development Logger that writes DebugLevel and above +// logs to standard error in a human-friendly format. +// +// It's a shortcut for NewDevelopmentConfig().Build(...Option). +func NewDevelopment(options ...zap.Option) (*zap.Logger, error) { + options = append(options, WrapCore()) + + return NewDevelopmentConfig().Build(options...) +} + +// NewDevelopmentWithCore is same as NewDevelopment but accepts a custom configured core +func NewDevelopmentWithCore(core zap.Option, options ...zap.Option) (*zap.Logger, error) { + options = append(options, core) + + return NewDevelopmentConfig().Build(options...) +} diff --git a/vendor/github.com/blendle/zapdriver/operation.go b/vendor/github.com/blendle/zapdriver/operation.go new file mode 100644 index 00000000000..e8b862f7954 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/operation.go @@ -0,0 +1,72 @@ +package zapdriver + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const operationKey = "logging.googleapis.com/operation" + +// Operation adds the correct Stackdriver "operation" field. +// +// Additional information about a potentially long-running operation with which +// a log entry is associated. +// +// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntryOperation +func Operation(id, producer string, first, last bool) zap.Field { + op := &operation{ + ID: id, + Producer: producer, + First: first, + Last: last, + } + + return zap.Object(operationKey, op) +} + +// OperationStart is a convenience function for `Operation`. It should be called +// for the first operation log. +func OperationStart(id, producer string) zap.Field { + return Operation(id, producer, true, false) +} + +// OperationCont is a convenience function for `Operation`. It should be called +// for any non-start/end operation log. +func OperationCont(id, producer string) zap.Field { + return Operation(id, producer, false, false) +} + +// OperationEnd is a convenience function for `Operation`. It should be called +// for the last operation log. +func OperationEnd(id, producer string) zap.Field { + return Operation(id, producer, false, true) +} + +// operation is the complete payload that can be interpreted by Stackdriver as +// an operation. +type operation struct { + // Optional. An arbitrary operation identifier. Log entries with the same + // identifier are assumed to be part of the same operation. + ID string `json:"id"` + + // Optional. An arbitrary producer identifier. The combination of id and + // producer must be globally unique. Examples for producer: + // "MyDivision.MyBigCompany.com", "github.com/MyProject/MyApplication". + Producer string `json:"producer"` + + // Optional. Set this to True if this is the first log entry in the operation. + First bool `json:"first"` + + // Optional. Set this to True if this is the last log entry in the operation. + Last bool `json:"last"` +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (op operation) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("id", op.ID) + enc.AddString("producer", op.Producer) + enc.AddBool("first", op.First) + enc.AddBool("last", op.Last) + + return nil +} diff --git a/vendor/github.com/blendle/zapdriver/report.go b/vendor/github.com/blendle/zapdriver/report.go new file mode 100644 index 00000000000..1bb8ac7617c --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/report.go @@ -0,0 +1,70 @@ +package zapdriver + +import ( + "runtime" + "strconv" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const contextKey = "context" + +// ErrorReport adds the correct Stackdriver "context" field for getting the log line +// reported as error. +// +// see: https://cloud.google.com/error-reporting/docs/formatting-error-messages +func ErrorReport(pc uintptr, file string, line int, ok bool) zap.Field { + return zap.Object(contextKey, newReportContext(pc, file, line, ok)) +} + +// reportLocation is the source code location information associated with the log entry +// for the purpose of reporting an error, +// if any. +type reportLocation struct { + File string `json:"filePath"` + Line string `json:"lineNumber"` + Function string `json:"functionName"` +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (location reportLocation) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("filePath", location.File) + enc.AddString("lineNumber", location.Line) + enc.AddString("functionName", location.Function) + + return nil +} + +// reportContext is the context information attached to a log for reporting errors +type reportContext struct { + ReportLocation reportLocation `json:"reportLocation"` +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (context reportContext) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddObject("reportLocation", context.ReportLocation) + + return nil +} + +func newReportContext(pc uintptr, file string, line int, ok bool) *reportContext { + if !ok { + return nil + } + + var function string + if fn := runtime.FuncForPC(pc); fn != nil { + function = fn.Name() + } + + context := &reportContext{ + ReportLocation: reportLocation{ + File: file, + Line: strconv.Itoa(line), + Function: function, + }, + } + + return context +} diff --git a/vendor/github.com/blendle/zapdriver/service.go b/vendor/github.com/blendle/zapdriver/service.go new file mode 100644 index 00000000000..134ff3634a6 --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/service.go @@ -0,0 +1,36 @@ +package zapdriver + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const serviceContextKey = "serviceContext" + +// ServiceContext adds the correct service information adding the log line +// It is a required field if an error needs to be reported. +// +// see: https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext +// see: https://cloud.google.com/error-reporting/docs/formatting-error-messages +func ServiceContext(name string) zap.Field { + return zap.Object(serviceContextKey, newServiceContext(name)) +} + +// serviceContext describes a running service that sends errors. +// Currently it only describes a service name. +type serviceContext struct { + Name string `json:"service"` +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (service_context serviceContext) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("service", service_context.Name) + + return nil +} + +func newServiceContext(name string) *serviceContext { + return &serviceContext{ + Name: name, + } +} diff --git a/vendor/github.com/blendle/zapdriver/source.go b/vendor/github.com/blendle/zapdriver/source.go new file mode 100644 index 00000000000..ff5ecf765ba --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/source.go @@ -0,0 +1,66 @@ +package zapdriver + +import ( + "runtime" + "strconv" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const sourceKey = "logging.googleapis.com/sourceLocation" + +// SourceLocation adds the correct Stackdriver "SourceLocation" field. +// +// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntrySourceLocation +func SourceLocation(pc uintptr, file string, line int, ok bool) zap.Field { + return zap.Object(sourceKey, newSource(pc, file, line, ok)) +} + +// source is the source code location information associated with the log entry, +// if any. +type source struct { + // Optional. Source file name. Depending on the runtime environment, this + // might be a simple name or a fully-qualified name. + File string `json:"file"` + + // Optional. Line within the source file. 1-based; 0 indicates no line number + // available. + Line string `json:"line"` + + // Optional. Human-readable name of the function or method being invoked, with + // optional context such as the class or package name. This information may be + // used in contexts such as the logs viewer, where a file and line number are + // less meaningful. + // + // The format should be dir/package.func. + Function string `json:"function"` +} + +// MarshalLogObject implements zapcore.ObjectMarshaller interface. +func (source source) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("file", source.File) + enc.AddString("line", source.Line) + enc.AddString("function", source.Function) + + return nil +} + +func newSource(pc uintptr, file string, line int, ok bool) *source { + if !ok { + return nil + } + + var function string + if fn := runtime.FuncForPC(pc); fn != nil { + function = fn.Name() + } + + source := &source{ + File: file, + Line: strconv.Itoa(line), + Function: function, + } + + return source +} diff --git a/vendor/github.com/blendle/zapdriver/trace.go b/vendor/github.com/blendle/zapdriver/trace.go new file mode 100644 index 00000000000..7e1e2e8ab3f --- /dev/null +++ b/vendor/github.com/blendle/zapdriver/trace.go @@ -0,0 +1,24 @@ +package zapdriver + +import ( + "fmt" + + "go.uber.org/zap" +) + +const ( + traceKey = "logging.googleapis.com/trace" + spanKey = "logging.googleapis.com/spanId" + traceSampledKey = "logging.googleapis.com/trace_sampled" +) + +// TraceContext adds the correct Stackdriver "trace", "span", "trace_sampled fields +// +// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry +func TraceContext(trace string, spanId string, sampled bool, projectName string) []zap.Field { + return []zap.Field{ + zap.String(traceKey, fmt.Sprintf("projects/%s/traces/%s", projectName, trace)), + zap.String(spanKey, spanId), + zap.Bool(traceSampledKey, sampled), + } +} diff --git a/vendor/knative.dev/pkg/logging/config.go b/vendor/knative.dev/pkg/logging/config.go index e1480033def..1effe1b35bf 100644 --- a/vendor/knative.dev/pkg/logging/config.go +++ b/vendor/knative.dev/pkg/logging/config.go @@ -23,6 +23,7 @@ import ( "os" "strings" + "github.com/blendle/zapdriver" "go.uber.org/zap" "go.uber.org/zap/zapcore" corev1 "k8s.io/api/core/v1" @@ -54,16 +55,16 @@ func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*za return enrichLoggerWithCommitID(logger), atomicLevel } - loggingCfg := zap.NewProductionConfig() + loggingCfg := zapdriver.NewProductionConfig() if levelOverride != "" { if level, err := levelFromString(levelOverride); err == nil { loggingCfg.Level = zap.NewAtomicLevelAt(*level) } } - logger, err2 := loggingCfg.Build(opts...) - if err2 != nil { - panic(err2) + logger, err = loggingCfg.Build(append(opts, zapdriver.WrapCore())...) + if err != nil { + panic(err) } slogger := enrichLoggerWithCommitID(logger.Named(fallbackLoggerName)) @@ -73,13 +74,14 @@ func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*za func enrichLoggerWithCommitID(logger *zap.Logger) *zap.SugaredLogger { commitID, err := changeset.Get() - if err == nil { - // Enrich logs with GitHub commit ID. - return logger.With(zap.String(logkey.GitHubCommitID, commitID)).Sugar() + if err != nil { + logger.Info("Fetch GitHub commit ID from kodata failed", zap.Error(err)) + return logger.Sugar() } - logger.Info("Fetch GitHub commit ID from kodata failed", zap.Error(err)) - return logger.Sugar() + // Enrich logs with GitHub commit ID. + return logger.With(zap.String(logkey.GitHubCommitID, commitID)).Sugar() + } // NewLoggerFromConfig creates a logger using the provided Config @@ -93,7 +95,7 @@ func NewLoggerFromConfig(config *Config, name string, opts ...zap.Option) (*zap. return logger.Named(name), level } -func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Option) (*zap.Logger, zap.AtomicLevel, error) { +func newLoggerFromConfig(configJSON, levelOverride string, opts []zap.Option) (*zap.Logger, zap.AtomicLevel, error) { loggingCfg, err := zapConfigFromJSON(configJSON) if err != nil { return nil, zap.AtomicLevel{}, err @@ -105,7 +107,7 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt } } - logger, err := loggingCfg.Build(opts...) + logger, err := loggingCfg.Build(append(opts, zapdriver.WrapCore())...) if err != nil { return nil, zap.AtomicLevel{}, err } @@ -116,15 +118,13 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt } func zapConfigFromJSON(configJSON string) (*zap.Config, error) { - if configJSON == "" { - return nil, errEmptyLoggerConfig - } - - loggingCfg := &zap.Config{} - if err := json.Unmarshal([]byte(configJSON), loggingCfg); err != nil { - return nil, err + loggingCfg := zapdriver.NewProductionConfig() + if configJSON != "" { + if err := json.Unmarshal([]byte(configJSON), &loggingCfg); err != nil { + return nil, err + } } - return loggingCfg, nil + return &loggingCfg, nil } // Config contains the configuration defined in the logging ConfigMap. @@ -134,31 +134,9 @@ type Config struct { LoggingLevel map[string]zapcore.Level } -const defaultZLC = `{ - "level": "info", - "development": false, - "outputPaths": ["stdout"], - "errorOutputPaths": ["stderr"], - "encoding": "json", - "encoderConfig": { - "timeKey": "ts", - "levelKey": "level", - "nameKey": "logger", - "callerKey": "caller", - "messageKey": "msg", - "stacktraceKey": "stacktrace", - "lineEnding": "", - "levelEncoder": "", - "timeEncoder": "iso8601", - "durationEncoder": "", - "callerEncoder": "" - } -}` - func defaultConfig() *Config { return &Config{ - LoggingConfig: defaultZLC, - LoggingLevel: make(map[string]zapcore.Level), + LoggingLevel: make(map[string]zapcore.Level), } } @@ -202,7 +180,6 @@ func levelFromString(level string) (*zapcore.Level, error) { // when a config map is updated func UpdateLevelFromConfigMap(logger *zap.SugaredLogger, atomicLevel zap.AtomicLevel, levelKey string) func(configMap *corev1.ConfigMap) { - return func(configMap *corev1.ConfigMap) { config, err := NewConfigFromConfigMap(configMap) if err != nil { diff --git a/vendor/knative.dev/pkg/network/handlers/error.go b/vendor/knative.dev/pkg/network/handlers/error.go deleted file mode 100644 index a6bd3bd03cc..00000000000 --- a/vendor/knative.dev/pkg/network/handlers/error.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 The Knative 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 handlers - -import "knative.dev/pkg/network" - -// Error sets up a handler suitable for use with the ErrorHandler field on -// httputil's reverse proxy, which logs /proc/net/sockstat data. -var Error = network.ErrorHandler diff --git a/vendor/knative.dev/pkg/version/version.go b/vendor/knative.dev/pkg/version/version.go index 9e13c1d19a5..cac1399a430 100644 --- a/vendor/knative.dev/pkg/version/version.go +++ b/vendor/knative.dev/pkg/version/version.go @@ -61,6 +61,12 @@ func CheckMinimumVersion(versioner discovery.ServerVersionInterface) error { return err } + // If no specific pre-release requirement is set, we default to "-0" to always allow + // pre-release versions of the same Major.Minor.Patch version. + if len(minimumVersion.Pre) == 0 { + minimumVersion.Pre = []semver.PRVersion{{VersionNum: 0}} + } + // Compare returns 1 if the first version is greater than the // second version. if currentVersion.LT(minimumVersion) { diff --git a/vendor/modules.txt b/vendor/modules.txt index fcd97f9747b..300d6b0f1b5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -72,6 +72,8 @@ github.com/aws/aws-sdk-go/service/sts/stsiface github.com/beorn7/perks/quantile # github.com/blang/semver/v4 v4.0.0 github.com/blang/semver/v4 +# github.com/blendle/zapdriver v1.3.1 +github.com/blendle/zapdriver # github.com/census-instrumentation/opencensus-proto v0.3.0 github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1 github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1 @@ -965,7 +967,7 @@ k8s.io/utils/trace ## explicit knative.dev/hack knative.dev/hack/shell -# knative.dev/pkg v0.0.0-20201130192436-e5346d90e980 +# knative.dev/pkg v0.0.0-20201207225040-7e918163fc4f ## explicit knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate