From 51701415e10d23b8d73a10254cd1f86a4ac7f274 Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Wed, 21 Jan 2026 17:45:53 +0100 Subject: [PATCH 01/14] feat(logger): added ConsoleJsonLogTransportService BREAKING CHANGE: - requires `@shiftcode/logger@^4.0.0` - ConsoleLogTransport renamed to BrowserConsoleLogTransportService and using its own config `BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG` - NodeConsoleLogTransport renamed to NodeConsoleLogTransportService and using its own config `NODE_CONSOLE_LOG_TRANSPORT_CONFIG` --- libs/components/package.json | 2 +- libs/core/package.json | 2 +- .../browser-console-log-transport.service.ts} | 31 +++-- ...with-browser-console-transport.function.ts | 28 ++++ .../console-json-log-transport.service.ts | 17 +++ ...ith-console-json-log-transport.function.ts | 27 ++++ ...le-log-transport-config.injection-token.ts | 5 - .../console/console-log-transport-config.ts | 5 - .../node-console-log-transport.service.ts | 54 -------- ...with-browser-console-transport.function.ts | 21 --- .../with-node-console-transport.function.ts | 21 --- .../helper/logging-time-format.const.spec.ts | 18 +++ .../helper/logging-time-format.const.ts | 10 ++ .../logger/helper/value-or-factory.type.ts | 1 + .../node-console/log-level-emoji.const.ts | 3 + .../node-console-log-transport.service.ts | 120 ++++++++++++++++++ .../with-node-console-transport.function.ts | 27 ++++ libs/core/src/public-api.ts | 12 +- package-lock.json | 14 +- package.json | 4 +- 20 files changed, 287 insertions(+), 135 deletions(-) rename libs/core/src/lib/logger/{console/console-log-transport.service.ts => browser-console/browser-console-log-transport.service.ts} (61%) create mode 100644 libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts create mode 100644 libs/core/src/lib/logger/console-json/console-json-log-transport.service.ts create mode 100644 libs/core/src/lib/logger/console-json/with-console-json-log-transport.function.ts delete mode 100644 libs/core/src/lib/logger/console/console-log-transport-config.injection-token.ts delete mode 100644 libs/core/src/lib/logger/console/console-log-transport-config.ts delete mode 100644 libs/core/src/lib/logger/console/node-console-log-transport.service.ts delete mode 100644 libs/core/src/lib/logger/console/with-browser-console-transport.function.ts delete mode 100644 libs/core/src/lib/logger/console/with-node-console-transport.function.ts create mode 100644 libs/core/src/lib/logger/helper/logging-time-format.const.spec.ts create mode 100644 libs/core/src/lib/logger/helper/logging-time-format.const.ts create mode 100644 libs/core/src/lib/logger/helper/value-or-factory.type.ts create mode 100644 libs/core/src/lib/logger/node-console/log-level-emoji.const.ts create mode 100644 libs/core/src/lib/logger/node-console/node-console-log-transport.service.ts create mode 100644 libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts diff --git a/libs/components/package.json b/libs/components/package.json index 0dcebe58..0c789cc4 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -20,7 +20,7 @@ "@angular/core": "^21.0.3", "@angular/forms": "^21.0.3", "@angular/router": "^21.0.3", - "@shiftcode/logger": "^3.0.0", + "@shiftcode/logger": "^4.0.0-pr250", "@shiftcode/ngx-core": "^13.0.0 || ^13.0.0-pr63", "rxjs": "^6.5.3 || ^7.4.0" } diff --git a/libs/core/package.json b/libs/core/package.json index ab530636..9bac9739 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -18,7 +18,7 @@ "@angular/core": "^21.0.3", "@angular/platform-browser": "^21.0.3", "@angular/router": "^21.0.3", - "@shiftcode/logger": "^3.0.0", + "@shiftcode/logger": "^4.0.0-pr250", "@shiftcode/utilities": "^4.0.0", "rxjs": "^6.5.3 || ^7.4.0" } diff --git a/libs/core/src/lib/logger/console/console-log-transport.service.ts b/libs/core/src/lib/logger/browser-console/browser-console-log-transport.service.ts similarity index 61% rename from libs/core/src/lib/logger/console/console-log-transport.service.ts rename to libs/core/src/lib/logger/browser-console/browser-console-log-transport.service.ts index d7b1ee4f..ebeab7da 100644 --- a/libs/core/src/lib/logger/console/console-log-transport.service.ts +++ b/libs/core/src/lib/logger/browser-console/browser-console-log-transport.service.ts @@ -1,15 +1,22 @@ -/* eslint-disable no-console */ import { isPlatformServer } from '@angular/common' -import { inject, Injectable, PLATFORM_ID } from '@angular/core' +import { inject, Injectable, InjectionToken, PLATFORM_ID } from '@angular/core' import { LogLevel, LogTransport } from '@shiftcode/logger' -import { leadingZero } from '../helper/leading-zero.function' -import { CONSOLE_LOG_TRANSPORT_CONFIG } from './console-log-transport-config.injection-token' +import { loggingTimeFormat } from '../helper/logging-time-format.const' + +export interface BrowserConsoleLogTransportConfig { + logLevel: LogLevel +} + +export const BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG = new InjectionToken( + 'BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG', + { factory: () => ({ logLevel: LogLevel.DEBUG }) }, +) @Injectable({ providedIn: 'root' }) -export class ConsoleLogTransport extends LogTransport { +export class BrowserConsoleLogTransportService extends LogTransport { constructor() { - super(inject(CONSOLE_LOG_TRANSPORT_CONFIG).logLevel) + super(inject(BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG).logLevel) if (isPlatformServer(inject(PLATFORM_ID))) { throw new Error('This log transport is only for client side use - consider using "NodeConsoleLogTransport"') } @@ -17,12 +24,8 @@ export class ConsoleLogTransport extends LogTransport { log(level: LogLevel, clazzName: string, color: string, timestamp: Date, args: any[]) { if (this.isLevelEnabled(level)) { - const now = [ - leadingZero(2, timestamp.getHours()), - leadingZero(2, timestamp.getMinutes()), - leadingZero(2, timestamp.getSeconds()), - leadingZero(3, timestamp.getMilliseconds()), - ].join(':') // 'HH:mm:ss:SSS' + const now = loggingTimeFormat.format(timestamp) + const firstArgument = args.splice(0, 1)[0] if (typeof firstArgument === 'string') { @@ -32,6 +35,7 @@ export class ConsoleLogTransport extends LogTransport { args.splice(0, 0, `%c${now} - ${clazzName} ::`, `color:${color}`, firstArgument) } + /* eslint-disable no-console */ switch (level) { case LogLevel.DEBUG: console.debug(...args) @@ -47,7 +51,10 @@ export class ConsoleLogTransport extends LogTransport { break case LogLevel.OFF: break + default: + return level // exhaustive check } + /* eslint-enable no-console */ } } } diff --git a/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts b/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts new file mode 100644 index 00000000..4a9551ca --- /dev/null +++ b/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts @@ -0,0 +1,28 @@ +import { LogTransport } from '@shiftcode/logger' + +import { LoggerFeature } from '../logger-feature.type' +import { LoggerFeatureKind } from '../logger-feature-kind.enum' +import { + BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG, + BrowserConsoleLogTransportConfig, + BrowserConsoleLogTransportService, +} from './browser-console-log-transport.service' + +export function withBrowserConsoleTransport( + browserConsoleLogTransportConfigOrFactory: + | BrowserConsoleLogTransportConfig + | (() => BrowserConsoleLogTransportConfig), +): LoggerFeature { + const configProvider = + typeof browserConsoleLogTransportConfigOrFactory === 'function' + ? { provide: BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG, useFactory: browserConsoleLogTransportConfigOrFactory } + : { provide: BROWSER_CONSOLE_LOG_TRANSPORT_CONFIG, useValue: browserConsoleLogTransportConfigOrFactory } + + return { + kind: LoggerFeatureKind.TRANSPORT, + providers: [ + configProvider, + { provide: LogTransport, useClass: BrowserConsoleLogTransportService, multi: true } + ], + } +} diff --git a/libs/core/src/lib/logger/console-json/console-json-log-transport.service.ts b/libs/core/src/lib/logger/console-json/console-json-log-transport.service.ts new file mode 100644 index 00000000..2761d907 --- /dev/null +++ b/libs/core/src/lib/logger/console-json/console-json-log-transport.service.ts @@ -0,0 +1,17 @@ +import { inject, Injectable, InjectionToken } from '@angular/core' +import { LogLevel } from '@shiftcode/logger' +import { ConsoleJsonLogTransport, ConsoleJsonLogTransportConfig } from '@shiftcode/logger' + +export { ConsoleJsonLogTransportConfig } from '@shiftcode/logger' + +export const CONSOLE_JSON_LOG_TRANSPORT_CONFIG = new InjectionToken( + 'CONSOLE_JSON_LOG_TRANSPORT_CONFIG', + { factory: () => ({ logLevel: LogLevel.DEBUG }) }, +) + +@Injectable({ providedIn: 'root' }) +export class ConsoleJsonLogTransportService extends ConsoleJsonLogTransport { + constructor() { + super(inject(CONSOLE_JSON_LOG_TRANSPORT_CONFIG)) + } +} diff --git a/libs/core/src/lib/logger/console-json/with-console-json-log-transport.function.ts b/libs/core/src/lib/logger/console-json/with-console-json-log-transport.function.ts new file mode 100644 index 00000000..125c148f --- /dev/null +++ b/libs/core/src/lib/logger/console-json/with-console-json-log-transport.function.ts @@ -0,0 +1,27 @@ +import { LogTransport } from '@shiftcode/logger' + +import { ValueOrFactory } from '../helper/value-or-factory.type' +import { LoggerFeature } from '../logger-feature.type' +import { LoggerFeatureKind } from '../logger-feature-kind.enum' +import { + CONSOLE_JSON_LOG_TRANSPORT_CONFIG, + ConsoleJsonLogTransportConfig, + ConsoleJsonLogTransportService, +} from './console-json-log-transport.service' + +export function withConsoleJsonLogTransport( + consoleJsonLogTransportConfig: ValueOrFactory, +): LoggerFeature { + return { + kind: LoggerFeatureKind.TRANSPORT, + providers: [ + { + provide: CONSOLE_JSON_LOG_TRANSPORT_CONFIG, + ...(typeof consoleJsonLogTransportConfig === 'function' + ? { useFactory: consoleJsonLogTransportConfig } + : { useValue: consoleJsonLogTransportConfig }), + }, + { provide: LogTransport, useClass: ConsoleJsonLogTransportService, multi: true }, + ], + } +} diff --git a/libs/core/src/lib/logger/console/console-log-transport-config.injection-token.ts b/libs/core/src/lib/logger/console/console-log-transport-config.injection-token.ts deleted file mode 100644 index f014d9ac..00000000 --- a/libs/core/src/lib/logger/console/console-log-transport-config.injection-token.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { InjectionToken } from '@angular/core' - -import { ConsoleLogTransportConfig } from './console-log-transport-config' - -export const CONSOLE_LOG_TRANSPORT_CONFIG = new InjectionToken('consoleLogTransportConfig') diff --git a/libs/core/src/lib/logger/console/console-log-transport-config.ts b/libs/core/src/lib/logger/console/console-log-transport-config.ts deleted file mode 100644 index f6cf4f06..00000000 --- a/libs/core/src/lib/logger/console/console-log-transport-config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LogLevel } from '@shiftcode/logger' - -export interface ConsoleLogTransportConfig { - logLevel: LogLevel -} diff --git a/libs/core/src/lib/logger/console/node-console-log-transport.service.ts b/libs/core/src/lib/logger/console/node-console-log-transport.service.ts deleted file mode 100644 index 9cedf5ae..00000000 --- a/libs/core/src/lib/logger/console/node-console-log-transport.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* eslint-disable no-console */ -import { isPlatformBrowser } from '@angular/common' -import { inject, Injectable, PLATFORM_ID } from '@angular/core' -import { LogLevel, LogTransport } from '@shiftcode/logger' -import { colorizeForConsole } from '@shiftcode/utilities' - -import { leadingZero } from '../helper/leading-zero.function' -import { CONSOLE_LOG_TRANSPORT_CONFIG } from './console-log-transport-config.injection-token' - -@Injectable({ providedIn: 'root' }) -export class NodeConsoleLogTransport extends LogTransport { - constructor() { - super(inject(CONSOLE_LOG_TRANSPORT_CONFIG).logLevel) - if (isPlatformBrowser(inject(PLATFORM_ID))) { - throw new Error('This log transport is only for server side use - consider using "ConsoleLogTransport"') - } - } - - log(level: LogLevel, clazzName: string, hexColor: string, timestamp: Date, args: any[]) { - if (this.isLevelEnabled(level)) { - const now = [ - leadingZero(2, timestamp.getHours()), - leadingZero(2, timestamp.getMinutes()), - leadingZero(2, timestamp.getSeconds()), - leadingZero(3, timestamp.getMilliseconds()), - ].join(':') // 'HH:mm:ss:SSS' - const firstArgument = args.splice(0, 1)[0] - - if (typeof firstArgument === 'string') { - // we have a string with potential message format - args.splice(0, 0, colorizeForConsole(`${now} - ${clazzName} :: ${firstArgument}`, hexColor)) - } else { - args.splice(0, 0, colorizeForConsole(`${now} - ${clazzName} ::`, hexColor), firstArgument) - } - - switch (level) { - case LogLevel.DEBUG: - console.debug(...args) - break - case LogLevel.ERROR: - console.error(...args) - break - case LogLevel.INFO: - console.info(...args) - break - case LogLevel.WARN: - console.warn(...args) - break - case LogLevel.OFF: - break - } - } - } -} diff --git a/libs/core/src/lib/logger/console/with-browser-console-transport.function.ts b/libs/core/src/lib/logger/console/with-browser-console-transport.function.ts deleted file mode 100644 index e2694160..00000000 --- a/libs/core/src/lib/logger/console/with-browser-console-transport.function.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { LogTransport } from '@shiftcode/logger' - -import { LoggerFeature } from '../logger-feature.type' -import { LoggerFeatureKind } from '../logger-feature-kind.enum' -import { ConsoleLogTransport } from './console-log-transport.service' -import { ConsoleLogTransportConfig } from './console-log-transport-config' -import { CONSOLE_LOG_TRANSPORT_CONFIG } from './console-log-transport-config.injection-token' - -export function withBrowserConsoleTransport( - consoleLoggerConfigOrFactory: ConsoleLogTransportConfig | (() => ConsoleLogTransportConfig), -): LoggerFeature { - const configProvider = - typeof consoleLoggerConfigOrFactory === 'function' - ? { provide: CONSOLE_LOG_TRANSPORT_CONFIG, useFactory: consoleLoggerConfigOrFactory } - : { provide: CONSOLE_LOG_TRANSPORT_CONFIG, useValue: consoleLoggerConfigOrFactory } - - return { - kind: LoggerFeatureKind.TRANSPORT, - providers: [configProvider, { provide: LogTransport, useClass: ConsoleLogTransport, multi: true }], - } -} diff --git a/libs/core/src/lib/logger/console/with-node-console-transport.function.ts b/libs/core/src/lib/logger/console/with-node-console-transport.function.ts deleted file mode 100644 index 33729321..00000000 --- a/libs/core/src/lib/logger/console/with-node-console-transport.function.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { LogTransport } from '@shiftcode/logger' - -import { LoggerFeature } from '../logger-feature.type' -import { LoggerFeatureKind } from '../logger-feature-kind.enum' -import { ConsoleLogTransportConfig } from './console-log-transport-config' -import { CONSOLE_LOG_TRANSPORT_CONFIG } from './console-log-transport-config.injection-token' -import { NodeConsoleLogTransport } from './node-console-log-transport.service' - -export function withNodeConsoleTransport( - consoleLoggerConfigOrFactory: ConsoleLogTransportConfig | (() => ConsoleLogTransportConfig), -): LoggerFeature { - const configProvider = - typeof consoleLoggerConfigOrFactory === 'function' - ? { provide: CONSOLE_LOG_TRANSPORT_CONFIG, useFactory: consoleLoggerConfigOrFactory } - : { provide: CONSOLE_LOG_TRANSPORT_CONFIG, useValue: consoleLoggerConfigOrFactory } - - return { - kind: LoggerFeatureKind.TRANSPORT, - providers: [configProvider, { provide: LogTransport, useClass: NodeConsoleLogTransport, multi: true }], - } -} diff --git a/libs/core/src/lib/logger/helper/logging-time-format.const.spec.ts b/libs/core/src/lib/logger/helper/logging-time-format.const.spec.ts new file mode 100644 index 00000000..e926b236 --- /dev/null +++ b/libs/core/src/lib/logger/helper/logging-time-format.const.spec.ts @@ -0,0 +1,18 @@ +import { loggingTimeFormat } from './logging-time-format.const' + +describe('timeFormat', () => { + it('should format time as HH:mm:ss.SSS', () => { + const timestamp = new Date('2024-01-15T14:30:45.123Z') + expect(loggingTimeFormat.format(timestamp)).toBe(`14:30:45.123`) + }) + + it('should format another time as HH:mm:ss.SSS', () => { + const timestamp = new Date('2024-01-01T23:59:59.999Z') + expect(loggingTimeFormat.format(timestamp)).toBe(`23:59:59.999`) + }) + + it('should format time with leading zeros as HH:mm:ss.SSS', () => { + const timestamp = new Date('2024-01-01T01:02:03.004Z') + expect(loggingTimeFormat.format(timestamp)).toBe(`01:02:03.004`) + }) +}) diff --git a/libs/core/src/lib/logger/helper/logging-time-format.const.ts b/libs/core/src/lib/logger/helper/logging-time-format.const.ts new file mode 100644 index 00000000..8f442380 --- /dev/null +++ b/libs/core/src/lib/logger/helper/logging-time-format.const.ts @@ -0,0 +1,10 @@ +/** + * Time formatter for logging timestamps in 'HH:MM:SS.sss' format. + */ +export const loggingTimeFormat = new Intl.DateTimeFormat('en-US', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + fractionalSecondDigits: 3, + hour12: false, +}) diff --git a/libs/core/src/lib/logger/helper/value-or-factory.type.ts b/libs/core/src/lib/logger/helper/value-or-factory.type.ts new file mode 100644 index 00000000..795035b4 --- /dev/null +++ b/libs/core/src/lib/logger/helper/value-or-factory.type.ts @@ -0,0 +1 @@ +export type ValueOrFactory = T | (() => T) diff --git a/libs/core/src/lib/logger/node-console/log-level-emoji.const.ts b/libs/core/src/lib/logger/node-console/log-level-emoji.const.ts new file mode 100644 index 00000000..7efad25e --- /dev/null +++ b/libs/core/src/lib/logger/node-console/log-level-emoji.const.ts @@ -0,0 +1,3 @@ +import { LogLevel } from '@shiftcode/logger' + +export const logLevelEmoji: Record = ['🐞', '💬', '💣', '🔥', ''] diff --git a/libs/core/src/lib/logger/node-console/node-console-log-transport.service.ts b/libs/core/src/lib/logger/node-console/node-console-log-transport.service.ts new file mode 100644 index 00000000..af4757d4 --- /dev/null +++ b/libs/core/src/lib/logger/node-console/node-console-log-transport.service.ts @@ -0,0 +1,120 @@ +import { isPlatformBrowser } from '@angular/common' +import { inject, Injectable, InjectionToken, PLATFORM_ID } from '@angular/core' +import { getJsonStringifyReplacer, LogLevel, LogTransport } from '@shiftcode/logger' +import { colorizeForConsole, jsonMapSetStringifyReplacer } from '@shiftcode/utilities' + +import { loggingTimeFormat } from '../helper/logging-time-format.const' +import { logLevelEmoji } from './log-level-emoji.const' + +export interface NodeConsoleLogTransportConfig { + logLevel: LogLevel + + /** + * custom replacer function for JSON serialization, default to @shiftcode/utilities jsonMapSetStringifyReplacer + */ + jsonStringifyReplacer?: (key: string, value: unknown) => unknown + + /** max depth for object serialization, default is 5 */ + maxDepth?: number +} + +export const NODE_CONSOLE_LOG_TRANSPORT_CONFIG = new InjectionToken( + 'NODE_CONSOLE_LOG_TRANSPORT_CONFIG', + { factory: () => ({ logLevel: LogLevel.DEBUG }) }, +) + +// we do not extend the NodeConsoleLogTransport from @shiftcode/logger since it uses `node:utils` which would break ts here without further changes +@Injectable({ providedIn: 'root' }) +export class NodeConsoleLogTransportService extends LogTransport { + private readonly config: NodeConsoleLogTransportConfig + + constructor() { + const config = inject(NODE_CONSOLE_LOG_TRANSPORT_CONFIG) + super(config.logLevel) + this.config = config + + if (isPlatformBrowser(inject(PLATFORM_ID))) { + throw new Error('This log transport is only for server side use - consider using "ConsoleLogTransport"') + } + } + + log(level: LogLevel, clazzName: string, hexColor: string, timestamp: Date, args: any[]) { + if (this.isLevelEnabled(level)) { + const now = loggingTimeFormat.format(timestamp) + // make sure to not alter the input args array + if (typeof args[0] === 'string') { + // if first arg is string, also colorize it + args = [ + logLevelEmoji[level], + colorizeForConsole(`${now} - ${clazzName} :: ${args[0]}`, hexColor), + ...args.slice(1).map(this.stringifyJson), + ] + } else { + args = [ + logLevelEmoji[level], + colorizeForConsole(`${now} - ${clazzName} ::`, hexColor), + ...args.map(this.stringifyJson), + ] + } + + /* eslint-disable no-console */ + switch (level) { + case LogLevel.DEBUG: + console.debug(...args) + break + case LogLevel.ERROR: + console.error(...args) + break + case LogLevel.INFO: + console.info(...args) + break + case LogLevel.WARN: + console.warn(...args) + break + case LogLevel.OFF: + break + default: + return level // exhaustive check + } + /* eslint-enable no-console */ + } + } + + private readonly stringifyJson = (data: unknown) => { + const maxDepth = this.config.maxDepth ?? 5 + const jsonStringifyReplacer = getJsonStringifyReplacer( + this.config.jsonStringifyReplacer ?? jsonMapSetStringifyReplacer, + ) + + const seen = new WeakMap() + let refCounter = 0 + const handleDepthAndCircularRefs = (value: unknown, depth: number = 0): unknown => { + if (depth > maxDepth) { + return '[max depth reached]' + } + + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return `[circular ref #${seen.get(value)}]` + } else { + seen.set(value, ++refCounter) + } + + if (Array.isArray(value)) { + return value.map((v) => handleDepthAndCircularRefs(v, depth + 1)) + } + + const result: any = {} + for (const [k, v] of Object.entries(value)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + result[k] = handleDepthAndCircularRefs(v, depth + 1) + } + return result + } + + return value + } + + return JSON.stringify(handleDepthAndCircularRefs(data), jsonStringifyReplacer) + } +} diff --git a/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts b/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts new file mode 100644 index 00000000..9efcb1cc --- /dev/null +++ b/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts @@ -0,0 +1,27 @@ + +import { LogTransport } from '@shiftcode/logger' + +import { ValueOrFactory } from '../helper/value-or-factory.type' +import { LoggerFeature } from '../logger-feature.type' +import { LoggerFeatureKind } from '../logger-feature-kind.enum' +import { + NODE_CONSOLE_LOG_TRANSPORT_CONFIG, + NodeConsoleLogTransportService, +} from './node-console-log-transport.service' + +export function withNodeConsoleTransport( + nodeConsoleLogTransportConfig: ValueOrFactory, +): LoggerFeature { + return { + kind: LoggerFeatureKind.TRANSPORT, + providers: [ + { + provide: NODE_CONSOLE_LOG_TRANSPORT_CONFIG, + ...(typeof nodeConsoleLogTransportConfig === 'function' + ? { useFactory: nodeConsoleLogTransportConfig } + : { useValue: nodeConsoleLogTransportConfig }), + }, + { provide: LogTransport, useClass: NodeConsoleLogTransportService, multi: true }, + ], + } +} diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index 8fbbc565..82401a66 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -29,12 +29,12 @@ export * from './lib/logger/cloudwatch/is-error.function' export * from './lib/logger/cloudwatch/with-cloudwatch-transport.function' // console logger -export * from './lib/logger/console/console-log-transport.service' -export * from './lib/logger/console/console-log-transport-config' -export * from './lib/logger/console/console-log-transport-config.injection-token' -export * from './lib/logger/console/node-console-log-transport.service' -export * from './lib/logger/console/with-browser-console-transport.function' -export * from './lib/logger/console/with-node-console-transport.function' +export * from './lib/logger/browser-console/browser-console-log-transport.service' +export * from './lib/logger/browser-console/with-browser-console-transport.function' +export * from './lib/logger/console-json/console-json-log-transport.service' +export * from './lib/logger/console-json/with-console-json-log-transport.function' +export * from './lib/logger/node-console/node-console-log-transport.service' +export * from './lib/logger/node-console/with-node-console-transport.function' // remote logger export * from './lib/logger/remote/remote-log.service' diff --git a/package-lock.json b/package-lock.json index baaf1584..92991984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@angular/platform-browser": "~21.0.3", "@angular/router": "~21.0.3", "@angular/ssr": "~21.0.2", - "@shiftcode/logger": "^3.0.0", + "@shiftcode/logger": "^4.0.0-pr250.6", "@shiftcode/utilities": "^4.0.0", "rxjs": "^6.5.3 || ^7.4.0", "tslib": "^2.5.0" @@ -57,7 +57,7 @@ "zone.js": "~0.15.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || ^24.0.0" + "node": "^22.12.0 || ^24.0.0" }, "optionalDependencies": { "@nx/nx-linux-x64-gnu": "^19.4.2", @@ -11361,15 +11361,15 @@ } }, "node_modules/@shiftcode/logger": { - "version": "3.0.0", - "resolved": "https://npm.pkg.github.com/download/@shiftcode/logger/3.0.0/da9b7d65a0545ebb5499b5f7ffd2e86ef90c6ce2", - "integrity": "sha512-UAUiG9iWHfXQbumY2y1Z0JjZoPJ+Ebq9FOd/+aFnp9zJrt7+zRTUPDdGj4sQ7vf8Hvis3dzRUdEmW4swgomxlg==", + "version": "4.0.0-pr250.6", + "resolved": "https://npm.pkg.github.com/download/@shiftcode/logger/4.0.0-pr250.6/c9160a219cc16982a7c1e2e430be929f0247e7de", + "integrity": "sha512-S4RrWQC1yFRev32IqUGDINjG0K1YP+/Qafeb7QaO5yvp97dbeNuUe3vKLIkbJ8g/8gu5C4cj1gH0/OWNq0R/qg==", "license": "UNLICENSED", "engines": { - "node": "^20.0.0 || ^22.0.0" + "node": "^22.0.0 || ^24.0.0" }, "peerDependencies": { - "@shiftcode/utilities": "^4.0.0 || ^4.0.0-pr45" + "@shiftcode/utilities": "^4.0.0" } }, "node_modules/@shiftcode/publish-helper": { diff --git a/package.json b/package.json index bacd629d..27462698 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@angular/platform-browser": "~21.0.3", "@angular/router": "~21.0.3", "@angular/ssr": "~21.0.2", - "@shiftcode/logger": "^3.0.0", + "@shiftcode/logger": "^4.0.0-pr250.6", "@shiftcode/utilities": "^4.0.0", "rxjs": "^6.5.3 || ^7.4.0", "tslib": "^2.5.0" @@ -73,6 +73,6 @@ "@rollup/rollup-linux-x64-gnu": "^4.20.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || ^24.0.0" + "node": "^22.12.0 || ^24.0.0" } } From 7937a882dba1eaadd78a8f9458199436238c82f5 Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Wed, 21 Jan 2026 18:56:04 +0100 Subject: [PATCH 02/14] feat(logger): add withCloudWatchTransportV2 / CloudWatchLogTransportServiceV2 to be used with the new cdk construct `CloudWatchApi` --- .../cloud-watch-log-api.service.ts | 96 ++++++++++++ ...ch-log-transport-config.injection-token.ts | 18 +++ .../cloud-watch-log-transport.service.ts | 24 +++ .../cloud-watch-v2/cloud-watch.service.ts | 147 ++++++++++++++++++ .../lib/logger/cloud-watch-v2/log-utils.ts | 9 ++ .../with-cloud-watch-transport.function.ts | 23 +++ .../src/lib/logger/logger.service.spec.ts | 3 +- libs/core/src/public-api.ts | 6 + 8 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts new file mode 100644 index 00000000..14fed543 --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts @@ -0,0 +1,96 @@ +// eslint-disable-next-line max-classes-per-file +import { inject, Injectable } from '@angular/core' +import { ContentType } from '@shiftcode/utilities' +import { CommonHttpHeader } from '@shiftcode/utilities' + +import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport-config.injection-token' + +export interface LogStream { + logStreamName: string + creationTime: number + lastIngestionTime: number | null +} + +export interface LogEvent { + message: string + timestamp: number +} + +export interface WriteLogEvents { + logEvents: LogEvent[] +} + +export class HttpError extends Error { + override readonly name: string = 'HttpError' + + constructor( + readonly statusCode: number, + message: string, + ) { + super(`${statusCode} - ${message}`) + } +} + +export class HttpApiError extends HttpError { + override readonly name: string = 'HttpApiError' + + constructor( + statusCode: number, + readonly errorCode: string, + message: string, + ) { + super(statusCode, `${message} (${errorCode})`) + } +} + +@Injectable({ providedIn: 'root' }) +export class CloudWatchLogApiService { + static readonly LOG_STREAMS_PATH = '/streams' + static readonly LOG_STREAMS_LOGS_PATH = '/streams/{logStreamName}/logs' + + private readonly apiUrl = inject(CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2).apiUrl + + async createLogStream(logStreamName: string): Promise { + const resp = await fetch(new URL(CloudWatchLogApiService.LOG_STREAMS_PATH, this.apiUrl), { + method: 'POST', + headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, + body: JSON.stringify({ logStreamName }), + }) + await this.handleError(resp) + } + + async describeLogStream(logStreamName: string): Promise { + const result = await fetch(`${CloudWatchLogApiService.LOG_STREAMS_PATH}/${logStreamName}`, { + method: 'GET', + headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, + }) + await this.handleError(result) + return (await result.json()) as LogStream + } + + async writeLogs(logStreamName: string, logs: LogEvent[]): Promise { + // todo: use beaconApi ? + const resp = await fetch(`${CloudWatchLogApiService.LOG_STREAMS_PATH}/${logStreamName}/logs`, { + method: 'POST', + headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, + body: JSON.stringify({ logEvents: logs } satisfies WriteLogEvents), + }) + await this.handleError(resp) + } + + private async handleError(resp: Response): Promise { + if (!resp.ok) { + const errorResponse: object = (await resp.json().catch(() => ({}))) ?? {} + if ( + 'message' in errorResponse && + typeof errorResponse.message === 'string' && + 'code' in errorResponse && + typeof errorResponse.code === 'string' + ) { + throw new HttpApiError(resp.status, errorResponse.code, errorResponse.message) + } else { + throw new HttpError(resp.status, 'unknown error') + } + } + } +} diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts new file mode 100644 index 00000000..2afaafca --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts @@ -0,0 +1,18 @@ +import { InjectionToken } from '@angular/core' +import { LogLevel } from '@shiftcode/logger' + +export interface CloudWatchLogTransportConfigV2 { + logLevel: LogLevel + apiUrl: string + + /** milliseconds until logs are flushed to aws */ + flushInterval: number + jsonStringifyReplacer?: (key: string, value: any) => any + + /** max number of sub-threshold log events to buffer before dropping oldest. default 100 */ + bufferSize?: number +} + +export const CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 = new InjectionToken( + 'CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2', +) diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts new file mode 100644 index 00000000..523c014a --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts @@ -0,0 +1,24 @@ +import { inject, Injectable } from '@angular/core' +import { LogLevel, LogTransport } from '@shiftcode/logger' + +import { CloudWatchServiceV2 } from './cloud-watch.service' +import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport-config.injection-token' + +/** + * The LogTransport implementation using {@link CloudWatchServiceV2}. + * Delegates all logging logic to the CloudWatchLogger. + * Requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG} to be provided. + */ +@Injectable({ providedIn: 'root' }) +export class CloudWatchLogTransportServiceV2 extends LogTransport { + private readonly cloudWatchLogger = inject(CloudWatchServiceV2) + + constructor() { + super(inject(CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2).logLevel) + } + + log(level: LogLevel, clazzName: string, _color: string, timestamp: Date, args: unknown[]): void { + // checking the log level is done in the cloudWatchLogger. important. + this.cloudWatchLogger.addMessage(level, clazzName, timestamp, args) + } +} diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts new file mode 100644 index 00000000..60bcb77b --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts @@ -0,0 +1,147 @@ +/* eslint-disable */ +import { inject, Injectable } from '@angular/core' +import { createJsonLogObjectData, getJsonStringifyReplacer, JsonLogObjectData, LogLevel } from '@shiftcode/logger' +import { jsonMapSetStringifyReplacer } from '@shiftcode/utilities' +import { buffer, catchError, defer, filter, first, mergeMap, Observable, of, Subject, timer } from 'rxjs' + +import { CloudWatchLogApiService, HttpApiError, LogEvent } from './cloud-watch-log-api.service' +import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport-config.injection-token' +import { pushToRingBuffer } from './log-utils' +import { LOG_REQUEST_INFO_FN } from '../log-request-info-fn.token' +import { ClientIdService } from '../../client-id/client-id.service' + +/** + * Service to send messages to the integration api for CloudWatch Logs + * requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG} to be provided + */ +@Injectable({ providedIn: 'root' }) +export class CloudWatchServiceV2 { + // max request per second per log stream + private static readonly CLOUD_WATCH_RATE_LIMIT = 1000 / 5 + + private readonly api = inject(CloudWatchLogApiService) + private readonly logsSubject = new Subject() + private readonly clientId: string + + private readonly logRequestInfoFn = inject(LOG_REQUEST_INFO_FN, { optional: true }) + private readonly config = inject(CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2) + private readonly jsonStringifyReplacer = this.config.jsonStringifyReplacer || jsonMapSetStringifyReplacer + private readonly bufferSize = this.config.bufferSize || 100 + + /** Ring buffer for log events below the configured level, flushed on ERROR */ + private pendingBuffer: LogEvent[] = [] + + constructor() { + const clientIdService = inject(ClientIdService) + + this.clientId = clientIdService.clientId + + // no instantiation if LogLevel === OFF + if (this.config.logLevel !== LogLevel.OFF) { + // validation + if (this.config.flushInterval <= CloudWatchServiceV2.CLOUD_WATCH_RATE_LIMIT) { + throw new Error( + `Flush interval must be greater than ${CloudWatchServiceV2.CLOUD_WATCH_RATE_LIMIT}ms --> CloudWatch Rate Limit`, + ) + } + + const ready = this.getOrCreateLogStream(clientIdService) + this.setupLogStream(ready) + } + } + + /** + * add message to the queue to send to CloudWatch Service + * only send when {@link CloudWatchLogTransportConfig#logLevel} is not {@link LogLevel#OFF } + */ + addMessage(level: LogLevel, context: string, timestamp: Date, args: unknown[]) { + if (this.config.logLevel === LogLevel.OFF) { + return + } + const logEvent = this.buildLogEvent(level, context, timestamp, args) + + // if level is below threshold, buffer the event + if (level < this.config.logLevel) { + pushToRingBuffer(this.pendingBuffer, logEvent, this.bufferSize) + return + } + + // on ERROR: flush buffered events first, then clear buffer + if (level === LogLevel.ERROR) { + for (const bufferedEvent of this.pendingBuffer) { + this.logsSubject.next(bufferedEvent) + } + this.pendingBuffer = [] + } + + this.logsSubject.next(logEvent) + } + + private buildLogEvent(level: LogLevel, context: string, timestamp: Date, args: unknown[]): LogEvent { + // Clone args to avoid mutating the original array + let logData: JsonLogObjectData & { requestInfo?: unknown } = createJsonLogObjectData(level, context, timestamp, [ + ...args, + ]) + + if (this.logRequestInfoFn) { + logData.requestInfo = this.logRequestInfoFn() + } + + return { + message: JSON.stringify(logData, getJsonStringifyReplacer(this.jsonStringifyReplacer)), + // time it is sent. not the time of the log (that one is included in the message object) + timestamp: new Date().getTime(), + } + } + + private getOrCreateLogStream({ createdInThisSession, clientId }: ClientIdService): Observable { + // return observable to keep it cold + return defer(async () => { + // if the clientId was created in this session, no LogStream can exist of it. + if (createdInThisSession) { + await this.api.createLogStream(clientId) + return + } + try { + await this.api.describeLogStream(clientId) + } catch (error) { + if (error instanceof HttpApiError && error.statusCode === 404) { + await this.api.createLogStream(clientId) + return + } + throw error + } + }) + } + + private setupLogStream(ready$: Observable): void { + // actual log subscription + this.logsSubject + .pipe( + // buffer logs --> wait for ready$ to complete - then setup the time based interval scheduler + buffer( + ready$.pipe( + first(), + mergeMap(() => timer(0, this.config.flushInterval)), + ), + ), + + // only none empty arrays + filter((logEvents) => logEvents?.length > 0), + + // put logs to cloudwatch + mergeMap(this.putLogEvents), + ) + .subscribe({ error: console.error.bind(console) }) + } + + private readonly putLogEvents = (events: LogEvent[]): Observable => { + // outer observable only for retry logic -- see below + return defer(() => this.api.writeLogs(this.clientId, events)).pipe( + catchError((err) => { + console.warn('unable to put logs to CloudWatch --> we try again with the next batch', err) + return of(void 0) + }), + ) + } +} diff --git a/libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts b/libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts new file mode 100644 index 00000000..d31cfcea --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts @@ -0,0 +1,9 @@ +/** + * Push an item to a ring buffer array. If the buffer exceeds maxSize, the oldest entry is removed. + */ +export function pushToRingBuffer(buffer: T[], item: T, maxSize: number): void { + buffer.push(item) + if (buffer.length > maxSize) { + buffer.shift() + } +} diff --git a/libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts b/libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts new file mode 100644 index 00000000..d06b6e94 --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts @@ -0,0 +1,23 @@ +import { LogTransport } from '@shiftcode/logger' + +import { ValueOrFactory } from '../helper/value-or-factory.type' +import { LoggerFeature } from '../logger-feature.type' +import { LoggerFeatureKind } from '../logger-feature-kind.enum' +import { CloudWatchLogTransportServiceV2 } from './cloud-watch-log-transport.service' +import { + CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2, + CloudWatchLogTransportConfigV2, +} from './cloud-watch-log-transport-config.injection-token' + +export function withCloudWatchTransportV2(config: ValueOrFactory): LoggerFeature { + return { + kind: LoggerFeatureKind.TRANSPORT, + providers: [ + { + provide: CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2, + ...(typeof config === 'function' ? { useFactory: config } : { useValue: config }), + }, + { provide: LogTransport, useClass: CloudWatchLogTransportServiceV2, multi: true }, + ], + } +} diff --git a/libs/core/src/lib/logger/logger.service.spec.ts b/libs/core/src/lib/logger/logger.service.spec.ts index 3faba019..2b2c0ed4 100644 --- a/libs/core/src/lib/logger/logger.service.spec.ts +++ b/libs/core/src/lib/logger/logger.service.spec.ts @@ -2,7 +2,8 @@ import { Component, Directive, inject, Injectable, InjectionToken, PLATFORM_ID } import { TestBed } from '@angular/core/testing' import { By } from '@angular/platform-browser' import { Logger, LogLevel, LogTransport } from '@shiftcode/logger' -import { LoggerService } from '@shiftcode/ngx-core' + +import { LoggerService } from './logger.service' interface MockLogTransportConfig { logLevel: LogLevel diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index 82401a66..4d89c77c 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -28,6 +28,12 @@ export * from './lib/logger/cloudwatch/cloud-watch-log-transport-config.model' export * from './lib/logger/cloudwatch/is-error.function' export * from './lib/logger/cloudwatch/with-cloudwatch-transport.function' +// cloudwatch v2 logger +export * from './lib/logger/cloud-watch-v2/cloud-watch.service' +export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport.service' +export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token' +export * from './lib/logger/cloud-watch-v2/with-cloud-watch-transport.function' + // console logger export * from './lib/logger/browser-console/browser-console-log-transport.service' export * from './lib/logger/browser-console/with-browser-console-transport.function' From 1ec8728b73670c62fb3b626ec2d5dd23086a3c94 Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Wed, 21 Jan 2026 19:02:34 +0100 Subject: [PATCH 03/14] style(logger): format --- .../with-browser-console-transport.function.ts | 5 +---- .../with-node-console-transport.function.ts | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts b/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts index 4a9551ca..e6a4fdd8 100644 --- a/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts +++ b/libs/core/src/lib/logger/browser-console/with-browser-console-transport.function.ts @@ -20,9 +20,6 @@ export function withBrowserConsoleTransport( return { kind: LoggerFeatureKind.TRANSPORT, - providers: [ - configProvider, - { provide: LogTransport, useClass: BrowserConsoleLogTransportService, multi: true } - ], + providers: [configProvider, { provide: LogTransport, useClass: BrowserConsoleLogTransportService, multi: true }], } } diff --git a/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts b/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts index 9efcb1cc..e74fd813 100644 --- a/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts +++ b/libs/core/src/lib/logger/node-console/with-node-console-transport.function.ts @@ -1,17 +1,11 @@ - import { LogTransport } from '@shiftcode/logger' import { ValueOrFactory } from '../helper/value-or-factory.type' import { LoggerFeature } from '../logger-feature.type' import { LoggerFeatureKind } from '../logger-feature-kind.enum' -import { - NODE_CONSOLE_LOG_TRANSPORT_CONFIG, - NodeConsoleLogTransportService, -} from './node-console-log-transport.service' +import { NODE_CONSOLE_LOG_TRANSPORT_CONFIG, NodeConsoleLogTransportService } from './node-console-log-transport.service' -export function withNodeConsoleTransport( - nodeConsoleLogTransportConfig: ValueOrFactory, -): LoggerFeature { +export function withNodeConsoleTransport(nodeConsoleLogTransportConfig: ValueOrFactory): LoggerFeature { return { kind: LoggerFeatureKind.TRANSPORT, providers: [ From c3a7f59e91f2a4f92a4a9b52d2eeefee31f33eb2 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Wed, 21 Jan 2026 18:04:42 +0000 Subject: [PATCH 04/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index 4663f680..b21838d2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "13.0.0", + "version": "14.0.0-pr76.0", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index 0c789cc4..8ee8aaec 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "13.0.0", + "version": "14.0.0-pr76.0", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index 9bac9739..ac863ae1 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "13.0.0", + "version": "14.0.0-pr76.0", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", From b289d5d1b736091d674975638d82465e6f2a4b4a Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Wed, 21 Jan 2026 19:07:17 +0100 Subject: [PATCH 05/14] fix(peer-deps): classic --- libs/components/package.json | 2 +- .../logger/cloud-watch-v2/cloud-watch-log-transport.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/components/package.json b/libs/components/package.json index 8ee8aaec..fb7ccef8 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -21,7 +21,7 @@ "@angular/forms": "^21.0.3", "@angular/router": "^21.0.3", "@shiftcode/logger": "^4.0.0-pr250", - "@shiftcode/ngx-core": "^13.0.0 || ^13.0.0-pr63", + "@shiftcode/ngx-core": "^14.0.0 || ^14.0.0-pr76", "rxjs": "^6.5.3 || ^7.4.0" } } diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts index 523c014a..01aaa52b 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts @@ -7,7 +7,7 @@ import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport /** * The LogTransport implementation using {@link CloudWatchServiceV2}. * Delegates all logging logic to the CloudWatchLogger. - * Requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG} to be provided. + * Requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2} to be provided. */ @Injectable({ providedIn: 'root' }) export class CloudWatchLogTransportServiceV2 extends LogTransport { From 6313bf3e7962d6492ceef975fccae334637a2b45 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Wed, 21 Jan 2026 18:09:37 +0000 Subject: [PATCH 06/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index b21838d2..b74b583c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "14.0.0-pr76.0", + "version": "14.0.0-pr76.1", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index fb7ccef8..ca39178f 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "14.0.0-pr76.0", + "version": "14.0.0-pr76.1", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index ac863ae1..51bc19f3 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "14.0.0-pr76.0", + "version": "14.0.0-pr76.1", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", From a73e5e760b3c0ce26a60debe5df595cb43c9ce3b Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Thu, 22 Jan 2026 15:07:18 +0100 Subject: [PATCH 07/14] feat(logger): add CloudWatchErrorHandlerV2 --- .../cloud-watch-error-handler.service.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts new file mode 100644 index 00000000..6b051e89 --- /dev/null +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts @@ -0,0 +1,22 @@ +import { ErrorHandler, inject, Injectable, Injector } from '@angular/core' +import { LogLevel } from '@shiftcode/logger' + +import { CloudWatchServiceV2 } from './cloud-watch.service' + +/** + * Angular ErrorHandler to send uncaught Errors to AWS CloudWatch Logs + * requires the {@link CloudWatchServiceV2} + */ +@Injectable({ providedIn: 'root' }) +export class CloudWatchErrorHandlerV2 extends ErrorHandler { + private readonly injector = inject(Injector) + + override handleError(error: any): void { + // prevent cyclic dependencies (eg. when CLOUD_WATCH_LOG_TRANSPORT_CONFIG needs config from httpClient request) + const cws = this.injector.get(CloudWatchServiceV2) + cws.addMessage(LogLevel.ERROR, 'BrowserJsException', new Date(), [error]) + + // call super.handleError to print error the angular way to the console + super.handleError(error) + } +} From 83e93304719b86df76aa652185fb52a9b3c61c9a Mon Sep 17 00:00:00 2001 From: Github Actions Date: Thu, 22 Jan 2026 14:12:44 +0000 Subject: [PATCH 08/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index b74b583c..31eb1cd4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "14.0.0-pr76.1", + "version": "14.0.0-pr76.2", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index ca39178f..0c35fdf5 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "14.0.0-pr76.1", + "version": "14.0.0-pr76.2", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index 51bc19f3..dccbea98 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "14.0.0-pr76.1", + "version": "14.0.0-pr76.2", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", From 5be7ed7278a9c0b41f725ed4a12c3e2dfa3d37f7 Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Thu, 22 Jan 2026 17:13:59 +0100 Subject: [PATCH 09/14] feat(logger): add CloudWatchErrorHandlerV2 --- libs/core/src/public-api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index 4d89c77c..4ac66ed2 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -30,6 +30,7 @@ export * from './lib/logger/cloudwatch/with-cloudwatch-transport.function' // cloudwatch v2 logger export * from './lib/logger/cloud-watch-v2/cloud-watch.service' +export * from './lib/logger/cloud-watch-v2/cloud-watch-error-handler.service' export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport.service' export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token' export * from './lib/logger/cloud-watch-v2/with-cloud-watch-transport.function' From dd9a19329ed07b99d33729b3c366d4f007727296 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Thu, 22 Jan 2026 16:16:07 +0000 Subject: [PATCH 10/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index 31eb1cd4..67d4ad75 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "14.0.0-pr76.2", + "version": "14.0.0-pr76.3", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index 0c35fdf5..0d9d6a65 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "14.0.0-pr76.2", + "version": "14.0.0-pr76.3", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index dccbea98..b3099f0e 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "14.0.0-pr76.2", + "version": "14.0.0-pr76.3", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", From ffe36b1d83a3eae882c77f395c78cfd4058c3c76 Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Fri, 23 Jan 2026 10:14:49 +0100 Subject: [PATCH 11/14] feat(logger): add CloudWatchLogApiService --- .../cloud-watch-v2/cloud-watch-log-api.service.ts | 14 ++++++++------ ...ts => cloud-watch-log-error-handler.service.ts} | 2 +- libs/core/src/public-api.ts | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) rename libs/core/src/lib/logger/cloud-watch-v2/{cloud-watch-error-handler.service.ts => cloud-watch-log-error-handler.service.ts} (92%) diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts index 14fed543..1fe513c8 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts @@ -43,15 +43,17 @@ export class HttpApiError extends HttpError { } } +enum ApiPath { + STREAMS = 'streams', + STREAM_LOGS = 'logs', +} + @Injectable({ providedIn: 'root' }) export class CloudWatchLogApiService { - static readonly LOG_STREAMS_PATH = '/streams' - static readonly LOG_STREAMS_LOGS_PATH = '/streams/{logStreamName}/logs' - private readonly apiUrl = inject(CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2).apiUrl async createLogStream(logStreamName: string): Promise { - const resp = await fetch(new URL(CloudWatchLogApiService.LOG_STREAMS_PATH, this.apiUrl), { + const resp = await fetch(new URL(ApiPath.STREAMS, this.apiUrl), { method: 'POST', headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, body: JSON.stringify({ logStreamName }), @@ -60,7 +62,7 @@ export class CloudWatchLogApiService { } async describeLogStream(logStreamName: string): Promise { - const result = await fetch(`${CloudWatchLogApiService.LOG_STREAMS_PATH}/${logStreamName}`, { + const result = await fetch(new URL(`${ApiPath.STREAMS}/${logStreamName}`, this.apiUrl), { method: 'GET', headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, }) @@ -70,7 +72,7 @@ export class CloudWatchLogApiService { async writeLogs(logStreamName: string, logs: LogEvent[]): Promise { // todo: use beaconApi ? - const resp = await fetch(`${CloudWatchLogApiService.LOG_STREAMS_PATH}/${logStreamName}/logs`, { + const resp = await fetch(new URL(`${ApiPath.STREAMS}/${logStreamName}/${ApiPath.STREAM_LOGS}`, this.apiUrl), { method: 'POST', headers: { [CommonHttpHeader.CONTENT_TYPE]: ContentType.JSON }, body: JSON.stringify({ logEvents: logs } satisfies WriteLogEvents), diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts similarity index 92% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts rename to libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts index 6b051e89..d75b024b 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-error-handler.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts @@ -8,7 +8,7 @@ import { CloudWatchServiceV2 } from './cloud-watch.service' * requires the {@link CloudWatchServiceV2} */ @Injectable({ providedIn: 'root' }) -export class CloudWatchErrorHandlerV2 extends ErrorHandler { +export class CloudWatchLogErrorHandlerV2 extends ErrorHandler { private readonly injector = inject(Injector) override handleError(error: any): void { diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index 4ac66ed2..ec26563a 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -30,7 +30,7 @@ export * from './lib/logger/cloudwatch/with-cloudwatch-transport.function' // cloudwatch v2 logger export * from './lib/logger/cloud-watch-v2/cloud-watch.service' -export * from './lib/logger/cloud-watch-v2/cloud-watch-error-handler.service' +export * from './lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service' export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport.service' export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token' export * from './lib/logger/cloud-watch-v2/with-cloud-watch-transport.function' From 047dce29eacd05898e3235a75f8e7729afe0117d Mon Sep 17 00:00:00 2001 From: Github Actions Date: Fri, 23 Jan 2026 09:17:14 +0000 Subject: [PATCH 12/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index 67d4ad75..0c7f802d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "14.0.0-pr76.3", + "version": "14.0.0-pr76.4", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index 0d9d6a65..69a30284 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "14.0.0-pr76.3", + "version": "14.0.0-pr76.4", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index b3099f0e..17f2d0e9 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "14.0.0-pr76.3", + "version": "14.0.0-pr76.4", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", From 207b8639452c2253873c33e0b48c337a79524a0a Mon Sep 17 00:00:00 2001 From: Simon Mumenthaler Date: Fri, 23 Jan 2026 10:19:50 +0100 Subject: [PATCH 13/14] refactor(logger): rename consistently --- .../cloud-watch-log-api.service.ts | 0 .../cloud-watch-log-error-handler.service.ts | 6 +++--- ...ud-watch-log-transport-config.injection-token.ts | 0 .../cloud-watch-log-transport.service.ts | 6 +++--- .../cloud-watch-log-utils.ts} | 1 + .../cloud-watch-log.service.ts} | 13 +++++++------ .../with-cloud-watch-log-transport.function.ts} | 2 +- libs/core/src/public-api.ts | 10 +++++----- 8 files changed, 20 insertions(+), 18 deletions(-) rename libs/core/src/lib/logger/{cloud-watch-v2 => cloud-watch-log-v2}/cloud-watch-log-api.service.ts (100%) rename libs/core/src/lib/logger/{cloud-watch-v2 => cloud-watch-log-v2}/cloud-watch-log-error-handler.service.ts (80%) rename libs/core/src/lib/logger/{cloud-watch-v2 => cloud-watch-log-v2}/cloud-watch-log-transport-config.injection-token.ts (100%) rename libs/core/src/lib/logger/{cloud-watch-v2 => cloud-watch-log-v2}/cloud-watch-log-transport.service.ts (79%) rename libs/core/src/lib/logger/{cloud-watch-v2/log-utils.ts => cloud-watch-log-v2/cloud-watch-log-utils.ts} (84%) rename libs/core/src/lib/logger/{cloud-watch-v2/cloud-watch.service.ts => cloud-watch-log-v2/cloud-watch-log.service.ts} (89%) rename libs/core/src/lib/logger/{cloud-watch-v2/with-cloud-watch-transport.function.ts => cloud-watch-log-v2/with-cloud-watch-log-transport.function.ts} (87%) diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-api.service.ts similarity index 100% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-api.service.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-api.service.ts diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-error-handler.service.ts similarity index 80% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-error-handler.service.ts index d75b024b..5ee2632b 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-error-handler.service.ts @@ -1,11 +1,11 @@ import { ErrorHandler, inject, Injectable, Injector } from '@angular/core' import { LogLevel } from '@shiftcode/logger' -import { CloudWatchServiceV2 } from './cloud-watch.service' +import { CloudWatchLogServiceV2 } from './cloud-watch-log.service' /** * Angular ErrorHandler to send uncaught Errors to AWS CloudWatch Logs - * requires the {@link CloudWatchServiceV2} + * requires the {@link CloudWatchLogServiceV2} */ @Injectable({ providedIn: 'root' }) export class CloudWatchLogErrorHandlerV2 extends ErrorHandler { @@ -13,7 +13,7 @@ export class CloudWatchLogErrorHandlerV2 extends ErrorHandler { override handleError(error: any): void { // prevent cyclic dependencies (eg. when CLOUD_WATCH_LOG_TRANSPORT_CONFIG needs config from httpClient request) - const cws = this.injector.get(CloudWatchServiceV2) + const cws = this.injector.get(CloudWatchLogServiceV2) cws.addMessage(LogLevel.ERROR, 'BrowserJsException', new Date(), [error]) // call super.handleError to print error the angular way to the console diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-transport-config.injection-token.ts similarity index 100% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-transport-config.injection-token.ts diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-transport.service.ts similarity index 79% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-transport.service.ts index 01aaa52b..bf28849e 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch-log-transport.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-transport.service.ts @@ -1,17 +1,17 @@ import { inject, Injectable } from '@angular/core' import { LogLevel, LogTransport } from '@shiftcode/logger' -import { CloudWatchServiceV2 } from './cloud-watch.service' +import { CloudWatchLogServiceV2 } from './cloud-watch-log.service' import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport-config.injection-token' /** - * The LogTransport implementation using {@link CloudWatchServiceV2}. + * The LogTransport implementation using {@link CloudWatchLogServiceV2}. * Delegates all logging logic to the CloudWatchLogger. * Requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2} to be provided. */ @Injectable({ providedIn: 'root' }) export class CloudWatchLogTransportServiceV2 extends LogTransport { - private readonly cloudWatchLogger = inject(CloudWatchServiceV2) + private readonly cloudWatchLogger = inject(CloudWatchLogServiceV2) constructor() { super(inject(CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2).logLevel) diff --git a/libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-utils.ts similarity index 84% rename from libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-utils.ts index d31cfcea..5740e2cb 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/log-utils.ts +++ b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log-utils.ts @@ -1,5 +1,6 @@ /** * Push an item to a ring buffer array. If the buffer exceeds maxSize, the oldest entry is removed. + * todo: use from @shiftcode/logger when available */ export function pushToRingBuffer(buffer: T[], item: T, maxSize: number): void { buffer.push(item) diff --git a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log.service.ts similarity index 89% rename from libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log.service.ts index 60bcb77b..af0bc69a 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/cloud-watch.service.ts +++ b/libs/core/src/lib/logger/cloud-watch-log-v2/cloud-watch-log.service.ts @@ -6,16 +6,16 @@ import { buffer, catchError, defer, filter, first, mergeMap, Observable, of, Sub import { CloudWatchLogApiService, HttpApiError, LogEvent } from './cloud-watch-log-api.service' import { CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2 } from './cloud-watch-log-transport-config.injection-token' -import { pushToRingBuffer } from './log-utils' +import { pushToRingBuffer } from './cloud-watch-log-utils' import { LOG_REQUEST_INFO_FN } from '../log-request-info-fn.token' import { ClientIdService } from '../../client-id/client-id.service' /** * Service to send messages to the integration api for CloudWatch Logs - * requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG} to be provided + * requires the {@link CLOUD_WATCH_LOG_TRANSPORT_CONFIG_V2} to be provided */ @Injectable({ providedIn: 'root' }) -export class CloudWatchServiceV2 { +export class CloudWatchLogServiceV2 { // max request per second per log stream private static readonly CLOUD_WATCH_RATE_LIMIT = 1000 / 5 @@ -39,9 +39,9 @@ export class CloudWatchServiceV2 { // no instantiation if LogLevel === OFF if (this.config.logLevel !== LogLevel.OFF) { // validation - if (this.config.flushInterval <= CloudWatchServiceV2.CLOUD_WATCH_RATE_LIMIT) { + if (this.config.flushInterval <= CloudWatchLogServiceV2.CLOUD_WATCH_RATE_LIMIT) { throw new Error( - `Flush interval must be greater than ${CloudWatchServiceV2.CLOUD_WATCH_RATE_LIMIT}ms --> CloudWatch Rate Limit`, + `Flush interval must be greater than ${CloudWatchLogServiceV2.CLOUD_WATCH_RATE_LIMIT}ms --> CloudWatch Rate Limit`, ) } @@ -62,7 +62,8 @@ export class CloudWatchServiceV2 { // if level is below threshold, buffer the event if (level < this.config.logLevel) { - pushToRingBuffer(this.pendingBuffer, logEvent, this.bufferSize) + // we use `structuredClone` to prevent potential mutations of the logEvent before it is actually sent + pushToRingBuffer(this.pendingBuffer, structuredClone(logEvent), this.bufferSize) return } diff --git a/libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts b/libs/core/src/lib/logger/cloud-watch-log-v2/with-cloud-watch-log-transport.function.ts similarity index 87% rename from libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts rename to libs/core/src/lib/logger/cloud-watch-log-v2/with-cloud-watch-log-transport.function.ts index d06b6e94..51a15dea 100644 --- a/libs/core/src/lib/logger/cloud-watch-v2/with-cloud-watch-transport.function.ts +++ b/libs/core/src/lib/logger/cloud-watch-log-v2/with-cloud-watch-log-transport.function.ts @@ -9,7 +9,7 @@ import { CloudWatchLogTransportConfigV2, } from './cloud-watch-log-transport-config.injection-token' -export function withCloudWatchTransportV2(config: ValueOrFactory): LoggerFeature { +export function withCloudWatchLogTransportV2(config: ValueOrFactory): LoggerFeature { return { kind: LoggerFeatureKind.TRANSPORT, providers: [ diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index ec26563a..ec44da36 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -29,11 +29,11 @@ export * from './lib/logger/cloudwatch/is-error.function' export * from './lib/logger/cloudwatch/with-cloudwatch-transport.function' // cloudwatch v2 logger -export * from './lib/logger/cloud-watch-v2/cloud-watch.service' -export * from './lib/logger/cloud-watch-v2/cloud-watch-log-error-handler.service' -export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport.service' -export * from './lib/logger/cloud-watch-v2/cloud-watch-log-transport-config.injection-token' -export * from './lib/logger/cloud-watch-v2/with-cloud-watch-transport.function' +export * from './lib/logger/cloud-watch-log-v2/cloud-watch-log.service' +export * from './lib/logger/cloud-watch-log-v2/cloud-watch-log-error-handler.service' +export * from './lib/logger/cloud-watch-log-v2/cloud-watch-log-transport.service' +export * from './lib/logger/cloud-watch-log-v2/cloud-watch-log-transport-config.injection-token' +export * from './lib/logger/cloud-watch-log-v2/with-cloud-watch-log-transport.function' // console logger export * from './lib/logger/browser-console/browser-console-log-transport.service' From 6471cb5242171b88f5ecf4862814144de7ce335e Mon Sep 17 00:00:00 2001 From: Github Actions Date: Fri, 23 Jan 2026 09:50:24 +0000 Subject: [PATCH 14/14] build(release): next version [skip_build] --- lerna.json | 2 +- libs/components/package.json | 2 +- libs/core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index 0c7f802d..f9e24dcd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,7 @@ { "useNx": false, "packages": ["libs/*", "apps/*"], - "version": "14.0.0-pr76.4", + "version": "14.0.0-pr76.5", "command": { "version": { "allowBranch": "*", diff --git a/libs/components/package.json b/libs/components/package.json index 69a30284..46e0e977 100644 --- a/libs/components/package.json +++ b/libs/components/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-components", - "version": "14.0.0-pr76.4", + "version": "14.0.0-pr76.5", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ", diff --git a/libs/core/package.json b/libs/core/package.json index 17f2d0e9..cbebc8b2 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -1,6 +1,6 @@ { "name": "@shiftcode/ngx-core", - "version": "14.0.0-pr76.4", + "version": "14.0.0-pr76.5", "repository": "https://github.com/shiftcode/sc-ng-commons-public", "license": "MIT", "author": "shiftcode GmbH ",