WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 910eed5

Browse files
Merge pull request #19760 from mozilla/PAY-3201
feat(payments-next): Capture error presence in CaptureTimingWithStatsD
2 parents 4f18ae8 + c4d9b53 commit 910eed5

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

libs/shared/metrics/statsd/src/lib/statsd.decorator.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ class TestClass {
3131
syncMethodWithCustomHandler() {
3232
return 'Custom Handler';
3333
}
34+
35+
@CaptureTimingWithStatsD()
36+
syncMethodWithError() {
37+
throw new Error('Sync error');
38+
}
39+
40+
@CaptureTimingWithStatsD()
41+
async asyncMethodWithError() {
42+
throw new Error('Async error');
43+
}
3444
}
3545

3646
describe('CaptureTimingWithStatsD', () => {
@@ -54,6 +64,7 @@ describe('CaptureTimingWithStatsD', () => {
5464
expect.any(Number),
5565
{
5666
sourceClass: 'TestClass',
67+
error: 'false',
5768
}
5869
);
5970
});
@@ -66,6 +77,7 @@ describe('CaptureTimingWithStatsD', () => {
6677
expect.any(Number),
6778
{
6879
sourceClass: 'TestClass',
80+
error: 'false',
6981
}
7082
);
7183
});
@@ -75,4 +87,54 @@ describe('CaptureTimingWithStatsD', () => {
7587
expect(mockCallback).toHaveBeenCalledTimes(1);
7688
expect(mockCallback).toHaveBeenCalledWith(expect.any(Number));
7789
});
90+
91+
it('should track error=true for synchronous methods that throw', () => {
92+
expect(() => instance.syncMethodWithError()).toThrow('Sync error');
93+
expect(mockStatsD.timing).toHaveBeenCalledTimes(2);
94+
expect(mockStatsD.timing).toHaveBeenCalledWith(
95+
'TestClass_syncMethodWithError',
96+
expect.any(Number),
97+
{
98+
sourceClass: 'TestClass',
99+
error: 'true',
100+
}
101+
);
102+
});
103+
104+
it('should track error=true for asynchronous methods that throw', async () => {
105+
await expect(instance.asyncMethodWithError()).rejects.toThrow('Async error');
106+
expect(mockStatsD.timing).toHaveBeenCalledTimes(2);
107+
expect(mockStatsD.timing).toHaveBeenCalledWith(
108+
'TestClass_asyncMethodWithError',
109+
expect.any(Number),
110+
{
111+
sourceClass: 'TestClass',
112+
error: 'true',
113+
}
114+
);
115+
});
116+
117+
it('should track error=false for successful synchronous methods', () => {
118+
instance.syncMethod();
119+
expect(mockStatsD.timing).toHaveBeenCalledWith(
120+
'TestClass',
121+
expect.any(Number),
122+
{
123+
methodName: 'syncMethod',
124+
error: 'false',
125+
}
126+
);
127+
});
128+
129+
it('should track error=false for successful asynchronous methods', async () => {
130+
await instance.asyncMethod();
131+
expect(mockStatsD.timing).toHaveBeenCalledWith(
132+
'TestClass',
133+
expect.any(Number),
134+
{
135+
methodName: 'asyncMethod',
136+
error: 'false',
137+
}
138+
);
139+
});
78140
});

libs/shared/metrics/statsd/src/lib/statsd.decorator.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,49 @@ export function CaptureTimingWithStatsD<
2222
const originalDef = descriptor.value;
2323

2424
descriptor.value = function (this: T, ...args: any[]) {
25-
const defaultHandler = function (this: T, elapsed: number) {
25+
const defaultHandler = function (this: T, elapsed: number, error = false) {
2626
this.statsd.timing(`${this.constructor.name}_${key}`, elapsed, {
2727
sourceClass: this.constructor.name,
28+
error: error.toString(),
2829
...options?.tags,
2930
});
3031
this.statsd.timing(this.constructor.name, elapsed, {
3132
methodName: key,
33+
error: error.toString(),
3234
...options?.tags,
3335
});
3436
};
3537
const handler = options?.handle || defaultHandler;
3638

3739
const start = performance.now();
38-
const originalReturnValue = originalDef.apply(this, args);
40+
let originalReturnValue;
41+
42+
try {
43+
originalReturnValue = originalDef.apply(this, args);
44+
} catch (err) {
45+
const end = performance.now();
46+
handler.apply(this, [end - start, true]);
47+
throw err;
48+
}
3949

4050
if (originalReturnValue instanceof Promise) {
4151
return originalReturnValue
4252
.then((value) => {
4353
const end = performance.now();
44-
handler.apply(this, [end - start]);
54+
handler.apply(this, [end - start, false]);
4555

4656
return value;
4757
})
4858
.catch((err) => {
4959
const end = performance.now();
50-
handler.apply(this, [end - start]);
60+
handler.apply(this, [end - start, true]);
5161

5262
throw err;
5363
});
5464
}
5565

5666
const end = performance.now();
57-
handler.apply(this, [end - start]);
67+
handler.apply(this, [end - start, false]);
5868

5969
return originalReturnValue;
6070
};

0 commit comments

Comments
 (0)