diff --git a/README.md b/README.md index f9c11a7..bd2d5c3 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,8 @@ Parent reconcilers tend to be quite simple, as they delegate their work to sub r ```go func FunctionReconciler(c reconcilers.Config) *reconcilers.ParentReconciler { - c.Log = c.Log.WithName("Function") - return &reconcilers.ParentReconciler{ + Name: "Function", Type: &buildv1alpha1.Function{}, Reconciler: reconcilers.Sequence{ FunctionTargetImageReconciler(c), @@ -81,10 +80,11 @@ While sync reconcilers have the ability to do anything a reconciler can do, it's ```go func FunctionTargetImageReconciler(c reconcilers.Config) reconcilers.SubReconciler { - c.Log = c.Log.WithName("TargetImage") - return &reconcilers.SyncReconciler{ + Name: "TargetImage", Sync: func(ctx context.Context, parent *buildv1alpha1.Function) error { + log := logr.FromContextOrDiscard(ctx) + targetImage, err := resolveTargetImage(ctx, c.Client, parent) if err != nil { return err @@ -125,9 +125,8 @@ Now it's time to create the child Image resource that will do the work of buildi ```go func FunctionChildImageReconciler(c reconcilers.Config) reconcilers.SubReconciler { - c.Log = c.Log.WithName("ChildImage") - return &reconcilers.ChildReconciler{ + Name: "ChildImage", ChildType: &kpackbuildv1alpha1.Image{}, ChildListType: &kpackbuildv1alpha1.ImageList{}, @@ -214,9 +213,8 @@ JSON encoding is used as the intermediate representation. Operations on a cast p ```go func FunctionReconciler(c reconcilers.Config) *reconcilers.ParentReconciler { - c.Log = c.Log.WithName("Function") - return &reconcilers.ParentReconciler{ + Name: "Function", Type: &buildv1alpha1.Function{}, Reconciler: reconcilers.Sequence{ &reconcilers.CastParent{ @@ -247,9 +245,8 @@ A Sequence is commonly used in a ParentReconciler, but may be used anywhere a Su ```go func FunctionReconciler(c reconcilers.Config) *reconcilers.ParentReconciler { - c.Log = c.Log.WithName("Function") - return &reconcilers.ParentReconciler{ + Name: "Function", Type: &buildv1alpha1.Function{}, Reconciler: reconcilers.Sequence{ FunctionTargetImageReconciler(c), @@ -391,9 +388,8 @@ The stash allows passing arbitrary state between sub reconcilers within the scop const exampleStashKey reconcilers.StashKey = "example" func StashExampleSubReconciler(c reconcilers.Config) reconcilers.SubReconciler { - c.Log = c.Log.WithName("StashExample") - return &reconcilers.SyncReconciler{ + Name: "StashExample", Sync: func(ctx context.Context, resource *examplev1.MyExample) error { value := Example{} // something we want to expose to a sub reconciler later in this chain reconcilers.StashValue(ctx, exampleStashKey, *value) @@ -406,9 +402,8 @@ func StashExampleSubReconciler(c reconcilers.Config) reconcilers.SubReconciler { func StashExampleSubReconciler(c reconcilers.Config) reconcilers.SubReconciler { - c.Log = c.Log.WithName("StashExample") - return &reconcilers.SyncReconciler{ + Name: "StashExample", Sync: func(ctx context.Context, resource *examplev1.MyExample) error { value, ok := reconcilers.RetrieveValue(ctx, exampleStashKey).(Example) if !ok { @@ -432,10 +427,11 @@ The stream gateways in projectriff fetch the image references they use to run fr ```go func InMemoryGatewaySyncConfigReconciler(c reconcilers.Config, namespace string) reconcilers.SubReconciler { - c.Log = c.Log.WithName("SyncConfig") - return &reconcilers.SyncReconciler{ + Name: "SyncConfig", Sync: func(ctx context.Context, parent *streamingv1alpha1.InMemoryGateway) error { + log := logr.FromContextOrDiscard(ctx) + var config corev1.ConfigMap key := types.NamespacedName{Namespace: namespace, Name: inmemoryGatewayImages} // track config for new images @@ -456,13 +452,13 @@ func InMemoryGatewaySyncConfigReconciler(c reconcilers.Config, namespace string) }, Config: c, - Setup: func(mgr reconcilers.Manager, bldr *reconcilers.Builder) error { + Setup: func(ctx context.Context, mgr reconcilers.Manager, bldr *reconcilers.Builder) error { // enqueue the tracking resource for reconciliation from changes to // tracked ConfigMaps. Internally `EnqueueTracked` sets up an // Informer to watch to changes of the target resource. When the // informer emits an event, the tracking resources are looked up // from the tracker and enqueded for reconciliation. - bldr.Watches(&source.Kind{Type: &corev1.ConfigMap{}}, reconcilers.EnqueueTracked(&corev1.ConfigMap{}, c.Tracker, c.Scheme)) + bldr.Watches(&source.Kind{Type: &corev1.ConfigMap{}}, reconcilers.EnqueueTracked(ctx, &corev1.ConfigMap{}, c.Tracker, c.Scheme)) return nil }, } diff --git a/reconcilers/enqueuer.go b/reconcilers/enqueuer.go index 72bb45c..5a7b171 100644 --- a/reconcilers/enqueuer.go +++ b/reconcilers/enqueuer.go @@ -6,6 +6,8 @@ SPDX-License-Identifier: Apache-2.0 package reconcilers import ( + "context" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -15,7 +17,7 @@ import ( "github.com/vmware-labs/reconciler-runtime/tracker" ) -func EnqueueTracked(by client.Object, t tracker.Tracker, s *runtime.Scheme) handler.EventHandler { +func EnqueueTracked(ctx context.Context, by client.Object, t tracker.Tracker, s *runtime.Scheme) handler.EventHandler { return handler.EnqueueRequestsFromMapFunc( func(a client.Object) []reconcile.Request { var requests []reconcile.Request @@ -29,7 +31,7 @@ func EnqueueTracked(by client.Object, t tracker.Tracker, s *runtime.Scheme) hand gvks[0], types.NamespacedName{Namespace: a.GetNamespace(), Name: a.GetName()}, ) - for _, item := range t.Lookup(key) { + for _, item := range t.Lookup(ctx, key) { requests = append(requests, reconcile.Request{NamespacedName: item}) } diff --git a/reconcilers/logger.go b/reconcilers/logger.go new file mode 100644 index 0000000..5e6e35b --- /dev/null +++ b/reconcilers/logger.go @@ -0,0 +1,68 @@ +/* +Copyright 2022 VMware, Inc. +SPDX-License-Identifier: Apache-2.0 +*/ + +package reconcilers + +import ( + "fmt" + "sync" + + "github.com/go-logr/logr" +) + +var ( + _ logr.LogSink = (*warnOnceLogSink)(nil) +) + +// Deprecated +func newWarnOnceLogger(log logr.Logger) logr.Logger { + return logr.New(&warnOnceLogSink{ + sink: log.GetSink(), + }) +} + +// Deprecated +type warnOnceLogSink struct { + sink logr.LogSink + once sync.Once +} + +func (s *warnOnceLogSink) Init(info logr.RuntimeInfo) { + s.sink.Init(info) +} + +func (s *warnOnceLogSink) Enabled(level int) bool { + return s.sink.Enabled(level) +} + +func (s *warnOnceLogSink) Info(level int, msg string, keysAndValues ...interface{}) { + s.warn() + s.sink.Info(level, msg, keysAndValues...) +} + +func (s *warnOnceLogSink) Error(err error, msg string, keysAndValues ...interface{}) { + s.warn() + s.sink.Error(err, msg, keysAndValues...) +} + +func (s *warnOnceLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { + return &warnOnceLogSink{ + sink: s.sink.WithValues(keysAndValues...), + once: s.once, + } +} + +func (s *warnOnceLogSink) WithName(name string) logr.LogSink { + return &warnOnceLogSink{ + sink: s.sink.WithName(name), + once: s.once, + } +} + +func (s *warnOnceLogSink) warn() { + s.once.Do(func() { + s.sink.Error(fmt.Errorf("Config.Log is deprecated"), "use a logger from the context: `log := logr.FromContext(ctx)`") + }) +} diff --git a/reconcilers/reconcilers.go b/reconcilers/reconcilers.go index 3e75975..2b126a0 100644 --- a/reconcilers/reconcilers.go +++ b/reconcilers/reconcilers.go @@ -19,6 +19,8 @@ import ( "k8s.io/apimachinery/pkg/api/equality" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/cache" "k8s.io/client-go/tools/record" @@ -41,21 +43,23 @@ type Config struct { client.Client APIReader client.Reader Recorder record.EventRecorder - Log logr.Logger Tracker tracker.Tracker + + // Deprecated: use a logger from the context instead `log := logr.FromContext(ctx)` + Log logr.Logger } // NewConfig creates a Config for a specific API type. Typically passed into a // reconciler. func NewConfig(mgr ctrl.Manager, apiType client.Object, syncPeriod time.Duration) Config { name := typeName(apiType) - log := ctrl.Log.WithName("controllers").WithName(name) + log := newWarnOnceLogger(ctrl.Log.WithName("controllers").WithName(name)) return Config{ Client: mgr.GetClient(), APIReader: mgr.GetAPIReader(), Recorder: mgr.GetEventRecorderFor(name), Log: log, - Tracker: tracker.New(syncPeriod, log.WithName("tracker")), + Tracker: tracker.New(syncPeriod), } } @@ -65,6 +69,11 @@ func NewConfig(mgr ctrl.Manager, apiType client.Object, syncPeriod time.Duration // resource's status is compared with the original status, updating the API // server if needed. type ParentReconciler struct { + // Name used to identify this reconciler. Defaults to `{Type}ParentReconciler`. Ideally unique, but not required to be so. + // + // +optional + Name string + // Type of resource to reconcile Type client.Object @@ -77,6 +86,15 @@ type ParentReconciler struct { } func (r *ParentReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { + if r.Name == "" { + r.Name = fmt.Sprintf("%sParentReconciler", typeName(r.Type)) + } + + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("parentType", gvk(r.Type, r.Config.Scheme())) + ctx = logr.NewContext(ctx, log) + ctx = StashParentType(ctx, r.Type) ctx = StashCastParentType(ctx, r.Type) bldr := ctrl.NewControllerManagedBy(mgr).For(r.Type) @@ -88,7 +106,10 @@ func (r *ParentReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manage func (r *ParentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { ctx = WithStash(ctx) - log := r.Log.WithValues("request", req.NamespacedName) + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("parentType", gvk(r.Type, r.Config.Scheme())) + ctx = logr.NewContext(ctx, log) ctx = StashParentType(ctx, r.Type) ctx = StashCastParentType(ctx, r.Type) @@ -128,7 +149,7 @@ func (r *ParentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr // update status log.Info("updating status", "diff", cmp.Diff(r.status(originalParent), r.status(parent))) if updateErr := r.Status().Update(ctx, parent); updateErr != nil { - log.Error(updateErr, "unable to update status", typeName(r.Type), parent) + log.Error(updateErr, "unable to update status") r.Recorder.Eventf(parent, corev1.EventTypeWarning, "StatusUpdateFailed", "Failed to update status: %v", updateErr) return ctrl.Result{}, updateErr @@ -250,6 +271,11 @@ var ( // SyncReconciler is a sub reconciler for custom reconciliation logic. No // behavior is defined directly. type SyncReconciler struct { + // Name used to identify this reconciler. Ideally unique, but not required to be so. + // + // +optional + Name string + // Setup performs initialization on the manager and builder this reconciler // will run with. It's common to setup field indexes and watch resources. // @@ -267,6 +293,12 @@ type SyncReconciler struct { } func (r *SyncReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, bldr *builder.Builder) error { + log := logr.FromContextOrDiscard(ctx) + if r.Name != "" { + log = log.WithName(r.Name) + } + ctx = logr.NewContext(ctx, log) + if r.Setup == nil { return nil } @@ -310,9 +342,15 @@ func (r *SyncReconciler) validate(ctx context.Context) error { } func (r *SyncReconciler) Reconcile(ctx context.Context, parent client.Object) (ctrl.Result, error) { + log := logr.FromContextOrDiscard(ctx) + if r.Name != "" { + log = log.WithName(r.Name) + } + ctx = logr.NewContext(ctx, log) + result, err := r.sync(ctx, parent) if err != nil { - r.Log.Error(err, "unable to sync", typeName(parent), parent) + log.Error(err, "unable to sync") return ctrl.Result{}, err } @@ -363,6 +401,12 @@ var ( // // During setup, the child resource type is registered to watch for changes. type ChildReconciler struct { + // Name used to identify this reconciler. Defaults to `{ChildType}ChildReconciler`. Ideally + // unique, but not required to be so. + // + // +optional + Name string + // ChildType is the resource being created/updated/deleted by the // reconciler. For example, a parent Deployment would have a ReplicaSet as a // child. @@ -452,6 +496,15 @@ type ChildReconciler struct { } func (r *ChildReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, bldr *builder.Builder) error { + if r.Name == "" { + r.Name = fmt.Sprintf("%sChildReconciler", typeName(r.ChildType)) + } + + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("childType", gvk(r.ChildType, r.Config.Scheme())) + ctx = logr.NewContext(ctx, log) + if err := r.validate(ctx); err != nil { return err } @@ -572,13 +625,17 @@ func (r *ChildReconciler) validate(ctx context.Context) error { } func (r *ChildReconciler) Reconcile(ctx context.Context, parent client.Object) (ctrl.Result, error) { + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("childType", gvk(r.ChildType, r.Config.Scheme())) + ctx = logr.NewContext(ctx, log) + if r.mutationCache == nil { r.mutationCache = cache.NewExpiring() } child, err := r.reconcile(ctx, parent) if err != nil { - parentType := RetrieveParentType(ctx) if apierrs.IsAlreadyExists(err) { // check if the resource blocking create is owned by the parent. // the created child from a previous turn may be slow to appear in the informer cache, but shouldn't appear @@ -590,11 +647,11 @@ func (r *ChildReconciler) Reconcile(ctx context.Context, parent client.Object) ( // skip updating the parent's status, fail and try again return ctrl.Result{}, err } - r.Log.Info("unable to reconcile child, not owned", typeName(parentType), parent, typeName(r.ChildType), r.sanitize(child)) + log.Info("unable to reconcile child, not owned", "child", namespaceName(conflicted), "ownerRefs", conflicted.GetOwnerReferences()) r.reflectChildStatusOnParent(parent, child, err) return ctrl.Result{}, nil } - r.Log.Error(err, "unable to reconcile child", typeName(parentType), parent) + log.Error(err, "unable to reconcile child") return ctrl.Result{}, err } r.reflectChildStatusOnParent(parent, child, err) @@ -603,6 +660,8 @@ func (r *ChildReconciler) Reconcile(ctx context.Context, parent client.Object) ( } func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) (client.Object, error) { + log := logr.FromContextOrDiscard(ctx) + actual := r.ChildType.DeepCopyObject().(client.Object) children := r.ChildListType.DeepCopyObject().(client.ObjectList) if err := r.List(ctx, children, client.InNamespace(parent.GetNamespace())); err != nil { @@ -614,7 +673,7 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( } else if len(items) > 1 { // this shouldn't happen, delete everything to a clean slate for _, extra := range items { - r.Log.Info("deleting extra child", typeName(r.ChildType), r.sanitize(extra)) + log.Info("deleting extra child", "child", namespaceName(extra)) if err := r.Delete(ctx, extra); err != nil { r.Recorder.Eventf(parent, corev1.EventTypeWarning, "DeleteFailed", "Failed to delete %s %q: %v", typeName(r.ChildType), extra.GetName(), err) @@ -637,16 +696,16 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( return nil, err } if !r.ourChild(parent, desired) { - r.Log.Info("object returned from DesiredChild does not match OurChild, this can result in orphaned children", "child", r.sanitize(desired)) + log.Info("object returned from DesiredChild does not match OurChild, this can result in orphaned children", "child", namespaceName(desired)) } } // delete child if no longer needed if desired == nil { if !actual.GetCreationTimestamp().Time.IsZero() { - r.Log.Info("deleting unwanted child", typeName(r.ChildType), r.sanitize(actual)) + log.Info("deleting unwanted child", "child", namespaceName(actual)) if err := r.Delete(ctx, actual); err != nil { - r.Log.Error(err, "unable to delete unwanted child", typeName(r.ChildType), r.sanitize(actual)) + log.Error(err, "unable to delete unwanted child", "child", namespaceName(actual)) r.Recorder.Eventf(parent, corev1.EventTypeWarning, "DeleteFailed", "Failed to delete %s %q: %v", typeName(r.ChildType), actual.GetName(), err) return nil, err @@ -659,9 +718,9 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( // create child if it doesn't exist if actual.GetName() == "" { - r.Log.Info("creating child", typeName(r.ChildType), r.sanitize(desired)) + log.Info("creating child", "child", r.sanitize(desired)) if err := r.Create(ctx, desired); err != nil { - r.Log.Error(err, "unable to create child", typeName(r.ChildType), r.sanitize(desired)) + log.Error(err, "unable to create child", "child", namespaceName(desired)) r.Recorder.Eventf(parent, corev1.EventTypeWarning, "CreationFailed", "Failed to create %s %q: %v", typeName(r.ChildType), desired.GetName(), err) return nil, err @@ -681,7 +740,7 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( err := patch.(*Patch).Apply(desiredPatched) if err != nil { // there's not much we can do, but let the normal update proceed - r.Log.Info("unable to patch desired child from mutation cache") + log.Info("unable to patch desired child from mutation cache") } } @@ -693,9 +752,9 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( // update child with desired changes current := actual.DeepCopyObject().(client.Object) r.mergeBeforeUpdate(current, desiredPatched) - r.Log.Info("reconciling child", "diff", cmp.Diff(r.sanitize(actual), r.sanitize(current))) + log.Info("updating child", "diff", cmp.Diff(r.sanitize(actual), r.sanitize(current))) if err := r.Update(ctx, current); err != nil { - r.Log.Error(err, "unable to update child", typeName(r.ChildType), r.sanitize(current)) + log.Error(err, "unable to update child", "child", namespaceName(current)) r.Recorder.Eventf(parent, corev1.EventTypeWarning, "UpdateFailed", "Failed to update %s %q: %v", typeName(r.ChildType), current.GetName(), err) return nil, err @@ -707,11 +766,12 @@ func (r *ChildReconciler) reconcile(ctx context.Context, parent client.Object) ( r.mergeBeforeUpdate(base, desired) patch, err := NewPatch(base, current) if err != nil { - r.Log.Error(err, "unable to generate mutation patch", "snapshot", r.sanitize(desired), "base", r.sanitize(base)) + log.Error(err, "unable to generate mutation patch", "snapshot", r.sanitize(desired), "base", r.sanitize(base)) } else { r.mutationCache.Set(current.GetUID(), patch, 1*time.Hour) } } + log.Info("updated child") r.Recorder.Eventf(parent, corev1.EventTypeNormal, "Updated", "Updated %s %q", typeName(r.ChildType), current.GetName()) @@ -879,6 +939,12 @@ func (r Sequence) aggregateResult(result, aggregate ctrl.Result) ctrl.Result { // cast parent are read-only. Attempts to mutate the parent will result in the // reconciler erring. type CastParent struct { + // Name used to identify this reconciler. Defaults to `{Type}CastParent`. Ideally unique, + // but not required to be so. + // + // +optional + Name string + // Type of resource to reconcile Type client.Object @@ -889,6 +955,15 @@ type CastParent struct { } func (r *CastParent) SetupWithManager(ctx context.Context, mgr ctrl.Manager, bldr *builder.Builder) error { + if r.Name == "" { + r.Name = fmt.Sprintf("%sCastParent", typeName(r.Type)) + } + + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("castParentType", typeName(r.Type)) + ctx = logr.NewContext(ctx, log) + if err := r.validate(ctx); err != nil { return err } @@ -910,6 +985,11 @@ func (r *CastParent) validate(ctx context.Context) error { } func (r *CastParent) Reconcile(ctx context.Context, parent client.Object) (ctrl.Result, error) { + log := logr.FromContextOrDiscard(ctx). + WithName(r.Name). + WithValues("castParentType", typeName(r.Type)) + ctx = logr.NewContext(ctx, log) + ctx, castParent, err := r.cast(ctx, parent) if err != nil { return ctrl.Result{}, err @@ -957,6 +1037,21 @@ func typeName(i interface{}) string { return t.Name() } +func gvk(obj client.Object, scheme *runtime.Scheme) schema.GroupVersionKind { + gvks, _, err := scheme.ObjectKinds(obj) + if err != nil { + return schema.GroupVersionKind{} + } + return gvks[0] +} + +func namespaceName(obj client.Object) types.NamespacedName { + return types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } +} + // MergeMaps flattens a sequence of maps into a single map. Keys in latter maps // overwrite previous keys. None of the arguments are mutated. func MergeMaps(maps ...map[string]string) map[string]string { diff --git a/testing/tracker.go b/testing/tracker.go index b8dc15a..ba34dc6 100644 --- a/testing/tracker.go +++ b/testing/tracker.go @@ -6,9 +6,9 @@ SPDX-License-Identifier: Apache-2.0 package testing import ( + "context" "time" - "github.com/go-logr/logr" "github.com/vmware-labs/reconciler-runtime/tracker" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -54,7 +54,7 @@ func NewTrackRequest(t, b client.Object, scheme *runtime.Scheme) TrackRequest { const maxDuration = time.Duration(1<<63 - 1) func createTracker() *mockTracker { - return &mockTracker{Tracker: tracker.New(maxDuration, logr.Discard()), reqs: []TrackRequest{}} + return &mockTracker{Tracker: tracker.New(maxDuration), reqs: []TrackRequest{}} } type mockTracker struct { @@ -64,15 +64,11 @@ type mockTracker struct { var _ tracker.Tracker = &mockTracker{} -func (t *mockTracker) Track(ref tracker.Key, obj types.NamespacedName) { - t.Tracker.Track(ref, obj) +func (t *mockTracker) Track(ctx context.Context, ref tracker.Key, obj types.NamespacedName) { + t.Tracker.Track(ctx, ref, obj) t.reqs = append(t.reqs, TrackRequest{Tracked: ref, Tracker: obj}) } func (t *mockTracker) getTrackRequests() []TrackRequest { - result := []TrackRequest{} - for _, req := range t.reqs { - result = append(result, req) - } - return result + return append([]TrackRequest{}, t.reqs...) } diff --git a/tracker/tracker.go b/tracker/tracker.go index 52c4817..f3c30c7 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -23,6 +23,7 @@ SPDX-License-Identifier: Apache-2.0 package tracker import ( + "context" "fmt" "sync" "time" @@ -37,10 +38,10 @@ import ( type Tracker interface { // Track tells us that "obj" is tracking changes to the // referenced object. - Track(ref Key, obj types.NamespacedName) + Track(ctx context.Context, ref Key, obj types.NamespacedName) // Lookup returns actively tracked objects for the reference. - Lookup(ref Key) []types.NamespacedName + Lookup(ctx context.Context, ref Key) []types.NamespacedName } func NewKey(gvk schema.GroupVersionKind, namespacedName types.NamespacedName) Key { @@ -63,9 +64,8 @@ func (k *Key) String() string { // register a particular resource as watching a resource for // a particular lease duration. This watch must be refreshed // periodically (e.g. by a controller resync) or it will expire. -func New(lease time.Duration, log logr.Logger) Tracker { +func New(lease time.Duration) Tracker { return &impl{ - log: log, leaseDuration: lease, } } @@ -90,7 +90,9 @@ var _ Tracker = (*impl)(nil) type set map[types.NamespacedName]time.Time // Track implements Tracker. -func (i *impl) Track(ref Key, obj types.NamespacedName) { +func (i *impl) Track(ctx context.Context, ref Key, obj types.NamespacedName) { + log := logr.FromContextOrDiscard(ctx).WithName("tracker") + i.m.Lock() defer i.m.Unlock() if i.mapping == nil { @@ -106,7 +108,7 @@ func (i *impl) Track(ref Key, obj types.NamespacedName) { i.mapping[ref.String()] = l - i.log.Info("tracking resource", "ref", ref.String(), "obj", obj.String(), "ttl", l[obj].UTC().Format(time.RFC3339)) + log.Info("tracking resource", "ref", ref.String(), "obj", obj.String(), "ttl", l[obj].UTC().Format(time.RFC3339)) } func isExpired(expiry time.Time) bool { @@ -114,7 +116,9 @@ func isExpired(expiry time.Time) bool { } // Lookup implements Tracker. -func (i *impl) Lookup(ref Key) []types.NamespacedName { +func (i *impl) Lookup(ctx context.Context, ref Key) []types.NamespacedName { + log := logr.FromContextOrDiscard(ctx).WithName("tracker") + items := []types.NamespacedName{} // TODO(mattmoor): Consider locking the mapping (global) for a @@ -123,7 +127,7 @@ func (i *impl) Lookup(ref Key) []types.NamespacedName { defer i.m.Unlock() s, ok := i.mapping[ref.String()] if !ok { - i.log.V(2).Info("no tracked items found", "ref", ref.String()) + log.V(2).Info("no tracked items found", "ref", ref.String()) return items } @@ -140,7 +144,7 @@ func (i *impl) Lookup(ref Key) []types.NamespacedName { delete(i.mapping, ref.String()) } - i.log.V(1).Info("found tracked items", "ref", ref.String(), "items", items) + log.V(1).Info("found tracked items", "ref", ref.String(), "items", items) return items }