1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package log contains utilities for fetching a new logger 18 // when one is not already available. 19 // 20 // # The Log Handle 21 // 22 // This package contains a root logr.Logger Log. It may be used to 23 // get a handle to whatever the root logging implementation is. By 24 // default, no implementation exists, and the handle returns "promises" 25 // to loggers. When the implementation is set using SetLogger, these 26 // "promises" will be converted over to real loggers. 27 // 28 // # Logr 29 // 30 // All logging in controller-runtime is structured, using a set of interfaces 31 // defined by a package called logr 32 // (https://pkg.go.dev/github.com/go-logr/logr). The sub-package zap provides 33 // helpers for setting up logr backed by Zap (go.uber.org/zap). 34 package log 35 36 import ( 37 "bytes" 38 "context" 39 "fmt" 40 "os" 41 "runtime/debug" 42 "sync/atomic" 43 "time" 44 45 "github.com/go-logr/logr" 46 ) 47 48 // SetLogger sets a concrete logging implementation for all deferred Loggers. 49 func SetLogger(l logr.Logger) { 50 logFullfilled.Store(true) 51 rootLog.Fulfill(l.GetSink()) 52 } 53 54 func eventuallyFulfillRoot() { 55 if logFullfilled.Load() { 56 return 57 } 58 if time.Since(rootLogCreated).Seconds() >= 30 { 59 if logFullfilled.CompareAndSwap(false, true) { 60 stack := debug.Stack() 61 stackLines := bytes.Count(stack, []byte{'\n'}) 62 sep := []byte{'\n', '\t', '>', ' ', ' '} 63 64 fmt.Fprintf(os.Stderr, 65 "[controller-runtime] log.SetLogger(...) was never called; logs will not be displayed.\nDetected at:%s%s", sep, 66 // prefix every line, so it's clear this is a stack trace related to the above message 67 bytes.Replace(stack, []byte{'\n'}, sep, stackLines-1), 68 ) 69 SetLogger(logr.New(NullLogSink{})) 70 } 71 } 72 } 73 74 var ( 75 logFullfilled atomic.Bool 76 ) 77 78 // Log is the base logger used by kubebuilder. It delegates 79 // to another logr.Logger. You *must* call SetLogger to 80 // get any actual logging. If SetLogger is not called within 81 // the first 30 seconds of a binaries lifetime, it will get 82 // set to a NullLogSink. 83 var ( 84 rootLog, rootLogCreated = func() (*delegatingLogSink, time.Time) { 85 return newDelegatingLogSink(NullLogSink{}), time.Now() 86 }() 87 Log = logr.New(rootLog) 88 ) 89 90 // FromContext returns a logger with predefined values from a context.Context. 91 func FromContext(ctx context.Context, keysAndValues ...interface{}) logr.Logger { 92 log := Log 93 if ctx != nil { 94 if logger, err := logr.FromContext(ctx); err == nil { 95 log = logger 96 } 97 } 98 return log.WithValues(keysAndValues...) 99 } 100 101 // IntoContext takes a context and sets the logger as one of its values. 102 // Use FromContext function to retrieve the logger. 103 func IntoContext(ctx context.Context, log logr.Logger) context.Context { 104 return logr.NewContext(ctx, log) 105 } 106