6
6
"fmt"
7
7
8
8
"github.com/getsentry/sentry-go"
9
+ "github.com/rs/zerolog"
9
10
appsv1 "k8s.io/api/apps/v1"
10
11
batchv1 "k8s.io/api/batch/v1"
11
12
v1 "k8s.io/api/core/v1"
@@ -16,17 +17,19 @@ const breadcrumbLimit = 20
16
17
17
18
func runEnhancers (ctx context.Context , eventObject * v1.Event , kind string , object metav1.Object , scope * sentry.Scope , sentryEvent * sentry.Event ) error {
18
19
19
- involvedObject := fmt .Sprintf ("%s/%s" , kind , object .GetName ())
20
- ctx , logger := getLoggerWithTag (ctx , "object" , involvedObject )
20
+ logger := zerolog .Ctx (ctx )
21
21
logger .Debug ().Msgf ("Running the enhancer" )
22
22
23
23
var err error
24
24
25
- // First, run the common enhancer
25
+ // First, run the common enhancer which
26
+ // does not need neither the event object
27
+ // nor the involved object
26
28
err = runCommonEnhancer (ctx , scope , sentryEvent )
27
29
if err != nil {
28
30
return err
29
31
}
32
+
30
33
// If an event object is provided, we call the event enhancer
31
34
if eventObject != nil {
32
35
err = eventEnhancer (ctx , scope , eventObject , sentryEvent )
@@ -35,42 +38,17 @@ func runEnhancers(ctx context.Context, eventObject *v1.Event, kind string, objec
35
38
}
36
39
}
37
40
38
- logger .Trace ().Msgf ("Current fingerprint: %v" , sentryEvent .Fingerprint )
39
- // Enhance message with object name
40
- message := sentryEvent .Message
41
- sentryEvent .Message = fmt .Sprintf ("%s: %s" , object .GetName (), sentryEvent .Message )
42
-
43
- // Adjust fingerprint.
44
- // If there's already a non-empty fingerprint set, we assume that it was set by
45
- // another enhancer, so we don't touch it.
46
- if len (sentryEvent .Fingerprint ) == 0 {
47
- sentryEvent .Fingerprint = []string {message }
48
- }
49
- logger .Trace ().Msgf ("Fingerprint after adjustment: %v" , sentryEvent .Fingerprint )
50
-
51
- // Find the root owners and their corresponding object kinds
52
- rootOwners , err := findRootOwners (ctx , & KindObjectPair {
53
- kind : kind ,
54
- object : object ,
55
- })
56
- if err != nil {
57
- return err
58
- }
59
-
60
- // Call the specific enhancer for the object
61
- callObjectEnhancer (ctx , scope , & KindObjectPair {
62
- kind ,
63
- object ,
64
- }, sentryEvent )
65
-
66
- // Call specific enhancers for all root owners
67
- // (there most likely is just one root owner)
68
- for _ , rootOwner := range rootOwners {
69
- callObjectEnhancer (ctx , scope , & rootOwner , sentryEvent )
41
+ // If an involved object is provided, we call the object enhancer
42
+ if object != nil {
43
+ err = objectEnhancer (ctx , scope , & KindObjectPair {
44
+ kind : kind ,
45
+ object : object ,
46
+ }, sentryEvent )
70
47
if err != nil {
71
48
return err
72
49
}
73
50
}
51
+
74
52
return nil
75
53
}
76
54
@@ -79,76 +57,6 @@ type KindObjectPair struct {
79
57
object metav1.Object
80
58
}
81
59
82
- func findRootOwners (ctx context.Context , kindObjPair * KindObjectPair ) ([]KindObjectPair , error ) {
83
-
84
- // use DFS to find the leaves of the owner references graph
85
- rootOwners , err := ownerRefDFS (ctx , kindObjPair )
86
- if err != nil {
87
- return nil , err
88
- }
89
-
90
- // if the object has no owner references
91
- if rootOwners [0 ].object .GetUID () == kindObjPair .object .GetUID () {
92
- return []KindObjectPair {}, nil
93
- }
94
-
95
- return rootOwners , nil
96
-
97
- }
98
-
99
- // this function finds performs DFS to find the leaves the owner references graph
100
- func ownerRefDFS (ctx context.Context , kindObjPair * KindObjectPair ) ([]KindObjectPair , error ) {
101
-
102
- parents := kindObjPair .object .GetOwnerReferences ()
103
- // the owners slice to be returned
104
- rootOwners := []KindObjectPair {}
105
-
106
- // base case: the object has no parents
107
- if len (parents ) == 0 {
108
- rootOwners = append (rootOwners , * kindObjPair )
109
- return rootOwners , nil
110
- }
111
-
112
- // recursive case: the object has parents to explore
113
- for _ , parent := range parents {
114
- parentObj , ok := findObject (ctx , parent .Kind , kindObjPair .object .GetNamespace (), parent .Name )
115
- if ! ok {
116
- return nil , errors .New ("error attempting to find root owneres" )
117
- }
118
- partialOwners , err := ownerRefDFS (ctx , & KindObjectPair {
119
- kind : parent .Kind ,
120
- object : parentObj ,
121
- })
122
- if err != nil {
123
- return nil , err
124
- }
125
- if partialOwners != nil {
126
- rootOwners = append (rootOwners , partialOwners ... )
127
- }
128
- }
129
- return rootOwners , nil
130
- }
131
-
132
- func callObjectEnhancer (ctx context.Context , scope * sentry.Scope , kindObjectPair * KindObjectPair , sentryEvent * sentry.Event ) error {
133
-
134
- var err error = nil
135
- switch kindObjectPair .kind {
136
- case KindPod :
137
- err = podEnhancer (ctx , scope , kindObjectPair .object , sentryEvent )
138
- case KindReplicaset :
139
- err = replicaSetEnhancer (ctx , scope , kindObjectPair .object , sentryEvent )
140
- case KindDeployment :
141
- err = deploymentEnhancer (ctx , scope , kindObjectPair .object , sentryEvent )
142
- case KindJob :
143
- err = jobEnhancer (ctx , scope , kindObjectPair .object , sentryEvent )
144
- case KindCronjob :
145
- err = cronjobEnhancer (ctx , scope , kindObjectPair .object , sentryEvent )
146
- default :
147
- sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , kindObjectPair .object .GetName ())
148
- }
149
- return err
150
- }
151
-
152
60
func eventEnhancer (ctx context.Context , scope * sentry.Scope , object metav1.Object , sentryEvent * sentry.Event ) error {
153
61
eventObj , ok := object .(* v1.Event )
154
62
if ! ok {
@@ -179,6 +87,79 @@ func eventEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Objec
179
87
return nil
180
88
}
181
89
90
+ func objectEnhancer (ctx context.Context , scope * sentry.Scope , kindObjectPair * KindObjectPair , sentryEvent * sentry.Event ) error {
91
+
92
+ objectTag := fmt .Sprintf ("%s/%s" , kindObjectPair .kind , kindObjectPair .object .GetName ())
93
+ ctx , logger := getLoggerWithTag (ctx , "object" , objectTag )
94
+
95
+ var err error = nil
96
+
97
+ logger .Trace ().Msgf ("Current fingerprint: %v" , sentryEvent .Fingerprint )
98
+
99
+ // Enhance message with object name
100
+ message := sentryEvent .Message
101
+ sentryEvent .Message = fmt .Sprintf ("%s: %s" , kindObjectPair .object .GetName (), sentryEvent .Message )
102
+
103
+ // Adjust fingerprint.
104
+ // If there's already a non-empty fingerprint set, we assume that it was set by
105
+ // another enhancer, so we don't touch it.
106
+ if len (sentryEvent .Fingerprint ) == 0 {
107
+ sentryEvent .Fingerprint = []string {message }
108
+ }
109
+ logger .Trace ().Msgf ("Fingerprint after adjustment: %v" , sentryEvent .Fingerprint )
110
+
111
+ // Find the root owners and their corresponding object kinds
112
+ rootOwners , err := findRootOwners (ctx , kindObjectPair )
113
+ if err != nil {
114
+ return err
115
+ }
116
+
117
+ // Might reset back to old fingerprint if
118
+ // there exists root owner(s) to the object
119
+ oldFingerprint := sentryEvent .Fingerprint
120
+ // Call the specific enhancer for the object
121
+ err = getKindEnhancer (kindObjectPair .kind )(ctx , scope , kindObjectPair .object , sentryEvent )
122
+ if err != nil {
123
+ return err
124
+ }
125
+ // Remove any fingerprinting so the event
126
+ // can be grouped by its owners instead
127
+ if len (rootOwners ) != 0 {
128
+ sentryEvent .Fingerprint = oldFingerprint
129
+ }
130
+
131
+ // Call specific enhancers for all root owners
132
+ // (there most likely is just one root owner)
133
+ for _ , rootOwner := range rootOwners {
134
+ err = getKindEnhancer (rootOwner .kind )(ctx , scope , rootOwner .object , sentryEvent )
135
+ if err != nil {
136
+ return err
137
+ }
138
+ }
139
+
140
+ return nil
141
+ }
142
+
143
+ func getKindEnhancer (kind string ) func (context.Context , * sentry.Scope , metav1.Object , * sentry.Event ) error {
144
+ switch kind {
145
+ case KindPod :
146
+ return podEnhancer
147
+ case KindReplicaset :
148
+ return replicaSetEnhancer
149
+ case KindDeployment :
150
+ return deploymentEnhancer
151
+ case KindJob :
152
+ return jobEnhancer
153
+ case KindCronjob :
154
+ return cronjobEnhancer
155
+ default :
156
+ return func (ctx context.Context , scope * sentry.Scope , object metav1.Object , sentryEvent * sentry.Event ) error {
157
+ sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , object .GetName ())
158
+ return nil
159
+ }
160
+ }
161
+ }
162
+
182
163
func podEnhancer (ctx context.Context , scope * sentry.Scope , object metav1.Object , sentryEvent * sentry.Event ) error {
183
164
podObj , ok := object .(* v1.Pod )
184
165
if ! ok {
@@ -189,10 +170,10 @@ func podEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
189
170
nodeName := podObj .Spec .NodeName
190
171
setTagIfNotEmpty (scope , "node_name" , nodeName )
191
172
192
- // Add the cronjob to the fingerprint
173
+ // Add the pod name to the fingerprint
193
174
sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , KindPod , podObj .Name )
194
175
195
- // Add the cronjob to the tag
176
+ // Add the pod to the tag
196
177
setTagIfNotEmpty (scope , "pod_name" , object .GetName ())
197
178
podObj .ManagedFields = []metav1.ManagedFieldsEntry {}
198
179
metadataJson , err := prettyJson (podObj .ObjectMeta )
@@ -202,7 +183,7 @@ func podEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
202
183
})
203
184
}
204
185
205
- // Add breadcrumb with cronjob timestamps
186
+ // Add breadcrumb with pod timestamps
206
187
scope .AddBreadcrumb (& sentry.Breadcrumb {
207
188
Message : fmt .Sprintf ("Created pod %s" , object .GetName ()),
208
189
Level : sentry .LevelInfo ,
@@ -221,10 +202,10 @@ func jobEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
221
202
return errors .New ("failed to cast object to Job object" )
222
203
}
223
204
224
- // Add the cronjob to the fingerprint
205
+ // Add the job to the fingerprint
225
206
sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , KindJob , jobObj .Name )
226
207
227
- // Add the cronjob to the tag
208
+ // Add the job to the tag
228
209
setTagIfNotEmpty (scope , "job_name" , object .GetName ())
229
210
jobObj .ManagedFields = []metav1.ManagedFieldsEntry {}
230
211
metadataJson , err := prettyJson (jobObj .ObjectMeta )
@@ -234,7 +215,7 @@ func jobEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
234
215
})
235
216
}
236
217
237
- // Add breadcrumb with cronjob timestamps
218
+ // Add breadcrumb with job timestamps
238
219
scope .AddBreadcrumb (& sentry.Breadcrumb {
239
220
Message : fmt .Sprintf ("Created job %s" , object .GetName ()),
240
221
Level : sentry .LevelInfo ,
@@ -286,10 +267,10 @@ func replicaSetEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
286
267
return errors .New ("failed to cast object to ReplicaSet object" )
287
268
}
288
269
289
- // Add the cronjob to the fingerprint
270
+ // Add the replicaset to the fingerprint
290
271
sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , KindReplicaset , replicasetObj .Name )
291
272
292
- // Add the cronjob to the tag
273
+ // Add the replicaset to the tag
293
274
setTagIfNotEmpty (scope , "replicaset_name" , object .GetName ())
294
275
replicasetObj .ManagedFields = []metav1.ManagedFieldsEntry {}
295
276
metadataJson , err := prettyJson (replicasetObj .ObjectMeta )
@@ -299,7 +280,7 @@ func replicaSetEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
299
280
})
300
281
}
301
282
302
- // Add breadcrumb with cronjob timestamps
283
+ // Add breadcrumb with replicaset timestamps
303
284
scope .AddBreadcrumb (& sentry.Breadcrumb {
304
285
Message : fmt .Sprintf ("Created replicaset %s" , object .GetName ()),
305
286
Level : sentry .LevelInfo ,
@@ -315,10 +296,10 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
315
296
if ! ok {
316
297
return errors .New ("failed to cast object to Deployment object" )
317
298
}
318
- // Add the cronjob to the fingerprint
299
+ // Add the deployment to the fingerprint
319
300
sentryEvent .Fingerprint = append (sentryEvent .Fingerprint , KindDeployment , deploymentObj .Name )
320
301
321
- // Add the cronjob to the tag
302
+ // Add the deployment to the tag
322
303
setTagIfNotEmpty (scope , "deployment_name" , object .GetName ())
323
304
deploymentObj .ManagedFields = []metav1.ManagedFieldsEntry {}
324
305
metadataJson , err := prettyJson (deploymentObj .ObjectMeta )
@@ -328,7 +309,7 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
328
309
})
329
310
}
330
311
331
- // Add breadcrumb with cronjob timestamps
312
+ // Add breadcrumb with deployment timestamps
332
313
scope .AddBreadcrumb (& sentry.Breadcrumb {
333
314
Message : fmt .Sprintf ("Created deployment %s" , object .GetName ()),
334
315
Level : sentry .LevelInfo ,
@@ -337,3 +318,55 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
337
318
338
319
return nil
339
320
}
321
+
322
+ // Finds the root owning objects of an object
323
+ // and returns an empty slice if the object has
324
+ // no owning objects
325
+ func findRootOwners (ctx context.Context , kindObjPair * KindObjectPair ) ([]KindObjectPair , error ) {
326
+
327
+ // Use DFS to find the leaves of the owner references graph
328
+ rootOwners , err := ownerRefDFS (ctx , kindObjPair )
329
+ if err != nil {
330
+ return nil , err
331
+ }
332
+
333
+ // If the object has no owner references
334
+ if rootOwners [0 ].object .GetUID () == kindObjPair .object .GetUID () {
335
+ return []KindObjectPair {}, nil
336
+ }
337
+
338
+ return rootOwners , nil
339
+ }
340
+
341
+ // Performs DFS to find the leaves the owner references graph
342
+ func ownerRefDFS (ctx context.Context , kindObjPair * KindObjectPair ) ([]KindObjectPair , error ) {
343
+
344
+ parents := kindObjPair .object .GetOwnerReferences ()
345
+ // the owners slice to be returned
346
+ rootOwners := []KindObjectPair {}
347
+
348
+ // base case: the object has no parents
349
+ if len (parents ) == 0 {
350
+ rootOwners = append (rootOwners , * kindObjPair )
351
+ return rootOwners , nil
352
+ }
353
+
354
+ // recursive case: the object has parents to explore
355
+ for _ , parent := range parents {
356
+ parentObj , ok := findObject (ctx , parent .Kind , kindObjPair .object .GetNamespace (), parent .Name )
357
+ if ! ok {
358
+ return nil , errors .New ("error attempting to find root owneres" )
359
+ }
360
+ partialOwners , err := ownerRefDFS (ctx , & KindObjectPair {
361
+ kind : parent .Kind ,
362
+ object : parentObj ,
363
+ })
364
+ if err != nil {
365
+ return nil , err
366
+ }
367
+ if partialOwners != nil {
368
+ rootOwners = append (rootOwners , partialOwners ... )
369
+ }
370
+ }
371
+ return rootOwners , nil
372
+ }
0 commit comments