1 package events 2 3 import ( 4 "github.com/go-logr/logr" 5 "k8s.io/apimachinery/pkg/runtime" 6 kuberecorder "k8s.io/client-go/tools/record" 7 "k8s.io/client-go/tools/reference" 8 ctrl "sigs.k8s.io/controller-runtime" 9 ) 10 11 // Recorder posts events to the Kubernetes API. 12 // 13 // Use it by embedding EventRecorder in reconciler struct: 14 // 15 // import ( 16 // ... 17 // kuberecorder "k8s.io/client-go/tools/record" 18 // ... 19 // ) 20 // 21 // type MyTypeReconciler { 22 // client.Client 23 // // ... etc. 24 // kuberecorder.EventRecorder 25 // } 26 // 27 // Use [NewRecorder] to create a working Recorder. 28 // 29 // TODO: add a retryable HTTP client & webhook and update 30 // [NewRecorder] to configure them 31 type Recorder struct { 32 // Name of the controller that emits events. 33 ReportingController string 34 35 // EventRecorder is the Kubernetes event recorder. 36 EventRecorder kuberecorder.EventRecorder 37 38 // Scheme to look up the recorded objects. 39 Scheme *runtime.Scheme 40 41 // Log is the recorder logger. 42 Log logr.Logger 43 } 44 45 var _ kuberecorder.EventRecorder = &Recorder{} 46 47 // NewRecorder creates an event Recorder with a Kubernetes event recorder. 48 func NewRecorder(mgr ctrl.Manager, log logr.Logger, reportingController string) *Recorder { 49 return &Recorder{ 50 Scheme: mgr.GetScheme(), 51 ReportingController: reportingController, 52 EventRecorder: mgr.GetEventRecorderFor(reportingController), 53 Log: log, 54 } 55 } 56 57 // Event constructs an event from the given information and puts it in the queue for sending. 58 // 'object' is the object this event is about. 59 // 'eventtype' of this event, and can be one of Normal, Warning. New types could be added in future 60 // 'reason' is the reason this event is generated. 'reason' should be short and unique; it 61 // should be in UpperCamelCase format (starting with a capital letter). "reason" will be used 62 // to automate handling of events. 63 // 'message' is intended to be human readable. 64 // 65 // The resulting event will be created in the same namespace as the reference object. 66 func (r *Recorder) Event(object runtime.Object, eventtype, reason, message string) { 67 r.AnnotatedEventf(object, nil, eventtype, reason, message) 68 } 69 70 // Eventf is just like [Event], but with a formatted message. 71 func (r *Recorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) { 72 r.AnnotatedEventf(object, nil, eventtype, reason, messageFmt, args...) 73 } 74 75 // AnnotatedEventf is just like [Event], but with a formatted message and annotations attached. 76 func (r *Recorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { 77 ref, err := reference.GetReference(r.Scheme, object) 78 if err != nil { 79 r.Log.Error(err, "failed to get object reference") 80 } 81 82 // Add object info in the logger. 83 _ = r.Log.WithValues("name", ref.Name, "namespace", ref.Namespace, "reconciler kind", ref.Kind) 84 85 // Forward the event to the Kubernetes recorder. 86 r.EventRecorder.AnnotatedEventf(object, annotations, eventtype, reason, messageFmt, args...) 87 88 // TODO: update this function to use retryable HTTP client and webhook when available/provided. 89 // See [AnnotatedEventf] in https://github.com/fluxcd/pkg/blob/main/runtime/events/recorder.go 90 // for an implementation example. 91 } 92