Skip to content

Commit 68f49f6

Browse files
committed
Trim grouper event titles
1 parent a7dcbb6 commit 68f49f6

3 files changed

Lines changed: 42 additions & 8 deletions

File tree

workers/grouper/src/data-filter.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import type { EventAddons, EventData } from '@hawk.so/types';
22
import { unsafeFields } from '../../../lib/utils/unsafeFields';
3+
import { rightTrim } from '../../../lib/utils/string';
34

45
/**
56
* Maximum depth for object traversal to prevent excessive memory allocations
67
*/
78
const MAX_TRAVERSAL_DEPTH = 20;
89

10+
/**
11+
* Maximum length for event title before appending ellipsis
12+
*/
13+
const MAX_TITLE_LENGTH = 400;
14+
915
/**
1016
* Recursively iterate through object and call function on each key
1117
*
@@ -135,13 +141,27 @@ export default class DataFilter {
135141
* @param event - event to process
136142
*/
137143
public processEvent(event: EventData<EventAddons>): void {
144+
this.trimEventTitle(event);
145+
138146
unsafeFields.forEach(field => {
139147
if (event[field]) {
140148
this.processField(event[field]);
141149
}
142150
});
143151
}
144152

153+
/**
154+
* Trim event title to the maximum allowed length.
155+
* It mutates the original object.
156+
*
157+
* @param event - event to process
158+
*/
159+
public trimEventTitle(event: EventData<EventAddons>): void {
160+
if (typeof event.title === 'string') {
161+
event.title = rightTrim(event.title, MAX_TITLE_LENGTH);
162+
}
163+
}
164+
145165
/**
146166
* Recursively iterates object and applies filtering to its entries
147167
*

workers/grouper/src/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const DB_DUPLICATE_KEY_ERROR = '11000';
5959
const DAILY_METRICS_RETENTION_DAYS = 90;
6060

6161
/**
62-
* Maximum length for backtrace code line or title
62+
* Maximum length for backtrace code line
6363
*/
6464
const MAX_CODE_LINE_LENGTH = 140;
6565

@@ -198,8 +198,6 @@ export default class GrouperWorker extends Worker {
198198
this.grouperMetrics.observePayloadSize(taskPayloadSize);
199199
this.memoryMonitor.logBeforeHandle(memoryBeforeHandle, handledTasksCount, taskPayloadSize, task.projectId);
200200

201-
this.logger.info(`[handle] project=${task.projectId} catcher=${task.catcherType} title="${task.payload.title}" payloadSize=${taskPayloadSize}b backtraceFrames=${task.payload.backtrace?.length ?? 0}`);
202-
203201
// FIX RELEASE TYPE
204202
// TODO: REMOVE AFTER 01.01.2026, after the most of the users update to new js catcher
205203
if (task.payload && task.payload.release !== undefined) {
@@ -209,6 +207,13 @@ export default class GrouperWorker extends Worker {
209207
};
210208
}
211209

210+
/**
211+
* Filter event data before logging and hashing so logs, hash and stored event stay consistent.
212+
*/
213+
this.dataFilter.processEvent(task.payload);
214+
215+
this.logger.info(`[handle] project=${task.projectId} catcher=${task.catcherType} title="${task.payload.title}" payloadSize=${taskPayloadSize}b backtraceFrames=${task.payload.backtrace?.length ?? 0}`);
216+
212217
let uniqueEventHash = await session.measureStep('hash', () => this.getUniqueEventHash(task));
213218
let existedEvent: GroupedEventDBScheme;
214219
let repetitionId = null;
@@ -219,11 +224,6 @@ export default class GrouperWorker extends Worker {
219224
* Trim source code lines to prevent memory leaks
220225
*/
221226
this.trimSourceCodeLines(task.payload);
222-
223-
/**
224-
* Filter sensitive information
225-
*/
226-
this.dataFilter.processEvent(task.payload);
227227
});
228228

229229
/**

workers/grouper/tests/index.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ describe('GrouperWorker', () => {
173173
expect(await eventsCollection.find().count()).toBe(1);
174174
});
175175

176+
test('Should trim event title to the maximum length before saving', async () => {
177+
const longTitle = 'A'.repeat(5000);
178+
179+
await worker.handle(generateTask({ title: longTitle }));
180+
181+
const savedEvent = await eventsCollection.findOne({});
182+
183+
/**
184+
* 400 chars + ellipsis
185+
*/
186+
expect(savedEvent.payload.title.length).toBe(401);
187+
expect(savedEvent.payload.title.endsWith('…')).toBe(true);
188+
});
189+
176190
test('Should increment total events count on each processing', async () => {
177191
await worker.handle(generateTask());
178192
await worker.handle(generateTask());

0 commit comments

Comments
 (0)