diff --git a/core-libs/setup/ssr/logger/loggers/default-express-server-logger.spec.ts b/core-libs/setup/ssr/logger/loggers/default-express-server-logger.spec.ts index 9f6bd811167..52f8ce642f7 100644 --- a/core-libs/setup/ssr/logger/loggers/default-express-server-logger.spec.ts +++ b/core-libs/setup/ssr/logger/loggers/default-express-server-logger.spec.ts @@ -1,7 +1,6 @@ import * as angularCore from '@angular/core'; import { Request } from 'express'; import { DefaultExpressServerLogger } from './default-express-server-logger'; -import { ExpressServerLoggerContext } from './express-server-logger'; const request = { originalUrl: 'test', @@ -33,7 +32,7 @@ describe('DefaultExpressServerLogger', () => { logger.log('test', { request: {} as Request }); expect(logSpy).toHaveBeenCalledWith( - logger['createLogMessage']('test', { request: {} as Request }) + logger['stringifyWithContext']('test', { request: {} as Request }) ); }); @@ -43,7 +42,7 @@ describe('DefaultExpressServerLogger', () => { logger.warn('test', { request: {} as Request }); expect(warnSpy).toHaveBeenCalledWith( - logger['createLogMessage']('test', { request: {} as Request }) + logger['stringifyWithContext']('test', { request: {} as Request }) ); }); @@ -55,7 +54,7 @@ describe('DefaultExpressServerLogger', () => { logger.error('test', { request: {} as Request }); expect(errorSpy).toHaveBeenCalledWith( - logger['createLogMessage']('test', { request: {} as Request }) + logger['stringifyWithContext']('test', { request: {} as Request }) ); }); @@ -65,7 +64,7 @@ describe('DefaultExpressServerLogger', () => { logger.info('test', { request: {} as Request }); expect(infoSpy).toHaveBeenCalledWith( - logger['createLogMessage']('test', { request: {} as Request }) + logger['stringifyWithContext']('test', { request: {} as Request }) ); }); @@ -77,7 +76,7 @@ describe('DefaultExpressServerLogger', () => { logger.debug('test', { request: {} as Request }); expect(debugSpy).toHaveBeenCalledWith( - logger['createLogMessage']('test', { request: {} as Request }) + logger['stringifyWithContext']('test', { request: {} as Request }) ); }); @@ -297,16 +296,13 @@ describe('DefaultExpressServerLogger', () => { describe('create log message', () => { it('should return message without request', () => { - const logMessage = logger['createLogMessage']( - 'test', - {} as ExpressServerLoggerContext - ); + const logMessage = logger['stringifyWithContext']('test', {}); expect(logMessage).not.toContain('request'); }); it('should return message with request', () => { - const logMessage = logger['createLogMessage']('test', { + const logMessage = logger['stringifyWithContext']('test', { request: {} as Request, }); @@ -314,6 +310,36 @@ describe('DefaultExpressServerLogger', () => { }); }); + describe('map context', () => { + it('should return context without request', () => { + const context = logger['mapContext']({ + options: {}, + }); + + expect(context).toMatchInlineSnapshot(` + { + "options": {}, + "timestamp": "2023-05-26T00:00:00.000Z", + } + `); + }); + + it('should return context with request', () => { + const context = logger['mapContext']({ request }); + + expect(context).toMatchInlineSnapshot(` + { + "request": { + "timeReceived": 2023-05-26T00:00:00.000Z, + "url": "test", + "uuid": "test", + }, + "timestamp": "2023-05-26T00:00:00.000Z", + } + `); + }); + }); + describe('map request', () => { it('should return mapped request', () => { const request = { diff --git a/core-libs/setup/ssr/logger/loggers/default-express-server-logger.ts b/core-libs/setup/ssr/logger/loggers/default-express-server-logger.ts index 73d3ad0fcba..d6b7fc82b2f 100644 --- a/core-libs/setup/ssr/logger/loggers/default-express-server-logger.ts +++ b/core-libs/setup/ssr/logger/loggers/default-express-server-logger.ts @@ -20,48 +20,73 @@ import { export class DefaultExpressServerLogger implements ExpressServerLogger { log(message: string, context: ExpressServerLoggerContext): void { /* eslint-disable-next-line no-console */ - console.log(this.createLogMessage(message, context)); + console.log(this.stringifyWithContext(message, context)); } warn(message: string, context: ExpressServerLoggerContext): void { /* eslint-disable-next-line no-console */ - console.warn(this.createLogMessage(message, context)); + console.warn(this.stringifyWithContext(message, context)); } error(message: string, context: ExpressServerLoggerContext): void { /* eslint-disable-next-line no-console */ - console.error(this.createLogMessage(message, context)); + console.error(this.stringifyWithContext(message, context)); } info(message: string, context: ExpressServerLoggerContext): void { /* eslint-disable-next-line no-console */ - console.info(this.createLogMessage(message, context)); + console.info(this.stringifyWithContext(message, context)); } debug(message: string, context: ExpressServerLoggerContext): void { /* eslint-disable-next-line no-console */ - console.debug(this.createLogMessage(message, context)); + console.debug(this.stringifyWithContext(message, context)); } - protected createLogMessage( + /** + * Converts a message and an ExpressServerLoggerContext object into a single JSON string containing both pieces of information, which can be used for logging purposes. + * + * @protected + * @param message - The message to be included in the log entry. + * @param context - The context object associated with the log entry. + * @returns A JSON string containing both the message and context information, suitable for logging. + */ + protected stringifyWithContext( message: string, context: ExpressServerLoggerContext ): string { + const logObject = { message, context: this.mapContext(context) }; + + return isDevMode() + ? JSON.stringify(logObject, null, 2) + : JSON.stringify(logObject); + } + + /** + * Map the context for the ExpressServerLogger + * + * @protected + * @param context - The logging context object to be mapped + * @returns - The mapped context with timestamp and request (if available) + */ + protected mapContext( + context: ExpressServerLoggerContext + ): Record { const timestamp = new Date().toISOString(); - const object = { - message, - context: { - timestamp, - ...context, - }, - }; + const outputContext = { timestamp, ...context }; + if (context.request) { - Object.assign(object.context, { + Object.assign(outputContext, { request: this.mapRequest(context.request), }); } - return isDevMode() - ? JSON.stringify(object, null, 2) - : JSON.stringify(object); + return outputContext; } + /** + * Maps a Request object into a JavaScript object with specific properties. + * + * @protected + * @param request - An Express Request object. + * @returns - A mapped request object. By default, it contains only "url", a random "uuid" and "timeReceived" of the request. + */ protected mapRequest(request: Request): Record { return { url: request.originalUrl, diff --git a/core-libs/setup/ssr/logger/loggers/express-server-logger.ts b/core-libs/setup/ssr/logger/loggers/express-server-logger.ts index 54e789000f2..5cff6937dd3 100644 --- a/core-libs/setup/ssr/logger/loggers/express-server-logger.ts +++ b/core-libs/setup/ssr/logger/loggers/express-server-logger.ts @@ -9,10 +9,10 @@ import { Request } from 'express'; /** * ExpressServerLoggerContext is used for log message in server side rendering. - * It contains request object and additional properties that can be used in log message. + * It contains optional request object and additional properties that can be used in log message. */ export interface ExpressServerLoggerContext { - request: Request; + request?: Request; [_key: string]: any; } diff --git a/core-libs/setup/ssr/optimized-engine/optimized-ssr-engine.ts b/core-libs/setup/ssr/optimized-engine/optimized-ssr-engine.ts index 5a3afc3f442..8faa7c2f275 100644 --- a/core-libs/setup/ssr/optimized-engine/optimized-ssr-engine.ts +++ b/core-libs/setup/ssr/optimized-engine/optimized-ssr-engine.ts @@ -95,7 +95,7 @@ export class OptimizedSsrEngine { if (this.ssrOptions.logger) { this.log(`[spartacus] SSR optimization engine initialized`, true, { options: loggableSsrOptions, - } as unknown as ExpressServerLoggerContext); //it expects ExpressServerLoggerContext, but the current logged message is printed at the start of the server and there is no request available yet. + }); } else { const stringifiedOptions = JSON.stringify(loggableSsrOptions, null, 2); this.log( @@ -335,7 +335,7 @@ export class OptimizedSsrEngine { context?: ExpressServerLoggerContext ): void { if (debug || this.ssrOptions?.debug) { - this.logger.log(message, context || ({} as ExpressServerLoggerContext)); + this.logger.log(message, context || {}); } } diff --git a/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.spec.ts b/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.spec.ts index b43464fcdde..ddd6ea81e49 100644 --- a/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.spec.ts +++ b/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.spec.ts @@ -727,6 +727,7 @@ describe('CpqConfiguratorNormalizer', () => { expect(group.attributes?.length).toBe(1); if (group.attributes) { expect(group.attributes[0].attrCode).toBe(cpqAttributeStdAttrCode); + expect(group.attributes[0].groupId).toBe(cpqGroupId.toString()); } else { fail(); } @@ -746,7 +747,7 @@ describe('CpqConfiguratorNormalizer', () => { expect(groups.length).toBe(1); expect(flatGroups.length).toBe(1); const group: Configurator.Group = groups[0]; - expect(group.id).toBe('0'); + expect(group.id).toBe('1'); expect(group.name).toBe('_GEN'); expect(group.description).toBe('General'); expect(group.configurable).toBe(true); diff --git a/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.ts b/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.ts index e0c5ce76172..d669b7a58e1 100644 --- a/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.ts +++ b/feature-libs/product-configurator/rulebased/cpq/rest/converters/cpq-configurator-normalizer.ts @@ -132,10 +132,10 @@ export class CpqConfiguratorNormalizer ) { const attributes: Configurator.Attribute[] = []; sourceAttributes.forEach((sourceAttribute) => - this.convertAttribute(sourceAttribute, 0, currency, attributes) + this.convertAttribute(sourceAttribute, 1, currency, attributes) ); const group: Configurator.Group = { - id: '0', + id: '1', name: '_GEN', configurable: true, complete: incompleteAttributes.length === 0,