/
recorder.go
130 lines (109 loc) · 4.12 KB
/
recorder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package events
import (
"context"
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/klog/v2"
)
// Recorder is a simple event recording interface.
type Recorder interface {
Event(reason, message string)
Eventf(reason, messageFmt string, args ...interface{})
Warning(reason, message string)
Warningf(reason, messageFmt string, args ...interface{})
// ForComponent allows to fiddle the component name before sending the event to sink.
// Making more unique components will prevent the spam filter in upstream event sink from dropping
// events.
ForComponent(componentName string) Recorder
// WithComponentSuffix is similar to ForComponent except it just suffix the current component name instead of overriding.
WithComponentSuffix(componentNameSuffix string) Recorder
// WithContext allows to set a context for event create API calls.
WithContext(ctx context.Context) Recorder
// ComponentName returns the current source component name for the event.
// This allows to suffix the original component name with 'sub-component'.
ComponentName() string
Shutdown()
}
// NewRecorder returns new event recorder.
func NewRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder {
return &recorder{
eventClient: client,
involvedObjectRef: involvedObjectRef,
sourceComponent: sourceComponentName,
}
}
// recorder is an implementation of Recorder interface.
type recorder struct {
eventClient corev1client.EventInterface
involvedObjectRef *corev1.ObjectReference
sourceComponent string
// TODO: This is not the right way to pass the context, but there is no other way without breaking event interface
ctx context.Context
}
func (r *recorder) ComponentName() string {
return r.sourceComponent
}
func (r *recorder) Shutdown() {}
func (r *recorder) ForComponent(componentName string) Recorder {
newRecorderForComponent := *r
newRecorderForComponent.sourceComponent = componentName
return &newRecorderForComponent
}
func (r *recorder) WithContext(ctx context.Context) Recorder {
r.ctx = ctx
return r
}
func (r *recorder) WithComponentSuffix(suffix string) Recorder {
return r.ForComponent(fmt.Sprintf("%s-%s", r.ComponentName(), suffix))
}
// Event emits the normal type event and allow formatting of message.
func (r *recorder) Eventf(reason, messageFmt string, args ...interface{}) {
r.Event(reason, fmt.Sprintf(messageFmt, args...))
}
// Warning emits the warning type event and allow formatting of message.
func (r *recorder) Warningf(reason, messageFmt string, args ...interface{}) {
r.Warning(reason, fmt.Sprintf(messageFmt, args...))
}
// Event emits the normal type event.
func (r *recorder) Event(reason, message string) {
event := makeEvent(r.involvedObjectRef, r.sourceComponent, corev1.EventTypeNormal, reason, message)
ctx := context.Background()
if r.ctx != nil {
ctx = r.ctx
}
if _, err := r.eventClient.Create(ctx, event, metav1.CreateOptions{}); err != nil {
klog.Warningf("Error creating event %+v: %v", event, err)
}
}
// Warning emits the warning type event.
func (r *recorder) Warning(reason, message string) {
event := makeEvent(r.involvedObjectRef, r.sourceComponent, corev1.EventTypeWarning, reason, message)
ctx := context.Background()
if r.ctx != nil {
ctx = r.ctx
}
if _, err := r.eventClient.Create(ctx, event, metav1.CreateOptions{}); err != nil {
klog.Warningf("Error creating event %+v: %v", event, err)
}
}
func makeEvent(involvedObjRef *corev1.ObjectReference, sourceComponent string, eventType, reason, message string) *corev1.Event {
currentTime := metav1.Time{Time: time.Now()}
event := &corev1.Event{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%v.%x", involvedObjRef.Name, currentTime.UnixNano()),
Namespace: involvedObjRef.Namespace,
},
InvolvedObject: *involvedObjRef,
Reason: reason,
Message: message,
Type: eventType,
Count: 1,
FirstTimestamp: currentTime,
LastTimestamp: currentTime,
}
event.Source.Component = sourceComponent
return event
}