@rsdk/logging 5.11.0-next.2 → 5.11.0-next.3

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.
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ export declare const LogSerializer: () => ClassDecorator;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LogSerializer = void 0;
4
+ require("reflect-metadata");
5
+ const constants_1 = require("../metadata/constants");
6
+ const logger_metadata_registry_1 = require("../metadata/logger-metadata.registry");
7
+ const logSerializerDecorator = function (target) {
8
+ const metadata = {
9
+ target: target,
10
+ };
11
+ Reflect.defineMetadata(constants_1.LOGGER_METADATA_KEY, metadata, target);
12
+ logger_metadata_registry_1.LoggerMetadataRegistry.registerSerializer(target, metadata);
13
+ };
14
+ const LogSerializer = () => logSerializerDecorator;
15
+ exports.LogSerializer = LogSerializer;
16
+ //# sourceMappingURL=log-serializer.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-serializer.decorator.js","sourceRoot":"","sources":["../../src/decorators/log-serializer.decorator.ts"],"names":[],"mappings":";;;AAGA,4BAA0B;AAE1B,qDAA4D;AAC5D,mFAA8E;AAG9E,MAAM,sBAAsB,GAAmB,UAC7C,MAAgB;IAEhB,MAAM,QAAQ,GAA6B;QACzC,MAAM,EAAE,MAAqB;KAC9B,CAAC;IAEF,OAAO,CAAC,cAAc,CAAC,+BAAmB,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9D,iDAAsB,CAAC,kBAAkB,CAAC,MAAqB,EAAE,QAAQ,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEK,MAAM,aAAa,GAAG,GAAmB,EAAE,CAAC,sBAAsB,CAAC;AAA7D,QAAA,aAAa,iBAAgD"}
@@ -1,6 +1,6 @@
1
1
  import type { ErrorLike } from '@rsdk/common';
2
2
  import type { Logger as Pino } from 'pino';
3
- import type { ILogger } from '../logger.interface';
3
+ import type { ILogger, LogSerializerBase } from '../logger.interface';
4
4
  import type { LoggingContext, OnMessage, Params } from '../types';
5
5
  import { LogLevel } from '../types';
6
6
  /**
@@ -16,7 +16,8 @@ export declare class PinoLogger implements ILogger {
16
16
  */
17
17
  private readonly _pino;
18
18
  private readonly emit;
19
- constructor(pino: GetLogger, emit: OnMessage, context: LoggingContext);
19
+ private readonly getSerializers;
20
+ constructor(pino: GetLogger, emit: OnMessage, context: LoggingContext, getSerializers: () => LogSerializerBase[]);
20
21
  get pino(): Pino;
21
22
  trace(params: Params): void;
22
23
  trace(message: string, params?: Params): void;
@@ -11,10 +11,12 @@ class PinoLogger {
11
11
  */
12
12
  _pino;
13
13
  emit;
14
- constructor(pino, emit, context) {
14
+ getSerializers;
15
+ constructor(pino, emit, context, getSerializers) {
15
16
  this._pino = pino;
16
17
  this.emit = emit;
17
18
  this.context = (0, helpers_1.stringifyContext)(context);
19
+ this.getSerializers = getSerializers;
18
20
  }
19
21
  get pino() {
20
22
  return this._pino();
@@ -53,18 +55,40 @@ class PinoLogger {
53
55
  }
54
56
  const paramsOrError = typeof arg1 === 'string' ? arg2 : arg1;
55
57
  if (paramsOrError) {
56
- const options = {
57
- sortKeys: common_1.sortErrorKeys,
58
- };
59
58
  if (level === 'fatal' || level === 'error') {
60
- args['error'] = (0, common_1.normalizer)()(paramsOrError, options);
59
+ args.error = paramsOrError;
61
60
  }
62
61
  else {
63
- Object.assign(args, (0, common_1.normalizer)()(paramsOrError, options));
62
+ Object.assign(args, paramsOrError);
64
63
  }
65
64
  }
66
- this.emit(level, { ...args, message });
67
- this.pino[level](args, message);
65
+ if (message) {
66
+ args.message = message;
67
+ }
68
+ const serializers = this.getSerializers();
69
+ for (const [key, value] of Object.entries(args)) {
70
+ // Пропускаем ненужные поля
71
+ if (key === 'context' || key === 'message')
72
+ continue;
73
+ if (value == null || typeof value !== 'object')
74
+ continue;
75
+ for (const serializer of serializers) {
76
+ try {
77
+ // eslint-disable-next-line unicorn/prefer-regexp-test
78
+ if (serializer.match(value)) {
79
+ const serialized = serializer.serialize(value);
80
+ if (serialized && typeof serialized === 'object') {
81
+ args[key] = serialized;
82
+ }
83
+ // Можно прервать цикл — нашли нужный сериалайзер
84
+ break;
85
+ }
86
+ }
87
+ catch { }
88
+ }
89
+ }
90
+ this.emit(level, args);
91
+ this.pino[level](args);
68
92
  }
69
93
  }
70
94
  exports.PinoLogger = PinoLogger;
@@ -1 +1 @@
1
- {"version":3,"file":"pino-logger.class.js","sourceRoot":"","sources":["../../src/implementations/pino-logger.class.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pino-logger.class.js","sourceRoot":"","sources":["../../src/implementations/pino-logger.class.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { DEFAULT_LEVEL } from './defaults';
2
- export * from './implementations';
3
- export * from './types';
4
- export * from './logger.interface';
5
- export * from './helpers';
6
- export * from './logger.factory';
2
+ export { PinoLogger } from './implementations/pino-logger.class';
3
+ export { LogLevel, Params, LoggerOptions, LoggingContext, OnMessage, LoggerSerealizerMetadata, } from './types';
4
+ export { ILogger, ILogSerializer, LogSerializerBase } from './logger.interface';
5
+ export { stringifyContext } from './helpers';
6
+ export { LoggerFactory } from './logger.factory';
7
+ export { LogSerializer } from './decorators/log-serializer.decorator';
package/dist/index.js CHANGED
@@ -1,25 +1,16 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
2
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.DEFAULT_LEVEL = void 0;
3
+ exports.LogSerializer = exports.LoggerFactory = exports.stringifyContext = exports.LogLevel = exports.PinoLogger = exports.DEFAULT_LEVEL = void 0;
18
4
  var defaults_1 = require("./defaults");
19
5
  Object.defineProperty(exports, "DEFAULT_LEVEL", { enumerable: true, get: function () { return defaults_1.DEFAULT_LEVEL; } });
20
- __exportStar(require("./implementations"), exports);
21
- __exportStar(require("./types"), exports);
22
- __exportStar(require("./logger.interface"), exports);
23
- __exportStar(require("./helpers"), exports);
24
- __exportStar(require("./logger.factory"), exports);
6
+ var pino_logger_class_1 = require("./implementations/pino-logger.class");
7
+ Object.defineProperty(exports, "PinoLogger", { enumerable: true, get: function () { return pino_logger_class_1.PinoLogger; } });
8
+ var types_1 = require("./types");
9
+ Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return types_1.LogLevel; } });
10
+ var helpers_1 = require("./helpers");
11
+ Object.defineProperty(exports, "stringifyContext", { enumerable: true, get: function () { return helpers_1.stringifyContext; } });
12
+ var logger_factory_1 = require("./logger.factory");
13
+ Object.defineProperty(exports, "LoggerFactory", { enumerable: true, get: function () { return logger_factory_1.LoggerFactory; } });
14
+ var log_serializer_decorator_1 = require("./decorators/log-serializer.decorator");
15
+ Object.defineProperty(exports, "LogSerializer", { enumerable: true, get: function () { return log_serializer_decorator_1.LogSerializer; } });
25
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uCAA2C;AAAlC,yGAAA,aAAa,OAAA;AAEtB,oDAAkC;AAClC,0CAAwB;AACxB,qDAAmC;AACnC,4CAA0B;AAC1B,mDAAiC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAA2C;AAAlC,yGAAA,aAAa,OAAA;AAEtB,yEAAiE;AAAxD,+GAAA,UAAU,OAAA;AACnB,iCAOiB;AANf,iGAAA,QAAQ,OAAA;AAQV,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AACzB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,kFAAsE;AAA7D,yHAAA,aAAa,OAAA"}
@@ -1,11 +1,11 @@
1
- import type { ILogger } from './logger.interface';
1
+ import type { ILogger, LogSerializerBase } from './logger.interface';
2
2
  import type { LoggerOptions, LoggingContext, OnMessage } from './types';
3
3
  /**
4
4
  * TODO: Дополнить доку
5
5
  * Фабрика является статической потому что
6
6
  */
7
7
  export declare class LoggerFactory {
8
- private static events;
8
+ private static readonly events;
9
9
  /**
10
10
  * Under the hood every logger instance will use this
11
11
  * static instance. Motivation for this is that it's much
@@ -16,7 +16,8 @@ export declare class LoggerFactory {
16
16
  * loggers (which are no used anywhere yet)
17
17
  */
18
18
  private static _globalPino;
19
- private static opts;
19
+ private static _serializers;
20
+ private static readonly opts;
20
21
  /**
21
22
  * Переконфигурация pino нужна потому, что изначально логгер инициализируется
22
23
  * с дефолтными настройками, т. к. конфигурация ещё не прочитана.
@@ -43,5 +44,24 @@ export declare class LoggerFactory {
43
44
  static applyInstrumentations<T extends Record<string, any>>(logHookFunction?: (record: T) => void): void;
44
45
  static onMessage(handler: OnMessage): void;
45
46
  static create(context: LoggingContext): ILogger;
47
+ static getSerializers(): LogSerializerBase[];
48
+ /**
49
+ * Manually set a serializer instance. Useful when using without DI.
50
+ * @param {string} name Unique name for the serializer
51
+ * @param {LogSerializerBase} serializer Serializer instance
52
+ */
53
+ static setSerializer(name: string, serializer: LogSerializerBase): void;
54
+ /**
55
+ * Remove a serializer by name.
56
+ * @param {string} name Name of the serializer to remove
57
+ * @returns {boolean} true if the serializer was removed, false if it didn't exist
58
+ */
59
+ static deleteSerializer(name: string): boolean;
60
+ /**
61
+ * Check if a serializer exists by name.
62
+ * @param {string} name Name of the serializer to check
63
+ * @returns {boolean} true if the serializer exists, false otherwise
64
+ */
65
+ static hasSerializer(name: string): boolean;
46
66
  private static applyOptions;
47
67
  }
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.LoggerFactory = void 0;
7
- const node_events_1 = __importDefault(require("node:events"));
4
+ const node_events_1 = require("node:events");
5
+ const logger_metadata_registry_1 = require("./metadata/logger-metadata.registry");
8
6
  const defaults_1 = require("./defaults");
9
7
  const implementations_1 = require("./implementations");
10
8
  /**
@@ -19,7 +17,7 @@ const requirePino = () => {
19
17
  */
20
18
  class LoggerFactory {
21
19
  // eslint-disable-next-line unicorn/prefer-event-target
22
- static events = new node_events_1.default();
20
+ static events = new node_events_1.EventEmitter();
23
21
  /**
24
22
  * Under the hood every logger instance will use this
25
23
  * static instance. Motivation for this is that it's much
@@ -33,6 +31,7 @@ class LoggerFactory {
33
31
  static _globalPino = requirePino()({
34
32
  level: defaults_1.DEFAULT_LEVEL,
35
33
  });
34
+ static _serializers = null;
36
35
  static opts = {
37
36
  level: defaults_1.DEFAULT_LEVEL,
38
37
  redact: [],
@@ -99,7 +98,51 @@ class LoggerFactory {
99
98
  this.events.on('msg', handler);
100
99
  }
101
100
  static create(context) {
102
- return new implementations_1.PinoLogger(() => this._globalPino, (level, data) => this.events.emit('msg', level, data), context);
101
+ return new implementations_1.PinoLogger(() => this._globalPino, (level, data) => this.events.emit('msg', level, data), context, () => this.getSerializers());
102
+ }
103
+ static getSerializers() {
104
+ if (this._serializers)
105
+ return Array.from(this._serializers.values());
106
+ const metas = logger_metadata_registry_1.LoggerMetadataRegistry.getSerializers();
107
+ this._serializers = new Map();
108
+ for (const meta of metas) {
109
+ try {
110
+ const instance = Reflect.construct(meta.target, []);
111
+ const serializerName = meta.target.name || meta.target.constructor.name;
112
+ this._serializers.set(serializerName, instance);
113
+ }
114
+ catch { }
115
+ }
116
+ return Array.from(this._serializers.values());
117
+ }
118
+ /**
119
+ * Manually set a serializer instance. Useful when using without DI.
120
+ * @param {string} name Unique name for the serializer
121
+ * @param {LogSerializerBase} serializer Serializer instance
122
+ */
123
+ static setSerializer(name, serializer) {
124
+ this._serializers ??= new Map();
125
+ this._serializers.set(name, serializer);
126
+ }
127
+ /**
128
+ * Remove a serializer by name.
129
+ * @param {string} name Name of the serializer to remove
130
+ * @returns {boolean} true if the serializer was removed, false if it didn't exist
131
+ */
132
+ static deleteSerializer(name) {
133
+ if (!this._serializers)
134
+ return false;
135
+ return this._serializers.delete(name);
136
+ }
137
+ /**
138
+ * Check if a serializer exists by name.
139
+ * @param {string} name Name of the serializer to check
140
+ * @returns {boolean} true if the serializer exists, false otherwise
141
+ */
142
+ static hasSerializer(name) {
143
+ if (!this._serializers)
144
+ return false;
145
+ return this._serializers.has(name);
103
146
  }
104
147
  static applyOptions(opts) {
105
148
  const { redact, level, stream = requirePino().destination() } = opts || {};
@@ -1 +1 @@
1
- {"version":3,"file":"logger.factory.js","sourceRoot":"","sources":["../src/logger.factory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.factory.js","sourceRoot":"","sources":["../src/logger.factory.ts"],"names":[],"mappings":"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"}
@@ -29,3 +29,8 @@ export interface ILogger {
29
29
  log(level: LogLevel, message: string, params?: Params): void;
30
30
  log(level: LogLevel, message: string, error?: ErrorLike): void;
31
31
  }
32
+ export interface ILogSerializer<TEntry, TSerialized> {
33
+ match(entry: unknown): entry is TEntry;
34
+ serialize(entry: TEntry): TSerialized;
35
+ }
36
+ export type LogSerializerBase = ILogSerializer<unknown, unknown>;
@@ -0,0 +1 @@
1
+ export declare const LOGGER_METADATA_KEY: unique symbol;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOGGER_METADATA_KEY = void 0;
4
+ exports.LOGGER_METADATA_KEY = Symbol('LOGGER_METADATA_KEY');
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/metadata/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Constructor } from '@rsdk/common';
2
+ import type { LoggerSerealizerMetadata } from '../types';
3
+ export declare class LoggerMetadataRegistry {
4
+ private static readonly serializers;
5
+ static registerSerializer(target: Constructor, metadata: LoggerSerealizerMetadata): void;
6
+ static getSerializers(): LoggerSerealizerMetadata[];
7
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoggerMetadataRegistry = void 0;
4
+ class LoggerMetadataRegistry {
5
+ static serializers = new Map();
6
+ static registerSerializer(target, metadata) {
7
+ this.serializers.set(target, metadata);
8
+ }
9
+ static getSerializers() {
10
+ return Array.from(this.serializers.values());
11
+ }
12
+ }
13
+ exports.LoggerMetadataRegistry = LoggerMetadataRegistry;
14
+ //# sourceMappingURL=logger-metadata.registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger-metadata.registry.js","sourceRoot":"","sources":["../../src/metadata/logger-metadata.registry.ts"],"names":[],"mappings":";;;AAIA,MAAa,sBAAsB;IACzB,MAAM,CAAU,WAAW,GAAG,IAAI,GAAG,EAG1C,CAAC;IAEJ,MAAM,CAAC,kBAAkB,CACvB,MAAmB,EACnB,QAAkC;QAElC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,CAAC,cAAc;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;;AAfH,wDAgBC"}
package/dist/types.d.ts CHANGED
@@ -16,3 +16,6 @@ export interface LoggerOptions {
16
16
  }
17
17
  export type LoggingContext = string | Constructor;
18
18
  export type OnMessage = (level: LogLevel, data: Record<string, unknown>) => void;
19
+ export interface LoggerSerealizerMetadata {
20
+ target: Constructor;
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsdk/logging",
3
- "version": "5.11.0-next.2",
3
+ "version": "5.11.0-next.3",
4
4
  "description": "Base framework independent logging functionality",
5
5
  "license": "Apache License 2.0",
6
6
  "publishConfig": {
@@ -15,7 +15,8 @@
15
15
  },
16
16
  "peerDependencies": {
17
17
  "@rsdk/common": "*",
18
+ "reflect-metadata": "^0.1.12 || ^0.2.0",
18
19
  "rxjs": "^7.1.0"
19
20
  },
20
- "gitHead": "f4af77602f7256e4d1c68831e298762f6ccbaa0f"
21
+ "gitHead": "aa43c0b62a5a8fb72694f3d9112ab19960e30265"
21
22
  }
@@ -0,0 +1,21 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import type { Constructor } from '@rsdk/common';
3
+
4
+ import 'reflect-metadata';
5
+
6
+ import { LOGGER_METADATA_KEY } from '../metadata/constants';
7
+ import { LoggerMetadataRegistry } from '../metadata/logger-metadata.registry';
8
+ import type { LoggerSerealizerMetadata } from '../types';
9
+
10
+ const logSerializerDecorator: ClassDecorator = function (
11
+ target: Function,
12
+ ): void {
13
+ const metadata: LoggerSerealizerMetadata = {
14
+ target: target as Constructor,
15
+ };
16
+
17
+ Reflect.defineMetadata(LOGGER_METADATA_KEY, metadata, target);
18
+ LoggerMetadataRegistry.registerSerializer(target as Constructor, metadata);
19
+ };
20
+
21
+ export const LogSerializer = (): ClassDecorator => logSerializerDecorator;
@@ -1,9 +1,9 @@
1
- import type { ErrorLike, NormalizeOptions } from '@rsdk/common';
2
- import { isErrorLike, normalizer, sortErrorKeys } from '@rsdk/common';
1
+ import type { ErrorLike } from '@rsdk/common';
2
+ import { isErrorLike } from '@rsdk/common';
3
3
  import type { Logger as Pino } from 'pino';
4
4
 
5
5
  import { stringifyContext } from '../helpers';
6
- import type { ILogger } from '../logger.interface';
6
+ import type { ILogger, LogSerializerBase } from '../logger.interface';
7
7
  import type { LoggingContext, OnMessage, Params } from '../types';
8
8
  import { LogLevel } from '../types';
9
9
 
@@ -23,11 +23,18 @@ export class PinoLogger implements ILogger {
23
23
  */
24
24
  private readonly _pino: GetLogger;
25
25
  private readonly emit: OnMessage;
26
-
27
- constructor(pino: GetLogger, emit: OnMessage, context: LoggingContext) {
26
+ private readonly getSerializers: () => LogSerializerBase[];
27
+
28
+ constructor(
29
+ pino: GetLogger,
30
+ emit: OnMessage,
31
+ context: LoggingContext,
32
+ getSerializers: () => LogSerializerBase[],
33
+ ) {
28
34
  this._pino = pino;
29
35
  this.emit = emit;
30
36
  this.context = stringifyContext(context);
37
+ this.getSerializers = getSerializers;
31
38
  }
32
39
 
33
40
  get pino(): Pino {
@@ -106,20 +113,42 @@ export class PinoLogger implements ILogger {
106
113
  }
107
114
 
108
115
  const paramsOrError = typeof arg1 === 'string' ? arg2 : arg1;
109
-
110
116
  if (paramsOrError) {
111
- const options: NormalizeOptions = {
112
- sortKeys: sortErrorKeys,
113
- };
114
-
115
117
  if (level === 'fatal' || level === 'error') {
116
- args['error'] = normalizer()(paramsOrError, options);
118
+ args.error = paramsOrError;
117
119
  } else {
118
- Object.assign(args, normalizer()(paramsOrError, options));
120
+ Object.assign(args, paramsOrError);
121
+ }
122
+ }
123
+
124
+ if (message) {
125
+ args.message = message;
126
+ }
127
+
128
+ const serializers = this.getSerializers();
129
+
130
+ for (const [key, value] of Object.entries(args)) {
131
+ // Пропускаем ненужные поля
132
+ if (key === 'context' || key === 'message') continue;
133
+ if (value == null || typeof value !== 'object') continue;
134
+
135
+ for (const serializer of serializers) {
136
+ try {
137
+ // eslint-disable-next-line unicorn/prefer-regexp-test
138
+ if (serializer.match(value)) {
139
+ const serialized = serializer.serialize(value);
140
+ if (serialized && typeof serialized === 'object') {
141
+ args[key] = serialized;
142
+ }
143
+
144
+ // Можно прервать цикл — нашли нужный сериалайзер
145
+ break;
146
+ }
147
+ } catch {}
119
148
  }
120
149
  }
121
150
 
122
- this.emit(level, { ...args, message });
123
- this.pino[level](args, message);
151
+ this.emit(level, args);
152
+ this.pino[level](args);
124
153
  }
125
154
  }
package/src/index.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  export { DEFAULT_LEVEL } from './defaults';
2
2
 
3
- export * from './implementations';
4
- export * from './types';
5
- export * from './logger.interface';
6
- export * from './helpers';
7
- export * from './logger.factory';
3
+ export { PinoLogger } from './implementations/pino-logger.class';
4
+ export {
5
+ LogLevel,
6
+ Params,
7
+ LoggerOptions,
8
+ LoggingContext,
9
+ OnMessage,
10
+ LoggerSerealizerMetadata,
11
+ } from './types';
12
+ export { ILogger, ILogSerializer, LogSerializerBase } from './logger.interface';
13
+ export { stringifyContext } from './helpers';
14
+ export { LoggerFactory } from './logger.factory';
15
+ export { LogSerializer } from './decorators/log-serializer.decorator';
@@ -1,12 +1,14 @@
1
- import EventEmitter from 'node:events';
1
+ import { EventEmitter } from 'node:events';
2
2
  import type _pino from 'pino';
3
3
  import type { Logger as Pino } from 'pino';
4
4
 
5
+ import { LoggerMetadataRegistry } from './metadata/logger-metadata.registry';
5
6
  import { DEFAULT_LEVEL } from './defaults';
6
7
  import { PinoLogger } from './implementations';
7
- import type { ILogger } from './logger.interface';
8
+ import type { ILogger, LogSerializerBase } from './logger.interface';
8
9
  import type {
9
10
  LoggerOptions,
11
+ LoggerSerealizerMetadata,
10
12
  LoggingContext,
11
13
  LogLevel,
12
14
  OnMessage,
@@ -25,7 +27,7 @@ const requirePino = (): typeof _pino => {
25
27
  */
26
28
  export class LoggerFactory {
27
29
  // eslint-disable-next-line unicorn/prefer-event-target
28
- private static events = new EventEmitter();
30
+ private static readonly events = new EventEmitter();
29
31
 
30
32
  /**
31
33
  * Under the hood every logger instance will use this
@@ -41,7 +43,9 @@ export class LoggerFactory {
41
43
  level: DEFAULT_LEVEL,
42
44
  });
43
45
 
44
- private static opts: LoggerOptions = {
46
+ private static _serializers: Map<string, LogSerializerBase> | null = null;
47
+
48
+ private static readonly opts: LoggerOptions = {
45
49
  level: DEFAULT_LEVEL,
46
50
  redact: [],
47
51
  stream: requirePino().destination(),
@@ -128,9 +132,62 @@ export class LoggerFactory {
128
132
  () => this._globalPino,
129
133
  (level: LogLevel, data: unknown) => this.events.emit('msg', level, data),
130
134
  context,
135
+ () => this.getSerializers(),
131
136
  );
132
137
  }
133
138
 
139
+ static getSerializers(): LogSerializerBase[] {
140
+ if (this._serializers) return Array.from(this._serializers.values());
141
+
142
+ const metas: LoggerSerealizerMetadata[] =
143
+ LoggerMetadataRegistry.getSerializers();
144
+
145
+ this._serializers = new Map<string, LogSerializerBase>();
146
+
147
+ for (const meta of metas) {
148
+ try {
149
+ const instance = Reflect.construct(meta.target, []);
150
+ const serializerName = meta.target.name || meta.target.constructor.name;
151
+
152
+ this._serializers.set(serializerName, instance);
153
+ } catch {}
154
+ }
155
+
156
+ return Array.from(this._serializers.values());
157
+ }
158
+
159
+ /**
160
+ * Manually set a serializer instance. Useful when using without DI.
161
+ * @param {string} name Unique name for the serializer
162
+ * @param {LogSerializerBase} serializer Serializer instance
163
+ */
164
+ static setSerializer(name: string, serializer: LogSerializerBase): void {
165
+ this._serializers ??= new Map<string, LogSerializerBase>();
166
+ this._serializers.set(name, serializer);
167
+ }
168
+
169
+ /**
170
+ * Remove a serializer by name.
171
+ * @param {string} name Name of the serializer to remove
172
+ * @returns {boolean} true if the serializer was removed, false if it didn't exist
173
+ */
174
+ static deleteSerializer(name: string): boolean {
175
+ if (!this._serializers) return false;
176
+
177
+ return this._serializers.delete(name);
178
+ }
179
+
180
+ /**
181
+ * Check if a serializer exists by name.
182
+ * @param {string} name Name of the serializer to check
183
+ * @returns {boolean} true if the serializer exists, false otherwise
184
+ */
185
+ static hasSerializer(name: string): boolean {
186
+ if (!this._serializers) return false;
187
+
188
+ return this._serializers.has(name);
189
+ }
190
+
134
191
  private static applyOptions(opts: Partial<LoggerOptions>): void {
135
192
  const { redact, level, stream = requirePino().destination() } = opts || {};
136
193
 
@@ -37,3 +37,10 @@ export interface ILogger {
37
37
  log(level: LogLevel, message: string, params?: Params): void;
38
38
  log(level: LogLevel, message: string, error?: ErrorLike): void;
39
39
  }
40
+
41
+ export interface ILogSerializer<TEntry, TSerialized> {
42
+ match(entry: unknown): entry is TEntry;
43
+ serialize(entry: TEntry): TSerialized;
44
+ }
45
+
46
+ export type LogSerializerBase = ILogSerializer<unknown, unknown>;
@@ -0,0 +1 @@
1
+ export const LOGGER_METADATA_KEY = Symbol('LOGGER_METADATA_KEY');
@@ -0,0 +1,21 @@
1
+ import type { Constructor } from '@rsdk/common';
2
+
3
+ import type { LoggerSerealizerMetadata } from '../types';
4
+
5
+ export class LoggerMetadataRegistry {
6
+ private static readonly serializers = new Map<
7
+ Constructor,
8
+ LoggerSerealizerMetadata
9
+ >();
10
+
11
+ static registerSerializer(
12
+ target: Constructor,
13
+ metadata: LoggerSerealizerMetadata,
14
+ ): void {
15
+ this.serializers.set(target, metadata);
16
+ }
17
+
18
+ static getSerializers(): LoggerSerealizerMetadata[] {
19
+ return Array.from(this.serializers.values());
20
+ }
21
+ }
package/src/types.ts CHANGED
@@ -24,3 +24,7 @@ export type OnMessage = (
24
24
  level: LogLevel,
25
25
  data: Record<string, unknown>,
26
26
  ) => void;
27
+
28
+ export interface LoggerSerealizerMetadata {
29
+ target: Constructor;
30
+ }