@adatechnology/logger 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -107,9 +107,7 @@ Ao realizar um log, você pode passar as seguintes propriedades para enriquecer
107
107
  - `libMethod`: O método interno da biblioteca sendo executado. Ex: `get`.
108
108
  - `meta`: Objeto com metadados adicionais (será exibido em uma única linha compacta).
109
109
 
110
- > ✅ **Padrão recomendado:** enviar payload estruturado em `meta`.
111
- >
112
- > ⚠️ **Compatibilidade legada:** payload em `params` ainda é aceito e promovido para `meta` internamente para não quebrar serviços antigos.
110
+ > ✅ **Padrão obrigatório:** enviar payload estruturado em `meta`.
113
111
 
114
112
  ### `meta` vs `params` (recomendação)
115
113
 
@@ -130,20 +128,7 @@ this.logger.error({
130
128
  });
131
129
  ```
132
130
 
133
- Exemplo legado (ainda funciona, mas evite em código novo):
134
-
135
- ```ts
136
- this.logger.error({
137
- message: "Exception caught in filter",
138
- context: "HttpExceptionFilter.logResponse",
139
- requestId,
140
- params: {
141
- request: { path, method, headers, params, query, body },
142
- response: { status, headers, messages },
143
- error: { type, message, status, body, details },
144
- },
145
- });
146
- ```
131
+ Campos fora do contrato (`message`, `context`, `meta`) não são recomendados na API pública.
147
132
 
148
133
  ### Exemplo de Log de Biblioteca
149
134
 
@@ -6,42 +6,52 @@ description: Patterns for @adatechnology/logger. Use when configuring Winston lo
6
6
  # 📝 Logger Standards
7
7
 
8
8
  ## 🚀 Setup Example
9
+
9
10
  ```typescript
10
11
  @Module({
11
12
  imports: [
12
13
  LoggerModule.forRoot({
13
- level: 'info',
14
- sensitiveKeys: ['password', 'token', 'clientSecret'],
14
+ level: "info",
15
+ sensitiveKeys: ["password", "token", "clientSecret"],
15
16
  }),
16
17
  ],
17
18
  })
18
19
  export class AppModule implements NestModule {
19
20
  configure(consumer: MiddlewareConsumer) {
20
21
  // Required to enable Request-ID tracking across async calls
21
- consumer.apply(RequestContextMiddleware).forRoutes('*');
22
+ consumer.apply(RequestContextMiddleware).forRoutes("*");
22
23
  }
23
24
  }
24
25
  ```
25
26
 
26
27
  ## 🏗️ Usage Pattern
28
+
27
29
  ```typescript
28
30
  @Injectable()
29
31
  export class MyService {
30
32
  constructor(
31
- @Inject(LOGGER_PROVIDER) private readonly logger: LoggerProviderInterface
33
+ @Inject(LOGGER_PROVIDER) private readonly logger: LoggerProviderInterface,
32
34
  ) {}
33
35
 
34
36
  doWork() {
35
- this.logger.info('Action performed', { userId: '123' });
37
+ this.logger.info({
38
+ message: "Action performed",
39
+ context: MyService.name,
40
+ meta: { userId: "123" },
41
+ });
36
42
  }
37
43
  }
38
44
  ```
39
45
 
40
46
  ## 🔐 Obfuscation
47
+
41
48
  The logger automatically hides values for keys defined in `sensitiveKeys`.
49
+
42
50
  - **Default Keys**: `password`, `token`, `authorization`, `cookie`, `secret`.
43
51
  - **Custom Keys**: Add via `LoggerModule.forRoot()`.
44
52
 
45
53
  ## 🛠️ Internal Mechanics
54
+
46
55
  - **Async Context**: Uses `AsyncLocalStorage` to store the Request-ID.
47
56
  - **Context Access**: Use `getContext()` to retrieve the current request state anywhere in the call stack.
57
+ - **Type naming**: aliases de tipagem com sufixo `Params`/`Result` devem usar **PascalCase** (ex.: `InfoParams`, `InfoResult`).
package/dist/index.d.ts CHANGED
@@ -21,18 +21,32 @@ declare enum LoggerLevel {
21
21
  WARN = "warn",
22
22
  ERROR = "error"
23
23
  }
24
- interface LogPayload {
24
+ type LogParams = {
25
25
  message: string;
26
26
  context?: string;
27
27
  meta?: Record<string, unknown>;
28
- }
28
+ };
29
+ type LogResult = void;
30
+ type DebugParams = LogParams;
31
+ type DebugResult = LogResult;
32
+ type InfoParams = LogParams;
33
+ type InfoResult = LogResult;
34
+ type WarnParams = LogParams;
35
+ type WarnResult = LogResult;
36
+ type ErrorParams = LogParams;
37
+ type ErrorResult = LogResult;
29
38
  interface LoggerProviderInterface {
30
- debug(payload: LogPayload): void;
31
- info(payload: LogPayload): void;
32
- warn(payload: LogPayload): void;
33
- error(payload: LogPayload): void;
39
+ debug(params: DebugParams): DebugResult;
40
+ info(params: InfoParams): InfoResult;
41
+ warn(params: WarnParams): WarnResult;
42
+ error(params: ErrorParams): ErrorResult;
34
43
  setContext?(context: string): void;
35
44
  }
45
+ type WriteLogParams = {
46
+ level: LoggerLevel;
47
+ payload: LogParams;
48
+ };
49
+ type WriteLogResult = LogResult;
36
50
 
37
51
  interface LoggerConfig extends WinstonModuleConfig {
38
52
  /**
@@ -109,6 +123,7 @@ declare class HttpLoggingInterceptor implements NestInterceptor {
109
123
  private readonly logger;
110
124
  private readonly reflector;
111
125
  private readonly excludedPaths;
126
+ private toErrorMessage;
112
127
  constructor(logger: LoggerProviderInterface, reflector: Reflector, config?: LoggerConfig);
113
128
  private isExcluded;
114
129
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
@@ -127,4 +142,4 @@ type RequestContext = Record<string, unknown> | undefined;
127
142
  declare function getContext(): RequestContext;
128
143
  declare function runWithContext<T>(ctx: Record<string, unknown>, fn: () => T): T;
129
144
 
130
- export { DEFAULT_LOGGER_CONFIG, ExcludeHttpLogging, HTTP_LOGGING_INTERCEPTOR, HTTP_LOGGING_INTERCEPTOR_CONTEXT, HttpLoggingInterceptor, LOGGER_CONFIG, LOGGER_PROVIDER, type LogPayload, type LoggerConfig, LoggerLevel, LoggerModule, type LoggerProviderInterface, RequestContextMiddleware, getContext, runWithContext };
145
+ export { DEFAULT_LOGGER_CONFIG, type DebugParams, type DebugResult, type ErrorParams, type ErrorResult, ExcludeHttpLogging, HTTP_LOGGING_INTERCEPTOR, HTTP_LOGGING_INTERCEPTOR_CONTEXT, HttpLoggingInterceptor, type InfoParams, type InfoResult, LOGGER_CONFIG, LOGGER_PROVIDER, type LogParams, type LogResult, type LoggerConfig, LoggerLevel, LoggerModule, type LoggerProviderInterface, RequestContextMiddleware, type WarnParams, type WarnResult, type WriteLogParams, type WriteLogResult, getContext, runWithContext };
package/dist/index.js CHANGED
@@ -9049,23 +9049,22 @@ var LoggerProvider = class {
9049
9049
  constructor(implementation) {
9050
9050
  this.implementation = implementation;
9051
9051
  }
9052
- debug(...args) {
9053
- return this.implementation.debug(...args);
9052
+ debug(params) {
9053
+ return this.implementation.debug(params);
9054
9054
  }
9055
- info(...args) {
9056
- return this.implementation.info(...args);
9055
+ info(params) {
9056
+ return this.implementation.info(params);
9057
9057
  }
9058
- warn(...args) {
9059
- return this.implementation.warn(...args);
9058
+ warn(params) {
9059
+ return this.implementation.warn(params);
9060
9060
  }
9061
- error(...args) {
9062
- return this.implementation.error(...args);
9061
+ error(params) {
9062
+ return this.implementation.error(params);
9063
9063
  }
9064
9064
  setContext(context) {
9065
9065
  if (typeof this.implementation.setContext === "function") {
9066
9066
  return this.implementation.setContext(context);
9067
9067
  }
9068
- return;
9069
9068
  }
9070
9069
  };
9071
9070
  LoggerProvider = _ts_decorate([
@@ -9085,7 +9084,7 @@ var HTTP_LOGGING_INTERCEPTOR = "HTTP_LOGGING_INTERCEPTOR";
9085
9084
  // src/implementations/winston/winston.logger.module.ts
9086
9085
  var import_common3 = require("@nestjs/common");
9087
9086
  var import_winston2 = require("winston");
9088
- var import_util = require("util");
9087
+ var import_node_util = require("util");
9089
9088
 
9090
9089
  // src/implementations/winston/winston.logger.provider.ts
9091
9090
  var import_common2 = require("@nestjs/common");
@@ -9101,8 +9100,8 @@ var LoggerLevel = /* @__PURE__ */ (function(LoggerLevel2) {
9101
9100
  })({});
9102
9101
 
9103
9102
  // src/context/async-context.service.ts
9104
- var import_async_hooks = require("async_hooks");
9105
- var asyncLocalStorage = new import_async_hooks.AsyncLocalStorage();
9103
+ var import_node_async_hooks = require("async_hooks");
9104
+ var asyncLocalStorage = new import_node_async_hooks.AsyncLocalStorage();
9106
9105
  function getContext() {
9107
9106
  return asyncLocalStorage.getStore();
9108
9107
  }
@@ -9166,44 +9165,45 @@ var WinstonLoggerProvider = class {
9166
9165
  this.logger = logger;
9167
9166
  this.obfuscator = obfuscator;
9168
9167
  }
9169
- debug(messageOrPayload, meta, context) {
9170
- this.handleLog(LoggerLevel.DEBUG, messageOrPayload, meta, context);
9168
+ debug(payload) {
9169
+ this.log({
9170
+ level: LoggerLevel.DEBUG,
9171
+ payload: {
9172
+ ...payload,
9173
+ context: payload.context || this.context
9174
+ }
9175
+ });
9171
9176
  }
9172
- info(messageOrPayload, meta, context) {
9173
- this.handleLog(LoggerLevel.INFO, messageOrPayload, meta, context);
9177
+ info(payload) {
9178
+ this.log({
9179
+ level: LoggerLevel.INFO,
9180
+ payload: {
9181
+ ...payload,
9182
+ context: payload.context || this.context
9183
+ }
9184
+ });
9174
9185
  }
9175
- warn(messageOrPayload, meta, context) {
9176
- this.handleLog(LoggerLevel.WARN, messageOrPayload, meta, context);
9186
+ warn(payload) {
9187
+ this.log({
9188
+ level: LoggerLevel.WARN,
9189
+ payload: {
9190
+ ...payload,
9191
+ context: payload.context || this.context
9192
+ }
9193
+ });
9177
9194
  }
9178
- error(messageOrPayload, meta, context) {
9179
- this.handleLog(LoggerLevel.ERROR, messageOrPayload, meta, context);
9195
+ error(payload) {
9196
+ this.log({
9197
+ level: LoggerLevel.ERROR,
9198
+ payload: {
9199
+ ...payload,
9200
+ context: payload.context || this.context
9201
+ }
9202
+ });
9180
9203
  }
9181
9204
  setContext(context) {
9182
9205
  this.context = context;
9183
9206
  }
9184
- handleLog(level, messageOrPayload, meta, context) {
9185
- let payload;
9186
- if (typeof messageOrPayload === "string") {
9187
- payload = {
9188
- message: messageOrPayload,
9189
- meta,
9190
- context: context || this.context
9191
- };
9192
- } else {
9193
- payload = {
9194
- ...messageOrPayload,
9195
- context: messageOrPayload.context || context || this.context,
9196
- meta: {
9197
- ...messageOrPayload.meta,
9198
- ...meta
9199
- }
9200
- };
9201
- }
9202
- this.log({
9203
- level,
9204
- payload
9205
- });
9206
- }
9207
9207
  log(params) {
9208
9208
  const { level, payload } = params;
9209
9209
  const { message, context, meta, ...rest } = payload;
@@ -9215,7 +9215,7 @@ var WinstonLoggerProvider = class {
9215
9215
  const logInfo = {
9216
9216
  ...rest,
9217
9217
  context: messageContext,
9218
- requestId: requestIdFromContext || payload.requestId,
9218
+ requestId: requestIdFromContext || rest.requestId,
9219
9219
  meta: obfuscatedMeta
9220
9220
  };
9221
9221
  this.logger.log(level, messageText, logInfo);
@@ -9332,6 +9332,163 @@ function _ts_decorate3(decorators, target, key, desc) {
9332
9332
  return c > 3 && r && Object.defineProperty(target, key, r), r;
9333
9333
  }
9334
9334
  __name(_ts_decorate3, "_ts_decorate");
9335
+ function asString(value) {
9336
+ if (typeof value === "string") return value;
9337
+ if (typeof value === "number" || typeof value === "boolean") {
9338
+ return String(value);
9339
+ }
9340
+ return void 0;
9341
+ }
9342
+ __name(asString, "asString");
9343
+ function colorizeText(useColors, color, reset, text) {
9344
+ return useColors ? `${color}${text}${reset}` : text;
9345
+ }
9346
+ __name(colorizeText, "colorizeText");
9347
+ function fillInfoFromMeta(info) {
9348
+ if (!info.meta || typeof info.meta !== "object") return;
9349
+ const meta = info.meta;
9350
+ const metadataKeys = [
9351
+ "requestId",
9352
+ "context",
9353
+ "source",
9354
+ "lib",
9355
+ "libVersion",
9356
+ "libMethod",
9357
+ "appName",
9358
+ "appVersion"
9359
+ ];
9360
+ for (const key of metadataKeys) {
9361
+ if (meta[key] && !info[key]) {
9362
+ info[key] = meta[key];
9363
+ delete meta[key];
9364
+ }
9365
+ }
9366
+ const logContext = meta.logContext;
9367
+ if (!logContext || info.source) return;
9368
+ const className = asString(logContext.className);
9369
+ const methodName = asString(logContext.methodName);
9370
+ if (className && methodName) {
9371
+ info.source = `${className}.${methodName}`;
9372
+ } else if (className) {
9373
+ info.source = className;
9374
+ } else if (methodName) {
9375
+ info.source = methodName;
9376
+ }
9377
+ }
9378
+ __name(fillInfoFromMeta, "fillInfoFromMeta");
9379
+ function applyDefaultInfoValues(info, config) {
9380
+ info.requestId = info.requestId || "no-request-id";
9381
+ info.context = info.context || config?.context || "App";
9382
+ info.appName = info.appName || config?.appName;
9383
+ info.appVersion = info.appVersion || config?.appVersion;
9384
+ info.lib = info.lib || config?.lib;
9385
+ info.libVersion = info.libVersion || config?.libVersion;
9386
+ }
9387
+ __name(applyDefaultInfoValues, "applyDefaultInfoValues");
9388
+ function buildMethodDisplays(params) {
9389
+ const { context, source, lib, libMethod, colorize } = params;
9390
+ let sourceDisplay = "";
9391
+ let libMethodDisplay = "";
9392
+ if (source) {
9393
+ sourceDisplay = `[${colorize(source)}]`;
9394
+ }
9395
+ if (lib) {
9396
+ const methodPath = libMethod ? `${context}.${libMethod}` : context;
9397
+ libMethodDisplay = `[${colorize(methodPath)}]`;
9398
+ if (source === context || source === methodPath) {
9399
+ sourceDisplay = "";
9400
+ }
9401
+ return {
9402
+ sourceDisplay,
9403
+ libMethodDisplay
9404
+ };
9405
+ }
9406
+ if (!source) {
9407
+ libMethodDisplay = `[${colorize(context)}]`;
9408
+ return {
9409
+ sourceDisplay,
9410
+ libMethodDisplay
9411
+ };
9412
+ }
9413
+ if (source.startsWith(`${context}.`) || source === context) {
9414
+ libMethodDisplay = `[${colorize(source)}]`;
9415
+ sourceDisplay = "";
9416
+ return {
9417
+ sourceDisplay,
9418
+ libMethodDisplay
9419
+ };
9420
+ }
9421
+ libMethodDisplay = `[${colorize(context)}]`;
9422
+ sourceDisplay = `[${colorize(source)}]`;
9423
+ return {
9424
+ sourceDisplay,
9425
+ libMethodDisplay
9426
+ };
9427
+ }
9428
+ __name(buildMethodDisplays, "buildMethodDisplays");
9429
+ function formatDevelopmentLog(infoInput, useColors, levelColorizer) {
9430
+ const info = infoInput;
9431
+ const level = asString(info.level) ?? "info";
9432
+ const message = asString(info.message) ?? "";
9433
+ const timestamp = asString(info.timestamp) ?? "";
9434
+ const requestId = asString(info.requestId) ?? "no-request-id";
9435
+ const context = asString(info.context) ?? "App";
9436
+ const source = asString(info.source);
9437
+ const appName = asString(info.appName);
9438
+ const appVersion = asString(info.appVersion);
9439
+ const lib = asString(info.lib);
9440
+ const libMethod = asString(info.libMethod);
9441
+ const libVersion = asString(info.libVersion);
9442
+ const stack = asString(info.stack);
9443
+ const meta = info.meta && typeof info.meta === "object" ? info.meta : void 0;
9444
+ const colors = {
9445
+ reset: "\x1B[0m",
9446
+ gray: "\x1B[90m",
9447
+ cyan: "\x1B[36m",
9448
+ magenta: "\x1B[35m",
9449
+ yellow: "\x1B[33m",
9450
+ red: "\x1B[31m",
9451
+ green: "\x1B[32m"
9452
+ };
9453
+ const coloredLevel = useColors ? levelColorizer.colorize(level, level.toUpperCase()) : level.toUpperCase();
9454
+ const coloredTime = colorizeText(useColors, colors.gray, colors.reset, timestamp);
9455
+ const coloredRequestId = colorizeText(useColors, colors.cyan, colors.reset, requestId);
9456
+ let appDisplay = "";
9457
+ if (appName) {
9458
+ const appText = appVersion ? `${appName}@${appVersion}` : appName;
9459
+ const appLabel = `App-${appText}`;
9460
+ appDisplay = `[${colorizeText(useColors, colors.green, colors.reset, appLabel)}]`;
9461
+ }
9462
+ let libDisplay = "";
9463
+ if (lib) {
9464
+ const libText = libVersion ? `${lib}:${libVersion}` : lib;
9465
+ libDisplay = `[${colorizeText(useColors, colors.yellow, colors.reset, libText)}]`;
9466
+ }
9467
+ const { sourceDisplay, libMethodDisplay } = buildMethodDisplays({
9468
+ context,
9469
+ source,
9470
+ lib,
9471
+ libMethod,
9472
+ colorize: /* @__PURE__ */ __name((text) => colorizeText(useColors, colors.magenta, colors.reset, text), "colorize")
9473
+ });
9474
+ let output = `${appDisplay}${libDisplay}[${coloredRequestId}][${coloredTime}]${sourceDisplay}${libMethodDisplay}[${coloredLevel}] - ${message}`;
9475
+ if (meta && typeof meta === "object" && Object.keys(meta).length > 0) {
9476
+ const inspectedMeta = (0, import_node_util.inspect)(meta, {
9477
+ colors: useColors,
9478
+ depth: null,
9479
+ compact: true,
9480
+ sorted: true,
9481
+ breakLength: Infinity
9482
+ });
9483
+ output += ` - ${inspectedMeta}`;
9484
+ }
9485
+ if (stack) {
9486
+ output += `
9487
+ ${colorizeText(useColors, colors.red, colors.reset, stack)}`;
9488
+ }
9489
+ return output;
9490
+ }
9491
+ __name(formatDevelopmentLog, "formatDevelopmentLog");
9335
9492
  var WinstonImplementationModule = class _WinstonImplementationModule {
9336
9493
  static {
9337
9494
  __name(this, "WinstonImplementationModule");
@@ -9406,124 +9563,13 @@ var WinstonImplementationModule = class _WinstonImplementationModule {
9406
9563
  const isProduction = config?.isProduction ?? process.env.NODE_ENV === "production";
9407
9564
  const useColors = config?.colorize !== false;
9408
9565
  const standardFields = (0, import_winston2.format)((info) => {
9409
- const meta = info.meta;
9410
- if (meta) {
9411
- if (meta.requestId && !info.requestId) {
9412
- info.requestId = meta.requestId;
9413
- delete meta.requestId;
9414
- }
9415
- if (meta.context && !info.context) {
9416
- info.context = meta.context;
9417
- delete meta.context;
9418
- }
9419
- if (meta.source && !info.source) {
9420
- info.source = meta.source;
9421
- delete meta.source;
9422
- }
9423
- if (meta.lib && !info.lib) {
9424
- info.lib = meta.lib;
9425
- delete meta.lib;
9426
- }
9427
- if (meta.libVersion && !info.libVersion) {
9428
- info.libVersion = meta.libVersion;
9429
- delete meta.libVersion;
9430
- }
9431
- if (meta.libMethod && !info.libMethod) {
9432
- info.libMethod = meta.libMethod;
9433
- delete meta.libMethod;
9434
- }
9435
- if (meta.appName && !info.appName) {
9436
- info.appName = meta.appName;
9437
- delete meta.appName;
9438
- }
9439
- if (meta.appVersion && !info.appVersion) {
9440
- info.appVersion = meta.appVersion;
9441
- delete meta.appVersion;
9442
- }
9443
- if (meta.logContext && !info.source) {
9444
- const lc = meta.logContext;
9445
- if (lc.className && lc.methodName) {
9446
- info.source = `${lc.className}.${lc.methodName}`;
9447
- } else if (lc.className) {
9448
- info.source = lc.className;
9449
- } else if (lc.methodName) {
9450
- info.source = lc.methodName;
9451
- }
9452
- }
9453
- }
9454
- info.requestId = info.requestId || "no-request-id";
9455
- info.context = info.context || config?.context || "App";
9456
- info.appName = info.appName || config?.appName;
9457
- info.appVersion = info.appVersion || config?.appVersion;
9458
- info.lib = info.lib || config?.lib;
9459
- info.libVersion = info.libVersion || config?.libVersion;
9460
- return info;
9566
+ const writableInfo = info;
9567
+ fillInfoFromMeta(writableInfo);
9568
+ applyDefaultInfoValues(writableInfo, config);
9569
+ return writableInfo;
9461
9570
  });
9462
9571
  const levelColorizer = import_winston2.format.colorize();
9463
- const developmentFormat = import_winston2.format.printf((info) => {
9464
- const { level, message, timestamp, requestId, context, source, meta, stack, appName, appVersion, lib, libMethod, libVersion } = info;
9465
- const colors = {
9466
- reset: "\x1B[0m",
9467
- gray: "\x1B[90m",
9468
- cyan: "\x1B[36m",
9469
- magenta: "\x1B[35m",
9470
- yellow: "\x1B[33m",
9471
- red: "\x1B[31m",
9472
- green: "\x1B[32m",
9473
- bold: "\x1B[1m"
9474
- };
9475
- const colorize = /* @__PURE__ */ __name((color, text) => useColors ? `${color}${text}${colors.reset}` : text, "colorize");
9476
- const coloredLevel = useColors ? levelColorizer.colorize(level, level.toUpperCase()) : level.toUpperCase();
9477
- const coloredTime = colorize(colors.gray, timestamp);
9478
- const coloredRequestId = colorize(colors.cyan, requestId);
9479
- let appDisplay = "";
9480
- if (appName) {
9481
- const appText = appVersion ? `${appName}@${appVersion}` : appName;
9482
- appDisplay = `[${colorize(colors.green, `App-${appText}`)}]`;
9483
- }
9484
- let libDisplay = "";
9485
- if (lib) {
9486
- const libText = libVersion ? `${lib}:${libVersion}` : lib;
9487
- libDisplay = `[${colorize(colors.yellow, libText)}]`;
9488
- }
9489
- const mag = colors.magenta;
9490
- let sourceDisplay = "";
9491
- let libMethodDisplay = "";
9492
- if (source) {
9493
- sourceDisplay = `[${colorize(mag, source)}]`;
9494
- }
9495
- if (lib) {
9496
- const methodPath = libMethod ? `${context}.${libMethod}` : context;
9497
- libMethodDisplay = `[${colorize(mag, methodPath)}]`;
9498
- if (source === context || source === methodPath) {
9499
- sourceDisplay = "";
9500
- }
9501
- } else if (!source) {
9502
- libMethodDisplay = `[${colorize(mag, context)}]`;
9503
- } else if (source.startsWith(`${context}.`) || source === context) {
9504
- libMethodDisplay = `[${colorize(mag, source)}]`;
9505
- sourceDisplay = "";
9506
- } else {
9507
- libMethodDisplay = `[${colorize(mag, context)}]`;
9508
- sourceDisplay = `[${colorize(mag, source)}]`;
9509
- }
9510
- let output = `${appDisplay}${libDisplay}[${coloredRequestId}][${coloredTime}]${sourceDisplay}${libMethodDisplay}[${coloredLevel}] - ${message}`;
9511
- if (meta && typeof meta === "object" && Object.keys(meta).length > 0) {
9512
- const inspectedMeta = (0, import_util.inspect)(meta, {
9513
- colors: useColors,
9514
- depth: null,
9515
- compact: true,
9516
- sorted: true,
9517
- breakLength: Infinity
9518
- });
9519
- output += ` - ${inspectedMeta}`;
9520
- }
9521
- if (stack) {
9522
- output += `
9523
- ${colorize(colors.red, stack)}`;
9524
- }
9525
- return output;
9526
- });
9572
+ const developmentFormat = import_winston2.format.printf((info) => formatDevelopmentLog(info, useColors, levelColorizer));
9527
9573
  const formats = [
9528
9574
  import_winston2.format.timestamp(),
9529
9575
  import_winston2.format.errors({
@@ -9548,7 +9594,10 @@ ${colorize(colors.red, stack)}`;
9548
9594
  consoleTransport
9549
9595
  ]
9550
9596
  };
9551
- const mergedOptions = Object.assign({}, defaultOptions, config?.loggerOptions || {});
9597
+ const mergedOptions = config?.loggerOptions ? {
9598
+ ...defaultOptions,
9599
+ ...config.loggerOptions
9600
+ } : defaultOptions;
9552
9601
  return (0, import_winston2.createLogger)(mergedOptions);
9553
9602
  }
9554
9603
  };
@@ -9598,6 +9647,15 @@ var HttpLoggingInterceptor = class {
9598
9647
  logger;
9599
9648
  reflector;
9600
9649
  excludedPaths;
9650
+ toErrorMessage(error) {
9651
+ if (error instanceof Error) return error.message;
9652
+ if (typeof error === "string") return error;
9653
+ try {
9654
+ return JSON.stringify(error);
9655
+ } catch {
9656
+ return "unknown error";
9657
+ }
9658
+ }
9601
9659
  constructor(logger, reflector, config) {
9602
9660
  this.logger = logger;
9603
9661
  this.reflector = reflector;
@@ -9666,7 +9724,7 @@ var HttpLoggingInterceptor = class {
9666
9724
  },
9667
9725
  response: {
9668
9726
  durationMs,
9669
- error: error instanceof Error ? error.message : String(error)
9727
+ error: this.toErrorMessage(error)
9670
9728
  }
9671
9729
  }
9672
9730
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adatechnology/logger",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,4 +1,4 @@
1
- import { AsyncLocalStorage } from "async_hooks";
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { RequestContext } from "./async-context.types";
3
3
 
4
4
  export const asyncLocalStorage = new AsyncLocalStorage<
@@ -1,6 +1,6 @@
1
1
  import { DynamicModule, Module, Provider } from "@nestjs/common";
2
2
  import { createLogger, format, transports, LoggerOptions } from "winston";
3
- import { inspect } from "util";
3
+ import { inspect } from "node:util";
4
4
  import { WinstonLoggerProvider } from "./winston.logger.provider";
5
5
  import {
6
6
  WINSTON_LOGGER,
@@ -11,6 +11,227 @@ import type { LoggerConfig } from "../../logger.config";
11
11
  import { DEFAULT_LOG_LEVEL } from "./winston.logger.constants";
12
12
  import { buildDefaultObfuscator } from "../../obfuscator";
13
13
 
14
+ type WritableLogInfo = Record<string, unknown> & {
15
+ level?: unknown;
16
+ message?: unknown;
17
+ timestamp?: unknown;
18
+ requestId?: unknown;
19
+ context?: unknown;
20
+ source?: unknown;
21
+ appName?: unknown;
22
+ appVersion?: unknown;
23
+ lib?: unknown;
24
+ libVersion?: unknown;
25
+ libMethod?: unknown;
26
+ stack?: unknown;
27
+ meta?: unknown;
28
+ };
29
+
30
+ type MetaLogContext = {
31
+ className?: unknown;
32
+ methodName?: unknown;
33
+ };
34
+
35
+ function asString(value: unknown): string | undefined {
36
+ if (typeof value === "string") return value;
37
+ if (typeof value === "number" || typeof value === "boolean") {
38
+ return String(value);
39
+ }
40
+ return undefined;
41
+ }
42
+
43
+ function colorizeText(
44
+ useColors: boolean,
45
+ color: string,
46
+ reset: string,
47
+ text: string,
48
+ ): string {
49
+ return useColors ? `${color}${text}${reset}` : text;
50
+ }
51
+
52
+ function fillInfoFromMeta(info: WritableLogInfo): void {
53
+ if (!info.meta || typeof info.meta !== "object") return;
54
+
55
+ const meta = info.meta as Record<string, unknown>;
56
+ const metadataKeys = [
57
+ "requestId",
58
+ "context",
59
+ "source",
60
+ "lib",
61
+ "libVersion",
62
+ "libMethod",
63
+ "appName",
64
+ "appVersion",
65
+ ] as const;
66
+
67
+ for (const key of metadataKeys) {
68
+ if (meta[key] && !info[key]) {
69
+ info[key] = meta[key];
70
+ delete meta[key];
71
+ }
72
+ }
73
+
74
+ const logContext = meta.logContext as MetaLogContext | undefined;
75
+ if (!logContext || info.source) return;
76
+
77
+ const className = asString(logContext.className);
78
+ const methodName = asString(logContext.methodName);
79
+
80
+ if (className && methodName) {
81
+ info.source = `${className}.${methodName}`;
82
+ } else if (className) {
83
+ info.source = className;
84
+ } else if (methodName) {
85
+ info.source = methodName;
86
+ }
87
+ }
88
+
89
+ function applyDefaultInfoValues(
90
+ info: WritableLogInfo,
91
+ config?: LoggerConfig,
92
+ ): void {
93
+ info.requestId = info.requestId || "no-request-id";
94
+ info.context = info.context || config?.context || "App";
95
+ info.appName = info.appName || config?.appName;
96
+ info.appVersion = info.appVersion || config?.appVersion;
97
+ info.lib = info.lib || config?.lib;
98
+ info.libVersion = info.libVersion || config?.libVersion;
99
+ }
100
+
101
+ function buildMethodDisplays(params: {
102
+ context: string;
103
+ source?: string;
104
+ lib?: string;
105
+ libMethod?: string;
106
+ colorize: (text: string) => string;
107
+ }): { sourceDisplay: string; libMethodDisplay: string } {
108
+ const { context, source, lib, libMethod, colorize } = params;
109
+
110
+ let sourceDisplay = "";
111
+ let libMethodDisplay = "";
112
+
113
+ if (source) {
114
+ sourceDisplay = `[${colorize(source)}]`;
115
+ }
116
+
117
+ if (lib) {
118
+ const methodPath = libMethod ? `${context}.${libMethod}` : context;
119
+ libMethodDisplay = `[${colorize(methodPath)}]`;
120
+ if (source === context || source === methodPath) {
121
+ sourceDisplay = "";
122
+ }
123
+ return { sourceDisplay, libMethodDisplay };
124
+ }
125
+
126
+ if (!source) {
127
+ libMethodDisplay = `[${colorize(context)}]`;
128
+ return { sourceDisplay, libMethodDisplay };
129
+ }
130
+
131
+ if (source.startsWith(`${context}.`) || source === context) {
132
+ libMethodDisplay = `[${colorize(source)}]`;
133
+ sourceDisplay = "";
134
+ return { sourceDisplay, libMethodDisplay };
135
+ }
136
+
137
+ libMethodDisplay = `[${colorize(context)}]`;
138
+ sourceDisplay = `[${colorize(source)}]`;
139
+ return { sourceDisplay, libMethodDisplay };
140
+ }
141
+
142
+ function formatDevelopmentLog(
143
+ infoInput: WritableLogInfo,
144
+ useColors: boolean,
145
+ levelColorizer: ReturnType<typeof format.colorize>,
146
+ ): string {
147
+ const info = infoInput;
148
+ const level = asString(info.level) ?? "info";
149
+ const message = asString(info.message) ?? "";
150
+ const timestamp = asString(info.timestamp) ?? "";
151
+ const requestId = asString(info.requestId) ?? "no-request-id";
152
+ const context = asString(info.context) ?? "App";
153
+ const source = asString(info.source);
154
+ const appName = asString(info.appName);
155
+ const appVersion = asString(info.appVersion);
156
+ const lib = asString(info.lib);
157
+ const libMethod = asString(info.libMethod);
158
+ const libVersion = asString(info.libVersion);
159
+ const stack = asString(info.stack);
160
+
161
+ const meta =
162
+ info.meta && typeof info.meta === "object"
163
+ ? (info.meta as Record<string, unknown>)
164
+ : undefined;
165
+
166
+ const colors = {
167
+ reset: "\x1b[0m",
168
+ gray: "\x1b[90m",
169
+ cyan: "\x1b[36m",
170
+ magenta: "\x1b[35m",
171
+ yellow: "\x1b[33m",
172
+ red: "\x1b[31m",
173
+ green: "\x1b[32m",
174
+ };
175
+
176
+ const coloredLevel = useColors
177
+ ? levelColorizer.colorize(level, level.toUpperCase())
178
+ : level.toUpperCase();
179
+
180
+ const coloredTime = colorizeText(
181
+ useColors,
182
+ colors.gray,
183
+ colors.reset,
184
+ timestamp,
185
+ );
186
+ const coloredRequestId = colorizeText(
187
+ useColors,
188
+ colors.cyan,
189
+ colors.reset,
190
+ requestId,
191
+ );
192
+
193
+ let appDisplay = "";
194
+ if (appName) {
195
+ const appText = appVersion ? `${appName}@${appVersion}` : appName;
196
+ const appLabel = `App-${appText}`;
197
+ appDisplay = `[${colorizeText(useColors, colors.green, colors.reset, appLabel)}]`;
198
+ }
199
+
200
+ let libDisplay = "";
201
+ if (lib) {
202
+ const libText = libVersion ? `${lib}:${libVersion}` : lib;
203
+ libDisplay = `[${colorizeText(useColors, colors.yellow, colors.reset, libText)}]`;
204
+ }
205
+
206
+ const { sourceDisplay, libMethodDisplay } = buildMethodDisplays({
207
+ context,
208
+ source,
209
+ lib,
210
+ libMethod,
211
+ colorize: (text) =>
212
+ colorizeText(useColors, colors.magenta, colors.reset, text),
213
+ });
214
+
215
+ let output = `${appDisplay}${libDisplay}[${coloredRequestId}][${coloredTime}]${sourceDisplay}${libMethodDisplay}[${coloredLevel}] - ${message}`;
216
+
217
+ if (meta && typeof meta === "object" && Object.keys(meta).length > 0) {
218
+ const inspectedMeta = inspect(meta, {
219
+ colors: useColors,
220
+ depth: null,
221
+ compact: true,
222
+ sorted: true,
223
+ breakLength: Infinity,
224
+ });
225
+ output += ` - ${inspectedMeta}`;
226
+ }
227
+
228
+ if (stack) {
229
+ output += `\n${colorizeText(useColors, colors.red, colors.reset, stack)}`;
230
+ }
231
+
232
+ return output;
233
+ }
234
+
14
235
  @Module({})
15
236
  export class WinstonImplementationModule {
16
237
  static forRoot(config?: LoggerConfig): DynamicModule {
@@ -91,181 +312,17 @@ export class WinstonImplementationModule {
91
312
 
92
313
  // Standard fields we want to ensure are in the log object
93
314
  const standardFields = format((info) => {
94
- // Extract requestId and context from meta if they exist there
95
- const meta = info.meta as any;
96
- if (meta) {
97
- if (meta.requestId && !info.requestId) {
98
- info.requestId = meta.requestId;
99
- delete meta.requestId;
100
- }
101
- if (meta.context && !info.context) {
102
- info.context = meta.context;
103
- delete meta.context;
104
- }
105
-
106
- // Extract source (used for className.methodName)
107
- if (meta.source && !info.source) {
108
- info.source = meta.source;
109
- delete meta.source;
110
- }
111
-
112
- // Support lib identification from metadata
113
- if (meta.lib && !info.lib) {
114
- info.lib = meta.lib;
115
- delete meta.lib;
116
- }
117
-
118
- // Support lib version identification from metadata
119
- if (meta.libVersion && !info.libVersion) {
120
- info.libVersion = meta.libVersion;
121
- delete meta.libVersion;
122
- }
123
-
124
- // Support lib method identification
125
- if (meta.libMethod && !info.libMethod) {
126
- info.libMethod = meta.libMethod;
127
- delete meta.libMethod;
128
- }
129
-
130
- // Support app identification from metadata
131
- if (meta.appName && !info.appName) {
132
- info.appName = meta.appName;
133
- delete meta.appName;
134
- }
135
-
136
- // Support app version identification from metadata
137
- if (meta.appVersion && !info.appVersion) {
138
- info.appVersion = meta.appVersion;
139
- delete meta.appVersion;
140
- }
141
-
142
- // Support logContext object from some providers
143
- if (meta.logContext && !info.source) {
144
- const lc = meta.logContext;
145
- if (lc.className && lc.methodName) {
146
- info.source = `${lc.className}.${lc.methodName}`;
147
- } else if (lc.className) {
148
- info.source = lc.className;
149
- } else if (lc.methodName) {
150
- info.source = lc.methodName;
151
- }
152
- }
153
- }
154
-
155
- // Default values
156
- info.requestId = info.requestId || "no-request-id";
157
- info.context = info.context || config?.context || "App";
158
- info.appName = info.appName || config?.appName;
159
- info.appVersion = info.appVersion || config?.appVersion;
160
- info.lib = info.lib || config?.lib;
161
- info.libVersion = info.libVersion || config?.libVersion;
162
-
163
- return info;
315
+ const writableInfo = info as WritableLogInfo;
316
+ fillInfoFromMeta(writableInfo);
317
+ applyDefaultInfoValues(writableInfo, config);
318
+ return writableInfo;
164
319
  });
165
320
 
166
321
  const levelColorizer = format.colorize();
167
322
 
168
323
  // Custom format for development (colorful and intuitive)
169
- const developmentFormat = format.printf(
170
- (info) => {
171
- const {
172
- level, message, timestamp, requestId, context, source,
173
- meta, stack, appName, appVersion, lib, libMethod, libVersion
174
- } = info;
175
-
176
- // Colors (using ANSI codes for precision)
177
- const colors = {
178
- reset: "\x1b[0m",
179
- gray: "\x1b[90m",
180
- cyan: "\x1b[36m",
181
- magenta: "\x1b[35m",
182
- yellow: "\x1b[33m",
183
- red: "\x1b[31m",
184
- green: "\x1b[32m",
185
- bold: "\x1b[1m",
186
- };
187
-
188
- const colorize = (color: string, text: string) =>
189
- useColors ? `${color}${text}${colors.reset}` : text;
190
-
191
- // No trailing space for the level itself, but keep it uppercase
192
- const coloredLevel = useColors
193
- ? levelColorizer.colorize(level, level.toUpperCase())
194
- : level.toUpperCase();
195
-
196
- const coloredTime = colorize(colors.gray, timestamp);
197
- const coloredRequestId = colorize(colors.cyan, requestId);
198
-
199
- // App identification: [App-example@0.0.3]
200
- let appDisplay = "";
201
- if (appName) {
202
- const appText = appVersion ? `${appName}@${appVersion}` : appName;
203
- appDisplay = `[${colorize(colors.green, `App-${appText}`)}]`;
204
- }
205
-
206
- // Lib identification: [@adatechnology/http-client:0.0.2]
207
- let libDisplay = "";
208
- if (lib) {
209
- const libText = libVersion ? `${lib}:${libVersion}` : lib;
210
- libDisplay = `[${colorize(colors.yellow, libText)}]`;
211
- }
212
-
213
- const mag = colors.magenta;
214
-
215
- // Context formatting logic:
216
- // [Source] (Magenta) - From the caller (e.g., HttpClientController.listPokemon)
217
- // [Context.Method] (Magenta) - From the lib itself (e.g., HttpRedisClient.get)
218
- let sourceDisplay = "";
219
- let libMethodDisplay = "";
220
-
221
- if (source) {
222
- sourceDisplay = `[${colorize(mag, source)}]`;
223
- }
224
-
225
- if (lib) {
226
- // Inside a library log
227
- const methodPath = libMethod ? `${context}.${libMethod}` : context;
228
- libMethodDisplay = `[${colorize(mag, methodPath)}]`;
229
-
230
- // If source is the same as context or methodPath, we can omit it to avoid duplication
231
- if (source === context || source === methodPath) {
232
- sourceDisplay = "";
233
- }
234
- } else if (!source) {
235
- // App-only log without source: use context
236
- libMethodDisplay = `[${colorize(mag, context)}]`;
237
- } else if (source.startsWith(`${context}.`) || source === context) {
238
- // App-only log where source is more specific than context: use source only
239
- libMethodDisplay = `[${colorize(mag, source)}]`;
240
- sourceDisplay = "";
241
- } else {
242
- // App-only log with different context and source
243
- libMethodDisplay = `[${colorize(mag, context)}]`;
244
- sourceDisplay = `[${colorize(mag, source)}]`;
245
- }
246
-
247
- // Header line: [App][Lib][requestId][timestamp][Source][LibMethod][LEVEL]
248
- let output = `${appDisplay}${libDisplay}[${coloredRequestId}][${coloredTime}]${sourceDisplay}${libMethodDisplay}[${coloredLevel}] - ${message}`;
249
-
250
- // Meta data (Pretty printed if not empty)
251
- if (meta && typeof meta === "object" && Object.keys(meta).length > 0) {
252
- const inspectedMeta = inspect(meta, {
253
- colors: useColors,
254
- depth: null,
255
- compact: true,
256
- sorted: true,
257
- breakLength: Infinity,
258
- });
259
- output += ` - ${inspectedMeta}`;
260
- }
261
-
262
- // Error stack trace
263
- if (stack) {
264
- output += `\n${colorize(colors.red, stack)}`;
265
- }
266
-
267
- return output;
268
- }
324
+ const developmentFormat = format.printf((info) =>
325
+ formatDevelopmentLog(info as WritableLogInfo, useColors, levelColorizer),
269
326
  );
270
327
 
271
328
  const formats = [
@@ -294,11 +351,9 @@ export class WinstonImplementationModule {
294
351
  transports: [consoleTransport],
295
352
  };
296
353
 
297
- const mergedOptions: LoggerOptions = Object.assign(
298
- {},
299
- defaultOptions,
300
- config?.loggerOptions || {},
301
- );
354
+ const mergedOptions: LoggerOptions = config?.loggerOptions
355
+ ? { ...defaultOptions, ...config.loggerOptions }
356
+ : defaultOptions;
302
357
 
303
358
  return createLogger(mergedOptions);
304
359
  }
@@ -1,10 +1,18 @@
1
1
  import { Injectable, Inject } from "@nestjs/common";
2
2
  import { Logger as WinstonLoggerType } from "winston";
3
3
  import {
4
- type LogPayload,
4
+ type DebugParams,
5
+ type DebugResult,
6
+ type ErrorParams,
7
+ type ErrorResult,
8
+ type InfoParams,
9
+ type InfoResult,
5
10
  type LoggerProviderInterface,
6
11
  LoggerLevel,
7
- type LogParams,
12
+ type WarnParams,
13
+ type WarnResult,
14
+ type WriteLogParams,
15
+ type WriteLogResult,
8
16
  } from "../../logger.interface";
9
17
  import type { Obfuscator } from "./winston.logger.types";
10
18
  import { getContext } from "../../context/async-context.service";
@@ -20,76 +28,67 @@ export class WinstonLoggerProvider implements LoggerProviderInterface {
20
28
  @Inject(WINSTON_OBFUSCATOR) private readonly obfuscator?: Obfuscator,
21
29
  ) {}
22
30
 
23
- debug(payload: LogPayload): void;
24
- debug(message: string, meta?: Record<string, unknown>, context?: string): void;
25
- debug(messageOrPayload: string | LogPayload, meta?: Record<string, unknown>, context?: string): void {
26
- this.handleLog(LoggerLevel.DEBUG, messageOrPayload, meta, context);
31
+ debug(payload: DebugParams): DebugResult {
32
+ this.log({
33
+ level: LoggerLevel.DEBUG,
34
+ payload: {
35
+ ...payload,
36
+ context: payload.context || this.context,
37
+ },
38
+ });
27
39
  }
28
40
 
29
- info(payload: LogPayload): void;
30
- info(message: string, meta?: Record<string, unknown>, context?: string): void;
31
- info(messageOrPayload: string | LogPayload, meta?: Record<string, unknown>, context?: string): void {
32
- this.handleLog(LoggerLevel.INFO, messageOrPayload, meta, context);
41
+ info(payload: InfoParams): InfoResult {
42
+ this.log({
43
+ level: LoggerLevel.INFO,
44
+ payload: {
45
+ ...payload,
46
+ context: payload.context || this.context,
47
+ },
48
+ });
33
49
  }
34
50
 
35
- warn(payload: LogPayload): void;
36
- warn(message: string, meta?: Record<string, unknown>, context?: string): void;
37
- warn(messageOrPayload: string | LogPayload, meta?: Record<string, unknown>, context?: string): void {
38
- this.handleLog(LoggerLevel.WARN, messageOrPayload, meta, context);
51
+ warn(payload: WarnParams): WarnResult {
52
+ this.log({
53
+ level: LoggerLevel.WARN,
54
+ payload: {
55
+ ...payload,
56
+ context: payload.context || this.context,
57
+ },
58
+ });
39
59
  }
40
60
 
41
- error(payload: LogPayload): void;
42
- error(message: string, meta?: Record<string, unknown>, context?: string): void;
43
- error(messageOrPayload: string | LogPayload, meta?: Record<string, unknown>, context?: string): void {
44
- this.handleLog(LoggerLevel.ERROR, messageOrPayload, meta, context);
61
+ error(payload: ErrorParams): ErrorResult {
62
+ this.log({
63
+ level: LoggerLevel.ERROR,
64
+ payload: {
65
+ ...payload,
66
+ context: payload.context || this.context,
67
+ },
68
+ });
45
69
  }
46
70
 
47
71
  setContext(context: string): void {
48
72
  this.context = context;
49
73
  }
50
74
 
51
- private handleLog(
52
- level: LoggerLevel,
53
- messageOrPayload: string | LogPayload,
54
- meta?: Record<string, unknown>,
55
- context?: string,
56
- ): void {
57
- let payload: LogPayload;
58
-
59
- if (typeof messageOrPayload === "string") {
60
- payload = {
61
- message: messageOrPayload,
62
- meta,
63
- context: context || this.context,
64
- };
65
- } else {
66
- payload = {
67
- ...messageOrPayload,
68
- context: messageOrPayload.context || context || this.context,
69
- meta: { ...messageOrPayload.meta, ...meta },
70
- };
71
- }
72
-
73
- this.log({ level, payload });
74
- }
75
-
76
- private log(params: LogParams) {
75
+ private log(params: WriteLogParams): WriteLogResult {
77
76
  const { level, payload } = params;
78
77
  // Extract standard fields but keep the rest to pass to Winston
79
78
  const { message, context, meta, ...rest } = payload as any;
80
-
79
+
81
80
  const messageText = message ?? EMPTY_STRING;
82
81
  const messageContext = context ?? this.context;
83
82
  const obfuscatedMeta = this.obfuscator ? this.obfuscator(meta) : meta;
84
83
 
85
84
  const requestContext = getContext();
86
- const requestIdFromContext = (requestContext as Record<string, unknown> | undefined)?.requestId;
87
-
85
+ const requestIdFromContext = requestContext?.requestId;
86
+
88
87
  // Merge everything into a flat info object for Winston
89
88
  const logInfo: Record<string, unknown> = {
90
89
  ...rest,
91
90
  context: messageContext,
92
- requestId: requestIdFromContext || payload.requestId,
91
+ requestId: requestIdFromContext || rest.requestId,
93
92
  meta: obfuscatedMeta,
94
93
  };
95
94
 
package/src/index.ts CHANGED
@@ -1,9 +1,20 @@
1
1
  export { LoggerModule } from "./logger.module";
2
2
  export { LOGGER_PROVIDER, LOGGER_CONFIG, HTTP_LOGGING_INTERCEPTOR } from "./logger.token";
3
3
  export type {
4
+ DebugParams,
5
+ DebugResult,
6
+ ErrorParams,
7
+ ErrorResult,
8
+ InfoParams,
9
+ InfoResult,
10
+ LogParams,
11
+ LogResult,
4
12
  LoggerProviderInterface,
5
- LogPayload,
6
13
  LoggerLevel,
14
+ WarnParams,
15
+ WarnResult,
16
+ WriteLogParams,
17
+ WriteLogResult,
7
18
  } from "./logger.interface";
8
19
  export { RequestContextMiddleware } from "./middleware/request-context.middleware";
9
20
  export { HttpLoggingInterceptor } from "./interceptors/http-logging.interceptor";
@@ -12,6 +12,16 @@ import { EXCLUDE_HTTP_LOGGING_KEY } from "./exclude-http-logging.decorator";
12
12
  export class HttpLoggingInterceptor implements NestInterceptor {
13
13
  private readonly excludedPaths: string[];
14
14
 
15
+ private toErrorMessage(error: unknown): string {
16
+ if (error instanceof Error) return error.message;
17
+ if (typeof error === "string") return error;
18
+ try {
19
+ return JSON.stringify(error);
20
+ } catch {
21
+ return "unknown error";
22
+ }
23
+ }
24
+
15
25
  constructor(
16
26
  @Inject(LOGGER_PROVIDER)
17
27
  private readonly logger: LoggerProviderInterface,
@@ -99,7 +109,7 @@ export class HttpLoggingInterceptor implements NestInterceptor {
99
109
  },
100
110
  response: {
101
111
  durationMs,
102
- error: error instanceof Error ? error.message : String(error),
112
+ error: this.toErrorMessage(error),
103
113
  },
104
114
  },
105
115
  });
@@ -5,21 +5,37 @@ export enum LoggerLevel {
5
5
  ERROR = "error",
6
6
  }
7
7
 
8
- export interface LogPayload {
8
+ export type LogParams = {
9
9
  message: string;
10
10
  context?: string;
11
11
  meta?: Record<string, unknown>;
12
- }
12
+ };
13
+
14
+ export type LogResult = void;
15
+
16
+ export type DebugParams = LogParams;
17
+ export type DebugResult = LogResult;
18
+
19
+ export type InfoParams = LogParams;
20
+ export type InfoResult = LogResult;
21
+
22
+ export type WarnParams = LogParams;
23
+ export type WarnResult = LogResult;
24
+
25
+ export type ErrorParams = LogParams;
26
+ export type ErrorResult = LogResult;
13
27
 
14
28
  export interface LoggerProviderInterface {
15
- debug(payload: LogPayload): void;
16
- info(payload: LogPayload): void;
17
- warn(payload: LogPayload): void;
18
- error(payload: LogPayload): void;
29
+ debug(params: DebugParams): DebugResult;
30
+ info(params: InfoParams): InfoResult;
31
+ warn(params: WarnParams): WarnResult;
32
+ error(params: ErrorParams): ErrorResult;
19
33
  setContext?(context: string): void;
20
34
  }
21
35
 
22
- export type LogParams = {
36
+ export type WriteLogParams = {
23
37
  level: LoggerLevel;
24
- payload: LogPayload;
38
+ payload: LogParams;
25
39
  };
40
+
41
+ export type WriteLogResult = LogResult;
@@ -1,5 +1,15 @@
1
1
  import { Injectable, Inject } from "@nestjs/common";
2
- import type { LoggerProviderInterface, LogPayload } from "./logger.interface";
2
+ import type {
3
+ DebugParams,
4
+ DebugResult,
5
+ ErrorParams,
6
+ ErrorResult,
7
+ InfoParams,
8
+ InfoResult,
9
+ LoggerProviderInterface,
10
+ WarnParams,
11
+ WarnResult,
12
+ } from "./logger.interface";
3
13
  import { WINSTON_LOGGER } from "./implementations/winston/winston.logger.token";
4
14
 
5
15
  @Injectable()
@@ -9,45 +19,24 @@ export class LoggerProvider implements LoggerProviderInterface {
9
19
  private readonly implementation: LoggerProviderInterface,
10
20
  ) {}
11
21
 
12
- debug(payload: LogPayload): void;
13
- debug(
14
- message: string,
15
- meta?: Record<string, unknown>,
16
- context?: string,
17
- ): void;
18
- debug(...args: unknown[]): void {
19
- // @ts-ignore - delegate to implementation which supports overloads
20
- return this.implementation.debug(...(args as any));
22
+ debug(params: DebugParams): DebugResult {
23
+ return this.implementation.debug(params);
21
24
  }
22
25
 
23
- info(payload: LogPayload): void;
24
- info(message: string, meta?: Record<string, unknown>, context?: string): void;
25
- info(...args: unknown[]): void {
26
- // @ts-ignore
27
- return this.implementation.info(...(args as any));
26
+ info(params: InfoParams): InfoResult {
27
+ return this.implementation.info(params);
28
28
  }
29
29
 
30
- warn(payload: LogPayload): void;
31
- warn(message: string, meta?: Record<string, unknown>, context?: string): void;
32
- warn(...args: unknown[]): void {
33
- // @ts-ignore
34
- return this.implementation.warn(...(args as any));
30
+ warn(params: WarnParams): WarnResult {
31
+ return this.implementation.warn(params);
35
32
  }
36
33
 
37
- error(payload: LogPayload): void;
38
- error(
39
- message: string,
40
- meta?: Record<string, unknown>,
41
- context?: string,
42
- ): void;
43
- error(...args: unknown[]): void {
44
- // @ts-ignore
45
- return this.implementation.error(...(args as any));
34
+ error(params: ErrorParams): ErrorResult {
35
+ return this.implementation.error(params);
46
36
  }
47
37
  setContext?(context: string): void {
48
38
  if (typeof this.implementation.setContext === "function") {
49
39
  return this.implementation.setContext(context);
50
40
  }
51
- return;
52
41
  }
53
42
  }