diff --git a/Gopkg.lock b/Gopkg.lock index 921a02e5cffa..4383fc59db4f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1104,9 +1104,12 @@ revision = "f8a0810f38afb8478882b3835a615aebfda39afa" [[projects]] - digest = "1:fa0be820e3b9d58b99264b0ca771ceeb36c7293f8409f70455d4a1e5253a87a0" + digest = "1:b28940274ee0e7b0b9e3fdeb55d63f812023100293b7e73d26c0261077a22e2e" name = "k8s.io/klog" - packages = ["."] + packages = [ + ".", + "klogr", + ] pruneopts = "UT" revision = "78315d914a8af2453db4864e69230b647b1ff711" version = "v0.3.2" @@ -1260,6 +1263,7 @@ "k8s.io/code-generator/cmd/lister-gen", "k8s.io/component-base/cli/flag", "k8s.io/klog", + "k8s.io/klog/klogr", "sigs.k8s.io/controller-runtime/pkg/client", "sigs.k8s.io/controller-runtime/pkg/client/config", "sigs.k8s.io/controller-runtime/pkg/client/fake", @@ -1268,6 +1272,7 @@ "sigs.k8s.io/controller-runtime/pkg/handler", "sigs.k8s.io/controller-runtime/pkg/manager", "sigs.k8s.io/controller-runtime/pkg/reconcile", + "sigs.k8s.io/controller-runtime/pkg/runtime/log", "sigs.k8s.io/controller-runtime/pkg/runtime/scheme", "sigs.k8s.io/controller-runtime/pkg/runtime/signals", "sigs.k8s.io/controller-runtime/pkg/source", diff --git a/cmd/manager/BUILD.bazel b/cmd/manager/BUILD.bazel index a0825811a163..ae0ad11ab6c4 100644 --- a/cmd/manager/BUILD.bazel +++ b/cmd/manager/BUILD.bazel @@ -10,8 +10,10 @@ go_library( "//pkg/controller:go_default_library", "//vendor/k8s.io/client-go/plugin/pkg/client/auth/gcp:go_default_library", "//vendor/k8s.io/klog:go_default_library", + "//vendor/k8s.io/klog/klogr:go_default_library", "//vendor/sigs.k8s.io/controller-runtime/pkg/client/config:go_default_library", "//vendor/sigs.k8s.io/controller-runtime/pkg/manager:go_default_library", + "//vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log:go_default_library", "//vendor/sigs.k8s.io/controller-runtime/pkg/runtime/signals:go_default_library", ], ) diff --git a/cmd/manager/main.go b/cmd/manager/main.go index f10eb99060b0..6b0e713e9107 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -18,15 +18,16 @@ package main import ( "flag" - "log" "time" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/klog" + "k8s.io/klog/klogr" "sigs.k8s.io/cluster-api/pkg/apis" "sigs.k8s.io/cluster-api/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/runtime/log" "sigs.k8s.io/controller-runtime/pkg/runtime/signals" ) @@ -38,39 +39,43 @@ func main() { flag.Parse() if *watchNamespace != "" { - log.Printf("Watching cluster-api objects only in namespace %q for reconciliation.", *watchNamespace) + klog.Infof("Watching cluster-api objects only in namespace %q for reconciliation", *watchNamespace) } - log.Printf("Registering Components.") - // Get a config to talk to the apiserver + + // Setup controller-runtime logger. + log.SetLogger(klogr.New()) + + // Get a config to talk to the api-server. cfg, err := config.GetConfig() if err != nil { - log.Fatal(err) + klog.Fatal(err) } - // Create a new Cmd to provide shared dependencies and start components + // Create a new Cmd to provide shared dependencies and start components. syncPeriod := 10 * time.Minute mgr, err := manager.New(cfg, manager.Options{ SyncPeriod: &syncPeriod, Namespace: *watchNamespace, }) + if err != nil { - log.Fatal(err) + klog.Fatalf("Failed to create new Manager: %v", err) } - log.Printf("Registering Components.") + klog.Info("Registering Components") - // Setup Scheme for all resources + // Setup Scheme for all resources. if err := apis.AddToScheme(mgr.GetScheme()); err != nil { - log.Fatal(err) + klog.Fatal(err) } - // Setup all Controllers + // Setup all Controllers. if err := controller.AddToManager(mgr); err != nil { - log.Fatal(err) + klog.Fatal(err) } - log.Printf("Starting the Cmd.") + klog.Info("Starting the Cmd") // Start the Cmd - log.Fatal(mgr.Start(signals.SetupSignalHandler())) + klog.Fatal(mgr.Start(signals.SetupSignalHandler())) } diff --git a/vendor/k8s.io/klog/klogr/BUILD.bazel b/vendor/k8s.io/klog/klogr/BUILD.bazel new file mode 100644 index 000000000000..3d37067ffef3 --- /dev/null +++ b/vendor/k8s.io/klog/klogr/BUILD.bazel @@ -0,0 +1,13 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["klogr.go"], + importmap = "sigs.k8s.io/cluster-api/vendor/k8s.io/klog/klogr", + importpath = "k8s.io/klog/klogr", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/go-logr/logr:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) diff --git a/vendor/k8s.io/klog/klogr/README.md b/vendor/k8s.io/klog/klogr/README.md new file mode 100644 index 000000000000..cfa5de617d38 --- /dev/null +++ b/vendor/k8s.io/klog/klogr/README.md @@ -0,0 +1,8 @@ +# Minimal Go logging using klog + +This package implements the [logr interface](https://github.com/go-logr/logr) +in terms of Kubernetes' [klog](https://github.com/kubernetes/klog). This +provides a relatively minimalist API to logging in Go, backed by a well-proven +implementation. + +This is a BETA grade implementation. diff --git a/vendor/k8s.io/klog/klogr/klogr.go b/vendor/k8s.io/klog/klogr/klogr.go new file mode 100644 index 000000000000..f63557daacd5 --- /dev/null +++ b/vendor/k8s.io/klog/klogr/klogr.go @@ -0,0 +1,194 @@ +// Package klogr implements github.com/go-logr/logr.Logger in terms of +// k8s.io/klog. +package klogr + +import ( + "bytes" + "encoding/json" + "fmt" + "runtime" + "sort" + + "github.com/go-logr/logr" + "k8s.io/klog" +) + +// New returns a logr.Logger which is implemented by klog. +func New() logr.Logger { + return klogger{ + level: 0, + prefix: "", + values: nil, + } +} + +type klogger struct { + level int + prefix string + values []interface{} +} + +func (l klogger) clone() klogger { + return klogger{ + level: l.level, + prefix: l.prefix, + values: copySlice(l.values), + } +} + +func copySlice(in []interface{}) []interface{} { + out := make([]interface{}, len(in)) + copy(out, in) + return out +} + +// Magic string for intermediate frames that we should ignore. +const autogeneratedFrameName = "" + +// Discover how many frames we need to climb to find the caller. This approach +// was suggested by Ian Lance Taylor of the Go team, so it *should* be safe +// enough (famous last words). +func framesToCaller() int { + // 1 is the immediate caller. 3 should be too many. + for i := 1; i < 3; i++ { + _, file, _, _ := runtime.Caller(i + 1) // +1 for this function's frame + if file != autogeneratedFrameName { + return i + } + } + return 1 // something went wrong, this is safe +} + +// trimDuplicates will deduplicates elements provided in multiple KV tuple +// slices, whilst maintaining the distinction between where the items are +// contained. +func trimDuplicates(kvLists ...[]interface{}) [][]interface{} { + // maintain a map of all seen keys + seenKeys := map[interface{}]struct{}{} + // build the same number of output slices as inputs + outs := make([][]interface{}, len(kvLists)) + // iterate over the input slices backwards, as 'later' kv specifications + // of the same key will take precedence over earlier ones + for i := len(kvLists) - 1; i >= 0; i-- { + // initialise this output slice + outs[i] = []interface{}{} + // obtain a reference to the kvList we are processing + kvList := kvLists[i] + + // start iterating at len(kvList) - 2 (i.e. the 2nd last item) for + // slices that have an even number of elements. + // We add (len(kvList) % 2) here to handle the case where there is an + // odd number of elements in a kvList. + // If there is an odd number, then the last element in the slice will + // have the value 'null'. + for i2 := len(kvList) - 2 + (len(kvList) % 2); i2 >= 0; i2 -= 2 { + k := kvList[i2] + // if we have already seen this key, do not include it again + if _, ok := seenKeys[k]; ok { + continue + } + // make a note that we've observed a new key + seenKeys[k] = struct{}{} + // attempt to obtain the value of the key + var v interface{} + // i2+1 should only ever be out of bounds if we handling the first + // iteration over a slice with an odd number of elements + if i2+1 < len(kvList) { + v = kvList[i2+1] + } + // add this KV tuple to the *start* of the output list to maintain + // the original order as we are iterating over the slice backwards + outs[i] = append([]interface{}{k, v}, outs[i]...) + } + } + return outs +} + +func flatten(kvList ...interface{}) string { + keys := make([]string, 0, len(kvList)) + vals := make(map[string]interface{}, len(kvList)) + for i := 0; i < len(kvList); i += 2 { + k, ok := kvList[i].(string) + if !ok { + panic(fmt.Sprintf("key is not a string: %s", pretty(kvList[i]))) + } + var v interface{} + if i+1 < len(kvList) { + v = kvList[i+1] + } + keys = append(keys, k) + vals[k] = v + } + sort.Strings(keys) + buf := bytes.Buffer{} + for i, k := range keys { + v := vals[k] + if i > 0 { + buf.WriteRune(' ') + } + buf.WriteString(pretty(k)) + buf.WriteString("=") + buf.WriteString(pretty(v)) + } + return buf.String() +} + +func pretty(value interface{}) string { + jb, _ := json.Marshal(value) + return string(jb) +} + +func (l klogger) Info(msg string, kvList ...interface{}) { + if l.Enabled() { + lvlStr := flatten("level", l.level) + msgStr := flatten("msg", msg) + trimmed := trimDuplicates(l.values, kvList) + fixedStr := flatten(trimmed[0]...) + userStr := flatten(trimmed[1]...) + klog.InfoDepth(framesToCaller(), l.prefix, " ", lvlStr, " ", msgStr, " ", fixedStr, " ", userStr) + } +} + +func (l klogger) Enabled() bool { + return bool(klog.V(klog.Level(l.level))) +} + +func (l klogger) Error(err error, msg string, kvList ...interface{}) { + msgStr := flatten("msg", msg) + var loggableErr interface{} + if err != nil { + loggableErr = err.Error() + } + errStr := flatten("error", loggableErr) + trimmed := trimDuplicates(l.values, kvList) + fixedStr := flatten(trimmed[0]...) + userStr := flatten(trimmed[1]...) + klog.ErrorDepth(framesToCaller(), l.prefix, " ", msgStr, " ", errStr, " ", fixedStr, " ", userStr) +} + +func (l klogger) V(level int) logr.InfoLogger { + new := l.clone() + new.level = level + return new +} + +// 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.Logger { + new := l.clone() + if len(l.prefix) > 0 { + new.prefix = l.prefix + "/" + } + new.prefix += name + return new +} + +func (l klogger) WithValues(kvList ...interface{}) logr.Logger { + new := l.clone() + new.values = append(new.values, kvList...) + return new +} + +var _ logr.Logger = klogger{} +var _ logr.InfoLogger = klogger{}