Skip to content
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

feat: CXSPA-2067 SSR Logging - Trace Context #17597

Merged
merged 31 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8d21931
feat: CXSPA-2067 SSR Logging - Trace Context
pawelfras Jun 30, 2023
11ff1c6
Add license header
github-actions[bot] Jun 30, 2023
8332b22
Merge branch 'develop-6.3.x' into feature/CXSPA-2067
pawelfras Jun 30, 2023
2128942
remove testin property
pawelfras Jun 30, 2023
4f070d4
adding more secure parser + refactor after review
pawelfras Aug 8, 2023
4b6a6b9
Add license header
github-actions[bot] Aug 8, 2023
acc37ab
fixing sonar issues
pawelfras Aug 8, 2023
368689a
Merge branch 'develop-6.4.x' into feature/CXSPA-2067
pawelfras Aug 8, 2023
4ccd1be
removing test values
pawelfras Aug 8, 2023
46a09de
adding error handling
pawelfras Aug 9, 2023
1bf0bec
fixing sonar issues
pawelfras Aug 24, 2023
6d312ec
refactor after review
pawelfras Sep 5, 2023
4faaea3
Add license header
github-actions[bot] Sep 5, 2023
a080d01
move request context logic to the separate file
pawelfras Sep 7, 2023
9a79313
refactor after review
pawelfras Sep 8, 2023
46151db
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 8, 2023
a494041
refactor after review
pawelfras Sep 11, 2023
5676812
refactor after review
pawelfras Sep 13, 2023
5d7c49d
Update core-libs/setup/ssr/optimized-engine/request-context.ts
pawelfras Sep 13, 2023
7959822
Update core-libs/setup/ssr/optimized-engine/request-context.ts
pawelfras Sep 13, 2023
47803a1
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 14, 2023
5d1774f
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
Platonn Sep 14, 2023
82a0ab7
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 18, 2023
9f20a21
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 19, 2023
af6d5ad
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
giancorderoortiz Sep 20, 2023
bf761ca
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 21, 2023
f0d45ab
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Sep 27, 2023
5b413d7
Merge branch 'develop-6.5.x' into feature/CXSPA-2067
pawelfras Oct 4, 2023
7438cb1
remove invalid traceparent from logs
pawelfras Oct 5, 2023
b50f2af
Merge branch 'develop-6.6.x' into feature/CXSPA-2067
pawelfras Oct 5, 2023
5d01b6a
Trigger Build
pawelfras Oct 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('decorateExpressEngine', () => {
req: {
protocol: 'https',
originalUrl: '/electronics/en/USD/cart',
get: jest.fn(() => 'site.com'),
get: jest.fn(() => {}),
app,
connection: {},
res: <Partial<Response>>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ const request = {
res: {
locals: {
cx: {
request: { uuid: 'test', timeReceived: new Date('2023-05-26') },
request: {
uuid: 'test',
timeReceived: new Date('2023-05-26'),
traceContext: {
version: '00',
traceId: 'd745f6735b44e81c0ae5410cb1fc8a0c',
parentId: '1b527c3828976b39',
traceFlags: '01',
},
},
},
},
},
Expand All @@ -26,60 +35,6 @@ describe('DefaultExpressServerLogger', () => {
expect(logger).toBeDefined();
});

it('should log message', () => {
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});

logger.log('test', { request: {} as Request });

expect(logSpy).toHaveBeenCalledWith(
logger['stringifyWithContext']('test', { request: {} as Request })
);
});

it('should warn message', () => {
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

logger.warn('test', { request: {} as Request });

expect(warnSpy).toHaveBeenCalledWith(
logger['stringifyWithContext']('test', { request: {} as Request })
);
});

it('should error message', () => {
const errorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});

logger.error('test', { request: {} as Request });

expect(errorSpy).toHaveBeenCalledWith(
logger['stringifyWithContext']('test', { request: {} as Request })
);
});

it('should info message', () => {
const infoSpy = jest.spyOn(console, 'info').mockImplementation(() => {});

logger.info('test', { request: {} as Request });

expect(infoSpy).toHaveBeenCalledWith(
logger['stringifyWithContext']('test', { request: {} as Request })
);
});

it('should debug message', () => {
const debugSpy = jest
.spyOn(console, 'debug')
.mockImplementation(() => {});

logger.debug('test', { request: {} as Request });

expect(debugSpy).toHaveBeenCalledWith(
logger['stringifyWithContext']('test', { request: {} as Request })
);
});

describe('is not dev mode', () => {
beforeEach(() => {
jest.spyOn(angularCore, 'isDevMode').mockReturnValue(false);
Expand All @@ -94,7 +49,7 @@ describe('DefaultExpressServerLogger', () => {

expect(debugSpy.mock.lastCall).toMatchInlineSnapshot(`
[
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z"}}}",
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z","traceContext":{"version":"00","traceId":"d745f6735b44e81c0ae5410cb1fc8a0c","parentId":"1b527c3828976b39","traceFlags":"01"}}}}",
]
`);
});
Expand All @@ -108,7 +63,7 @@ describe('DefaultExpressServerLogger', () => {

expect(debugSpy.mock.lastCall).toMatchInlineSnapshot(`
[
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z"}}}",
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z","traceContext":{"version":"00","traceId":"d745f6735b44e81c0ae5410cb1fc8a0c","parentId":"1b527c3828976b39","traceFlags":"01"}}}}",
]
`);
});
Expand All @@ -122,23 +77,12 @@ describe('DefaultExpressServerLogger', () => {

expect(debugSpy.mock.lastCall).toMatchInlineSnapshot(`
[
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z"}}}",
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z","traceContext":{"version":"00","traceId":"d745f6735b44e81c0ae5410cb1fc8a0c","parentId":"1b527c3828976b39","traceFlags":"01"}}}}",
]
`);
});

it('should info proper shape of the JSON', () => {
const request = {
originalUrl: 'test',
res: {
locals: {
cx: {
request: { uuid: 'test', timeReceived: new Date() },
},
},
},
} as unknown as Request;

const debugSpy = jest
.spyOn(console, 'info')
.mockImplementation(() => {});
Expand All @@ -147,7 +91,7 @@ describe('DefaultExpressServerLogger', () => {

expect(debugSpy.mock.lastCall).toMatchInlineSnapshot(`
[
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z"}}}",
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z","traceContext":{"version":"00","traceId":"d745f6735b44e81c0ae5410cb1fc8a0c","parentId":"1b527c3828976b39","traceFlags":"01"}}}}",
]
`);
});
Expand All @@ -161,7 +105,7 @@ describe('DefaultExpressServerLogger', () => {

expect(debugSpy.mock.lastCall).toMatchInlineSnapshot(`
[
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z"}}}",
"{"message":"test","context":{"timestamp":"2023-05-26T00:00:00.000Z","request":{"url":"test","uuid":"test","timeReceived":"2023-05-26T00:00:00.000Z","traceContext":{"version":"00","traceId":"d745f6735b44e81c0ae5410cb1fc8a0c","parentId":"1b527c3828976b39","traceFlags":"01"}}}}",
]
`);
});
Expand All @@ -188,7 +132,13 @@ describe('DefaultExpressServerLogger', () => {
"request": {
"url": "test",
"uuid": "test",
"timeReceived": "2023-05-26T00:00:00.000Z"
"timeReceived": "2023-05-26T00:00:00.000Z",
"traceContext": {
"version": "00",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"parentId": "1b527c3828976b39",
"traceFlags": "01"
}
}
}
}",
Expand All @@ -212,7 +162,13 @@ describe('DefaultExpressServerLogger', () => {
"request": {
"url": "test",
"uuid": "test",
"timeReceived": "2023-05-26T00:00:00.000Z"
"timeReceived": "2023-05-26T00:00:00.000Z",
"traceContext": {
"version": "00",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"parentId": "1b527c3828976b39",
"traceFlags": "01"
}
}
}
}",
Expand All @@ -236,7 +192,13 @@ describe('DefaultExpressServerLogger', () => {
"request": {
"url": "test",
"uuid": "test",
"timeReceived": "2023-05-26T00:00:00.000Z"
"timeReceived": "2023-05-26T00:00:00.000Z",
"traceContext": {
"version": "00",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"parentId": "1b527c3828976b39",
"traceFlags": "01"
}
}
}
}",
Expand All @@ -260,7 +222,13 @@ describe('DefaultExpressServerLogger', () => {
"request": {
"url": "test",
"uuid": "test",
"timeReceived": "2023-05-26T00:00:00.000Z"
"timeReceived": "2023-05-26T00:00:00.000Z",
"traceContext": {
"version": "00",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"parentId": "1b527c3828976b39",
"traceFlags": "01"
}
}
}
}",
Expand All @@ -284,7 +252,13 @@ describe('DefaultExpressServerLogger', () => {
"request": {
"url": "test",
"uuid": "test",
"timeReceived": "2023-05-26T00:00:00.000Z"
"timeReceived": "2023-05-26T00:00:00.000Z",
"traceContext": {
"version": "00",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"parentId": "1b527c3828976b39",
"traceFlags": "01"
}
}
}
}",
Expand All @@ -303,7 +277,7 @@ describe('DefaultExpressServerLogger', () => {

it('should return message with request', () => {
const logMessage = logger['stringifyWithContext']('test', {
request: {} as Request,
request,
});

expect(logMessage).toContain('request');
Expand Down Expand Up @@ -331,6 +305,12 @@ describe('DefaultExpressServerLogger', () => {
{
"request": {
"timeReceived": 2023-05-26T00:00:00.000Z,
"traceContext": {
"parentId": "1b527c3828976b39",
"traceFlags": "01",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"version": "00",
},
"url": "test",
"uuid": "test",
},
Expand All @@ -342,23 +322,47 @@ describe('DefaultExpressServerLogger', () => {

describe('map request', () => {
it('should return mapped request', () => {
const request = {
const mappedRequest = logger['mapRequest'](request);

expect(mappedRequest).toMatchInlineSnapshot(`
{
"timeReceived": 2023-05-26T00:00:00.000Z,
"traceContext": {
"parentId": "1b527c3828976b39",
"traceFlags": "01",
"traceId": "d745f6735b44e81c0ae5410cb1fc8a0c",
"version": "00",
},
"url": "test",
"uuid": "test",
}
`);
});

it('should return mapped request without traceContext prop if traceparent is not available', () => {
const requestWithoutTraceContext = {
originalUrl: 'test',
res: {
locals: {
cx: {
request: { uuid: 'test', timeReceived: new Date() },
request: {
uuid: 'test',
timeReceived: new Date('2023-05-26'),
},
},
},
},
} as any;
} as unknown as Request;

const mappedRequest = logger['mapRequest'](request);
const mappedRequest = logger['mapRequest'](requestWithoutTraceContext);

expect(mappedRequest).toEqual({
url: 'test',
...request.res?.locals.cx.request,
});
expect(mappedRequest).toMatchInlineSnapshot(`
{
"timeReceived": 2023-05-26T00:00:00.000Z,
"url": "test",
"uuid": "test",
}
`);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { isDevMode } from '@angular/core';
import { Request } from 'express';
import { getRequestContext } from '../../optimized-engine/request-context';
import {
ExpressServerLogger,
ExpressServerLoggerContext,
Expand All @@ -16,6 +17,11 @@ import {
* Default logger used in SSR (ExpressJS) to enhance logs visible e.g. in monitoring tools e.g. Kibana.
* It outputs a JSON with properties "message" and "context",
* which contains a "timestamp" and details of the "request" ("url", "uuid", "timeReceived")
*
* The output "context" JSON will contain also a property "traceContext"
* with "traceId", "parentId", "version" and "traceFlags",
* if only the given request has the special header "traceparent" (specifed in
* the "W3C TraceContext" document. See https://www.w3.org/TR/trace-context/#traceparent-header ).
*/
export class DefaultExpressServerLogger implements ExpressServerLogger {
log(message: string, context: ExpressServerLoggerContext): void {
Expand Down Expand Up @@ -90,7 +96,7 @@ export class DefaultExpressServerLogger implements ExpressServerLogger {
protected mapRequest(request: Request): Record<string, any> {
return {
url: request.originalUrl,
...request.res?.locals.cx.request,
...getRequestContext(request),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { InvalidTraceparentFormatError } from './invalid-traceparent-format-error';

describe('InvalidTraceparentFormatError', () => {
it('should be an instance of InstantiationError', () => {
const error = new InvalidTraceparentFormatError();
expect(error).toBeInstanceOf(InvalidTraceparentFormatError);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2023 SAP Spartacus team <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Error thrown when the traceparent header has an invalid format.
*/
export class InvalidTraceparentFormatError extends Error {
constructor() {
super('Traceparent header has invalid format.');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { InvalidTraceparentLengthError } from './invalid-traceparent-length-error';

describe('InvalidTraceparentFormatError', () => {
it('should be an instance of InstantiationError', () => {
const error = new InvalidTraceparentLengthError(0);
expect(error).toBeInstanceOf(InvalidTraceparentLengthError);
});

it('should have the correct message', () => {
const error = new InvalidTraceparentLengthError(20);
expect(error.message).toBe(
`Traceparent header has invalid length: ${20}. Expected 55 characters.`
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2023 SAP Spartacus team <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Error thrown when the traceparent header has an invalid length.
* @param traceparentLength The length of the traceparent header.
*/
export class InvalidTraceparentLengthError extends Error {
constructor(traceparentLength: number) {
super(
`Traceparent header has invalid length: ${traceparentLength}. Expected 55 characters.`
);
}
}
Loading
Loading