mirror of https://github.com/knative/caching.git
upgrade to latest dependencies (#617)
bumping k8s.io/apimachinery 276a8a7...276a8a7: bumping k8s.io/client-go b425fb6...97582f2: > 97582f2 Update dependencies to v0.23.5 tag bumping knative.dev/hack 14f832e...f067737: > f067737 Adding code of conduct to reference knative/community's CoC (# 162) bumping k8s.io/api a1613d7...cd271e7: > cd271e7 Update dependencies to v0.23.5 tag > a6b2207 Merge pull request # 108139 from liggitt/automated-cherry-pick-of-# 108138-upstream-release-1.23 > 80b93d4 Revert v1beta1 PodDisruptionBudget select patchStrategy bumping k8s.io/code-generator fb849a7...fb849a7: bumping knative.dev/pkg e6e3cf0...1f7514a: > 1f7514a bump k8s deps to v0.23.5 (# 2469) > 19a2589 fix coverage settings (# 2471) > 2daa86a Electors can provide an initial set of buckets (# 2473) Signed-off-by: Knative Automation <automation@knative.team>
This commit is contained in:
parent
defaf7bb43
commit
0755a974c6
12
go.mod
12
go.mod
|
@ -5,11 +5,11 @@ go 1.15
|
|||
require (
|
||||
github.com/google/go-cmp v0.5.6
|
||||
go.uber.org/zap v1.19.1
|
||||
k8s.io/api v0.23.4
|
||||
k8s.io/apimachinery v0.23.4
|
||||
k8s.io/client-go v0.23.4
|
||||
k8s.io/code-generator v0.23.4
|
||||
k8s.io/api v0.23.5
|
||||
k8s.io/apimachinery v0.23.5
|
||||
k8s.io/client-go v0.23.5
|
||||
k8s.io/code-generator v0.23.5
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65
|
||||
knative.dev/hack v0.0.0-20220318020218-14f832e506f8
|
||||
knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765
|
||||
knative.dev/hack v0.0.0-20220328133751-f06773764ce3
|
||||
knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2
|
||||
)
|
||||
|
|
24
go.sum
24
go.sum
|
@ -1118,16 +1118,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E=
|
||||
k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI=
|
||||
k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA=
|
||||
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||
k8s.io/apiextensions-apiserver v0.23.4/go.mod h1:TWYAKymJx7nLMxWCgWm2RYGXHrGlVZnxIlGnvtfYu+g=
|
||||
k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM=
|
||||
k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||
k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0=
|
||||
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||
k8s.io/apiserver v0.23.4/go.mod h1:A6l/ZcNtxGfPSqbFDoxxOjEjSKBaQmE+UTveOmMkpNc=
|
||||
k8s.io/client-go v0.23.4 h1:YVWvPeerA2gpUudLelvsolzH7c2sFoXXR5wM/sWqNFU=
|
||||
k8s.io/client-go v0.23.4/go.mod h1:PKnIL4pqLuvYUK1WU7RLTMYKPiIh7MYShLshtRY9cj0=
|
||||
k8s.io/code-generator v0.23.4 h1:MmDMH74oo8YD4r+KdUzd/VVmXUeXf5u0owLI9wZWP5Y=
|
||||
k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8=
|
||||
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||
k8s.io/code-generator v0.23.4/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
k8s.io/code-generator v0.23.5 h1:xn3a6J5pUL49AoH6SPrOFtnB5cvdMl76f/bEY176R3c=
|
||||
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
k8s.io/component-base v0.23.4/go.mod h1:8o3Gg8i2vnUXGPOwciiYlkSaZT+p+7gA9Scoz8y4W4E=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20220307231824-4627b89bbf1b h1:vEhKDJESYfeRiaBNmRvO+/12RAo1cFeu6vGm1fBFY34=
|
||||
|
@ -1135,8 +1139,8 @@ k8s.io/gengo v0.0.0-20220307231824-4627b89bbf1b/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAE
|
|||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.40.2-0.20220227211518-7ea6d6adb645 h1:9ralYm+Xufh/NgewZj+kGEkERlOA9bfSbpvxt9bLrUg=
|
||||
k8s.io/klog/v2 v2.40.2-0.20220227211518-7ea6d6adb645/go.mod h1:N3kgBtsFxMb4nQ0eBDgbHEt/dtxBuTkSFQ+7K5OUoz4=
|
||||
k8s.io/klog/v2 v2.60.1-0.20220317184644-43cc75f9ae89 h1:bUNlsw5yb353zbKMj8srOr6V2Ajhz1VkTKonP1L8r2o=
|
||||
k8s.io/klog/v2 v2.60.1-0.20220317184644-43cc75f9ae89/go.mod h1:N3kgBtsFxMb4nQ0eBDgbHEt/dtxBuTkSFQ+7K5OUoz4=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
|
@ -1144,10 +1148,10 @@ k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
|||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
knative.dev/hack v0.0.0-20220224013837-e1785985d364/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/hack v0.0.0-20220318020218-14f832e506f8 h1:7NcKM2USd6d3Vu/jJ4QziMUEUC+Y3yJ9xqusI/Pv0y0=
|
||||
knative.dev/hack v0.0.0-20220318020218-14f832e506f8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765 h1:6ma46SWoj3Oiplz29qk8GZiYKhVAmx7CWzl9iHT7iFU=
|
||||
knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765/go.mod h1:nKJ2L4o7or3j58eqMK843kbIM0SiYnAXXsisfEQECS8=
|
||||
knative.dev/hack v0.0.0-20220328133751-f06773764ce3 h1:kXLX7HS7gwQglz+p8ohdxDdO3akLAN+MTfz/B+eUeu4=
|
||||
knative.dev/hack v0.0.0-20220328133751-f06773764ce3/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2 h1:dJ1YKQ1IvCfxtYqS1dHm18VT153ntHi5uJsFVv7oxfc=
|
||||
knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2/go.mod h1:5xt0nzCwxvQ2N4w71smY7pYm5nVrQ8qnRsMinSLVpio=
|
||||
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=
|
||||
|
|
|
@ -144,7 +144,6 @@ message PodDisruptionBudgetSpec {
|
|||
// A null selector selects no pods.
|
||||
// An empty selector ({}) also selects no pods, which differs from standard behavior of selecting all pods.
|
||||
// In policy/v1, an empty selector will select all pods in the namespace.
|
||||
// +patchStrategy=replace
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2;
|
||||
|
||||
|
|
|
@ -36,9 +36,8 @@ type PodDisruptionBudgetSpec struct {
|
|||
// A null selector selects no pods.
|
||||
// An empty selector ({}) also selects no pods, which differs from standard behavior of selecting all pods.
|
||||
// In policy/v1, an empty selector will select all pods in the namespace.
|
||||
// +patchStrategy=replace
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty" patchStrategy:"replace" protobuf:"bytes,2,opt,name=selector"`
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,2,opt,name=selector"`
|
||||
|
||||
// An eviction is allowed if at most "maxUnavailable" pods selected by
|
||||
// "selector" are unavailable after the eviction, i.e. even in absence of
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes 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 klog
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// This file provides the implementation of
|
||||
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-instrumentation/1602-structured-logging
|
||||
//
|
||||
// SetLogger and ClearLogger were originally added to klog.go and got moved
|
||||
// here. Contextual logging adds a way to retrieve a Logger for direct logging
|
||||
// without the logging calls in klog.go.
|
||||
//
|
||||
// The global variables are expected to be modified only during sequential
|
||||
// parts of a program (init, serial tests) and therefore are not protected by
|
||||
// mutex locking.
|
||||
|
||||
var (
|
||||
// contextualLoggingEnabled controls whether contextual logging is
|
||||
// active. Disabling it may have some small performance benefit.
|
||||
contextualLoggingEnabled = true
|
||||
|
||||
// globalLogger is the global Logger chosen by users of klog, nil if
|
||||
// none is available.
|
||||
globalLogger *Logger
|
||||
|
||||
// globalLoggerOptions contains the options that were supplied for
|
||||
// globalLogger.
|
||||
globalLoggerOptions loggerOptions
|
||||
|
||||
// klogLogger is used as fallback for logging through the normal klog code
|
||||
// when no Logger is set.
|
||||
klogLogger logr.Logger = logr.New(&klogger{})
|
||||
)
|
||||
|
||||
// SetLogger sets a Logger implementation that will be used as backing
|
||||
// implementation of the traditional klog log calls. klog will do its own
|
||||
// verbosity checks before calling logger.V().Info. logger.Error is always
|
||||
// called, regardless of the klog verbosity settings.
|
||||
//
|
||||
// If set, all log lines will be suppressed from the regular output, and
|
||||
// redirected to the logr implementation.
|
||||
// Use as:
|
||||
// ...
|
||||
// klog.SetLogger(zapr.NewLogger(zapLog))
|
||||
//
|
||||
// To remove a backing logr implemention, use ClearLogger. Setting an
|
||||
// empty logger with SetLogger(logr.Logger{}) does not work.
|
||||
//
|
||||
// Modifying the logger is not thread-safe and should be done while no other
|
||||
// goroutines invoke log calls, usually during program initialization.
|
||||
func SetLogger(logger logr.Logger) {
|
||||
SetLoggerWithOptions(logger)
|
||||
}
|
||||
|
||||
// SetLoggerWithOptions is a more flexible version of SetLogger. Without
|
||||
// additional options, it behaves exactly like SetLogger. By passing
|
||||
// ContextualLogger(true) as option, it can be used to set a logger that then
|
||||
// will also get called directly by applications which retrieve it via
|
||||
// FromContext, Background, or TODO.
|
||||
//
|
||||
// Supporting direct calls is recommended because it avoids the overhead of
|
||||
// routing log entries through klogr into klog and then into the actual Logger
|
||||
// backend.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func SetLoggerWithOptions(logger logr.Logger, opts ...LoggerOption) {
|
||||
globalLogger = &logger
|
||||
globalLoggerOptions = loggerOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(&globalLoggerOptions)
|
||||
}
|
||||
}
|
||||
|
||||
// ContextualLogger determines whether the logger passed to
|
||||
// SetLoggerWithOptions may also get called directly. Such a logger cannot rely
|
||||
// on verbosity checking in klog.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func ContextualLogger(enabled bool) LoggerOption {
|
||||
return func(o *loggerOptions) {
|
||||
o.contextualLogger = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// FlushLogger provides a callback for flushing data buffered by the logger.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func FlushLogger(flush func()) LoggerOption {
|
||||
return func(o *loggerOptions) {
|
||||
o.flush = flush
|
||||
}
|
||||
}
|
||||
|
||||
// LoggerOption implements the functional parameter paradigm for
|
||||
// SetLoggerWithOptions.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type LoggerOption func(o *loggerOptions)
|
||||
|
||||
type loggerOptions struct {
|
||||
contextualLogger bool
|
||||
flush func()
|
||||
}
|
||||
|
||||
// ClearLogger removes a backing Logger implementation if one was set earlier
|
||||
// with SetLogger.
|
||||
//
|
||||
// Modifying the logger is not thread-safe and should be done while no other
|
||||
// goroutines invoke log calls, usually during program initialization.
|
||||
func ClearLogger() {
|
||||
globalLogger = nil
|
||||
globalLoggerOptions = loggerOptions{}
|
||||
}
|
||||
|
||||
// EnableContextualLogging controls whether contextual logging is enabled.
|
||||
// By default it is enabled. When disabled, FromContext avoids looking up
|
||||
// the logger in the context and always returns the global logger.
|
||||
// LoggerWithValues, LoggerWithName, and NewContext become no-ops
|
||||
// and return their input logger respectively context. This may be useful
|
||||
// to avoid the additional overhead for contextual logging.
|
||||
//
|
||||
// This must be called during initialization before goroutines are started.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func EnableContextualLogging(enabled bool) {
|
||||
contextualLoggingEnabled = enabled
|
||||
}
|
||||
|
||||
// FromContext retrieves a logger set by the caller or, if not set,
|
||||
// falls back to the program's global logger (a Logger instance or klog
|
||||
// itself).
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func FromContext(ctx context.Context) Logger {
|
||||
if contextualLoggingEnabled {
|
||||
if logger, err := logr.FromContext(ctx); err == nil {
|
||||
return logger
|
||||
}
|
||||
}
|
||||
|
||||
return Background()
|
||||
}
|
||||
|
||||
// TODO can be used as a last resort by code that has no means of
|
||||
// receiving a logger from its caller. FromContext or an explicit logger
|
||||
// parameter should be used instead.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func TODO() Logger {
|
||||
return Background()
|
||||
}
|
||||
|
||||
// Background retrieves the fallback logger. It should not be called before
|
||||
// that logger was initialized by the program and not by code that should
|
||||
// better receive a logger via its parameters. TODO can be used as a temporary
|
||||
// solution for such code.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func Background() Logger {
|
||||
if globalLoggerOptions.contextualLogger {
|
||||
// Is non-nil because globalLoggerOptions.contextualLogger is
|
||||
// only true if a logger was set.
|
||||
return *globalLogger
|
||||
}
|
||||
|
||||
return klogLogger
|
||||
}
|
||||
|
||||
// LoggerWithValues returns logger.WithValues(...kv) when
|
||||
// contextual logging is enabled, otherwise the logger.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func LoggerWithValues(logger Logger, kv ...interface{}) Logger {
|
||||
if contextualLoggingEnabled {
|
||||
return logger.WithValues(kv...)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// LoggerWithName returns logger.WithName(name) when contextual logging is
|
||||
// enabled, otherwise the logger.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func LoggerWithName(logger Logger, name string) Logger {
|
||||
if contextualLoggingEnabled {
|
||||
return logger.WithName(name)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// NewContext returns logr.NewContext(ctx, logger) when
|
||||
// contextual logging is enabled, otherwise ctx.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func NewContext(ctx context.Context, logger Logger) context.Context {
|
||||
if contextualLoggingEnabled {
|
||||
return logr.NewContext(ctx, logger)
|
||||
}
|
||||
return ctx
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
// Copyright 2022 The Kubernetes 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 klog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// ExitFlushTimeout is the timeout that klog has traditionally used during
|
||||
// calls like Fatal or Exit when flushing log data right before exiting.
|
||||
// Applications that replace those calls and do not have some specific
|
||||
// requirements like "exit immediately" can use this value as parameter
|
||||
// for FlushAndExit.
|
||||
//
|
||||
// Can be set for testing purpose or to change the application's
|
||||
// default.
|
||||
ExitFlushTimeout = 10 * time.Second
|
||||
|
||||
// OsExit is the function called by FlushAndExit to terminate the program.
|
||||
//
|
||||
// Can be set for testing purpose or to change the application's
|
||||
// default behavior. Note that the function should not simply return
|
||||
// because callers of functions like Fatal will not expect that.
|
||||
OsExit = os.Exit
|
||||
)
|
||||
|
||||
// FlushAndExit flushes log data for a certain amount of time and then calls
|
||||
// os.Exit. Combined with some logging call it provides a replacement for
|
||||
// traditional calls like Fatal or Exit.
|
||||
func FlushAndExit(flushTimeout time.Duration, exitCode int) {
|
||||
timeoutFlush(flushTimeout)
|
||||
OsExit(exitCode)
|
||||
}
|
||||
|
||||
// timeoutFlush calls Flush and returns when it completes or after timeout
|
||||
// elapses, whichever happens first. This is needed because the hooks invoked
|
||||
// by Flush may deadlock when klog.Fatal is called from a hook that holds
|
||||
// a lock. Flushing also might take too long.
|
||||
func timeoutFlush(timeout time.Duration) {
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
Flush() // calls logging.lockAndFlushAll()
|
||||
done <- true
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(timeout):
|
||||
fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes 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 klog
|
||||
|
||||
import (
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// The reason for providing these aliases is to allow code to work with logr
|
||||
// without directly importing it.
|
||||
|
||||
// Logger in this package is exactly the same as logr.Logger.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type Logger = logr.Logger
|
||||
|
||||
// LogSink in this package is exactly the same as logr.LogSink.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type LogSink = logr.LogSink
|
||||
|
||||
// Runtimeinfo in this package is exactly the same as logr.RuntimeInfo.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type RuntimeInfo = logr.RuntimeInfo
|
||||
|
||||
var (
|
||||
// New is an alias for logr.New.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This variable is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
New = logr.New
|
||||
)
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes 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 klog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// ObjectRef references a kubernetes object
|
||||
type ObjectRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
func (ref ObjectRef) String() string {
|
||||
if ref.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s", ref.Namespace, ref.Name)
|
||||
}
|
||||
return ref.Name
|
||||
}
|
||||
|
||||
// MarshalLog ensures that loggers with support for structured output will log
|
||||
// as a struct by removing the String method via a custom type.
|
||||
func (ref ObjectRef) MarshalLog() interface{} {
|
||||
type or ObjectRef
|
||||
return or(ref)
|
||||
}
|
||||
|
||||
var _ logr.Marshaler = ObjectRef{}
|
||||
|
||||
// KMetadata is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
|
||||
// this interface may expand in the future, but will always be a subset of the
|
||||
// kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
|
||||
type KMetadata interface {
|
||||
GetName() string
|
||||
GetNamespace() string
|
||||
}
|
||||
|
||||
// KObj returns ObjectRef from ObjectMeta
|
||||
func KObj(obj KMetadata) ObjectRef {
|
||||
if obj == nil {
|
||||
return ObjectRef{}
|
||||
}
|
||||
if val := reflect.ValueOf(obj); val.Kind() == reflect.Ptr && val.IsNil() {
|
||||
return ObjectRef{}
|
||||
}
|
||||
|
||||
return ObjectRef{
|
||||
Name: obj.GetName(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
}
|
||||
}
|
||||
|
||||
// KRef returns ObjectRef from name and namespace
|
||||
func KRef(namespace, name string) ObjectRef {
|
||||
return ObjectRef{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// KObjs returns slice of ObjectRef from an slice of ObjectMeta
|
||||
func KObjs(arg interface{}) []ObjectRef {
|
||||
s := reflect.ValueOf(arg)
|
||||
if s.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
objectRefs := make([]ObjectRef, 0, s.Len())
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if v, ok := s.Index(i).Interface().(KMetadata); ok {
|
||||
objectRefs = append(objectRefs, KObj(v))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return objectRefs
|
||||
}
|
|
@ -81,7 +81,6 @@ import (
|
|||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -396,7 +395,7 @@ func init() {
|
|||
logging.addDirHeader = false
|
||||
logging.skipLogHeaders = false
|
||||
logging.oneOutput = false
|
||||
logging.flushD = newFlushDaemon(flushInterval, logging.lockAndFlushAll, nil)
|
||||
logging.flushD = newFlushDaemon(logging.lockAndFlushAll, nil)
|
||||
}
|
||||
|
||||
// InitFlags is for explicitly initializing the flags.
|
||||
|
@ -450,6 +449,9 @@ type loggingT struct {
|
|||
file [severity.NumSeverity]flushSyncWriter
|
||||
// flushD holds a flushDaemon that frequently flushes log file buffers.
|
||||
flushD *flushDaemon
|
||||
// flushInterval is the interval for periodic flushing. If zero,
|
||||
// the global default will be used.
|
||||
flushInterval time.Duration
|
||||
// pcs is used in V to avoid an allocation when computing the caller's PC.
|
||||
pcs [1]uintptr
|
||||
// vmap is a cache of the V Level for each V() call site, identified by PC.
|
||||
|
@ -487,9 +489,6 @@ type loggingT struct {
|
|||
// If true, add the file directory to the header
|
||||
addDirHeader bool
|
||||
|
||||
// If set, all output will be redirected unconditionally to the provided logr.Logger
|
||||
logr *logr.Logger
|
||||
|
||||
// If true, messages will not be propagated to lower severity log levels
|
||||
oneOutput bool
|
||||
|
||||
|
@ -689,7 +688,7 @@ func (l *loggingT) printS(err error, s severity.Severity, depth int, msg string,
|
|||
serialize.KVListFormat(&b.Buffer, "err", err)
|
||||
}
|
||||
serialize.KVListFormat(&b.Buffer, keysAndValues...)
|
||||
l.printDepth(s, logging.logr, nil, depth+1, &b.Buffer)
|
||||
l.printDepth(s, globalLogger, nil, depth+1, &b.Buffer)
|
||||
// Make the buffer available for reuse.
|
||||
l.bufferCache.PutBuffer(b)
|
||||
}
|
||||
|
@ -711,34 +710,6 @@ func (rb *redirectBuffer) Write(bytes []byte) (n int, err error) {
|
|||
return rb.w.Write(bytes)
|
||||
}
|
||||
|
||||
// SetLogger will set the backing logr implementation for klog.
|
||||
// If set, all log lines will be suppressed from the regular Output, and
|
||||
// redirected to the logr implementation.
|
||||
// Use as:
|
||||
// ...
|
||||
// klog.SetLogger(zapr.NewLogger(zapLog))
|
||||
//
|
||||
// To remove a backing logr implemention, use ClearLogger. Setting an
|
||||
// empty logger with SetLogger(logr.Logger{}) does not work.
|
||||
//
|
||||
// Modifying the logger is not thread-safe and should be done while no other
|
||||
// goroutines invoke log calls, usually during program initialization.
|
||||
func SetLogger(logr logr.Logger) {
|
||||
logging.logr = &logr
|
||||
}
|
||||
|
||||
// ClearLogger removes a backing logr implementation if one was set earlier
|
||||
// with SetLogger.
|
||||
//
|
||||
// Modifying the logger is not thread-safe and should be done while no other
|
||||
// goroutines invoke log calls, usually during program initialization.
|
||||
func ClearLogger() {
|
||||
logging.mu.Lock()
|
||||
defer logging.mu.Unlock()
|
||||
|
||||
logging.logr = nil
|
||||
}
|
||||
|
||||
// SetOutput sets the output destination for all severities
|
||||
func SetOutput(w io.Writer) {
|
||||
logging.mu.Lock()
|
||||
|
@ -794,7 +765,7 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
|
|||
// TODO: set 'severity' and caller information as structured log info
|
||||
// keysAndValues := []interface{}{"severity", severityName[s], "file", file, "line", line}
|
||||
if s == severity.ErrorLog {
|
||||
logging.logr.WithCallDepth(depth+3).Error(nil, string(data))
|
||||
globalLogger.WithCallDepth(depth+3).Error(nil, string(data))
|
||||
} else {
|
||||
log.WithCallDepth(depth + 3).Info(string(data))
|
||||
}
|
||||
|
@ -847,8 +818,8 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
|
|||
if atomic.LoadUint32(&fatalNoStacks) > 0 {
|
||||
l.mu.Unlock()
|
||||
isLocked = false
|
||||
timeoutFlush(10 * time.Second)
|
||||
os.Exit(1)
|
||||
timeoutFlush(ExitFlushTimeout)
|
||||
OsExit(1)
|
||||
}
|
||||
// Dump all goroutine stacks before exiting.
|
||||
trace := stacks(true)
|
||||
|
@ -865,8 +836,8 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
|
|||
}
|
||||
l.mu.Unlock()
|
||||
isLocked = false
|
||||
timeoutFlush(10 * time.Second)
|
||||
os.Exit(255) // C++ uses -1, which is silly because it's anded(&) with 255 anyway.
|
||||
timeoutFlush(ExitFlushTimeout)
|
||||
OsExit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
|
||||
}
|
||||
l.bufferCache.PutBuffer(buf)
|
||||
|
||||
|
@ -876,23 +847,6 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
|
|||
}
|
||||
}
|
||||
|
||||
// timeoutFlush calls Flush and returns when it completes or after timeout
|
||||
// elapses, whichever happens first. This is needed because the hooks invoked
|
||||
// by Flush may deadlock when klog.Fatal is called from a hook that holds
|
||||
// a lock.
|
||||
func timeoutFlush(timeout time.Duration) {
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
Flush() // calls logging.lockAndFlushAll()
|
||||
done <- true
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(timeout):
|
||||
fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout)
|
||||
}
|
||||
}
|
||||
|
||||
// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines.
|
||||
func stacks(all bool) []byte {
|
||||
// We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
|
||||
|
@ -929,7 +883,7 @@ func (l *loggingT) exit(err error) {
|
|||
return
|
||||
}
|
||||
l.flushAll()
|
||||
os.Exit(2)
|
||||
OsExit(2)
|
||||
}
|
||||
|
||||
// syncBuffer joins a bufio.Writer to its underlying file, providing access to the
|
||||
|
@ -1025,7 +979,11 @@ const bufferSize = 256 * 1024
|
|||
// createFiles creates all the log files for severity from sev down to infoLog.
|
||||
// l.mu is held.
|
||||
func (l *loggingT) createFiles(sev severity.Severity) error {
|
||||
l.flushD.run()
|
||||
interval := l.flushInterval
|
||||
if interval == 0 {
|
||||
interval = flushInterval
|
||||
}
|
||||
l.flushD.run(interval)
|
||||
now := time.Now()
|
||||
// Files are created in decreasing severity order, so as soon as we find one
|
||||
// has already been created, we can stop.
|
||||
|
@ -1049,7 +1007,6 @@ const flushInterval = 5 * time.Second
|
|||
type flushDaemon struct {
|
||||
mu sync.Mutex
|
||||
clock clock.WithTicker
|
||||
interval time.Duration
|
||||
flush func()
|
||||
stopC chan struct{}
|
||||
stopDone chan struct{}
|
||||
|
@ -1057,20 +1014,19 @@ type flushDaemon struct {
|
|||
|
||||
// newFlushDaemon returns a new flushDaemon. If the passed clock is nil, a
|
||||
// clock.RealClock is used.
|
||||
func newFlushDaemon(interval time.Duration, flush func(), tickClock clock.WithTicker) *flushDaemon {
|
||||
func newFlushDaemon(flush func(), tickClock clock.WithTicker) *flushDaemon {
|
||||
if tickClock == nil {
|
||||
tickClock = clock.RealClock{}
|
||||
}
|
||||
return &flushDaemon{
|
||||
interval: interval,
|
||||
flush: flush,
|
||||
clock: tickClock,
|
||||
flush: flush,
|
||||
clock: tickClock,
|
||||
}
|
||||
}
|
||||
|
||||
// run starts a goroutine that periodically calls the daemons flush function.
|
||||
// Calling run on an already running daemon will have no effect.
|
||||
func (f *flushDaemon) run() {
|
||||
func (f *flushDaemon) run(interval time.Duration) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
|
@ -1081,7 +1037,7 @@ func (f *flushDaemon) run() {
|
|||
f.stopC = make(chan struct{}, 1)
|
||||
f.stopDone = make(chan struct{}, 1)
|
||||
|
||||
ticker := f.clock.NewTicker(f.interval)
|
||||
ticker := f.clock.NewTicker(interval)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
defer func() { f.stopDone <- struct{}{} }()
|
||||
|
@ -1128,6 +1084,13 @@ func StopFlushDaemon() {
|
|||
logging.flushD.stop()
|
||||
}
|
||||
|
||||
// StartFlushDaemon ensures that the flush daemon runs with the given delay
|
||||
// between flush calls. If it is already running, it gets restarted.
|
||||
func StartFlushDaemon(interval time.Duration) {
|
||||
StopFlushDaemon()
|
||||
logging.flushD.run(interval)
|
||||
}
|
||||
|
||||
// lockAndFlushAll is like flushAll but locks l.mu first.
|
||||
func (l *loggingT) lockAndFlushAll() {
|
||||
l.mu.Lock()
|
||||
|
@ -1146,6 +1109,9 @@ func (l *loggingT) flushAll() {
|
|||
file.Sync() // ignore error
|
||||
}
|
||||
}
|
||||
if globalLoggerOptions.flush != nil {
|
||||
globalLoggerOptions.flush()
|
||||
}
|
||||
}
|
||||
|
||||
// CopyStandardLogTo arranges for messages written to the Go "log" package's
|
||||
|
@ -1192,7 +1158,7 @@ func (lb logBridge) Write(b []byte) (n int, err error) {
|
|||
}
|
||||
// printWithFileLine with alsoToStderr=true, so standard log messages
|
||||
// always appear on standard error.
|
||||
logging.printWithFileLine(severity.Severity(lb), logging.logr, logging.filter, file, line, true, text)
|
||||
logging.printWithFileLine(severity.Severity(lb), globalLogger, logging.filter, file, line, true, text)
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
|
@ -1230,10 +1196,10 @@ type Verbose struct {
|
|||
}
|
||||
|
||||
func newVerbose(level Level, b bool) Verbose {
|
||||
if logging.logr == nil {
|
||||
if globalLogger == nil {
|
||||
return Verbose{b, nil}
|
||||
}
|
||||
v := logging.logr.V(int(level))
|
||||
v := globalLogger.V(int(level))
|
||||
return Verbose{b, &v}
|
||||
}
|
||||
|
||||
|
@ -1352,7 +1318,7 @@ func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
|
|||
// InfoSDepth acts as InfoS but uses depth to determine which call frame to log.
|
||||
// InfoSDepth(0, "msg") is the same as InfoS("msg").
|
||||
func InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
|
||||
logging.infoS(logging.logr, logging.filter, depth, msg, keysAndValues...)
|
||||
logging.infoS(globalLogger, logging.filter, depth, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// InfoSDepth is equivalent to the global InfoSDepth function, guarded by the value of v.
|
||||
|
@ -1381,37 +1347,37 @@ func (v Verbose) ErrorS(err error, msg string, keysAndValues ...interface{}) {
|
|||
// Info logs to the INFO log.
|
||||
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||
func Info(args ...interface{}) {
|
||||
logging.print(severity.InfoLog, logging.logr, logging.filter, args...)
|
||||
logging.print(severity.InfoLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// InfoDepth acts as Info but uses depth to determine which call frame to log.
|
||||
// InfoDepth(0, "msg") is the same as Info("msg").
|
||||
func InfoDepth(depth int, args ...interface{}) {
|
||||
logging.printDepth(severity.InfoLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printDepth(severity.InfoLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Infoln logs to the INFO log.
|
||||
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||
func Infoln(args ...interface{}) {
|
||||
logging.println(severity.InfoLog, logging.logr, logging.filter, args...)
|
||||
logging.println(severity.InfoLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// InfolnDepth acts as Infoln but uses depth to determine which call frame to log.
|
||||
// InfolnDepth(0, "msg") is the same as Infoln("msg").
|
||||
func InfolnDepth(depth int, args ...interface{}) {
|
||||
logging.printlnDepth(severity.InfoLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printlnDepth(severity.InfoLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Infof logs to the INFO log.
|
||||
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
logging.printf(severity.InfoLog, logging.logr, logging.filter, format, args...)
|
||||
logging.printf(severity.InfoLog, globalLogger, logging.filter, format, args...)
|
||||
}
|
||||
|
||||
// InfofDepth acts as Infof but uses depth to determine which call frame to log.
|
||||
// InfofDepth(0, "msg", args...) is the same as Infof("msg", args...).
|
||||
func InfofDepth(depth int, format string, args ...interface{}) {
|
||||
logging.printfDepth(severity.InfoLog, logging.logr, logging.filter, depth, format, args...)
|
||||
logging.printfDepth(severity.InfoLog, globalLogger, logging.filter, depth, format, args...)
|
||||
}
|
||||
|
||||
// InfoS structured logs to the INFO log.
|
||||
|
@ -1423,79 +1389,79 @@ func InfofDepth(depth int, format string, args ...interface{}) {
|
|||
// output:
|
||||
// >> I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kubedns" status="ready"
|
||||
func InfoS(msg string, keysAndValues ...interface{}) {
|
||||
logging.infoS(logging.logr, logging.filter, 0, msg, keysAndValues...)
|
||||
logging.infoS(globalLogger, logging.filter, 0, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// Warning logs to the WARNING and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||
func Warning(args ...interface{}) {
|
||||
logging.print(severity.WarningLog, logging.logr, logging.filter, args...)
|
||||
logging.print(severity.WarningLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// WarningDepth acts as Warning but uses depth to determine which call frame to log.
|
||||
// WarningDepth(0, "msg") is the same as Warning("msg").
|
||||
func WarningDepth(depth int, args ...interface{}) {
|
||||
logging.printDepth(severity.WarningLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printDepth(severity.WarningLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Warningln logs to the WARNING and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||
func Warningln(args ...interface{}) {
|
||||
logging.println(severity.WarningLog, logging.logr, logging.filter, args...)
|
||||
logging.println(severity.WarningLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// WarninglnDepth acts as Warningln but uses depth to determine which call frame to log.
|
||||
// WarninglnDepth(0, "msg") is the same as Warningln("msg").
|
||||
func WarninglnDepth(depth int, args ...interface{}) {
|
||||
logging.printlnDepth(severity.WarningLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printlnDepth(severity.WarningLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Warningf logs to the WARNING and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
logging.printf(severity.WarningLog, logging.logr, logging.filter, format, args...)
|
||||
logging.printf(severity.WarningLog, globalLogger, logging.filter, format, args...)
|
||||
}
|
||||
|
||||
// WarningfDepth acts as Warningf but uses depth to determine which call frame to log.
|
||||
// WarningfDepth(0, "msg", args...) is the same as Warningf("msg", args...).
|
||||
func WarningfDepth(depth int, format string, args ...interface{}) {
|
||||
logging.printfDepth(severity.WarningLog, logging.logr, logging.filter, depth, format, args...)
|
||||
logging.printfDepth(severity.WarningLog, globalLogger, logging.filter, depth, format, args...)
|
||||
}
|
||||
|
||||
// Error logs to the ERROR, WARNING, and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||
func Error(args ...interface{}) {
|
||||
logging.print(severity.ErrorLog, logging.logr, logging.filter, args...)
|
||||
logging.print(severity.ErrorLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// ErrorDepth acts as Error but uses depth to determine which call frame to log.
|
||||
// ErrorDepth(0, "msg") is the same as Error("msg").
|
||||
func ErrorDepth(depth int, args ...interface{}) {
|
||||
logging.printDepth(severity.ErrorLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printDepth(severity.ErrorLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||
func Errorln(args ...interface{}) {
|
||||
logging.println(severity.ErrorLog, logging.logr, logging.filter, args...)
|
||||
logging.println(severity.ErrorLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// ErrorlnDepth acts as Errorln but uses depth to determine which call frame to log.
|
||||
// ErrorlnDepth(0, "msg") is the same as Errorln("msg").
|
||||
func ErrorlnDepth(depth int, args ...interface{}) {
|
||||
logging.printlnDepth(severity.ErrorLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printlnDepth(severity.ErrorLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Errorf logs to the ERROR, WARNING, and INFO logs.
|
||||
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
logging.printf(severity.ErrorLog, logging.logr, logging.filter, format, args...)
|
||||
logging.printf(severity.ErrorLog, globalLogger, logging.filter, format, args...)
|
||||
}
|
||||
|
||||
// ErrorfDepth acts as Errorf but uses depth to determine which call frame to log.
|
||||
// ErrorfDepth(0, "msg", args...) is the same as Errorf("msg", args...).
|
||||
func ErrorfDepth(depth int, format string, args ...interface{}) {
|
||||
logging.printfDepth(severity.ErrorLog, logging.logr, logging.filter, depth, format, args...)
|
||||
logging.printfDepth(severity.ErrorLog, globalLogger, logging.filter, depth, format, args...)
|
||||
}
|
||||
|
||||
// ErrorS structured logs to the ERROR, WARNING, and INFO logs.
|
||||
|
@ -1508,97 +1474,97 @@ func ErrorfDepth(depth int, format string, args ...interface{}) {
|
|||
// output:
|
||||
// >> E1025 00:15:15.525108 1 controller_utils.go:114] "Failed to update pod status" err="timeout"
|
||||
func ErrorS(err error, msg string, keysAndValues ...interface{}) {
|
||||
logging.errorS(err, logging.logr, logging.filter, 0, msg, keysAndValues...)
|
||||
logging.errorS(err, globalLogger, logging.filter, 0, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// ErrorSDepth acts as ErrorS but uses depth to determine which call frame to log.
|
||||
// ErrorSDepth(0, "msg") is the same as ErrorS("msg").
|
||||
func ErrorSDepth(depth int, err error, msg string, keysAndValues ...interface{}) {
|
||||
logging.errorS(err, logging.logr, logging.filter, depth, msg, keysAndValues...)
|
||||
logging.errorS(err, globalLogger, logging.filter, depth, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
|
||||
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
||||
// including a stack trace of all running goroutines, then calls OsExit(255).
|
||||
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||
func Fatal(args ...interface{}) {
|
||||
logging.print(severity.FatalLog, logging.logr, logging.filter, args...)
|
||||
logging.print(severity.FatalLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
|
||||
// FatalDepth(0, "msg") is the same as Fatal("msg").
|
||||
func FatalDepth(depth int, args ...interface{}) {
|
||||
logging.printDepth(severity.FatalLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printDepth(severity.FatalLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
||||
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
||||
// including a stack trace of all running goroutines, then calls OsExit(255).
|
||||
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||
func Fatalln(args ...interface{}) {
|
||||
logging.println(severity.FatalLog, logging.logr, logging.filter, args...)
|
||||
logging.println(severity.FatalLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// FatallnDepth acts as Fatalln but uses depth to determine which call frame to log.
|
||||
// FatallnDepth(0, "msg") is the same as Fatalln("msg").
|
||||
func FatallnDepth(depth int, args ...interface{}) {
|
||||
logging.printlnDepth(severity.FatalLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printlnDepth(severity.FatalLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
|
||||
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
||||
// including a stack trace of all running goroutines, then calls OsExit(255).
|
||||
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
logging.printf(severity.FatalLog, logging.logr, logging.filter, format, args...)
|
||||
logging.printf(severity.FatalLog, globalLogger, logging.filter, format, args...)
|
||||
}
|
||||
|
||||
// FatalfDepth acts as Fatalf but uses depth to determine which call frame to log.
|
||||
// FatalfDepth(0, "msg", args...) is the same as Fatalf("msg", args...).
|
||||
func FatalfDepth(depth int, format string, args ...interface{}) {
|
||||
logging.printfDepth(severity.FatalLog, logging.logr, logging.filter, depth, format, args...)
|
||||
logging.printfDepth(severity.FatalLog, globalLogger, logging.filter, depth, format, args...)
|
||||
}
|
||||
|
||||
// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks.
|
||||
// It allows Exit and relatives to use the Fatal logs.
|
||||
var fatalNoStacks uint32
|
||||
|
||||
// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||
// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls OsExit(1).
|
||||
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||
func Exit(args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.print(severity.FatalLog, logging.logr, logging.filter, args...)
|
||||
logging.print(severity.FatalLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// ExitDepth acts as Exit but uses depth to determine which call frame to log.
|
||||
// ExitDepth(0, "msg") is the same as Exit("msg").
|
||||
func ExitDepth(depth int, args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.printDepth(severity.FatalLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printDepth(severity.FatalLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||
// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls OsExit(1).
|
||||
func Exitln(args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.println(severity.FatalLog, logging.logr, logging.filter, args...)
|
||||
logging.println(severity.FatalLog, globalLogger, logging.filter, args...)
|
||||
}
|
||||
|
||||
// ExitlnDepth acts as Exitln but uses depth to determine which call frame to log.
|
||||
// ExitlnDepth(0, "msg") is the same as Exitln("msg").
|
||||
func ExitlnDepth(depth int, args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.printlnDepth(severity.FatalLog, logging.logr, logging.filter, depth, args...)
|
||||
logging.printlnDepth(severity.FatalLog, globalLogger, logging.filter, depth, args...)
|
||||
}
|
||||
|
||||
// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||
// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls OsExit(1).
|
||||
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||
func Exitf(format string, args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.printf(severity.FatalLog, logging.logr, logging.filter, format, args...)
|
||||
logging.printf(severity.FatalLog, globalLogger, logging.filter, format, args...)
|
||||
}
|
||||
|
||||
// ExitfDepth acts as Exitf but uses depth to determine which call frame to log.
|
||||
// ExitfDepth(0, "msg", args...) is the same as Exitf("msg", args...).
|
||||
func ExitfDepth(depth int, format string, args ...interface{}) {
|
||||
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||
logging.printfDepth(severity.FatalLog, logging.logr, logging.filter, depth, format, args...)
|
||||
logging.printfDepth(severity.FatalLog, globalLogger, logging.filter, depth, format, args...)
|
||||
}
|
||||
|
||||
// LogFilter is a collection of functions that can filter all logging calls,
|
||||
|
@ -1616,73 +1582,3 @@ type LogFilter interface {
|
|||
func SetLogFilter(filter LogFilter) {
|
||||
logging.filter = filter
|
||||
}
|
||||
|
||||
// ObjectRef references a kubernetes object
|
||||
type ObjectRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
func (ref ObjectRef) String() string {
|
||||
if ref.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s", ref.Namespace, ref.Name)
|
||||
}
|
||||
return ref.Name
|
||||
}
|
||||
|
||||
// MarshalLog ensures that loggers with support for structured output will log
|
||||
// as a struct by removing the String method via a custom type.
|
||||
func (ref ObjectRef) MarshalLog() interface{} {
|
||||
type or ObjectRef
|
||||
return or(ref)
|
||||
}
|
||||
|
||||
var _ logr.Marshaler = ObjectRef{}
|
||||
|
||||
// KMetadata is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
|
||||
// this interface may expand in the future, but will always be a subset of the
|
||||
// kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
|
||||
type KMetadata interface {
|
||||
GetName() string
|
||||
GetNamespace() string
|
||||
}
|
||||
|
||||
// KObj returns ObjectRef from ObjectMeta
|
||||
func KObj(obj KMetadata) ObjectRef {
|
||||
if obj == nil {
|
||||
return ObjectRef{}
|
||||
}
|
||||
if val := reflect.ValueOf(obj); val.Kind() == reflect.Ptr && val.IsNil() {
|
||||
return ObjectRef{}
|
||||
}
|
||||
|
||||
return ObjectRef{
|
||||
Name: obj.GetName(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
}
|
||||
}
|
||||
|
||||
// KRef returns ObjectRef from name and namespace
|
||||
func KRef(namespace, name string) ObjectRef {
|
||||
return ObjectRef{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// KObjs returns slice of ObjectRef from an slice of ObjectMeta
|
||||
func KObjs(arg interface{}) []ObjectRef {
|
||||
s := reflect.ValueOf(arg)
|
||||
if s.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
objectRefs := make([]ObjectRef, 0, s.Len())
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if v, ok := s.Index(i).Interface().(KMetadata); ok {
|
||||
objectRefs = append(objectRefs, KObj(v))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return objectRefs
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes 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 klog
|
||||
|
||||
import (
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
"k8s.io/klog/v2/internal/serialize"
|
||||
)
|
||||
|
||||
// NewKlogr returns a logger that is functionally identical to
|
||||
// klogr.NewWithOptions(klogr.FormatKlog), i.e. it passes through to klog. The
|
||||
// difference is that it uses a simpler implementation.
|
||||
//
|
||||
// Experimental
|
||||
//
|
||||
// Notice: This function is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func NewKlogr() Logger {
|
||||
return New(&klogger{})
|
||||
}
|
||||
|
||||
// klogger is a subset of klogr/klogr.go. It had to be copied to break an
|
||||
// import cycle (klogr wants to use klog, and klog wants to use klogr).
|
||||
type klogger struct {
|
||||
level int
|
||||
callDepth int
|
||||
prefix string
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
func (l *klogger) Init(info logr.RuntimeInfo) {
|
||||
l.callDepth += info.CallDepth
|
||||
}
|
||||
|
||||
func (l klogger) Info(level int, msg string, kvList ...interface{}) {
|
||||
trimmed := serialize.TrimDuplicates(l.values, kvList)
|
||||
if l.prefix != "" {
|
||||
msg = l.prefix + ": " + msg
|
||||
}
|
||||
V(Level(level)).InfoSDepth(l.callDepth+1, msg, append(trimmed[0], trimmed[1]...)...)
|
||||
}
|
||||
|
||||
func (l klogger) Enabled(level int) bool {
|
||||
return V(Level(level)).Enabled()
|
||||
}
|
||||
|
||||
func (l klogger) Error(err error, msg string, kvList ...interface{}) {
|
||||
trimmed := serialize.TrimDuplicates(l.values, kvList)
|
||||
if l.prefix != "" {
|
||||
msg = l.prefix + ": " + msg
|
||||
}
|
||||
ErrorSDepth(l.callDepth+1, err, msg, append(trimmed[0], trimmed[1]...)...)
|
||||
}
|
||||
|
||||
// WithName returns a new logr.Logger with the specified name appended. klogr
|
||||
// uses '/' characters to separate name elements. Callers should not pass '/'
|
||||
// in the provided name string, but this library does not actually enforce that.
|
||||
func (l klogger) WithName(name string) logr.LogSink {
|
||||
if len(l.prefix) > 0 {
|
||||
l.prefix = l.prefix + "/"
|
||||
}
|
||||
l.prefix += name
|
||||
return &l
|
||||
}
|
||||
|
||||
func (l klogger) WithValues(kvList ...interface{}) logr.LogSink {
|
||||
l.values = serialize.WithValues(l.values, kvList)
|
||||
return &l
|
||||
}
|
||||
|
||||
func (l klogger) WithCallDepth(depth int) logr.LogSink {
|
||||
l.callDepth += depth
|
||||
return &l
|
||||
}
|
||||
|
||||
var _ logr.LogSink = &klogger{}
|
||||
var _ logr.CallDepthLogSink = &klogger{}
|
|
@ -0,0 +1,3 @@
|
|||
## Knative Community Code of Conduct
|
||||
|
||||
The [Knative Community Code of Conduct](https://github.com/knative/community/blob/main/CODE-OF-CONDUCT.md) is defined in the [Knative community repository](https://github.com/knative/community).
|
|
@ -1,4 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
Please see the Knative Community
|
||||
[Contributor Covenant Code of Conduct](https://www.knative.dev/contributing/code-of-conduct/).
|
|
@ -468,6 +468,13 @@ func (c *Impl) RunContext(ctx context.Context, threadiness int) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ib, ok := le.(kle.ElectorWithInitialBuckets); ok {
|
||||
for _, b := range ib.InitialBuckets() {
|
||||
// No need to provide an enq function since the controller
|
||||
// is not processing items
|
||||
la.Promote(b, nil)
|
||||
}
|
||||
}
|
||||
sg.Add(1)
|
||||
go func() {
|
||||
defer sg.Done()
|
||||
|
|
|
@ -80,6 +80,12 @@ type Elector interface {
|
|||
Run(context.Context)
|
||||
}
|
||||
|
||||
// ElectorWithInitialBuckets is an optional interface for electors to
|
||||
// supply an initial set of buckets
|
||||
type ElectorWithInitialBuckets interface {
|
||||
InitialBuckets() []reconciler.Bucket
|
||||
}
|
||||
|
||||
// BuildElector builds a leaderelection.LeaderElector for the named LeaderAware
|
||||
// reconciler using a builder added to the context via WithStandardLeaderElectorBuilder.
|
||||
func BuildElector(ctx context.Context, la reconciler.LeaderAware, queueName string, enq func(reconciler.Bucket, types.NamespacedName)) (Elector, error) {
|
||||
|
@ -255,11 +261,22 @@ type unopposedElector struct {
|
|||
enq func(reconciler.Bucket, types.NamespacedName)
|
||||
}
|
||||
|
||||
var (
|
||||
_ Elector = (*unopposedElector)(nil)
|
||||
_ ElectorWithInitialBuckets = (*unopposedElector)(nil)
|
||||
)
|
||||
|
||||
// Run implements Elector
|
||||
func (ue *unopposedElector) Run(ctx context.Context) {
|
||||
ue.la.Promote(ue.bkt, ue.enq)
|
||||
}
|
||||
|
||||
func (ue *unopposedElector) InitialBuckets() []reconciler.Bucket {
|
||||
return []reconciler.Bucket{
|
||||
reconciler.UniversalBucket(),
|
||||
}
|
||||
}
|
||||
|
||||
type runAll struct {
|
||||
les []Elector
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ gopkg.in/inf.v0
|
|||
gopkg.in/yaml.v2
|
||||
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gopkg.in/yaml.v3
|
||||
# k8s.io/api v0.23.4
|
||||
# k8s.io/api v0.23.5
|
||||
## explicit
|
||||
k8s.io/api/admissionregistration/v1
|
||||
k8s.io/api/admissionregistration/v1beta1
|
||||
|
@ -355,7 +355,7 @@ k8s.io/api/scheduling/v1beta1
|
|||
k8s.io/api/storage/v1
|
||||
k8s.io/api/storage/v1alpha1
|
||||
k8s.io/api/storage/v1beta1
|
||||
# k8s.io/apimachinery v0.23.4
|
||||
# k8s.io/apimachinery v0.23.5
|
||||
## explicit
|
||||
k8s.io/apimachinery/pkg/api/equality
|
||||
k8s.io/apimachinery/pkg/api/errors
|
||||
|
@ -404,7 +404,7 @@ k8s.io/apimachinery/pkg/version
|
|||
k8s.io/apimachinery/pkg/watch
|
||||
k8s.io/apimachinery/third_party/forked/golang/json
|
||||
k8s.io/apimachinery/third_party/forked/golang/reflect
|
||||
# k8s.io/client-go v0.23.4
|
||||
# k8s.io/client-go v0.23.5
|
||||
## explicit
|
||||
k8s.io/client-go/applyconfigurations/admissionregistration/v1
|
||||
k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1
|
||||
|
@ -530,7 +530,7 @@ k8s.io/client-go/util/homedir
|
|||
k8s.io/client-go/util/keyutil
|
||||
k8s.io/client-go/util/retry
|
||||
k8s.io/client-go/util/workqueue
|
||||
# k8s.io/code-generator v0.23.4
|
||||
# k8s.io/code-generator v0.23.5
|
||||
## explicit
|
||||
k8s.io/code-generator
|
||||
k8s.io/code-generator/cmd/client-gen
|
||||
|
@ -576,7 +576,7 @@ k8s.io/gengo/generator
|
|||
k8s.io/gengo/namer
|
||||
k8s.io/gengo/parser
|
||||
k8s.io/gengo/types
|
||||
# k8s.io/klog/v2 v2.40.2-0.20220227211518-7ea6d6adb645
|
||||
# k8s.io/klog/v2 v2.60.1-0.20220317184644-43cc75f9ae89
|
||||
k8s.io/klog/v2
|
||||
k8s.io/klog/v2/internal/buffer
|
||||
k8s.io/klog/v2/internal/serialize
|
||||
|
@ -600,10 +600,10 @@ k8s.io/utils/integer
|
|||
k8s.io/utils/internal/third_party/forked/golang/net
|
||||
k8s.io/utils/net
|
||||
k8s.io/utils/trace
|
||||
# knative.dev/hack v0.0.0-20220318020218-14f832e506f8
|
||||
# knative.dev/hack v0.0.0-20220328133751-f06773764ce3
|
||||
## explicit
|
||||
knative.dev/hack
|
||||
# knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765
|
||||
# knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2
|
||||
## explicit
|
||||
knative.dev/pkg/apis
|
||||
knative.dev/pkg/apis/duck
|
||||
|
|
Loading…
Reference in New Issue