func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
	logger := gen.log
	defer utilruntime.HandleCrash()
	logger.Info("start")
	defer logger.Info("shutting down")
	if !cache.WaitForCacheSync(stopCh, gen.cpSynced, gen.pSynced) {
		logger.Info("failed to sync informer cache")
	}
	for i := 0; i < workers; i++ {
		go wait.Until(gen.runWorker, time.Second, stopCh)
	}
	<-stopCh
}
Run begins generator
package event
import (
	"time"
	"github.com/go-logr/logr"
	"github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
	kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
	kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
	client "github.com/kyverno/kyverno/pkg/dclient"
	"github.com/kyverno/kyverno/pkg/resourcecache"
	v1 "k8s.io/api/core/v1"
	errors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog/v2"
)
type Generator struct {
	client *client.Client
	cpLister kyvernolister.ClusterPolicyLister
	cpSynced cache.InformerSynced
	pLister kyvernolister.PolicyLister
	pSynced cache.InformerSynced
	queue workqueue.RateLimitingInterface
	policyCtrRecorder record.EventRecorder
	admissionCtrRecorder record.EventRecorder
	genPolicyRecorder record.EventRecorder
	resCache          resourcecache.ResourceCache
	log               logr.Logger
}
type Interface interface {
	Add(infoList ...Info)
}
func NewEventGenerator(client *client.Client, cpInformer kyvernoinformer.ClusterPolicyInformer, pInformer kyvernoinformer.PolicyInformer, resCache resourcecache.ResourceCache, log logr.Logger) *Generator {
	gen := Generator{
		client:               client,
		cpLister:             cpInformer.Lister(),
		cpSynced:             cpInformer.Informer().HasSynced,
		pLister:              pInformer.Lister(),
		pSynced:              pInformer.Informer().HasSynced,
		queue:                workqueue.NewNamedRateLimitingQueue(rateLimiter(), eventWorkQueueName),
		policyCtrRecorder:    initRecorder(client, PolicyController, log),
		admissionCtrRecorder: initRecorder(client, AdmissionController, log),
		genPolicyRecorder:    initRecorder(client, GeneratePolicyController, log),
		resCache:             resCache,
		log:                  log,
	}
	return &gen
}
func rateLimiter() workqueue.RateLimiter {
	return workqueue.DefaultItemBasedRateLimiter()
}
func initRecorder(client *client.Client, eventSource Source, log logr.Logger) record.EventRecorder {
	err := scheme.AddToScheme(scheme.Scheme)
	if err != nil {
		log.Error(err, "failed to add to scheme")
		return nil
	}
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartLogging(klog.V(5).Infof)
	eventInterface, err := client.GetEventsInterface()
	if err != nil {
		log.Error(err, "failed to get event interface for logging")
		return nil
	}
	eventBroadcaster.StartRecordingToSink(
		&typedcorev1.EventSinkImpl{
			Interface: eventInterface})
	recorder := eventBroadcaster.NewRecorder(
		scheme.Scheme,
		v1.EventSource{Component: eventSource.String()})
	return recorder
}
func (gen *Generator) Add(infos ...Info) {
	logger := gen.log
	for _, info := range infos {
		if info.Name == "" {
			logger.V(4).Info("not creating an event as the resource has not been assigned a name yet", "kind", info.Kind, "name", info.Name, "namespace", info.Namespace)
			continue
		}
		gen.queue.Add(info)
	}
}