mirror of https://github.com/docker/buildx.git
vendor: github.com/google/certificate-transparency-go v1.1.4
full diff: - https://github.com/google/certificate-transparency-go/compare/v1.0.21...v1.1.4 - https://github.com/kubernetes/klog/compare/v2.30.0...v2.80.1 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
6dd5589a9c
commit
8a70e7634d
5
go.mod
5
go.mod
|
@ -94,7 +94,7 @@ require (
|
|||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/google/certificate-transparency-go v1.0.21 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
|
@ -130,6 +130,7 @@ require (
|
|||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/spf13/viper v1.14.0 // indirect
|
||||
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect
|
||||
|
@ -164,7 +165,7 @@ require (
|
|||
gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
|
|
11
go.sum
11
go.sum
|
@ -284,8 +284,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
|
||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY=
|
||||
github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
|
@ -504,8 +504,9 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
|||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 h1:ka9QPuQg2u4LGipiZGsgkg3rJCo4iIUCy75FddM0GRQ=
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
|
||||
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
|
||||
|
@ -996,8 +997,8 @@ k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
|
|||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
|
||||
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
reviewers:
|
||||
- jayunit100
|
||||
- hoegaarden
|
||||
- andyxning
|
||||
- neolit123
|
||||
- harshanarayana
|
||||
- pohly
|
||||
- yagonobre
|
||||
- vincepri
|
||||
- detiber
|
||||
approvers:
|
||||
- dims
|
||||
- thockin
|
||||
- justinsb
|
||||
- tallclair
|
||||
- piosz
|
||||
- brancz
|
||||
- lavalamp
|
||||
- serathius
|
||||
emeritus_approvers:
|
||||
- brancz
|
||||
- justinsb
|
||||
- lavalamp
|
||||
- piosz
|
||||
- tallclair
|
||||
|
|
|
@ -23,6 +23,20 @@ Historical context is available here:
|
|||
* https://groups.google.com/forum/#!msg/kubernetes-sig-architecture/wCWiWf3Juzs/hXRVBH90CgAJ
|
||||
* https://groups.google.com/forum/#!msg/kubernetes-dev/7vnijOMhLS0/1oRiNtigBgAJ
|
||||
|
||||
## Release versioning
|
||||
|
||||
Semantic versioning is used in this repository. It contains several Go modules
|
||||
with different levels of stability:
|
||||
- `k8s.io/klog/v2` - stable API, `vX.Y.Z` tags
|
||||
- `examples` - no stable API, no tags, no intention to ever stabilize
|
||||
|
||||
Exempt from the API stability guarantee are items (packages, functions, etc.)
|
||||
which are marked explicitly as `EXPERIMENTAL` in their docs comment. Those
|
||||
may still change in incompatible ways or get removed entirely. This can only
|
||||
be used for code that is used in tests to avoid situations where non-test
|
||||
code from two different Kubernetes dependencies depends on incompatible
|
||||
releases of klog because an experimental API was changed.
|
||||
|
||||
----
|
||||
|
||||
How to use klog
|
||||
|
@ -32,6 +46,7 @@ How to use klog
|
|||
- You can now use `log_file` instead of `log_dir` for logging to a single file (See `examples/log_file/usage_log_file.go`)
|
||||
- If you want to redirect everything logged using klog somewhere else (say syslog!), you can use `klog.SetOutput()` method and supply a `io.Writer`. (See `examples/set_output/usage_set_output.go`)
|
||||
- For more logging conventions (See [Logging Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md))
|
||||
- See our documentation on [pkg.go.dev/k8s.io](https://pkg.go.dev/k8s.io/klog).
|
||||
|
||||
**NOTE**: please use the newer go versions that support semantic import versioning in modules, ideally go 1.11.4 or greater.
|
||||
|
||||
|
@ -85,7 +100,7 @@ The comment from glog.go introduces the ideas:
|
|||
|
||||
glog.Fatalf("Initialization failed: %s", err)
|
||||
|
||||
See the documentation for the V function for an explanation
|
||||
See the documentation of the V function for an explanation
|
||||
of these examples:
|
||||
|
||||
if glog.V(2) {
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
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 (
|
||||
// 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.
|
||||
func SetLoggerWithOptions(logger logr.Logger, opts ...LoggerOption) {
|
||||
logging.logger = &logger
|
||||
logging.loggerOptions = loggerOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(&logging.loggerOptions)
|
||||
}
|
||||
}
|
||||
|
||||
// ContextualLogger determines whether the logger passed to
|
||||
// SetLoggerWithOptions may also get called directly. Such a logger cannot rely
|
||||
// on verbosity checking in klog.
|
||||
func ContextualLogger(enabled bool) LoggerOption {
|
||||
return func(o *loggerOptions) {
|
||||
o.contextualLogger = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// FlushLogger provides a callback for flushing data buffered by the logger.
|
||||
func FlushLogger(flush func()) LoggerOption {
|
||||
return func(o *loggerOptions) {
|
||||
o.flush = flush
|
||||
}
|
||||
}
|
||||
|
||||
// LoggerOption implements the functional parameter paradigm for
|
||||
// SetLoggerWithOptions.
|
||||
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() {
|
||||
logging.logger = nil
|
||||
logging.loggerOptions = 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.
|
||||
func EnableContextualLogging(enabled bool) {
|
||||
logging.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).
|
||||
func FromContext(ctx context.Context) Logger {
|
||||
if logging.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.
|
||||
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.
|
||||
func Background() Logger {
|
||||
if logging.loggerOptions.contextualLogger {
|
||||
// Is non-nil because logging.loggerOptions.contextualLogger is
|
||||
// only true if a logger was set.
|
||||
return *logging.logger
|
||||
}
|
||||
|
||||
return klogLogger
|
||||
}
|
||||
|
||||
// LoggerWithValues returns logger.WithValues(...kv) when
|
||||
// contextual logging is enabled, otherwise the logger.
|
||||
func LoggerWithValues(logger Logger, kv ...interface{}) Logger {
|
||||
if logging.contextualLoggingEnabled {
|
||||
return logger.WithValues(kv...)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// LoggerWithName returns logger.WithName(name) when contextual logging is
|
||||
// enabled, otherwise the logger.
|
||||
func LoggerWithName(logger Logger, name string) Logger {
|
||||
if logging.contextualLoggingEnabled {
|
||||
return logger.WithName(name)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// NewContext returns logr.NewContext(ctx, logger) when
|
||||
// contextual logging is enabled, otherwise ctx.
|
||||
func NewContext(ctx context.Context, logger Logger) context.Context {
|
||||
if logging.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,38 @@
|
|||
/*
|
||||
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.
|
||||
type Logger = logr.Logger
|
||||
|
||||
// LogSink in this package is exactly the same as logr.LogSink.
|
||||
type LogSink = logr.LogSink
|
||||
|
||||
// Runtimeinfo in this package is exactly the same as logr.RuntimeInfo.
|
||||
type RuntimeInfo = logr.RuntimeInfo
|
||||
|
||||
var (
|
||||
// New is an alias for logr.New.
|
||||
New = logr.New
|
||||
)
|
|
@ -0,0 +1,159 @@
|
|||
// 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 buffer provides a cache for byte.Buffer instances that can be reused
|
||||
// to avoid frequent allocation and deallocation. It also has utility code
|
||||
// for log header formatting that use these buffers.
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2/internal/severity"
|
||||
)
|
||||
|
||||
var (
|
||||
// Pid is inserted into log headers. Can be overridden for tests.
|
||||
Pid = os.Getpid()
|
||||
)
|
||||
|
||||
// Buffer holds a single byte.Buffer for reuse. The zero value is ready for
|
||||
// use. It also provides some helper methods for output formatting.
|
||||
type Buffer struct {
|
||||
bytes.Buffer
|
||||
Tmp [64]byte // temporary byte array for creating headers.
|
||||
next *Buffer
|
||||
}
|
||||
|
||||
// Buffers manages the reuse of individual buffer instances. It is thread-safe.
|
||||
type Buffers struct {
|
||||
// mu protects the free list. It is separate from the main mutex
|
||||
// so buffers can be grabbed and printed to without holding the main lock,
|
||||
// for better parallelization.
|
||||
mu sync.Mutex
|
||||
|
||||
// freeList is a list of byte buffers, maintained under mu.
|
||||
freeList *Buffer
|
||||
}
|
||||
|
||||
// GetBuffer returns a new, ready-to-use buffer.
|
||||
func (bl *Buffers) GetBuffer() *Buffer {
|
||||
bl.mu.Lock()
|
||||
b := bl.freeList
|
||||
if b != nil {
|
||||
bl.freeList = b.next
|
||||
}
|
||||
bl.mu.Unlock()
|
||||
if b == nil {
|
||||
b = new(Buffer)
|
||||
} else {
|
||||
b.next = nil
|
||||
b.Reset()
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// PutBuffer returns a buffer to the free list.
|
||||
func (bl *Buffers) PutBuffer(b *Buffer) {
|
||||
if b.Len() >= 256 {
|
||||
// Let big buffers die a natural death.
|
||||
return
|
||||
}
|
||||
bl.mu.Lock()
|
||||
b.next = bl.freeList
|
||||
bl.freeList = b
|
||||
bl.mu.Unlock()
|
||||
}
|
||||
|
||||
// Some custom tiny helper functions to print the log header efficiently.
|
||||
|
||||
const digits = "0123456789"
|
||||
|
||||
// twoDigits formats a zero-prefixed two-digit integer at buf.Tmp[i].
|
||||
func (buf *Buffer) twoDigits(i, d int) {
|
||||
buf.Tmp[i+1] = digits[d%10]
|
||||
d /= 10
|
||||
buf.Tmp[i] = digits[d%10]
|
||||
}
|
||||
|
||||
// nDigits formats an n-digit integer at buf.Tmp[i],
|
||||
// padding with pad on the left.
|
||||
// It assumes d >= 0.
|
||||
func (buf *Buffer) nDigits(n, i, d int, pad byte) {
|
||||
j := n - 1
|
||||
for ; j >= 0 && d > 0; j-- {
|
||||
buf.Tmp[i+j] = digits[d%10]
|
||||
d /= 10
|
||||
}
|
||||
for ; j >= 0; j-- {
|
||||
buf.Tmp[i+j] = pad
|
||||
}
|
||||
}
|
||||
|
||||
// someDigits formats a zero-prefixed variable-width integer at buf.Tmp[i].
|
||||
func (buf *Buffer) someDigits(i, d int) int {
|
||||
// Print into the top, then copy down. We know there's space for at least
|
||||
// a 10-digit number.
|
||||
j := len(buf.Tmp)
|
||||
for {
|
||||
j--
|
||||
buf.Tmp[j] = digits[d%10]
|
||||
d /= 10
|
||||
if d == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return copy(buf.Tmp[i:], buf.Tmp[j:])
|
||||
}
|
||||
|
||||
// FormatHeader formats a log header using the provided file name and line number.
|
||||
func (buf *Buffer) FormatHeader(s severity.Severity, file string, line int, now time.Time) {
|
||||
if line < 0 {
|
||||
line = 0 // not a real line number, but acceptable to someDigits
|
||||
}
|
||||
if s > severity.FatalLog {
|
||||
s = severity.InfoLog // for safety.
|
||||
}
|
||||
|
||||
// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
|
||||
// It's worth about 3X. Fprintf is hard.
|
||||
_, month, day := now.Date()
|
||||
hour, minute, second := now.Clock()
|
||||
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
|
||||
buf.Tmp[0] = severity.Char[s]
|
||||
buf.twoDigits(1, int(month))
|
||||
buf.twoDigits(3, day)
|
||||
buf.Tmp[5] = ' '
|
||||
buf.twoDigits(6, hour)
|
||||
buf.Tmp[8] = ':'
|
||||
buf.twoDigits(9, minute)
|
||||
buf.Tmp[11] = ':'
|
||||
buf.twoDigits(12, second)
|
||||
buf.Tmp[14] = '.'
|
||||
buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
|
||||
buf.Tmp[21] = ' '
|
||||
buf.nDigits(7, 22, Pid, ' ') // TODO: should be TID
|
||||
buf.Tmp[29] = ' '
|
||||
buf.Write(buf.Tmp[:30])
|
||||
buf.WriteString(file)
|
||||
buf.Tmp[0] = ':'
|
||||
n := buf.someDigits(1, line)
|
||||
buf.Tmp[n+1] = ']'
|
||||
buf.Tmp[n+2] = ' '
|
||||
buf.Write(buf.Tmp[:n+3])
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
# Clock
|
||||
|
||||
This package provides an interface for time-based operations. It allows
|
||||
mocking time for testing.
|
||||
|
||||
This is a copy of k8s.io/utils/clock. We have to copy it to avoid a circular
|
||||
dependency (k8s.io/klog -> k8s.io/utils -> k8s.io/klog).
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
Copyright 2014 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 clock
|
||||
|
||||
import "time"
|
||||
|
||||
// PassiveClock allows for injecting fake or real clocks into code
|
||||
// that needs to read the current time but does not support scheduling
|
||||
// activity in the future.
|
||||
type PassiveClock interface {
|
||||
Now() time.Time
|
||||
Since(time.Time) time.Duration
|
||||
}
|
||||
|
||||
// Clock allows for injecting fake or real clocks into code that
|
||||
// needs to do arbitrary things based on time.
|
||||
type Clock interface {
|
||||
PassiveClock
|
||||
// After returns the channel of a new Timer.
|
||||
// This method does not allow to free/GC the backing timer before it fires. Use
|
||||
// NewTimer instead.
|
||||
After(d time.Duration) <-chan time.Time
|
||||
// NewTimer returns a new Timer.
|
||||
NewTimer(d time.Duration) Timer
|
||||
// Sleep sleeps for the provided duration d.
|
||||
// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
|
||||
Sleep(d time.Duration)
|
||||
// Tick returns the channel of a new Ticker.
|
||||
// This method does not allow to free/GC the backing ticker. Use
|
||||
// NewTicker from WithTicker instead.
|
||||
Tick(d time.Duration) <-chan time.Time
|
||||
}
|
||||
|
||||
// WithTicker allows for injecting fake or real clocks into code that
|
||||
// needs to do arbitrary things based on time.
|
||||
type WithTicker interface {
|
||||
Clock
|
||||
// NewTicker returns a new Ticker.
|
||||
NewTicker(time.Duration) Ticker
|
||||
}
|
||||
|
||||
// WithDelayedExecution allows for injecting fake or real clocks into
|
||||
// code that needs to make use of AfterFunc functionality.
|
||||
type WithDelayedExecution interface {
|
||||
Clock
|
||||
// AfterFunc executes f in its own goroutine after waiting
|
||||
// for d duration and returns a Timer whose channel can be
|
||||
// closed by calling Stop() on the Timer.
|
||||
AfterFunc(d time.Duration, f func()) Timer
|
||||
}
|
||||
|
||||
// WithTickerAndDelayedExecution allows for injecting fake or real clocks
|
||||
// into code that needs Ticker and AfterFunc functionality
|
||||
type WithTickerAndDelayedExecution interface {
|
||||
WithTicker
|
||||
// AfterFunc executes f in its own goroutine after waiting
|
||||
// for d duration and returns a Timer whose channel can be
|
||||
// closed by calling Stop() on the Timer.
|
||||
AfterFunc(d time.Duration, f func()) Timer
|
||||
}
|
||||
|
||||
// Ticker defines the Ticker interface.
|
||||
type Ticker interface {
|
||||
C() <-chan time.Time
|
||||
Stop()
|
||||
}
|
||||
|
||||
var _ = WithTicker(RealClock{})
|
||||
|
||||
// RealClock really calls time.Now()
|
||||
type RealClock struct{}
|
||||
|
||||
// Now returns the current time.
|
||||
func (RealClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// Since returns time since the specified timestamp.
|
||||
func (RealClock) Since(ts time.Time) time.Duration {
|
||||
return time.Since(ts)
|
||||
}
|
||||
|
||||
// After is the same as time.After(d).
|
||||
// This method does not allow to free/GC the backing timer before it fires. Use
|
||||
// NewTimer instead.
|
||||
func (RealClock) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
}
|
||||
|
||||
// NewTimer is the same as time.NewTimer(d)
|
||||
func (RealClock) NewTimer(d time.Duration) Timer {
|
||||
return &realTimer{
|
||||
timer: time.NewTimer(d),
|
||||
}
|
||||
}
|
||||
|
||||
// AfterFunc is the same as time.AfterFunc(d, f).
|
||||
func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
|
||||
return &realTimer{
|
||||
timer: time.AfterFunc(d, f),
|
||||
}
|
||||
}
|
||||
|
||||
// Tick is the same as time.Tick(d)
|
||||
// This method does not allow to free/GC the backing ticker. Use
|
||||
// NewTicker instead.
|
||||
func (RealClock) Tick(d time.Duration) <-chan time.Time {
|
||||
return time.Tick(d)
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker.
|
||||
func (RealClock) NewTicker(d time.Duration) Ticker {
|
||||
return &realTicker{
|
||||
ticker: time.NewTicker(d),
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep is the same as time.Sleep(d)
|
||||
// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
|
||||
func (RealClock) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
// Timer allows for injecting fake or real timers into code that
|
||||
// needs to do arbitrary things based on time.
|
||||
type Timer interface {
|
||||
C() <-chan time.Time
|
||||
Stop() bool
|
||||
Reset(d time.Duration) bool
|
||||
}
|
||||
|
||||
var _ = Timer(&realTimer{})
|
||||
|
||||
// realTimer is backed by an actual time.Timer.
|
||||
type realTimer struct {
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
// C returns the underlying timer's channel.
|
||||
func (r *realTimer) C() <-chan time.Time {
|
||||
return r.timer.C
|
||||
}
|
||||
|
||||
// Stop calls Stop() on the underlying timer.
|
||||
func (r *realTimer) Stop() bool {
|
||||
return r.timer.Stop()
|
||||
}
|
||||
|
||||
// Reset calls Reset() on the underlying timer.
|
||||
func (r *realTimer) Reset(d time.Duration) bool {
|
||||
return r.timer.Reset(d)
|
||||
}
|
||||
|
||||
type realTicker struct {
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
func (r *realTicker) C() <-chan time.Time {
|
||||
return r.ticker.C
|
||||
}
|
||||
|
||||
func (r *realTicker) Stop() {
|
||||
r.ticker.Stop()
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 dbg provides some helper code for call traces.
|
||||
package dbg
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Stacks is a wrapper for runtime.Stack that attempts to recover the data for
|
||||
// all goroutines or the calling one.
|
||||
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.
|
||||
n := 10000
|
||||
if all {
|
||||
n = 100000
|
||||
}
|
||||
var trace []byte
|
||||
for i := 0; i < 5; i++ {
|
||||
trace = make([]byte, n)
|
||||
nbytes := runtime.Stack(trace, all)
|
||||
if nbytes < len(trace) {
|
||||
return trace[:nbytes]
|
||||
}
|
||||
n *= 2
|
||||
}
|
||||
return trace
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
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 serialize
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// WithValues implements LogSink.WithValues. The old key/value pairs are
|
||||
// assumed to be well-formed, the new ones are checked and padded if
|
||||
// necessary. It returns a new slice.
|
||||
func WithValues(oldKV, newKV []interface{}) []interface{} {
|
||||
if len(newKV) == 0 {
|
||||
return oldKV
|
||||
}
|
||||
newLen := len(oldKV) + len(newKV)
|
||||
hasMissingValue := newLen%2 != 0
|
||||
if hasMissingValue {
|
||||
newLen++
|
||||
}
|
||||
// The new LogSink must have its own slice.
|
||||
kv := make([]interface{}, 0, newLen)
|
||||
kv = append(kv, oldKV...)
|
||||
kv = append(kv, newKV...)
|
||||
if hasMissingValue {
|
||||
kv = append(kv, missingValue)
|
||||
}
|
||||
return kv
|
||||
}
|
||||
|
||||
// MergeKVs deduplicates elements provided in two key/value slices.
|
||||
//
|
||||
// Keys in each slice are expected to be unique, so duplicates can only occur
|
||||
// when the first and second slice contain the same key. When that happens, the
|
||||
// key/value pair from the second slice is used. The first slice must be well-formed
|
||||
// (= even key/value pairs). The second one may have a missing value, in which
|
||||
// case the special "missing value" is added to the result.
|
||||
func MergeKVs(first, second []interface{}) []interface{} {
|
||||
maxLength := len(first) + (len(second)+1)/2*2
|
||||
if maxLength == 0 {
|
||||
// Nothing to do at all.
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(first) == 0 && len(second)%2 == 0 {
|
||||
// Nothing to be overridden, second slice is well-formed
|
||||
// and can be used directly.
|
||||
return second
|
||||
}
|
||||
|
||||
// Determine which keys are in the second slice so that we can skip
|
||||
// them when iterating over the first one. The code intentionally
|
||||
// favors performance over completeness: we assume that keys are string
|
||||
// constants and thus compare equal when the string values are equal. A
|
||||
// string constant being overridden by, for example, a fmt.Stringer is
|
||||
// not handled.
|
||||
overrides := map[interface{}]bool{}
|
||||
for i := 0; i < len(second); i += 2 {
|
||||
overrides[second[i]] = true
|
||||
}
|
||||
merged := make([]interface{}, 0, maxLength)
|
||||
for i := 0; i+1 < len(first); i += 2 {
|
||||
key := first[i]
|
||||
if overrides[key] {
|
||||
continue
|
||||
}
|
||||
merged = append(merged, key, first[i+1])
|
||||
}
|
||||
merged = append(merged, second...)
|
||||
if len(merged)%2 != 0 {
|
||||
merged = append(merged, missingValue)
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
const missingValue = "(MISSING)"
|
||||
|
||||
// KVListFormat serializes all key/value pairs into the provided buffer.
|
||||
// A space gets inserted before the first pair and between each pair.
|
||||
func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
|
||||
for i := 0; i < len(keysAndValues); i += 2 {
|
||||
var v interface{}
|
||||
k := keysAndValues[i]
|
||||
if i+1 < len(keysAndValues) {
|
||||
v = keysAndValues[i+1]
|
||||
} else {
|
||||
v = missingValue
|
||||
}
|
||||
b.WriteByte(' ')
|
||||
// Keys are assumed to be well-formed according to
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
|
||||
// for the sake of performance. Keys with spaces,
|
||||
// special characters, etc. will break parsing.
|
||||
if sK, ok := k.(string); ok {
|
||||
// Avoid one allocation when the key is a string, which
|
||||
// normally it should be.
|
||||
b.WriteString(sK)
|
||||
} else {
|
||||
b.WriteString(fmt.Sprintf("%s", k))
|
||||
}
|
||||
|
||||
// The type checks are sorted so that more frequently used ones
|
||||
// come first because that is then faster in the common
|
||||
// cases. In Kubernetes, ObjectRef (a Stringer) is more common
|
||||
// than plain strings
|
||||
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
|
||||
switch v := v.(type) {
|
||||
case fmt.Stringer:
|
||||
writeStringValue(b, true, StringerToString(v))
|
||||
case string:
|
||||
writeStringValue(b, true, v)
|
||||
case error:
|
||||
writeStringValue(b, true, ErrorToString(v))
|
||||
case logr.Marshaler:
|
||||
value := MarshalerToValue(v)
|
||||
// A marshaler that returns a string is useful for
|
||||
// delayed formatting of complex values. We treat this
|
||||
// case like a normal string. This is useful for
|
||||
// multi-line support.
|
||||
//
|
||||
// We could do this by recursively formatting a value,
|
||||
// but that comes with the risk of infinite recursion
|
||||
// if a marshaler returns itself. Instead we call it
|
||||
// only once and rely on it returning the intended
|
||||
// value directly.
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
writeStringValue(b, true, value)
|
||||
default:
|
||||
writeStringValue(b, false, fmt.Sprintf("%+v", value))
|
||||
}
|
||||
case []byte:
|
||||
// In https://github.com/kubernetes/klog/pull/237 it was decided
|
||||
// to format byte slices with "%+q". The advantages of that are:
|
||||
// - readable output if the bytes happen to be printable
|
||||
// - non-printable bytes get represented as unicode escape
|
||||
// sequences (\uxxxx)
|
||||
//
|
||||
// The downsides are that we cannot use the faster
|
||||
// strconv.Quote here and that multi-line output is not
|
||||
// supported. If developers know that a byte array is
|
||||
// printable and they want multi-line output, they can
|
||||
// convert the value to string before logging it.
|
||||
b.WriteByte('=')
|
||||
b.WriteString(fmt.Sprintf("%+q", v))
|
||||
default:
|
||||
writeStringValue(b, false, fmt.Sprintf("%+v", v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StringerToString converts a Stringer to a string,
|
||||
// handling panics if they occur.
|
||||
func StringerToString(s fmt.Stringer) (ret string) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ret = fmt.Sprintf("<panic: %s>", err)
|
||||
}
|
||||
}()
|
||||
ret = s.String()
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalerToValue invokes a marshaler and catches
|
||||
// panics.
|
||||
func MarshalerToValue(m logr.Marshaler) (ret interface{}) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ret = fmt.Sprintf("<panic: %s>", err)
|
||||
}
|
||||
}()
|
||||
ret = m.MarshalLog()
|
||||
return
|
||||
}
|
||||
|
||||
// ErrorToString converts an error to a string,
|
||||
// handling panics if they occur.
|
||||
func ErrorToString(err error) (ret string) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ret = fmt.Sprintf("<panic: %s>", err)
|
||||
}
|
||||
}()
|
||||
ret = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
func writeStringValue(b *bytes.Buffer, quote bool, v string) {
|
||||
data := []byte(v)
|
||||
index := bytes.IndexByte(data, '\n')
|
||||
if index == -1 {
|
||||
b.WriteByte('=')
|
||||
if quote {
|
||||
// Simple string, quote quotation marks and non-printable characters.
|
||||
b.WriteString(strconv.Quote(v))
|
||||
return
|
||||
}
|
||||
// Non-string with no line breaks.
|
||||
b.WriteString(v)
|
||||
return
|
||||
}
|
||||
|
||||
// Complex multi-line string, show as-is with indention like this:
|
||||
// I... "hello world" key=<
|
||||
// <tab>line 1
|
||||
// <tab>line 2
|
||||
// >
|
||||
//
|
||||
// Tabs indent the lines of the value while the end of string delimiter
|
||||
// is indented with a space. That has two purposes:
|
||||
// - visual difference between the two for a human reader because indention
|
||||
// will be different
|
||||
// - no ambiguity when some value line starts with the end delimiter
|
||||
//
|
||||
// One downside is that the output cannot distinguish between strings that
|
||||
// end with a line break and those that don't because the end delimiter
|
||||
// will always be on the next line.
|
||||
b.WriteString("=<\n")
|
||||
for index != -1 {
|
||||
b.WriteByte('\t')
|
||||
b.Write(data[0 : index+1])
|
||||
data = data[index+1:]
|
||||
index = bytes.IndexByte(data, '\n')
|
||||
}
|
||||
if len(data) == 0 {
|
||||
// String ended with line break, don't add another.
|
||||
b.WriteString(" >")
|
||||
} else {
|
||||
// No line break at end of last line, write rest of string and
|
||||
// add one.
|
||||
b.WriteByte('\t')
|
||||
b.Write(data)
|
||||
b.WriteString("\n >")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// 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 severity provides definitions for klog severity (info, warning, ...)
|
||||
package severity
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// severity identifies the sort of log: info, warning etc. The binding to flag.Value
|
||||
// is handled in klog.go
|
||||
type Severity int32 // sync/atomic int32
|
||||
|
||||
// These constants identify the log levels in order of increasing severity.
|
||||
// A message written to a high-severity log file is also written to each
|
||||
// lower-severity log file.
|
||||
const (
|
||||
InfoLog Severity = iota
|
||||
WarningLog
|
||||
ErrorLog
|
||||
FatalLog
|
||||
NumSeverity = 4
|
||||
)
|
||||
|
||||
// Char contains one shortcut letter per severity level.
|
||||
const Char = "IWEF"
|
||||
|
||||
// Name contains one name per severity level.
|
||||
var Name = []string{
|
||||
InfoLog: "INFO",
|
||||
WarningLog: "WARNING",
|
||||
ErrorLog: "ERROR",
|
||||
FatalLog: "FATAL",
|
||||
}
|
||||
|
||||
// ByName looks up a severity level by name.
|
||||
func ByName(s string) (Severity, bool) {
|
||||
s = strings.ToUpper(s)
|
||||
for i, name := range Name {
|
||||
if name == s {
|
||||
return Severity(i), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
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
|
||||
//
|
||||
// DEPRECATED: Use KObjSlice instead, it has better performance.
|
||||
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
|
||||
}
|
||||
|
||||
// KObjSlice takes a slice of objects that implement the KMetadata interface
|
||||
// and returns an object that gets logged as a slice of ObjectRef values or a
|
||||
// string containing those values, depending on whether the logger prefers text
|
||||
// output or structured output.
|
||||
//
|
||||
// An error string is logged when KObjSlice is not passed a suitable slice.
|
||||
//
|
||||
// Processing of the argument is delayed until the value actually gets logged,
|
||||
// in contrast to KObjs where that overhead is incurred regardless of whether
|
||||
// the result is needed.
|
||||
func KObjSlice(arg interface{}) interface{} {
|
||||
return kobjSlice{arg: arg}
|
||||
}
|
||||
|
||||
type kobjSlice struct {
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = kobjSlice{}
|
||||
var _ logr.Marshaler = kobjSlice{}
|
||||
|
||||
func (ks kobjSlice) String() string {
|
||||
objectRefs, err := ks.process()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%v", objectRefs)
|
||||
}
|
||||
|
||||
func (ks kobjSlice) MarshalLog() interface{} {
|
||||
objectRefs, err := ks.process()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return objectRefs
|
||||
}
|
||||
|
||||
func (ks kobjSlice) process() ([]interface{}, error) {
|
||||
s := reflect.ValueOf(ks.arg)
|
||||
switch s.Kind() {
|
||||
case reflect.Invalid:
|
||||
// nil parameter, print as nil.
|
||||
return nil, nil
|
||||
case reflect.Slice:
|
||||
// Okay, handle below.
|
||||
default:
|
||||
return nil, fmt.Errorf("<KObjSlice needs a slice, got type %T>", ks.arg)
|
||||
}
|
||||
objectRefs := make([]interface{}, 0, s.Len())
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
item := s.Index(i).Interface()
|
||||
if item == nil {
|
||||
objectRefs = append(objectRefs, nil)
|
||||
} else if v, ok := item.(KMetadata); ok {
|
||||
objectRefs = append(objectRefs, KObj(v))
|
||||
} else {
|
||||
return nil, fmt.Errorf("<KObjSlice needs a slice of values implementing KMetadata, got type %T>", item)
|
||||
}
|
||||
}
|
||||
return objectRefs, nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -22,9 +22,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -57,38 +55,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func getUserName() string {
|
||||
userNameOnce.Do(func() {
|
||||
// On Windows, the Go 'user' package requires netapi32.dll.
|
||||
// This affects Windows Nano Server:
|
||||
// https://github.com/golang/go/issues/21867
|
||||
// Fallback to using environment variables.
|
||||
if runtime.GOOS == "windows" {
|
||||
u := os.Getenv("USERNAME")
|
||||
if len(u) == 0 {
|
||||
return
|
||||
}
|
||||
// Sanitize the USERNAME since it may contain filepath separators.
|
||||
u = strings.Replace(u, `\`, "_", -1)
|
||||
|
||||
// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
|
||||
d := os.Getenv("USERDOMAIN")
|
||||
if len(d) != 0 {
|
||||
userName = d + "_" + u
|
||||
} else {
|
||||
userName = u
|
||||
}
|
||||
} else {
|
||||
current, err := user.Current()
|
||||
if err == nil {
|
||||
userName = current.Username
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return userName
|
||||
}
|
||||
|
||||
// shortHostname returns its argument, truncating at the first period.
|
||||
// For instance, given "www.google.com" it returns "www".
|
||||
func shortHostname(hostname string) string {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package klog
|
||||
|
||||
import (
|
||||
"os/user"
|
||||
)
|
||||
|
||||
func getUserName() string {
|
||||
userNameOnce.Do(func() {
|
||||
current, err := user.Current()
|
||||
if err == nil {
|
||||
userName = current.Username
|
||||
}
|
||||
})
|
||||
|
||||
return userName
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package klog
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getUserName() string {
|
||||
userNameOnce.Do(func() {
|
||||
// On Windows, the Go 'user' package requires netapi32.dll.
|
||||
// This affects Windows Nano Server:
|
||||
// https://github.com/golang/go/issues/21867
|
||||
// Fallback to using environment variables.
|
||||
u := os.Getenv("USERNAME")
|
||||
if len(u) == 0 {
|
||||
return
|
||||
}
|
||||
// Sanitize the USERNAME since it may contain filepath separators.
|
||||
u = strings.Replace(u, `\`, "_", -1)
|
||||
|
||||
// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
|
||||
d := os.Getenv("USERDOMAIN")
|
||||
if len(d) != 0 {
|
||||
userName = d + "_" + u
|
||||
} else {
|
||||
userName = u
|
||||
}
|
||||
})
|
||||
|
||||
return userName
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
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.
|
||||
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{}) {
|
||||
merged := serialize.MergeKVs(l.values, kvList)
|
||||
if l.prefix != "" {
|
||||
msg = l.prefix + ": " + msg
|
||||
}
|
||||
V(Level(level)).InfoSDepth(l.callDepth+1, msg, merged...)
|
||||
}
|
||||
|
||||
func (l klogger) Enabled(level int) bool {
|
||||
return V(Level(level)).Enabled()
|
||||
}
|
||||
|
||||
func (l klogger) Error(err error, msg string, kvList ...interface{}) {
|
||||
merged := serialize.MergeKVs(l.values, kvList)
|
||||
if l.prefix != "" {
|
||||
msg = l.prefix + ": " + msg
|
||||
}
|
||||
ErrorSDepth(l.callDepth+1, err, msg, merged...)
|
||||
}
|
||||
|
||||
// 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{}
|
|
@ -365,8 +365,8 @@ github.com/golang/protobuf/ptypes/any
|
|||
github.com/golang/protobuf/ptypes/duration
|
||||
github.com/golang/protobuf/ptypes/timestamp
|
||||
github.com/golang/protobuf/ptypes/wrappers
|
||||
# github.com/google/certificate-transparency-go v1.0.21
|
||||
## explicit
|
||||
# github.com/google/certificate-transparency-go v1.1.4
|
||||
## explicit; go 1.17
|
||||
# github.com/google/go-cmp v0.5.9
|
||||
## explicit; go 1.13
|
||||
github.com/google/go-cmp/cmp
|
||||
|
@ -600,6 +600,8 @@ github.com/prometheus/procfs/internal/fs
|
|||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/rogpeppe/go-internal v1.8.1
|
||||
## explicit; go 1.16
|
||||
# github.com/sergi/go-diff v1.2.0
|
||||
## explicit; go 1.12
|
||||
# github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002
|
||||
## explicit
|
||||
github.com/serialx/hashring
|
||||
|
@ -1124,9 +1126,14 @@ k8s.io/client-go/util/homedir
|
|||
k8s.io/client-go/util/jsonpath
|
||||
k8s.io/client-go/util/keyutil
|
||||
k8s.io/client-go/util/workqueue
|
||||
# k8s.io/klog/v2 v2.30.0
|
||||
# k8s.io/klog/v2 v2.80.1
|
||||
## explicit; go 1.13
|
||||
k8s.io/klog/v2
|
||||
k8s.io/klog/v2/internal/buffer
|
||||
k8s.io/klog/v2/internal/clock
|
||||
k8s.io/klog/v2/internal/dbg
|
||||
k8s.io/klog/v2/internal/serialize
|
||||
k8s.io/klog/v2/internal/severity
|
||||
# k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b
|
||||
## explicit; go 1.12
|
||||
k8s.io/utils/integer
|
||||
|
|
Loading…
Reference in New Issue