mirror of https://github.com/knative/client.git
upgrade to latest dependencies (#1164)
Signed-off-by: Knative Automation <automation@knative.team>
This commit is contained in:
parent
24945049e7
commit
03d8236b62
8
go.mod
8
go.mod
|
|
@ -22,11 +22,11 @@ require (
|
|||
k8s.io/cli-runtime v0.18.8
|
||||
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
|
||||
k8s.io/code-generator v0.18.12
|
||||
knative.dev/eventing v0.19.1-0.20201201072837-da18ee0a75f9
|
||||
knative.dev/eventing v0.19.1-0.20201202221809-1d3519c16565
|
||||
knative.dev/hack v0.0.0-20201201234937-fddbf732e450
|
||||
knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
|
||||
knative.dev/pkg v0.0.0-20201130192436-e5346d90e980
|
||||
knative.dev/serving v0.19.1-0.20201201235537-c8e2ccb33125
|
||||
knative.dev/networking v0.0.0-20201203234509-4cd0793eed11
|
||||
knative.dev/pkg v0.0.0-20201204013209-b89ac2a63293
|
||||
knative.dev/serving v0.19.1-0.20201204004409-4bbc460995d6
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
|
|
|
|||
25
go.sum
25
go.sum
|
|
@ -123,6 +123,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
|||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
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/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
|
||||
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
|
|
@ -1221,29 +1223,30 @@ k8s.io/legacy-cloud-providers v0.18.8/go.mod h1:tgp4xYf6lvjrWnjQwTOPvWQE9IVqSBGP
|
|||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
|
||||
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6/go.mod h1:IocU4F1XK8udXpTRC4m9KWyEVtT928sSP+T7Oy34UDg=
|
||||
knative.dev/eventing v0.19.1-0.20201201072837-da18ee0a75f9 h1:BdM5UGM+zs5NuVAtBqnZ4WeOmxbfqen4cYzNGsT2gsE=
|
||||
knative.dev/eventing v0.19.1-0.20201201072837-da18ee0a75f9/go.mod h1:Kd4J2Lcc6L0LMIVOUKYR5utJtTYbX201qZGgDDEWGrQ=
|
||||
knative.dev/caching v0.0.0-20201202014037-fc10335afb00/go.mod h1:LWpD8X3fJcsDzfika4rzu1avRJqCmv2OOyTNoD8OHsQ=
|
||||
knative.dev/eventing v0.19.1-0.20201202221809-1d3519c16565 h1:Xj/WF2mG4tyJvGEsuh6V311J/nwP3wPRJ1ioMO/Urs0=
|
||||
knative.dev/eventing v0.19.1-0.20201202221809-1d3519c16565/go.mod h1:LeCXV+DSK6WMrgTJVE/Vyrpj5mo1BzbnpucjQh8zYf4=
|
||||
knative.dev/hack v0.0.0-20201112185459-01a34c573bd8 h1:RNbZsAjhswBPtl4C5C5gEFX5/GfWIOZQxfYD9DhkHdY=
|
||||
knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/hack v0.0.0-20201120192952-353db687ec5b h1:Lc+AKgwhAZUD98mN++qTHeeaP6FRmS8fcwc/rXkP8G0=
|
||||
knative.dev/hack v0.0.0-20201120192952-353db687ec5b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed h1:DrTU+vxQrNJtySxyNovUtl4si0ozjtU/AYhYaTz34YA=
|
||||
knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed/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/networking v0.0.0-20201125133435-4b21f11ccfa7 h1:O40i4ZCYfpaw7m1yUwtmRhBOdT0HRp3MYD4PWaRzYqI=
|
||||
knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7/go.mod h1:EpImbpW3gu85Mg39GT7gUJTVYLtFYWDsZQCZlKFmGUM=
|
||||
knative.dev/networking v0.0.0-20201203005409-47ea2396c447/go.mod h1:9MYaP1/cs1zYvvvr+gda2XRW1e1WqmUE0xKVxkwmUXw=
|
||||
knative.dev/networking v0.0.0-20201203234509-4cd0793eed11 h1:sogSEftyYRTNZ3g2Ynmvw8djj9X0RwBNa9GCDDLQMr4=
|
||||
knative.dev/networking v0.0.0-20201203234509-4cd0793eed11/go.mod h1:vj8h8ODz+HnStJgIgvAY2pyc146SJA1CaB9iKFpSjiM=
|
||||
knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed h1:4LNEFhvD2Ya4WgCD3SC1WGXz81bjEvQgbcpe5XACI3I=
|
||||
knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed/go.mod h1:nxlh3CUvx6WBPr1WKD96AHxFZPD2UKRDo9RUp8ILTyQ=
|
||||
knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a h1:pdJpLaq50mLKrPWYSQgTH2p64Dk7Fq/xID6l0F69cVY=
|
||||
knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug=
|
||||
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-20201203005309-e45bbefd1d63/go.mod h1:efRLl6Z597X5r3TTt/I73cQIDDV1He6LMN1y4HQlkHU=
|
||||
knative.dev/pkg v0.0.0-20201203193109-a536174bdf99/go.mod h1:Jtbz2/1gB8EZgZA4VvabTxM+AcDt2WL2P0RaFnKcOX8=
|
||||
knative.dev/pkg v0.0.0-20201204013209-b89ac2a63293 h1:6iXRbYUw05l6vnKiUsZSE1HRbsc8hulSs9Y2mTGVMxM=
|
||||
knative.dev/pkg v0.0.0-20201204013209-b89ac2a63293/go.mod h1:Jtbz2/1gB8EZgZA4VvabTxM+AcDt2WL2P0RaFnKcOX8=
|
||||
knative.dev/reconciler-test v0.0.0-20201124190335-83a44efcdfef/go.mod h1:YSs1y1rgnjs8w39/drLIOQbWvZUQwqApvd+EizO8UsA=
|
||||
knative.dev/serving v0.19.1-0.20201201235537-c8e2ccb33125 h1:VHSN0ro9go0wOBJ/oENy2UTEDKDBP6Yylco9bD1ZWok=
|
||||
knative.dev/serving v0.19.1-0.20201201235537-c8e2ccb33125/go.mod h1:AugxGYLC/dnisz5X6huxxMbi2YJswwuzlDp2LEu293c=
|
||||
knative.dev/serving v0.19.1-0.20201204004409-4bbc460995d6 h1:8oq1P5XKceDVdBk9sqIc6IvdRP7xV00CRKMWTo/kAzU=
|
||||
knative.dev/serving v0.19.1-0.20201204004409-4bbc460995d6/go.mod h1:0V/DzxYUwB2dCUbn9V0BP2csI5r2ULLxQAGGNr6ZxB0=
|
||||
pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1 @@
|
|||
vendor/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.<key>`. 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)))
|
||||
```
|
||||
|
|
@ -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"},
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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=
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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...)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
@ -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,14 +55,14 @@ 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...)
|
||||
logger, err2 := loggingCfg.Build(append(opts, zapdriver.WrapCore())...)
|
||||
if err2 != nil {
|
||||
panic(err2)
|
||||
}
|
||||
|
|
@ -105,7 +106,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 +117,13 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt
|
|||
}
|
||||
|
||||
func zapConfigFromJSON(configJSON string) (*zap.Config, error) {
|
||||
if configJSON == "" {
|
||||
return nil, errEmptyLoggerConfig
|
||||
loggingCfg := zapdriver.NewProductionConfig()
|
||||
if configJSON != "" {
|
||||
if err := json.Unmarshal([]byte(configJSON), &loggingCfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
loggingCfg := &zap.Config{}
|
||||
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 +133,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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ github.com/aws/aws-sdk-go/service/sts
|
|||
github.com/aws/aws-sdk-go/service/sts/stsiface
|
||||
# github.com/beorn7/perks v1.0.1
|
||||
github.com/beorn7/perks/quantile
|
||||
# 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
|
||||
|
|
@ -843,7 +845,7 @@ k8s.io/kube-openapi/pkg/util/sets
|
|||
k8s.io/utils/buffer
|
||||
k8s.io/utils/integer
|
||||
k8s.io/utils/trace
|
||||
# knative.dev/eventing v0.19.1-0.20201201072837-da18ee0a75f9
|
||||
# knative.dev/eventing v0.19.1-0.20201202221809-1d3519c16565
|
||||
## explicit
|
||||
knative.dev/eventing/pkg/apis/config
|
||||
knative.dev/eventing/pkg/apis/configs
|
||||
|
|
@ -876,12 +878,12 @@ knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake
|
|||
# knative.dev/hack v0.0.0-20201201234937-fddbf732e450
|
||||
## explicit
|
||||
knative.dev/hack
|
||||
# knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
|
||||
# knative.dev/networking v0.0.0-20201203234509-4cd0793eed11
|
||||
## explicit
|
||||
knative.dev/networking/pkg
|
||||
knative.dev/networking/pkg/apis/networking
|
||||
knative.dev/networking/pkg/apis/networking/v1alpha1
|
||||
# knative.dev/pkg v0.0.0-20201130192436-e5346d90e980
|
||||
# knative.dev/pkg v0.0.0-20201204013209-b89ac2a63293
|
||||
## explicit
|
||||
knative.dev/pkg/apis
|
||||
knative.dev/pkg/apis/duck
|
||||
|
|
@ -925,7 +927,7 @@ knative.dev/pkg/tracing/config
|
|||
knative.dev/pkg/tracing/propagation
|
||||
knative.dev/pkg/tracing/propagation/tracecontextb3
|
||||
knative.dev/pkg/tracker
|
||||
# knative.dev/serving v0.19.1-0.20201201235537-c8e2ccb33125
|
||||
# knative.dev/serving v0.19.1-0.20201204004409-4bbc460995d6
|
||||
## explicit
|
||||
knative.dev/serving/pkg/apis/autoscaling
|
||||
knative.dev/serving/pkg/apis/autoscaling/v1alpha1
|
||||
|
|
|
|||
Loading…
Reference in New Issue