Skip to content

Conversation

@qiujian16
Copy link
Member

@qiujian16 qiujian16 commented Nov 24, 2025

Summary

Related issue(s)

Fixes #

Summary by CodeRabbit

  • New Features

    • Added event recording capabilities for controllers with contextual logging support.
    • Introduced context-aware event handling for improved traceability across the event recording system.
  • Refactor

    • Updated event recording methods to require context parameters, removing legacy context management mechanisms and streamlining the event handling flow.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci openshift-ci bot requested a review from deads2k November 24, 2025 08:28
@openshift-ci
Copy link

openshift-ci bot commented Nov 24, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: qiujian16

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

Walkthrough

This pull request introduces a context-aware event recording system for controllers. It adds new recorder implementations for Kubernetes-native and logging-based event recording, updates the Recorder interface to accept context parameters directly (removing the previous WithContext mechanism), and integrates the recorder into the controller context.

Changes

Cohort / File(s) Summary
New event recorder implementations
pkg/basecontroller/events/event_recorder.go, pkg/basecontroller/events/logging_recorder.go
Adds NewEventRecorder function for Kubernetes event recording with EventsV1 client integration. Introduces ContextualLoggingEventRecorder type that logs events with component and reason fields via klog, including component accessor methods.
Recorder interface and implementation refactor
pkg/basecontroller/events/recorder.go
Updates Recorder interface to accept context.Context parameter in Event, Eventf, Warning, and Warningf methods. Removes WithContext method and stored ctx field from recorder struct. Implementations now use passed context directly rather than stored state.
Controller context integration
pkg/basecontroller/factory/controller_context.go, pkg/basecontroller/factory/interfaces.go
Adds recorder field to syncContext initialized with NewContextualLoggingEventRecorder. Extends SyncContext interface with new Recorder() accessor method. Imports events package.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Interface signature changes: All implementations of Recorder must be updated to accept context parameters; this is a breaking change that requires verifying all call sites throughout the codebase.
  • New type implementations: ContextualLoggingEventRecorder and NewEventRecorder need validation for correctness of logging behavior and Kubernetes event handling.
  • Integration correctness: Verify syncContext initialization and that the recorder is properly threaded through the controller lifecycle.

Suggested labels

approved, lgtm

Suggested reviewers

  • deads2k

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete, containing only the repository template with empty sections for Summary and Related issue(s). Fill in the Summary section with a concise overview of the changes, and complete the Related issue(s) section with the issue number if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title mentions adding a contextual logging-based recorder, which aligns with the main changes that introduce ContextualLoggingEventRecorder and update the Recorder interface to accept context parameters.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qiujian16 qiujian16 changed the title 🌱 Add contextual loggin based recorder 🌱 Add contextual logging based recorder Nov 24, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/basecontroller/events/logging_recorder.go (1)

38-45: Consider removing the "INFO:" prefix for cleaner logs.

The implementation correctly uses klog.FromContext and structured logging with component and reason fields. However, the "INFO:" prefix in the message might be redundant since the log level already indicates this is an info-level message.

If you'd like cleaner output, consider this diff:

 func (r *ContextualLoggingEventRecorder) Event(ctx context.Context, reason, message string) {
 	logger := klog.FromContext(ctx)
-	logger.Info(fmt.Sprintf("INFO: %s", message), "component", r.component, "reason", reason)
+	logger.Info(message, "component", r.component, "reason", reason)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb2d8ba and a72e5e8.

⛔ Files ignored due to path filters (17)
  • vendor/k8s.io/client-go/tools/events/OWNERS is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/doc.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/event_broadcaster.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/event_recorder.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/fake.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/helper.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/events/interfaces.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/internal/events/interfaces.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/OWNERS is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/doc.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/event.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/events_cache.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/fake.go is excluded by !vendor/**
  • vendor/k8s.io/client-go/tools/record/util/util.go is excluded by !vendor/**
  • vendor/k8s.io/utils/internal/third_party/forked/golang/golang-lru/lru.go is excluded by !vendor/**
  • vendor/k8s.io/utils/lru/lru.go is excluded by !vendor/**
  • vendor/modules.txt is excluded by !vendor/**
📒 Files selected for processing (5)
  • pkg/basecontroller/events/event_recorder.go (1 hunks)
  • pkg/basecontroller/events/logging_recorder.go (1 hunks)
  • pkg/basecontroller/events/recorder.go (2 hunks)
  • pkg/basecontroller/factory/controller_context.go (2 hunks)
  • pkg/basecontroller/factory/interfaces.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
pkg/basecontroller/events/event_recorder.go (1)
pkg/basecontroller/events/recorder.go (1)
  • NewRecorder (37-43)
pkg/basecontroller/events/logging_recorder.go (1)
pkg/basecontroller/events/recorder.go (1)
  • Recorder (15-34)
pkg/basecontroller/factory/controller_context.go (2)
pkg/basecontroller/events/recorder.go (1)
  • Recorder (15-34)
pkg/basecontroller/events/logging_recorder.go (1)
  • NewContextualLoggingEventRecorder (16-20)
pkg/basecontroller/factory/interfaces.go (1)
pkg/basecontroller/events/recorder.go (1)
  • Recorder (15-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: integration
  • GitHub Check: unit
  • GitHub Check: verify
🔇 Additional comments (12)
pkg/basecontroller/events/recorder.go (3)

69-75: LGTM!

Both Eventf and Warningf correctly accept and forward the context parameter to their respective base methods with formatted messages.


79-92: LGTM!

Both Event and Warning methods correctly use the provided context when creating events. Error handling appropriately logs failures without blocking the caller, which is consistent with the fire-and-forget pattern for event recording.


16-19: Breaking API change has been properly implemented across all implementations and call sites.

All implementations of the Recorder interface have been correctly updated to require context.Context as the first parameter. The two implementations (recorder and ContextualLoggingEventRecorder) both have matching signatures, internal method routing properly propagates context (e.g., EventfEvent, WarningfWarning), and the public API exposed through SyncContext.Recorder() provides the correct type. The factory instantiation uses the updated constructor signatures. No orphaned calls with the old signature pattern were found.

pkg/basecontroller/factory/interfaces.go (2)

5-5: LGTM!

The import of the events package is necessary to support the new Recorder() method in the SyncContext interface.


39-40: No issues found—all SyncContext implementations have been properly updated.

The verification confirms that syncContext is the sole implementation of the SyncContext interface and both required methods are correctly implemented:

  • Queue() (line 32 of controller_context.go)
  • Recorder() (line 36 of controller_context.go)

The compile-time assertion (var _ SyncContext = syncContext{}) at line 19 validates interface compliance and would fail to compile if any method were missing.

pkg/basecontroller/factory/controller_context.go (4)

9-9: LGTM!

The events package import is necessary to support the new recorder field and initialization.


15-16: LGTM!

The recorder field is properly added to the syncContext struct with the correct type. The interface compliance assertion at line 19 confirms the struct implements the updated SyncContext interface.


28-28: LGTM!

The recorder is appropriately initialized with NewContextualLoggingEventRecorder, which provides a logging-based recorder that doesn't require Kubernetes API access. The controller name is correctly passed as the component identifier.


36-38: LGTM!

The Recorder() method correctly implements the SyncContext interface requirement and returns the initialized recorder.

pkg/basecontroller/events/logging_recorder.go (2)

10-20: LGTM!

The ContextualLoggingEventRecorder struct and constructor are well-designed. The simple structure with a component field enables component-aware logging while maintaining the Recorder interface contract.


22-36: LGTM!

The component management methods are correctly implemented:

  • ForComponent safely creates a new recorder instance with a different component
  • WithComponentSuffix properly builds on ForComponent for component hierarchies
  • Shutdown as a no-op is appropriate for a logging-only recorder
pkg/basecontroller/events/event_recorder.go (1)

11-22: Based on verification of the codebase and k8s.io/client-go documentation showing that canceling the context will shut down the broadcaster, and Shutdown doesn't need to be called, I can now provide the corrected assessment:

Broadcaster context cleanup is already handled correctly—remove the verification requirement.

The function properly leverages StartRecordingToSinkWithContext(ctx), which ensures the broadcaster shuts down automatically when the provided context is cancelled. No additional verification is needed for context cleanup.

However, the review's documentation suggestions remain valid:

  • Return type clarity: The function returns k8s.io/client-go/tools/events.EventRecorder, not the local events.Recorder interface defined in this package. This differs from NewContextualLoggingEventRecorder (which returns the local interface).
  • Lifecycle documentation: Callers should understand that broadcaster cleanup is automatic via context cancellation and that no manual shutdown call is required.

Consider adding package-level documentation explaining:

  1. When to use NewEventRecorder (returns k8s client-go type with full event sink/sink recording) vs. NewContextualLoggingEventRecorder (returns local Recorder interface with logging-only behavior)
  2. That the returned recorder's lifetime is tied to the provided context

Comment on lines +47 to +54
func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
logger := klog.FromContext(ctx)
logger.Info(fmt.Sprintf("WARNING: %s", message), "component", r.component, "reason", reason)
}

func (r *ContextualLoggingEventRecorder) Warningf(ctx context.Context, reason, messageFmt string, args ...interface{}) {
r.Warning(ctx, reason, fmt.Sprintf(messageFmt, args...))
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Warning events should use a distinct log level.

The Warning method currently uses logger.Info, which logs warnings at the same severity as normal events. This prevents users from filtering warnings separately using log level flags (e.g., -v flag in klog).

Consider using a distinct log level for warnings:

 func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
 	logger := klog.FromContext(ctx)
-	logger.Info(fmt.Sprintf("WARNING: %s", message), "component", r.component, "reason", reason)
+	logger.V(1).Info(message, "component", r.component, "reason", reason, "eventType", "Warning")
 }

Or use the error level if these represent actual problems:

 func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
 	logger := klog.FromContext(ctx)
-	logger.Info(fmt.Sprintf("WARNING: %s", message), "component", r.component, "reason", reason)
+	logger.Error(nil, message, "component", r.component, "reason", reason)
 }

The choice depends on your logging strategy and how you want warnings filtered.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
logger := klog.FromContext(ctx)
logger.Info(fmt.Sprintf("WARNING: %s", message), "component", r.component, "reason", reason)
}
func (r *ContextualLoggingEventRecorder) Warningf(ctx context.Context, reason, messageFmt string, args ...interface{}) {
r.Warning(ctx, reason, fmt.Sprintf(messageFmt, args...))
}
func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
logger := klog.FromContext(ctx)
logger.V(1).Info(message, "component", r.component, "reason", reason, "eventType", "Warning")
}
func (r *ContextualLoggingEventRecorder) Warningf(ctx context.Context, reason, messageFmt string, args ...interface{}) {
r.Warning(ctx, reason, fmt.Sprintf(messageFmt, args...))
}
Suggested change
func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
logger := klog.FromContext(ctx)
logger.Info(fmt.Sprintf("WARNING: %s", message), "component", r.component, "reason", reason)
}
func (r *ContextualLoggingEventRecorder) Warningf(ctx context.Context, reason, messageFmt string, args ...interface{}) {
r.Warning(ctx, reason, fmt.Sprintf(messageFmt, args...))
}
func (r *ContextualLoggingEventRecorder) Warning(ctx context.Context, reason, message string) {
logger := klog.FromContext(ctx)
logger.Error(nil, message, "component", r.component, "reason", reason)
}
func (r *ContextualLoggingEventRecorder) Warningf(ctx context.Context, reason, messageFmt string, args ...interface{}) {
r.Warning(ctx, reason, fmt.Sprintf(messageFmt, args...))
}
🤖 Prompt for AI Agents
In pkg/basecontroller/events/logging_recorder.go around lines 47-54, the Warning
method currently uses logger.Info which does not distinguish warnings from
normal info; replace logger.Info with logger.Error(nil, ...) so warnings are
logged at the error/warning severity (and update Warningf to call the changed
Warning implementation) — ensure the Error call keeps the same message and
key/value pairs ("component", r.component, "reason", reason).

@skeeey
Copy link
Member

skeeey commented Nov 24, 2025

/lgtm

@openshift-ci openshift-ci bot added the lgtm label Nov 24, 2025
@openshift-merge-bot openshift-merge-bot bot merged commit 8ba6d23 into open-cluster-management-io:main Nov 24, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants