Skip to content

Commit aae4c2e

Browse files
authored
Merge pull request #47778 from dominictb/fix/47509-log-serialize
fix: serialize request.data in logging middleware
2 parents 6760f96 + 876adf8 commit aae4c2e

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/libs/Middleware/Logging.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,34 @@ import type Request from '@src/types/onyx/Request';
66
import type Response from '@src/types/onyx/Response';
77
import type Middleware from './types';
88

9+
function getCircularReplacer() {
10+
const ancestors: unknown[] = [];
11+
return function (this: unknown, key: string, value: unknown): unknown {
12+
if (typeof value !== 'object' || value === null) {
13+
return value;
14+
}
15+
// `this` is the object that value is contained in, i.e the direct parent
16+
// eslint-disable-next-line no-invalid-this
17+
while (ancestors.length > 0 && ancestors.at(-1) !== this) {
18+
ancestors.pop();
19+
}
20+
if (ancestors.includes(value)) {
21+
return '[Circular]';
22+
}
23+
ancestors.push(value);
24+
return value;
25+
};
26+
}
27+
28+
function serializeLoggingData<T extends Record<string, unknown> | undefined>(logData: T): T | null {
29+
try {
30+
return JSON.parse(JSON.stringify(logData, getCircularReplacer())) as T;
31+
} catch (error) {
32+
Log.hmmm('Failed to serialize log data', {error});
33+
return null;
34+
}
35+
}
36+
937
function logRequestDetails(message: string, request: Request, response?: Response | void) {
1038
// Don't log about log or else we'd cause an infinite loop
1139
if (request.command === 'Log') {
@@ -38,7 +66,10 @@ function logRequestDetails(message: string, request: Request, response?: Respons
3866
* requests because they contain sensitive information.
3967
*/
4068
if (request.command !== 'AuthenticatePusher') {
41-
extraData.request = request;
69+
extraData.request = {
70+
...request,
71+
data: serializeLoggingData(request.data),
72+
};
4273
extraData.response = response;
4374
}
4475

@@ -125,3 +156,5 @@ const Logging: Middleware = (response, request) => {
125156
};
126157

127158
export default Logging;
159+
160+
export {serializeLoggingData};

tests/unit/LoggingMiddlewareTest.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {serializeLoggingData} from '@libs/Middleware/Logging';
2+
3+
describe('LoggingMiddleware', () => {
4+
describe('getCircularReplacer', () => {
5+
it('should return "[Circular]" for circular references', () => {
6+
const obj: Record<string, unknown> = {};
7+
obj.obj = obj;
8+
const result = serializeLoggingData(obj);
9+
expect(result).toEqual({obj: '[Circular]'});
10+
});
11+
12+
it('should return the original value for non-circular references', () => {
13+
const obj: Record<string, unknown> = {};
14+
obj.foo = 'bar';
15+
const result = serializeLoggingData(obj);
16+
expect(result).toEqual({foo: 'bar'});
17+
});
18+
19+
it('should not stringify function in the object', () => {
20+
const obj: Record<string, unknown> = {
21+
foo: () => 'bar',
22+
baz: 'baz',
23+
};
24+
const result = serializeLoggingData(obj);
25+
expect(result).toEqual({baz: 'baz'});
26+
});
27+
});
28+
});

0 commit comments

Comments
 (0)