@rsdk/logging 5.11.0 → 5.11.1-next.1

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.
@@ -4,7 +4,9 @@ exports.LogSerializer = void 0;
4
4
  require("reflect-metadata");
5
5
  const constants_1 = require("../metadata/constants");
6
6
  const logger_metadata_registry_1 = require("../metadata/logger-metadata.registry");
7
- const logSerializerDecorator = function (target) {
7
+ const logSerializerDecorator = function (
8
+ // eslint-disable-next-line @typescript-eslint/ban-types
9
+ target) {
8
10
  const metadata = {
9
11
  target: target,
10
12
  };
@@ -1 +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
+ {"version":3,"file":"log-serializer.decorator.js","sourceRoot":"","sources":["../../src/decorators/log-serializer.decorator.ts"],"names":[],"mappings":";;;AAEA,4BAA0B;AAE1B,qDAA4D;AAC5D,mFAA8E;AAG9E,MAAM,sBAAsB,GAAmB;AAC7C,wDAAwD;AACxD,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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DEFAULT_LEVEL } from './defaults';
2
2
  export { PinoLogger } from './implementations/pino-logger.class';
3
- export { LogLevel, Params, LoggerOptions, LoggingContext, OnMessage, LoggerSerealizerMetadata, } from './types';
3
+ export { LogLevel, Params, LoggerOptions, LoggingContext, OnMessage, LoggerSerializerMetadata, LogTimestampFormat, } from './types';
4
4
  export { ILogger, ILogSerializer, LogSerializerBase } from './logger.interface';
5
5
  export { stringifyContext } from './helpers';
6
6
  export { LoggerFactory } from './logger.factory';
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogSerializer = exports.LoggerFactory = exports.stringifyContext = exports.LogLevel = exports.PinoLogger = exports.DEFAULT_LEVEL = void 0;
3
+ exports.LogSerializer = exports.LoggerFactory = exports.stringifyContext = exports.LogTimestampFormat = exports.LogLevel = exports.PinoLogger = exports.DEFAULT_LEVEL = void 0;
4
4
  var defaults_1 = require("./defaults");
5
5
  Object.defineProperty(exports, "DEFAULT_LEVEL", { enumerable: true, get: function () { return defaults_1.DEFAULT_LEVEL; } });
6
6
  var pino_logger_class_1 = require("./implementations/pino-logger.class");
7
7
  Object.defineProperty(exports, "PinoLogger", { enumerable: true, get: function () { return pino_logger_class_1.PinoLogger; } });
8
8
  var types_1 = require("./types");
9
9
  Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return types_1.LogLevel; } });
10
+ Object.defineProperty(exports, "LogTimestampFormat", { enumerable: true, get: function () { return types_1.LogTimestampFormat; } });
10
11
  var helpers_1 = require("./helpers");
11
12
  Object.defineProperty(exports, "stringifyContext", { enumerable: true, get: function () { return helpers_1.stringifyContext; } });
12
13
  var logger_factory_1 = require("./logger.factory");
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,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
+ {"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,iCAQiB;AAPf,iGAAA,QAAQ,OAAA;AAMR,2GAAA,kBAAkB,OAAA;AAGpB,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AACzB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,kFAAsE;AAA7D,yHAAA,aAAa,OAAA"}
@@ -6,6 +6,8 @@ import type { LoggerOptions, LoggingContext, OnMessage } from './types';
6
6
  */
7
7
  export declare class LoggerFactory {
8
8
  private static readonly events;
9
+ private static opts;
10
+ private static pinoTimestampFormatMap;
9
11
  /**
10
12
  * Under the hood every logger instance will use this
11
13
  * static instance. Motivation for this is that it's much
@@ -17,7 +19,10 @@ export declare class LoggerFactory {
17
19
  */
18
20
  private static _globalPino;
19
21
  private static _serializers;
20
- private static readonly opts;
22
+ /** Ссылка на активный worker-транспорт для закрытия его воркеров. */
23
+ private static _activeTransport;
24
+ /** Конфиг, по которому собран _activeTransport (для переиспользования воркера). */
25
+ private static _activeTransportConfig;
21
26
  /**
22
27
  * Переконфигурация pino нужна потому, что изначально логгер инициализируется
23
28
  * с дефолтными настройками, т. к. конфигурация ещё не прочитана.
@@ -42,6 +47,11 @@ export declare class LoggerFactory {
42
47
  * при помощи cli - можно немного упростить архитектуру
43
48
  */
44
49
  static applyInstrumentations<T extends Record<string, any>>(logHookFunction?: (record: T) => void): void;
50
+ /**
51
+ * Сливает буфер worker-транспорта и завершает его воркеры. Без вызова на
52
+ * остановке приложения забуференные логи теряются, а воркеры висят.
53
+ */
54
+ static shutdown(timeoutMs?: number): Promise<void>;
45
55
  static onMessage(handler: OnMessage): void;
46
56
  static create(context: LoggingContext): ILogger;
47
57
  static getSerializers(): LogSerializerBase[];
@@ -64,4 +74,31 @@ export declare class LoggerFactory {
64
74
  */
65
75
  static hasSerializer(name: string): boolean;
66
76
  private static applyOptions;
77
+ /**
78
+ * `stream`/`transport` исключаем из опций: способ доставки задаётся вторым
79
+ * аргументом `pino()`, а pino запрещает одновременно `transport` в опциях и
80
+ * stream-аргумент.
81
+ */
82
+ private static buildPinoOptions;
83
+ /**
84
+ * Создаёт инстанс pino. Воркер транспорта переиспользуется, если объект
85
+ * конфига транспорта тот же по ссылке (сравнение identity, не по значению).
86
+ * Это покрывает связку reconfigure→applyInstrumentations (между ними
87
+ * this.opts.transport не пересобирается) и не даёт пересоздавать и тут же
88
+ * закрывать только что поднятый, возможно медленный, OTEL-воркер. Новый
89
+ * объект конфига (например, при config.onUpdate) ожидаемо пересоздаёт воркер.
90
+ */
91
+ private static instantiatePino;
92
+ /**
93
+ * Поднимает worker-транспорт, закрыв предыдущий. Обработчик 'error' не даёт
94
+ * асинхронной ошибке воркера уронить процесс, но делает её видимой в stderr
95
+ * (сам логгер использовать нельзя — упал его транспорт). Ошибку резолва
96
+ * таргета pino.transport(...) бросает синхронно — она долетает до старта.
97
+ */
98
+ private static createTransport;
99
+ /**
100
+ * Завершает воркеры предыдущего транспорта (best-effort, не блокируя). stdout
101
+ * не затрагивается: для него хэндл не сохраняется.
102
+ */
103
+ private static disposeActiveTransport;
67
104
  }
@@ -5,10 +5,13 @@ const node_events_1 = require("node:events");
5
5
  const logger_metadata_registry_1 = require("./metadata/logger-metadata.registry");
6
6
  const defaults_1 = require("./defaults");
7
7
  const implementations_1 = require("./implementations");
8
+ const types_1 = require("./types");
9
+ const DEFAULT_SHUTDOWN_TIMEOUT_MS = 1000;
8
10
  /**
9
11
  * ATTENTION: require('pino') тут не просто так, в общем они нужны для корректной работы хуков из `@opentelemetry/instrumentation-pino`
10
12
  */
11
13
  const requirePino = () => {
14
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
12
15
  return require('pino');
13
16
  };
14
17
  /**
@@ -18,6 +21,18 @@ const requirePino = () => {
18
21
  class LoggerFactory {
19
22
  // eslint-disable-next-line unicorn/prefer-event-target
20
23
  static events = new node_events_1.EventEmitter();
24
+ static opts = {
25
+ level: defaults_1.DEFAULT_LEVEL,
26
+ redact: [],
27
+ stream: requirePino().destination(),
28
+ timestampFormat: types_1.LogTimestampFormat.isoTime,
29
+ };
30
+ static pinoTimestampFormatMap = {
31
+ [types_1.LogTimestampFormat.epochTime]: requirePino().stdTimeFunctions.epochTime,
32
+ [types_1.LogTimestampFormat.unixTime]: requirePino().stdTimeFunctions.unixTime,
33
+ [types_1.LogTimestampFormat.nullTime]: requirePino().stdTimeFunctions.nullTime,
34
+ [types_1.LogTimestampFormat.isoTime]: requirePino().stdTimeFunctions.isoTime,
35
+ };
21
36
  /**
22
37
  * Under the hood every logger instance will use this
23
38
  * static instance. Motivation for this is that it's much
@@ -27,16 +42,16 @@ class LoggerFactory {
27
42
  * Downside is that the idea is not composable with child
28
43
  * loggers (which are no used anywhere yet)
29
44
  */
30
- // eslint-disable-next-line @typescript-eslint/no-var-requires
45
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
31
46
  static _globalPino = requirePino()({
32
47
  level: defaults_1.DEFAULT_LEVEL,
48
+ timestamp: this.pinoTimestampFormatMap[this.opts.timestampFormat],
33
49
  });
34
50
  static _serializers = null;
35
- static opts = {
36
- level: defaults_1.DEFAULT_LEVEL,
37
- redact: [],
38
- stream: requirePino().destination(),
39
- };
51
+ /** Ссылка на активный worker-транспорт для закрытия его воркеров. */
52
+ static _activeTransport = null;
53
+ /** Конфиг, по которому собран _activeTransport (для переиспользования воркера). */
54
+ static _activeTransportConfig = null;
40
55
  /**
41
56
  * Переконфигурация pino нужна потому, что изначально логгер инициализируется
42
57
  * с дефолтными настройками, т. к. конфигурация ещё не прочитана.
@@ -46,8 +61,7 @@ class LoggerFactory {
46
61
  */
47
62
  static reconfigure(opts) {
48
63
  this.applyOptions(opts);
49
- const { stream, ...other } = this.opts;
50
- this._globalPino = requirePino()(other, stream);
64
+ this._globalPino = this.instantiatePino();
51
65
  }
52
66
  /**
53
67
  * Этот метод должен быть вызван после того, как подключен instrumentation-pino.
@@ -65,10 +79,7 @@ class LoggerFactory {
65
79
  * при помощи cli - можно немного упростить архитектуру
66
80
  */
67
81
  static applyInstrumentations(logHookFunction) {
68
- const { stream, ...other } = this.opts;
69
- // eslint-disable-next-line @typescript-eslint/no-var-requires
70
- this._globalPino = requirePino()({
71
- ...other,
82
+ this._globalPino = this.instantiatePino({
72
83
  /**
73
84
  * Функция которая позволяет добавить дополнительные данные в логи Pino
74
85
  */
@@ -78,21 +89,47 @@ class LoggerFactory {
78
89
  * Реализация взята с официальной документации
79
90
  * https://getpino.io/#/docs/api?id=logmethod
80
91
  */
81
- logMethod: function (inputArgs,
82
92
  // eslint-disable-next-line @typescript-eslint/ban-types
83
- method) {
84
- if (inputArgs.length >= 2) {
85
- const arg1 = inputArgs.shift() || {};
86
- const arg2 = inputArgs.shift();
93
+ logMethod: function (inputArgs, method) {
94
+ const arg1 = inputArgs[0];
95
+ if (arg1 && typeof arg1 === 'object') {
87
96
  logHookFunction(arg1);
88
- // eslint-disable-next-line unicorn/prefer-reflect-apply
89
- return method.apply(this, [arg1, arg2, ...inputArgs]);
90
97
  }
98
+ // eslint-disable-next-line unicorn/prefer-reflect-apply
91
99
  return method.apply(this, inputArgs);
92
100
  },
93
101
  }
94
102
  : {},
95
- }, stream);
103
+ });
104
+ }
105
+ /**
106
+ * Сливает буфер worker-транспорта и завершает его воркеры. Без вызова на
107
+ * остановке приложения забуференные логи теряются, а воркеры висят.
108
+ */
109
+ static async shutdown(timeoutMs = DEFAULT_SHUTDOWN_TIMEOUT_MS) {
110
+ const stream = this._activeTransport;
111
+ if (!stream)
112
+ return;
113
+ this._activeTransport = null;
114
+ this._activeTransportConfig = null;
115
+ await new Promise((resolve) => {
116
+ let settled = false;
117
+ const finish = () => {
118
+ if (settled)
119
+ return;
120
+ settled = true;
121
+ resolve();
122
+ };
123
+ try {
124
+ stream.on('close', finish);
125
+ stream.flush(() => stream.end());
126
+ }
127
+ catch {
128
+ finish();
129
+ }
130
+ const timer = setTimeout(finish, timeoutMs);
131
+ timer.unref?.();
132
+ });
96
133
  }
97
134
  static onMessage(handler) {
98
135
  this.events.on('msg', handler);
@@ -145,8 +182,105 @@ class LoggerFactory {
145
182
  return this._serializers.has(name);
146
183
  }
147
184
  static applyOptions(opts) {
148
- const { redact, level, stream = requirePino().destination() } = opts || {};
149
- Object.assign(this.opts, { redact, level: level ?? defaults_1.DEFAULT_LEVEL, stream });
185
+ const { redact, level, stream, transport, timestampFormat } = opts || {};
186
+ const base = {
187
+ redact: redact ?? this.opts.redact ?? [],
188
+ level: level ?? defaults_1.DEFAULT_LEVEL,
189
+ timestampFormat: timestampFormat ?? types_1.LogTimestampFormat.isoTime,
190
+ };
191
+ /**
192
+ * Выбираем ровно один способ доставки. Если ни stream, ни transport не
193
+ * переданы — сохраняем текущий, чтобы частичный reconfigure({ level }) не
194
+ * сбрасывал ранее заданный transport.
195
+ */
196
+ if (transport) {
197
+ this.opts = { ...base, transport };
198
+ }
199
+ else if (stream) {
200
+ this.opts = { ...base, stream };
201
+ }
202
+ else if (this.opts.transport) {
203
+ this.opts = { ...base, transport: this.opts.transport };
204
+ }
205
+ else {
206
+ this.opts = {
207
+ ...base,
208
+ stream: this.opts.stream ?? requirePino().destination(),
209
+ };
210
+ }
211
+ }
212
+ /**
213
+ * `stream`/`transport` исключаем из опций: способ доставки задаётся вторым
214
+ * аргументом `pino()`, а pino запрещает одновременно `transport` в опциях и
215
+ * stream-аргумент.
216
+ */
217
+ static buildPinoOptions(extra = {}) {
218
+ const { timestampFormat, stream: _stream, transport: _transport, ...other } = this.opts;
219
+ return {
220
+ ...other,
221
+ timestamp: this.pinoTimestampFormatMap[timestampFormat],
222
+ ...extra,
223
+ };
224
+ }
225
+ /**
226
+ * Создаёт инстанс pino. Воркер транспорта переиспользуется, если объект
227
+ * конфига транспорта тот же по ссылке (сравнение identity, не по значению).
228
+ * Это покрывает связку reconfigure→applyInstrumentations (между ними
229
+ * this.opts.transport не пересобирается) и не даёт пересоздавать и тут же
230
+ * закрывать только что поднятый, возможно медленный, OTEL-воркер. Новый
231
+ * объект конфига (например, при config.onUpdate) ожидаемо пересоздаёт воркер.
232
+ */
233
+ static instantiatePino(extra = {}) {
234
+ const pino = requirePino();
235
+ const options = this.buildPinoOptions(extra);
236
+ if (!this.opts.transport) {
237
+ this.disposeActiveTransport();
238
+ return pino(options, this.opts.stream);
239
+ }
240
+ const reuse = this._activeTransport &&
241
+ this.opts.transport === this._activeTransportConfig;
242
+ const stream = reuse
243
+ ? this._activeTransport
244
+ : this.createTransport(this.opts.transport);
245
+ return pino(options, stream);
246
+ }
247
+ /**
248
+ * Поднимает worker-транспорт, закрыв предыдущий. Обработчик 'error' не даёт
249
+ * асинхронной ошибке воркера уронить процесс, но делает её видимой в stderr
250
+ * (сам логгер использовать нельзя — упал его транспорт). Ошибку резолва
251
+ * таргета pino.transport(...) бросает синхронно — она долетает до старта.
252
+ */
253
+ static createTransport(transport) {
254
+ this.disposeActiveTransport();
255
+ const stream = requirePino().transport(transport);
256
+ stream.on('error', (...args) => {
257
+ const error = args[0];
258
+ const message = error instanceof Error ? error.message : String(error);
259
+ process.stderr.write(`[@rsdk/logging] transport error: ${message}\n`);
260
+ });
261
+ this._activeTransport = stream;
262
+ this._activeTransportConfig = transport;
263
+ return stream;
264
+ }
265
+ /**
266
+ * Завершает воркеры предыдущего транспорта (best-effort, не блокируя). stdout
267
+ * не затрагивается: для него хэндл не сохраняется.
268
+ */
269
+ static disposeActiveTransport() {
270
+ const previous = this._activeTransport;
271
+ if (!previous)
272
+ return;
273
+ this._activeTransport = null;
274
+ this._activeTransportConfig = null;
275
+ // на teardown ошибки ожидаемы (например, "end() took too long" у медленных
276
+ // транспортов) — глушим их молча и не держим event loop
277
+ previous.unref?.();
278
+ previous.removeAllListeners?.('error');
279
+ previous.on('error', () => { });
280
+ try {
281
+ previous.end();
282
+ }
283
+ catch { }
150
284
  }
151
285
  }
152
286
  exports.LoggerFactory = LoggerFactory;
@@ -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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"}
@@ -1,7 +1,7 @@
1
1
  import type { Constructor } from '@rsdk/common';
2
- import type { LoggerSerealizerMetadata } from '../types';
2
+ import type { LoggerSerializerMetadata } from '../types';
3
3
  export declare class LoggerMetadataRegistry {
4
4
  private static readonly serializers;
5
- static registerSerializer(target: Constructor, metadata: LoggerSerealizerMetadata): void;
6
- static getSerializers(): LoggerSerealizerMetadata[];
5
+ static registerSerializer(target: Constructor, metadata: LoggerSerializerMetadata): void;
6
+ static getSerializers(): LoggerSerializerMetadata[];
7
7
  }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Constructor } from '@rsdk/common';
2
2
  import type pino from 'pino';
3
+ import type { TransportMultiOptions } from 'pino';
3
4
  export declare enum LogLevel {
4
5
  fatal = "fatal",
5
6
  error = "error",
@@ -8,14 +9,33 @@ export declare enum LogLevel {
8
9
  debug = "debug",
9
10
  trace = "trace"
10
11
  }
12
+ export declare enum LogTimestampFormat {
13
+ epochTime = "epochTime",
14
+ unixTime = "unixTime",
15
+ nullTime = "nullTime",
16
+ isoTime = "isoTime"
17
+ }
18
+ export type TimeFn = () => string;
11
19
  export type Params = Record<string, unknown>;
12
- export interface LoggerOptions {
20
+ export interface LoggerOptionsBase {
13
21
  level: LogLevel;
14
22
  redact: string[];
15
- stream: pino.DestinationStream;
23
+ timestampFormat: LogTimestampFormat;
16
24
  }
25
+ /**
26
+ * `stream` и `transport` — взаимоисключающие способы доставки (pino не
27
+ * принимает оба сразу). Это закодировано в типе: задание одного запрещает
28
+ * другой.
29
+ */
30
+ export type LoggerOptions = LoggerOptionsBase & ({
31
+ stream?: pino.DestinationStream;
32
+ transport?: never;
33
+ } | {
34
+ stream?: never;
35
+ transport?: TransportMultiOptions;
36
+ });
17
37
  export type LoggingContext = string | Constructor;
18
38
  export type OnMessage = (level: LogLevel, data: Record<string, unknown>) => void;
19
- export interface LoggerSerealizerMetadata {
39
+ export interface LoggerSerializerMetadata {
20
40
  target: Constructor;
21
41
  }
package/dist/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogLevel = void 0;
3
+ exports.LogTimestampFormat = exports.LogLevel = void 0;
4
4
  var LogLevel;
5
5
  (function (LogLevel) {
6
6
  LogLevel["fatal"] = "fatal";
@@ -10,4 +10,11 @@ var LogLevel;
10
10
  LogLevel["debug"] = "debug";
11
11
  LogLevel["trace"] = "trace";
12
12
  })(LogLevel || (exports.LogLevel = LogLevel = {}));
13
+ var LogTimestampFormat;
14
+ (function (LogTimestampFormat) {
15
+ LogTimestampFormat["epochTime"] = "epochTime";
16
+ LogTimestampFormat["unixTime"] = "unixTime";
17
+ LogTimestampFormat["nullTime"] = "nullTime";
18
+ LogTimestampFormat["isoTime"] = "isoTime";
19
+ })(LogTimestampFormat || (exports.LogTimestampFormat = LogTimestampFormat = {}));
13
20
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAGA,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,yBAAa,CAAA;IACb,yBAAa,CAAA;IACb,2BAAe,CAAA;IACf,2BAAe,CAAA;AACjB,CAAC,EAPW,QAAQ,wBAAR,QAAQ,QAOnB"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAIA,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,yBAAa,CAAA;IACb,yBAAa,CAAA;IACb,2BAAe,CAAA;IACf,2BAAe,CAAA;AACjB,CAAC,EAPW,QAAQ,wBAAR,QAAQ,QAOnB;AAED,IAAY,kBAKX;AALD,WAAY,kBAAkB;IAC5B,6CAAuB,CAAA;IACvB,2CAAqB,CAAA;IACrB,2CAAqB,CAAA;IACrB,yCAAmB,CAAA;AACrB,CAAC,EALW,kBAAkB,kCAAlB,kBAAkB,QAK7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsdk/logging",
3
- "version": "5.11.0",
3
+ "version": "5.11.1-next.1",
4
4
  "description": "Base framework independent logging functionality",
5
5
  "license": "Apache License 2.0",
6
6
  "publishConfig": {
@@ -18,5 +18,5 @@
18
18
  "reflect-metadata": "^0.1.12 || ^0.2.0",
19
19
  "rxjs": "^7.1.0"
20
20
  },
21
- "gitHead": "d8e12d8a65395fd0023db77febbf11c9b3c340bc"
21
+ "gitHead": "b562f667d53198750aab0a70649b9ab17c0419c1"
22
22
  }
@@ -1,16 +1,16 @@
1
- /* eslint-disable @typescript-eslint/ban-types */
2
1
  import type { Constructor } from '@rsdk/common';
3
2
 
4
3
  import 'reflect-metadata';
5
4
 
6
5
  import { LOGGER_METADATA_KEY } from '../metadata/constants';
7
6
  import { LoggerMetadataRegistry } from '../metadata/logger-metadata.registry';
8
- import type { LoggerSerealizerMetadata } from '../types';
7
+ import type { LoggerSerializerMetadata } from '../types';
9
8
 
10
9
  const logSerializerDecorator: ClassDecorator = function (
10
+ // eslint-disable-next-line @typescript-eslint/ban-types
11
11
  target: Function,
12
12
  ): void {
13
- const metadata: LoggerSerealizerMetadata = {
13
+ const metadata: LoggerSerializerMetadata = {
14
14
  target: target as Constructor,
15
15
  };
16
16
 
package/src/index.ts CHANGED
@@ -7,7 +7,8 @@ export {
7
7
  LoggerOptions,
8
8
  LoggingContext,
9
9
  OnMessage,
10
- LoggerSerealizerMetadata,
10
+ LoggerSerializerMetadata,
11
+ LogTimestampFormat,
11
12
  } from './types';
12
13
  export { ILogger, ILogSerializer, LogSerializerBase } from './logger.interface';
13
14
  export { stringifyContext } from './helpers';
@@ -1,6 +1,11 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import type _pino from 'pino';
3
- import type { Logger as Pino } from 'pino';
3
+ import type {
4
+ DestinationStream,
5
+ Logger as Pino,
6
+ LoggerOptions as LoggerOptsPino,
7
+ TransportMultiOptions,
8
+ } from 'pino';
4
9
 
5
10
  import { LoggerMetadataRegistry } from './metadata/logger-metadata.registry';
6
11
  import { DEFAULT_LEVEL } from './defaults';
@@ -8,16 +13,32 @@ import { PinoLogger } from './implementations';
8
13
  import type { ILogger, LogSerializerBase } from './logger.interface';
9
14
  import type {
10
15
  LoggerOptions,
11
- LoggerSerealizerMetadata,
16
+ LoggerOptionsBase,
17
+ LoggerSerializerMetadata,
12
18
  LoggingContext,
13
19
  LogLevel,
14
20
  OnMessage,
21
+ TimeFn,
15
22
  } from './types';
23
+ import { LogTimestampFormat } from './types';
24
+
25
+ /** Хэндл worker-транспорта pino (thread-stream) для teardown воркеров. */
26
+ interface TransportStream extends DestinationStream {
27
+ end(): void;
28
+ flush(cb?: (err?: Error) => void): void;
29
+ flushSync(): void;
30
+ unref(): void;
31
+ on(event: string, listener: (...args: unknown[]) => void): void;
32
+ removeAllListeners(event?: string): void;
33
+ }
34
+
35
+ const DEFAULT_SHUTDOWN_TIMEOUT_MS = 1000;
16
36
 
17
37
  /**
18
38
  * ATTENTION: require('pino') тут не просто так, в общем они нужны для корректной работы хуков из `@opentelemetry/instrumentation-pino`
19
39
  */
20
40
  const requirePino = (): typeof _pino => {
41
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
21
42
  return require('pino');
22
43
  };
23
44
 
@@ -29,6 +50,20 @@ export class LoggerFactory {
29
50
  // eslint-disable-next-line unicorn/prefer-event-target
30
51
  private static readonly events = new EventEmitter();
31
52
 
53
+ private static opts: LoggerOptions = {
54
+ level: DEFAULT_LEVEL,
55
+ redact: [],
56
+ stream: requirePino().destination(),
57
+ timestampFormat: LogTimestampFormat.isoTime,
58
+ };
59
+
60
+ private static pinoTimestampFormatMap: Record<LogTimestampFormat, TimeFn> = {
61
+ [LogTimestampFormat.epochTime]: requirePino().stdTimeFunctions.epochTime,
62
+ [LogTimestampFormat.unixTime]: requirePino().stdTimeFunctions.unixTime,
63
+ [LogTimestampFormat.nullTime]: requirePino().stdTimeFunctions.nullTime,
64
+ [LogTimestampFormat.isoTime]: requirePino().stdTimeFunctions.isoTime,
65
+ };
66
+
32
67
  /**
33
68
  * Under the hood every logger instance will use this
34
69
  * static instance. Motivation for this is that it's much
@@ -38,18 +73,19 @@ export class LoggerFactory {
38
73
  * Downside is that the idea is not composable with child
39
74
  * loggers (which are no used anywhere yet)
40
75
  */
41
- // eslint-disable-next-line @typescript-eslint/no-var-requires
76
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
42
77
  private static _globalPino: Pino = requirePino()({
43
78
  level: DEFAULT_LEVEL,
79
+ timestamp: this.pinoTimestampFormatMap[this.opts.timestampFormat],
44
80
  });
45
81
 
46
82
  private static _serializers: Map<string, LogSerializerBase> | null = null;
47
83
 
48
- private static readonly opts: LoggerOptions = {
49
- level: DEFAULT_LEVEL,
50
- redact: [],
51
- stream: requirePino().destination(),
52
- };
84
+ /** Ссылка на активный worker-транспорт для закрытия его воркеров. */
85
+ private static _activeTransport: TransportStream | null = null;
86
+
87
+ /** Конфиг, по которому собран _activeTransport (для переиспользования воркера). */
88
+ private static _activeTransportConfig: TransportMultiOptions | null = null;
53
89
 
54
90
  /**
55
91
  * Переконфигурация pino нужна потому, что изначально логгер инициализируется
@@ -61,9 +97,7 @@ export class LoggerFactory {
61
97
  static reconfigure(opts: Partial<LoggerOptions>): void {
62
98
  this.applyOptions(opts);
63
99
 
64
- const { stream, ...other } = this.opts;
65
-
66
- this._globalPino = requirePino()(other, stream);
100
+ this._globalPino = this.instantiatePino();
67
101
  }
68
102
 
69
103
  /**
@@ -84,43 +118,64 @@ export class LoggerFactory {
84
118
  static applyInstrumentations<T extends Record<string, any>>(
85
119
  logHookFunction?: (record: T) => void,
86
120
  ): void {
87
- const { stream, ...other } = this.opts;
88
-
89
- // eslint-disable-next-line @typescript-eslint/no-var-requires
90
- this._globalPino = requirePino()(
91
- {
92
- ...other,
93
-
94
- /**
95
- * Функция которая позволяет добавить дополнительные данные в логи Pino
96
- */
97
- hooks: logHookFunction
98
- ? {
99
- /**
100
- * Реализация взята с официальной документации
101
- * https://getpino.io/#/docs/api?id=logmethod
102
- */
103
- logMethod: function (
104
- inputArgs: any[],
105
- // eslint-disable-next-line @typescript-eslint/ban-types
106
- method: Function,
107
- ): unknown {
108
- if (inputArgs.length >= 2) {
109
- const arg1: T = inputArgs.shift() || {};
110
- const arg2 = inputArgs.shift();
111
-
112
- logHookFunction(arg1);
113
-
114
- // eslint-disable-next-line unicorn/prefer-reflect-apply
115
- return method.apply(this, [arg1, arg2, ...inputArgs]);
116
- }
117
- return method.apply(this, inputArgs);
118
- },
119
- }
120
- : {},
121
- },
122
- stream,
123
- );
121
+ this._globalPino = this.instantiatePino({
122
+ /**
123
+ * Функция которая позволяет добавить дополнительные данные в логи Pino
124
+ */
125
+ hooks: logHookFunction
126
+ ? {
127
+ /**
128
+ * Реализация взята с официальной документации
129
+ * https://getpino.io/#/docs/api?id=logmethod
130
+ */
131
+ // eslint-disable-next-line @typescript-eslint/ban-types
132
+ logMethod: function (inputArgs: any[], method: Function): unknown {
133
+ const arg1 = inputArgs[0];
134
+ if (arg1 && typeof arg1 === 'object') {
135
+ logHookFunction(arg1 as T);
136
+ }
137
+ // eslint-disable-next-line unicorn/prefer-reflect-apply
138
+ return method.apply(this, inputArgs);
139
+ },
140
+ }
141
+ : {},
142
+ });
143
+ }
144
+
145
+ /**
146
+ * Сливает буфер worker-транспорта и завершает его воркеры. Без вызова на
147
+ * остановке приложения забуференные логи теряются, а воркеры висят.
148
+ */
149
+ static async shutdown(
150
+ timeoutMs: number = DEFAULT_SHUTDOWN_TIMEOUT_MS,
151
+ ): Promise<void> {
152
+ const stream = this._activeTransport;
153
+
154
+ if (!stream) return;
155
+
156
+ this._activeTransport = null;
157
+ this._activeTransportConfig = null;
158
+
159
+ await new Promise<void>((resolve) => {
160
+ let settled = false;
161
+
162
+ const finish = (): void => {
163
+ if (settled) return;
164
+ settled = true;
165
+ resolve();
166
+ };
167
+
168
+ try {
169
+ stream.on('close', finish);
170
+ stream.flush(() => stream.end());
171
+ } catch {
172
+ finish();
173
+ }
174
+
175
+ const timer = setTimeout(finish, timeoutMs);
176
+
177
+ timer.unref?.();
178
+ });
124
179
  }
125
180
 
126
181
  static onMessage(handler: OnMessage): void {
@@ -139,7 +194,7 @@ export class LoggerFactory {
139
194
  static getSerializers(): LogSerializerBase[] {
140
195
  if (this._serializers) return Array.from(this._serializers.values());
141
196
 
142
- const metas: LoggerSerealizerMetadata[] =
197
+ const metas: LoggerSerializerMetadata[] =
143
198
  LoggerMetadataRegistry.getSerializers();
144
199
 
145
200
  this._serializers = new Map<string, LogSerializerBase>();
@@ -189,8 +244,130 @@ export class LoggerFactory {
189
244
  }
190
245
 
191
246
  private static applyOptions(opts: Partial<LoggerOptions>): void {
192
- const { redact, level, stream = requirePino().destination() } = opts || {};
247
+ const { redact, level, stream, transport, timestampFormat } = opts || {};
248
+
249
+ const base: LoggerOptionsBase = {
250
+ redact: redact ?? this.opts.redact ?? [],
251
+ level: level ?? DEFAULT_LEVEL,
252
+ timestampFormat: timestampFormat ?? LogTimestampFormat.isoTime,
253
+ };
254
+
255
+ /**
256
+ * Выбираем ровно один способ доставки. Если ни stream, ни transport не
257
+ * переданы — сохраняем текущий, чтобы частичный reconfigure({ level }) не
258
+ * сбрасывал ранее заданный transport.
259
+ */
260
+ if (transport) {
261
+ this.opts = { ...base, transport };
262
+ } else if (stream) {
263
+ this.opts = { ...base, stream };
264
+ } else if (this.opts.transport) {
265
+ this.opts = { ...base, transport: this.opts.transport };
266
+ } else {
267
+ this.opts = {
268
+ ...base,
269
+ stream: this.opts.stream ?? requirePino().destination(),
270
+ };
271
+ }
272
+ }
273
+
274
+ /**
275
+ * `stream`/`transport` исключаем из опций: способ доставки задаётся вторым
276
+ * аргументом `pino()`, а pino запрещает одновременно `transport` в опциях и
277
+ * stream-аргумент.
278
+ */
279
+ private static buildPinoOptions(
280
+ extra: Partial<LoggerOptsPino> = {},
281
+ ): LoggerOptsPino {
282
+ const {
283
+ timestampFormat,
284
+ stream: _stream,
285
+ transport: _transport,
286
+ ...other
287
+ } = this.opts;
288
+
289
+ return {
290
+ ...other,
291
+ timestamp: this.pinoTimestampFormatMap[timestampFormat],
292
+ ...extra,
293
+ };
294
+ }
295
+
296
+ /**
297
+ * Создаёт инстанс pino. Воркер транспорта переиспользуется, если объект
298
+ * конфига транспорта тот же по ссылке (сравнение identity, не по значению).
299
+ * Это покрывает связку reconfigure→applyInstrumentations (между ними
300
+ * this.opts.transport не пересобирается) и не даёт пересоздавать и тут же
301
+ * закрывать только что поднятый, возможно медленный, OTEL-воркер. Новый
302
+ * объект конфига (например, при config.onUpdate) ожидаемо пересоздаёт воркер.
303
+ */
304
+ private static instantiatePino(extra: Partial<LoggerOptsPino> = {}): Pino {
305
+ const pino = requirePino();
306
+ const options = this.buildPinoOptions(extra);
307
+
308
+ if (!this.opts.transport) {
309
+ this.disposeActiveTransport();
310
+
311
+ return pino(options, this.opts.stream);
312
+ }
313
+
314
+ const reuse =
315
+ this._activeTransport &&
316
+ this.opts.transport === this._activeTransportConfig;
317
+
318
+ const stream = reuse
319
+ ? this._activeTransport!
320
+ : this.createTransport(this.opts.transport);
321
+
322
+ return pino(options, stream);
323
+ }
324
+
325
+ /**
326
+ * Поднимает worker-транспорт, закрыв предыдущий. Обработчик 'error' не даёт
327
+ * асинхронной ошибке воркера уронить процесс, но делает её видимой в stderr
328
+ * (сам логгер использовать нельзя — упал его транспорт). Ошибку резолва
329
+ * таргета pino.transport(...) бросает синхронно — она долетает до старта.
330
+ */
331
+ private static createTransport(
332
+ transport: TransportMultiOptions,
333
+ ): TransportStream {
334
+ this.disposeActiveTransport();
335
+
336
+ const stream = requirePino().transport(transport) as TransportStream;
337
+
338
+ stream.on('error', (...args: unknown[]) => {
339
+ const error = args[0];
340
+ const message = error instanceof Error ? error.message : String(error);
341
+
342
+ process.stderr.write(`[@rsdk/logging] transport error: ${message}\n`);
343
+ });
344
+
345
+ this._activeTransport = stream;
346
+ this._activeTransportConfig = transport;
347
+
348
+ return stream;
349
+ }
350
+
351
+ /**
352
+ * Завершает воркеры предыдущего транспорта (best-effort, не блокируя). stdout
353
+ * не затрагивается: для него хэндл не сохраняется.
354
+ */
355
+ private static disposeActiveTransport(): void {
356
+ const previous = this._activeTransport;
357
+
358
+ if (!previous) return;
359
+
360
+ this._activeTransport = null;
361
+ this._activeTransportConfig = null;
362
+
363
+ // на teardown ошибки ожидаемы (например, "end() took too long" у медленных
364
+ // транспортов) — глушим их молча и не держим event loop
365
+ previous.unref?.();
366
+ previous.removeAllListeners?.('error');
367
+ previous.on('error', () => {});
193
368
 
194
- Object.assign(this.opts, { redact, level: level ?? DEFAULT_LEVEL, stream });
369
+ try {
370
+ previous.end();
371
+ } catch {}
195
372
  }
196
373
  }
@@ -1,21 +1,21 @@
1
1
  import type { Constructor } from '@rsdk/common';
2
2
 
3
- import type { LoggerSerealizerMetadata } from '../types';
3
+ import type { LoggerSerializerMetadata } from '../types';
4
4
 
5
5
  export class LoggerMetadataRegistry {
6
6
  private static readonly serializers = new Map<
7
7
  Constructor,
8
- LoggerSerealizerMetadata
8
+ LoggerSerializerMetadata
9
9
  >();
10
10
 
11
11
  static registerSerializer(
12
12
  target: Constructor,
13
- metadata: LoggerSerealizerMetadata,
13
+ metadata: LoggerSerializerMetadata,
14
14
  ): void {
15
15
  this.serializers.set(target, metadata);
16
16
  }
17
17
 
18
- static getSerializers(): LoggerSerealizerMetadata[] {
18
+ static getSerializers(): LoggerSerializerMetadata[] {
19
19
  return Array.from(this.serializers.values());
20
20
  }
21
21
  }
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Constructor } from '@rsdk/common';
2
2
  import type pino from 'pino';
3
+ import type { TransportMultiOptions } from 'pino';
3
4
 
4
5
  export enum LogLevel {
5
6
  fatal = 'fatal',
@@ -10,14 +11,34 @@ export enum LogLevel {
10
11
  trace = 'trace',
11
12
  }
12
13
 
14
+ export enum LogTimestampFormat {
15
+ epochTime = 'epochTime',
16
+ unixTime = 'unixTime',
17
+ nullTime = 'nullTime',
18
+ isoTime = 'isoTime',
19
+ }
20
+
21
+ export type TimeFn = () => string;
22
+
13
23
  export type Params = Record<string, unknown>;
14
24
 
15
- export interface LoggerOptions {
25
+ export interface LoggerOptionsBase {
16
26
  level: LogLevel;
17
27
  redact: string[];
18
- stream: pino.DestinationStream;
28
+ timestampFormat: LogTimestampFormat;
19
29
  }
20
30
 
31
+ /**
32
+ * `stream` и `transport` — взаимоисключающие способы доставки (pino не
33
+ * принимает оба сразу). Это закодировано в типе: задание одного запрещает
34
+ * другой.
35
+ */
36
+ export type LoggerOptions = LoggerOptionsBase &
37
+ (
38
+ | { stream?: pino.DestinationStream; transport?: never }
39
+ | { stream?: never; transport?: TransportMultiOptions }
40
+ );
41
+
21
42
  export type LoggingContext = string | Constructor;
22
43
 
23
44
  export type OnMessage = (
@@ -25,6 +46,6 @@ export type OnMessage = (
25
46
  data: Record<string, unknown>,
26
47
  ) => void;
27
48
 
28
- export interface LoggerSerealizerMetadata {
49
+ export interface LoggerSerializerMetadata {
29
50
  target: Constructor;
30
51
  }