Skip to content

Commit ef57964

Browse files
authored
Merge pull request kubernetes-sigs#1095 from vincepri/logger-manager-controller
✨ Add options to configure a logger for manager and controllers
2 parents de782a3 + 829c816 commit ef57964

File tree

5 files changed

+65
-20
lines changed

5 files changed

+65
-20
lines changed

pkg/builder/controller.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import (
2020
"fmt"
2121
"strings"
2222

23+
"github.com/go-logr/logr"
2324
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/runtime/schema"
2426
"k8s.io/client-go/rest"
2527
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2628
"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -45,6 +47,7 @@ type Builder struct {
4547
config *rest.Config
4648
ctrl controller.Controller
4749
ctrlOptions controller.Options
50+
log logr.Logger
4851
name string
4952
}
5053

@@ -155,6 +158,12 @@ func (blder *Builder) Named(name string) *Builder {
155158
return blder
156159
}
157160

161+
// WithLogger overrides the controller options's logger used.
162+
func (blder *Builder) WithLogger(log logr.Logger) *Builder {
163+
blder.log = log
164+
return blder
165+
}
166+
158167
// Complete builds the Application ControllerManagedBy.
159168
func (blder *Builder) Complete(r reconcile.Reconciler) error {
160169
_, err := blder.Build(r)
@@ -228,26 +237,33 @@ func (blder *Builder) loadRestConfig() {
228237
}
229238
}
230239

231-
func (blder *Builder) getControllerName() (string, error) {
240+
func (blder *Builder) getControllerName(gvk schema.GroupVersionKind) string {
232241
if blder.name != "" {
233-
return blder.name, nil
242+
return blder.name
234243
}
235-
gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
236-
if err != nil {
237-
return "", err
238-
}
239-
return strings.ToLower(gvk.Kind), nil
244+
return strings.ToLower(gvk.Kind)
240245
}
241246

242247
func (blder *Builder) doController(r reconcile.Reconciler) error {
243-
name, err := blder.getControllerName()
244-
if err != nil {
245-
return err
246-
}
247248
ctrlOptions := blder.ctrlOptions
248249
if ctrlOptions.Reconciler == nil {
249250
ctrlOptions.Reconciler = r
250251
}
251-
blder.ctrl, err = newController(name, blder.mgr, ctrlOptions)
252+
253+
// Retrieve the GVK from the object we're reconciling
254+
// to prepopulate logger information, and to optionally generate a default name.
255+
gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
256+
if err != nil {
257+
return err
258+
}
259+
260+
// Setup the logger.
261+
if ctrlOptions.Log == nil {
262+
ctrlOptions.Log = blder.mgr.GetLogger()
263+
}
264+
ctrlOptions.Log = ctrlOptions.Log.WithValues("reconcilerGroup", gvk.Group, "reconcilerKind", gvk.Kind)
265+
266+
// Build the controller and return.
267+
blder.ctrl, err = newController(blder.getControllerName(gvk), blder.mgr, ctrlOptions)
252268
return err
253269
}

pkg/controller/controller.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ package controller
1919
import (
2020
"fmt"
2121

22+
"github.com/go-logr/logr"
2223
"k8s.io/client-go/util/workqueue"
2324
"sigs.k8s.io/controller-runtime/pkg/handler"
2425
"sigs.k8s.io/controller-runtime/pkg/internal/controller"
25-
"sigs.k8s.io/controller-runtime/pkg/internal/log"
2626
"sigs.k8s.io/controller-runtime/pkg/manager"
2727
"sigs.k8s.io/controller-runtime/pkg/predicate"
2828
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
@@ -42,6 +42,9 @@ type Options struct {
4242
// Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
4343
// The overall is a token bucket and the per-item is exponential.
4444
RateLimiter ratelimiter.RateLimiter
45+
46+
// Log is the logger used for this controller.
47+
Log logr.Logger
4548
}
4649

4750
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
@@ -96,22 +99,24 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
9699
options.RateLimiter = workqueue.DefaultControllerRateLimiter()
97100
}
98101

102+
if options.Log == nil {
103+
options.Log = mgr.GetLogger()
104+
}
105+
99106
// Inject dependencies into Reconciler
100107
if err := mgr.SetFields(options.Reconciler); err != nil {
101108
return nil, err
102109
}
103110

104111
// Create controller with dependencies set
105-
c := &controller.Controller{
112+
return &controller.Controller{
106113
Do: options.Reconciler,
107114
MakeQueue: func() workqueue.RateLimitingInterface {
108115
return workqueue.NewNamedRateLimitingQueue(options.RateLimiter, name)
109116
},
110117
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
111118
SetFields: mgr.SetFields,
112119
Name: name,
113-
Log: log.RuntimeLog.WithName("controller").WithValues("controller", name),
114-
}
115-
116-
return c, nil
120+
Log: options.Log.WithName("controller").WithValues("controller", name),
121+
}, nil
117122
}

pkg/internal/controller/controller.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,13 @@ func (c *Controller) reconcileHandler(obj interface{}) bool {
228228
return true
229229
}
230230

231+
log := c.Log.WithValues("name", req.Name, "namespace", req.Namespace)
232+
231233
// RunInformersAndControllers the syncHandler, passing it the namespace/Name string of the
232234
// resource to be synced.
233235
if result, err := c.Do.Reconcile(req); err != nil {
234236
c.Queue.AddRateLimited(req)
235-
c.Log.Error(err, "Reconciler error", "name", req.Name, "namespace", req.Namespace)
237+
log.Error(err, "Reconciler error")
236238
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
237239
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, "error").Inc()
238240
return false
@@ -256,7 +258,7 @@ func (c *Controller) reconcileHandler(obj interface{}) bool {
256258
c.Queue.Forget(obj)
257259

258260
// TODO(directxman12): What does 1 mean? Do we want level constants? Do we want levels at all?
259-
c.Log.V(1).Info("Successfully Reconciled", "name", req.Name, "namespace", req.Namespace)
261+
log.V(1).Info("Successfully Reconciled")
260262

261263
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, "success").Inc()
262264
// Return true, don't take a break

pkg/manager/internal.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"sync"
2626
"time"
2727

28+
"github.com/go-logr/logr"
2829
"github.com/prometheus/client_golang/prometheus/promhttp"
2930
"k8s.io/apimachinery/pkg/api/meta"
3031
"k8s.io/apimachinery/pkg/runtime"
@@ -133,6 +134,10 @@ type controllerManager struct {
133134
// It and `internalStop` should point to the same channel.
134135
internalStopper chan<- struct{}
135136

137+
// Logger is the logger that should be used by this manager.
138+
// If none is set, it defaults to log.Log global logger.
139+
logger logr.Logger
140+
136141
// leaderElectionCancel is used to cancel the leader election. It is distinct from internalStopper,
137142
// because for safety reasons we need to os.Exit() when we lose the leader election, meaning that
138143
// it must be deferred until after gracefulShutdown is done.
@@ -357,6 +362,10 @@ func (cm *controllerManager) GetWebhookServer() *webhook.Server {
357362
return cm.webhookServer
358363
}
359364

365+
func (cm *controllerManager) GetLogger() logr.Logger {
366+
return cm.logger
367+
}
368+
360369
func (cm *controllerManager) serveMetrics(stop <-chan struct{}) {
361370
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
362371
ErrorHandling: promhttp.HTTPErrorOnError,

pkg/manager/manager.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"sigs.k8s.io/controller-runtime/pkg/healthz"
3737
internalrecorder "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
3838
"sigs.k8s.io/controller-runtime/pkg/leaderelection"
39+
logf "sigs.k8s.io/controller-runtime/pkg/log"
3940
"sigs.k8s.io/controller-runtime/pkg/metrics"
4041
"sigs.k8s.io/controller-runtime/pkg/recorder"
4142
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -111,6 +112,9 @@ type Manager interface {
111112

112113
// GetWebhookServer returns a webhook.Server
113114
GetWebhookServer() *webhook.Server
115+
116+
// GetLogger returns this manager's logger.
117+
GetLogger() logr.Logger
114118
}
115119

116120
// Options are the arguments for creating a new Manager
@@ -131,6 +135,10 @@ type Options struct {
131135
// so that all controllers will not send list requests simultaneously.
132136
SyncPeriod *time.Duration
133137

138+
// Logger is the logger that should be used by this manager.
139+
// If none is set, it defaults to log.Log global logger.
140+
Logger logr.Logger
141+
134142
// LeaderElection determines whether or not to use leader election when
135143
// starting the manager.
136144
LeaderElection bool
@@ -345,6 +353,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
345353
mapper: mapper,
346354
metricsListener: metricsListener,
347355
metricsExtraHandlers: metricsExtraHandlers,
356+
logger: options.Logger,
348357
internalStop: stop,
349358
internalStopper: stop,
350359
elected: make(chan struct{}),
@@ -462,5 +471,9 @@ func setOptionsDefaults(options Options) Options {
462471
options.GracefulShutdownTimeout = &gracefulShutdownTimeout
463472
}
464473

474+
if options.Logger == nil {
475+
options.Logger = logf.Log
476+
}
477+
465478
return options
466479
}

0 commit comments

Comments
 (0)