-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add error message normalization utility #1694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
|
||
| // Extract UUIDs | ||
| normalized = normalized.replace( | ||
| /\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(\/|$|\)|\s)/gi, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we abstract these into a variable so I know what the regex does? I know there is a comment, but I would rather have a named constant or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely. Good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented
| extractedValues: Record<string, string>; | ||
| } { | ||
| const extractedValues: Record<string, string> = {}; | ||
| let counter = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we name this counter variable something a little more obvious? What is it counting, errors? errorCount or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractedValueIndex would be more appropriate
It is the index of the value extracted from the original message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if abcd is replaced first, extractedValueIndex is 1. and it becomes var1 in the normalized output. Incrementing from there for every match and replacement.
| normalized = normalized.replace( | ||
| /\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(\/|$|\)|\s)/gi, | ||
| (_match, uuid, after) => { | ||
| const placeholder = `{var${counter}}`; | ||
| extractedValues[placeholder] = uuid; | ||
| counter++; | ||
| return `/${placeholder}${after}`; | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inline regex chains are hard to follow. Consider something like:
const NORMALIZATION_PATTERNS = {
uuid: {
pattern: /\/([0-9a-f]{8}-[0-9a-f]{4}-...)/gi,
replacer: (_, uuid, after, placeholder) => `/${placeholder}${after}`,
},
numericPathId: {
pattern: /\/(\d+)(\/|$|\)|\s)/g,
replacer: (_, num, after, placeholder) => `/${placeholder}${after}`,
},
// ... etc
};
// Then just loop:
for (const { pattern, replacer } of Object.values(NORMALIZATION_PATTERNS)) {
normalized = normalized.replace(pattern, (...args) => {
const placeholder = `{var${counter++}}`;
return replacer(...args, placeholder);
});
}Why:
-
Readable - pattern names explain intent without reading the regex
-
Testable - can unit test individual patterns in isolation
-
Maintainable - adding/modifying patterns is just editing the object, not hunting through a chain of .replace() calls
Not blocking, but would make future debugging much easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dig it. I'll be adding something like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented
| if (normalized.length > 200) { | ||
| normalized = normalized.substring(0, 197) + "..."; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets replace some of these magic numbers:
const MAX_MESSAGE_LENGTH = 200;
const MAX_MESSAGE_TRUNCATED_LENGTH = 197
There are a few more above as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented
| // Extract quoted strings | ||
| normalized = normalized.replace(/"([^"]+)"/g, (_match, content) => { | ||
| const placeholder = `{var${counter}}`; | ||
| extractedValues[placeholder] = content; | ||
| counter++; | ||
| return placeholder; | ||
| }); | ||
|
|
||
| normalized = normalized.replace(/'([^']+)'/g, (_match, content) => { | ||
| const placeholder = `{var${counter}}`; | ||
| extractedValues[placeholder] = content; | ||
| counter++; | ||
| return placeholder; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these be replaces with one? /["']([^"']+)["']/g
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current approach (two separate patterns):
- /"([^"]+)"/g - matches "hello" ✓
- /'([^']+)'/g - matches 'world' ✓
- Won't match "mixed' or 'mixed" ✗
Suggested pattern /["']([^"']+)["']/g:
- Matches "hello" ✓
- Matches 'world' ✓
- Also matches "mixed' and 'mixed" ✓ (probably not desirable)
For error message normalization, we likely want to extract properly quoted strings only, not strings with mismatched quotes. Mismatched quotes are often syntax errors or literal parts of the error message itself, not dynamic values we want to normalize.
Claude's recommendation: Keep the two separate patterns for correctness. The slight code duplication is worth ensuring we only extract properly quoted strings.
Let me know if you have strong feelings to the alternate approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented
3e8c8af to
1119b6f
Compare
eae3b11 to
8bd6752
Compare
1119b6f to
7ab4019
Compare
Add utility to normalize error messages by extracting dynamic values (UUIDs, IDs, hashes, etc.) and replacing them with placeholders. This enables better error grouping in monitoring tools.
8bd6752 to
1a7c437
Compare
7ab4019 to
d7fc62b
Compare

Description
Added error message normalization functionality to standardize error messages by extracting dynamic values (UUIDs, IDs, hashes, etc.) and replacing them with placeholders. This helps group similar errors that differ only in their dynamic values.
The implementation includes:
normalizeErrorMessagefunction that extracts various types of dynamic valuesType of Change
Checklist
Test Instructions
Run the test suite with
npm test src/services/errorManagement/normalizeErrorMessage.test.tsto verify the functionality works as expected.