Skip to content

Commit 243c08f

Browse files
fix: correct fingerprinting and common enhancer call (#78)
* fix fingerprinting and common enhancer call * refactor enhancers
1 parent ea40479 commit 243c08f

File tree

2 files changed

+156
-124
lines changed

2 files changed

+156
-124
lines changed

enhancers.go

Lines changed: 150 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77

88
"github.com/getsentry/sentry-go"
9+
"github.com/rs/zerolog"
910
appsv1 "k8s.io/api/apps/v1"
1011
batchv1 "k8s.io/api/batch/v1"
1112
v1 "k8s.io/api/core/v1"
@@ -16,17 +17,19 @@ const breadcrumbLimit = 20
1617

1718
func runEnhancers(ctx context.Context, eventObject *v1.Event, kind string, object metav1.Object, scope *sentry.Scope, sentryEvent *sentry.Event) error {
1819

19-
involvedObject := fmt.Sprintf("%s/%s", kind, object.GetName())
20-
ctx, logger := getLoggerWithTag(ctx, "object", involvedObject)
20+
logger := zerolog.Ctx(ctx)
2121
logger.Debug().Msgf("Running the enhancer")
2222

2323
var err error
2424

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
2628
err = runCommonEnhancer(ctx, scope, sentryEvent)
2729
if err != nil {
2830
return err
2931
}
32+
3033
// If an event object is provided, we call the event enhancer
3134
if eventObject != nil {
3235
err = eventEnhancer(ctx, scope, eventObject, sentryEvent)
@@ -35,42 +38,17 @@ func runEnhancers(ctx context.Context, eventObject *v1.Event, kind string, objec
3538
}
3639
}
3740

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)
7047
if err != nil {
7148
return err
7249
}
7350
}
51+
7452
return nil
7553
}
7654

@@ -79,76 +57,6 @@ type KindObjectPair struct {
7957
object metav1.Object
8058
}
8159

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-
15260
func eventEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object, sentryEvent *sentry.Event) error {
15361
eventObj, ok := object.(*v1.Event)
15462
if !ok {
@@ -179,6 +87,79 @@ func eventEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Objec
17987
return nil
18088
}
18189

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+
182163
func podEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object, sentryEvent *sentry.Event) error {
183164
podObj, ok := object.(*v1.Pod)
184165
if !ok {
@@ -189,10 +170,10 @@ func podEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
189170
nodeName := podObj.Spec.NodeName
190171
setTagIfNotEmpty(scope, "node_name", nodeName)
191172

192-
// Add the cronjob to the fingerprint
173+
// Add the pod name to the fingerprint
193174
sentryEvent.Fingerprint = append(sentryEvent.Fingerprint, KindPod, podObj.Name)
194175

195-
// Add the cronjob to the tag
176+
// Add the pod to the tag
196177
setTagIfNotEmpty(scope, "pod_name", object.GetName())
197178
podObj.ManagedFields = []metav1.ManagedFieldsEntry{}
198179
metadataJson, err := prettyJson(podObj.ObjectMeta)
@@ -202,7 +183,7 @@ func podEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
202183
})
203184
}
204185

205-
// Add breadcrumb with cronjob timestamps
186+
// Add breadcrumb with pod timestamps
206187
scope.AddBreadcrumb(&sentry.Breadcrumb{
207188
Message: fmt.Sprintf("Created pod %s", object.GetName()),
208189
Level: sentry.LevelInfo,
@@ -221,10 +202,10 @@ func jobEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
221202
return errors.New("failed to cast object to Job object")
222203
}
223204

224-
// Add the cronjob to the fingerprint
205+
// Add the job to the fingerprint
225206
sentryEvent.Fingerprint = append(sentryEvent.Fingerprint, KindJob, jobObj.Name)
226207

227-
// Add the cronjob to the tag
208+
// Add the job to the tag
228209
setTagIfNotEmpty(scope, "job_name", object.GetName())
229210
jobObj.ManagedFields = []metav1.ManagedFieldsEntry{}
230211
metadataJson, err := prettyJson(jobObj.ObjectMeta)
@@ -234,7 +215,7 @@ func jobEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.Object,
234215
})
235216
}
236217

237-
// Add breadcrumb with cronjob timestamps
218+
// Add breadcrumb with job timestamps
238219
scope.AddBreadcrumb(&sentry.Breadcrumb{
239220
Message: fmt.Sprintf("Created job %s", object.GetName()),
240221
Level: sentry.LevelInfo,
@@ -286,10 +267,10 @@ func replicaSetEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
286267
return errors.New("failed to cast object to ReplicaSet object")
287268
}
288269

289-
// Add the cronjob to the fingerprint
270+
// Add the replicaset to the fingerprint
290271
sentryEvent.Fingerprint = append(sentryEvent.Fingerprint, KindReplicaset, replicasetObj.Name)
291272

292-
// Add the cronjob to the tag
273+
// Add the replicaset to the tag
293274
setTagIfNotEmpty(scope, "replicaset_name", object.GetName())
294275
replicasetObj.ManagedFields = []metav1.ManagedFieldsEntry{}
295276
metadataJson, err := prettyJson(replicasetObj.ObjectMeta)
@@ -299,7 +280,7 @@ func replicaSetEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
299280
})
300281
}
301282

302-
// Add breadcrumb with cronjob timestamps
283+
// Add breadcrumb with replicaset timestamps
303284
scope.AddBreadcrumb(&sentry.Breadcrumb{
304285
Message: fmt.Sprintf("Created replicaset %s", object.GetName()),
305286
Level: sentry.LevelInfo,
@@ -315,10 +296,10 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
315296
if !ok {
316297
return errors.New("failed to cast object to Deployment object")
317298
}
318-
// Add the cronjob to the fingerprint
299+
// Add the deployment to the fingerprint
319300
sentryEvent.Fingerprint = append(sentryEvent.Fingerprint, KindDeployment, deploymentObj.Name)
320301

321-
// Add the cronjob to the tag
302+
// Add the deployment to the tag
322303
setTagIfNotEmpty(scope, "deployment_name", object.GetName())
323304
deploymentObj.ManagedFields = []metav1.ManagedFieldsEntry{}
324305
metadataJson, err := prettyJson(deploymentObj.ObjectMeta)
@@ -328,7 +309,7 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
328309
})
329310
}
330311

331-
// Add breadcrumb with cronjob timestamps
312+
// Add breadcrumb with deployment timestamps
332313
scope.AddBreadcrumb(&sentry.Breadcrumb{
333314
Message: fmt.Sprintf("Created deployment %s", object.GetName()),
334315
Level: sentry.LevelInfo,
@@ -337,3 +318,55 @@ func deploymentEnhancer(ctx context.Context, scope *sentry.Scope, object metav1.
337318

338319
return nil
339320
}
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

Comments
 (0)