@rsdk/core 5.7.0-next.2 → 6.0.0-next.0

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.
Files changed (261) hide show
  1. package/dist/config/index.d.ts +0 -1
  2. package/dist/config/index.js +0 -1
  3. package/dist/config/index.js.map +1 -1
  4. package/dist/config/metadata/decorators/declare-property.decorator.d.ts +2 -1
  5. package/dist/config/metadata/decorators/declare-property.decorator.js.map +1 -1
  6. package/dist/config/metadata/decorators/property.decorator.d.ts +2 -1
  7. package/dist/config/metadata/decorators/property.decorator.js.map +1 -1
  8. package/dist/config/sources/implementations/json-file.source.js +1 -2
  9. package/dist/config/sources/implementations/json-file.source.js.map +1 -1
  10. package/dist/config/sources/implementations/relodable-json-file.source.js +1 -2
  11. package/dist/config/sources/implementations/relodable-json-file.source.js.map +1 -1
  12. package/dist/config/types.d.ts +1 -20
  13. package/dist/config/types.js.map +1 -1
  14. package/dist/exceptions.handling/default.formatter.d.ts +6 -0
  15. package/dist/exceptions.handling/default.formatter.js +12 -0
  16. package/dist/exceptions.handling/default.formatter.js.map +1 -0
  17. package/dist/exceptions.handling/default.sender.d.ts +8 -0
  18. package/dist/exceptions.handling/default.sender.js +13 -0
  19. package/dist/exceptions.handling/default.sender.js.map +1 -0
  20. package/dist/exceptions.handling/global-exceptions.config.js +1 -1
  21. package/dist/exceptions.handling/global-exceptions.config.js.map +1 -1
  22. package/dist/exceptions.handling/global-exceptions.filter.d.ts +8 -11
  23. package/dist/exceptions.handling/global-exceptions.filter.js +38 -56
  24. package/dist/exceptions.handling/global-exceptions.filter.js.map +1 -1
  25. package/dist/exceptions.handling/global-exceptions.interceptor.d.ts +18 -0
  26. package/dist/exceptions.handling/global-exceptions.interceptor.js +57 -0
  27. package/dist/exceptions.handling/global-exceptions.interceptor.js.map +1 -0
  28. package/dist/exceptions.handling/global-exceptions.module.d.ts +2 -23
  29. package/dist/exceptions.handling/global-exceptions.module.js +38 -3
  30. package/dist/exceptions.handling/global-exceptions.module.js.map +1 -1
  31. package/dist/exceptions.handling/types.d.ts +2 -2
  32. package/dist/index.d.ts +31 -2
  33. package/dist/index.js +34 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/logging/constants.d.ts +1 -0
  36. package/dist/logging/constants.js +5 -0
  37. package/dist/logging/constants.js.map +1 -0
  38. package/dist/logging/decorators/inject-logger.decorator.js +2 -2
  39. package/dist/logging/decorators/inject-logger.decorator.js.map +1 -1
  40. package/dist/logging/formatters/default.formatter.d.ts +7 -0
  41. package/dist/logging/formatters/default.formatter.js +17 -0
  42. package/dist/logging/formatters/default.formatter.js.map +1 -0
  43. package/dist/logging/formatters/index.d.ts +2 -0
  44. package/dist/{config/parsers/array → logging/formatters}/index.js +2 -1
  45. package/dist/logging/formatters/index.js.map +1 -0
  46. package/dist/logging/formatters/interfaces.d.ts +23 -0
  47. package/dist/logging/formatters/interfaces.js +3 -0
  48. package/dist/logging/formatters/interfaces.js.map +1 -0
  49. package/dist/logging/index.d.ts +3 -2
  50. package/dist/logging/index.js +6 -4
  51. package/dist/logging/index.js.map +1 -1
  52. package/dist/logging/logging-core.module.d.ts +10 -0
  53. package/dist/logging/{logger-initializing.module.js → logging-core.module.js} +46 -10
  54. package/dist/logging/logging-core.module.js.map +1 -0
  55. package/dist/logging/{logging.module.d.ts → logging-instances.module.d.ts} +1 -1
  56. package/dist/logging/{logging.module.js → logging-instances.module.js} +8 -9
  57. package/dist/logging/logging-instances.module.js.map +1 -0
  58. package/dist/logging/logging.config.d.ts +3 -0
  59. package/dist/logging/logging.config.js +29 -4
  60. package/dist/logging/logging.config.js.map +1 -1
  61. package/dist/logging/logging.interceptor.d.ts +37 -0
  62. package/dist/logging/logging.interceptor.js +124 -0
  63. package/dist/logging/logging.interceptor.js.map +1 -0
  64. package/dist/metrics/metrics.config.js +3 -2
  65. package/dist/metrics/metrics.config.js.map +1 -1
  66. package/dist/platform.context.d.ts +1 -1
  67. package/dist/platform.context.js +3 -2
  68. package/dist/platform.context.js.map +1 -1
  69. package/dist/platform.module.js +19 -6
  70. package/dist/platform.module.js.map +1 -1
  71. package/dist/tracing/constants.d.ts +4 -5
  72. package/dist/tracing/constants.js +9 -7
  73. package/dist/tracing/constants.js.map +1 -1
  74. package/dist/tracing/index.d.ts +1 -0
  75. package/dist/tracing/index.js +1 -0
  76. package/dist/tracing/index.js.map +1 -1
  77. package/dist/tracing/request-id/index.d.ts +4 -0
  78. package/dist/{config/parsers/enum → tracing/request-id}/index.js +4 -1
  79. package/dist/tracing/request-id/index.js.map +1 -0
  80. package/dist/tracing/request-id/metadata.helpers.d.ts +13 -0
  81. package/dist/tracing/request-id/metadata.helpers.js +23 -0
  82. package/dist/tracing/request-id/metadata.helpers.js.map +1 -0
  83. package/dist/tracing/request-id/request-id-gen.decorator.d.ts +8 -0
  84. package/dist/tracing/request-id/request-id-gen.decorator.js +17 -0
  85. package/dist/tracing/request-id/request-id-gen.decorator.js.map +1 -0
  86. package/dist/tracing/request-id/types.d.ts +2 -0
  87. package/dist/tracing/request-id/types.js +3 -0
  88. package/dist/tracing/request-id/types.js.map +1 -0
  89. package/dist/tracing/request-id/with-prefix.fn.d.ts +30 -0
  90. package/dist/tracing/request-id/with-prefix.fn.js +36 -0
  91. package/dist/tracing/request-id/with-prefix.fn.js.map +1 -0
  92. package/dist/tracing/tracing.config.d.ts +5 -0
  93. package/dist/tracing/tracing.config.js +42 -0
  94. package/dist/tracing/tracing.config.js.map +1 -0
  95. package/dist/tracing/tracing.interceptor.d.ts +7 -9
  96. package/dist/tracing/tracing.interceptor.js +30 -28
  97. package/dist/tracing/tracing.interceptor.js.map +1 -1
  98. package/dist/tracing/tracing.module.d.ts +13 -2
  99. package/dist/tracing/tracing.module.js +60 -17
  100. package/dist/tracing/tracing.module.js.map +1 -1
  101. package/dist/transport/protocol.detector.d.ts +1 -1
  102. package/dist/transport/protocol.detector.js +17 -2
  103. package/dist/transport/protocol.detector.js.map +1 -1
  104. package/dist/transport/transport.module.d.ts +0 -1
  105. package/dist/transport/transport.module.js +0 -20
  106. package/dist/transport/transport.module.js.map +1 -1
  107. package/dist/types/plugins.d.ts +2 -15
  108. package/dist/types/plugins.js.map +1 -1
  109. package/dist/types/transports.d.ts +23 -13
  110. package/dist/types/transports.js.map +1 -1
  111. package/dist/unhandled-rejection.handler.js +8 -13
  112. package/dist/unhandled-rejection.handler.js.map +1 -1
  113. package/package.json +3 -2
  114. package/src/config/index.ts +0 -1
  115. package/src/config/metadata/decorators/declare-property.decorator.ts +3 -1
  116. package/src/config/metadata/decorators/property.decorator.ts +3 -5
  117. package/src/config/sources/implementations/json-file.source.ts +1 -2
  118. package/src/config/sources/implementations/relodable-json-file.source.ts +1 -2
  119. package/src/config/types.ts +2 -23
  120. package/src/exceptions.handling/default.formatter.ts +11 -0
  121. package/src/exceptions.handling/default.sender.ts +15 -0
  122. package/src/exceptions.handling/global-exceptions.config.ts +2 -2
  123. package/src/exceptions.handling/global-exceptions.filter.ts +45 -77
  124. package/src/exceptions.handling/global-exceptions.interceptor.ts +57 -0
  125. package/src/exceptions.handling/global-exceptions.module.ts +46 -33
  126. package/src/exceptions.handling/types.ts +2 -2
  127. package/src/index.ts +53 -2
  128. package/src/logging/constants.ts +1 -0
  129. package/src/logging/decorators/inject-logger.decorator.ts +2 -2
  130. package/src/logging/formatters/default.formatter.ts +17 -0
  131. package/src/logging/formatters/index.ts +2 -0
  132. package/src/logging/formatters/interfaces.ts +34 -0
  133. package/src/logging/index.ts +3 -2
  134. package/src/logging/logging-core.module.ts +102 -0
  135. package/src/logging/{logging.module.ts → logging-instances.module.ts} +2 -4
  136. package/src/logging/logging.config.ts +22 -6
  137. package/src/logging/logging.interceptor.ts +138 -0
  138. package/src/metrics/metrics.config.ts +3 -1
  139. package/src/platform.context.ts +5 -2
  140. package/src/platform.module.ts +28 -7
  141. package/src/tracing/constants.ts +8 -7
  142. package/src/tracing/index.ts +1 -0
  143. package/src/tracing/request-id/index.ts +4 -0
  144. package/src/tracing/request-id/metadata.helpers.ts +24 -0
  145. package/src/tracing/request-id/request-id-gen.decorator.ts +16 -0
  146. package/src/tracing/request-id/types.ts +6 -0
  147. package/src/tracing/request-id/with-prefix.fn.ts +44 -0
  148. package/src/tracing/tracing.config.ts +23 -0
  149. package/src/tracing/tracing.interceptor.ts +36 -31
  150. package/src/tracing/tracing.module.ts +68 -19
  151. package/src/transport/protocol.detector.ts +24 -4
  152. package/src/transport/transport.module.ts +0 -25
  153. package/src/types/plugins.ts +11 -22
  154. package/src/types/transports.ts +32 -16
  155. package/src/unhandled-rejection.handler.ts +10 -18
  156. package/test/logging.interceptor.spec.ts +292 -0
  157. package/dist/config/parsers/array/array.parser.d.ts +0 -11
  158. package/dist/config/parsers/array/array.parser.js +0 -33
  159. package/dist/config/parsers/array/array.parser.js.map +0 -1
  160. package/dist/config/parsers/array/index.d.ts +0 -1
  161. package/dist/config/parsers/array/index.js.map +0 -1
  162. package/dist/config/parsers/boolean/bool.parser.d.ts +0 -6
  163. package/dist/config/parsers/boolean/bool.parser.js +0 -20
  164. package/dist/config/parsers/boolean/bool.parser.js.map +0 -1
  165. package/dist/config/parsers/boolean/index.d.ts +0 -1
  166. package/dist/config/parsers/boolean/index.js +0 -18
  167. package/dist/config/parsers/boolean/index.js.map +0 -1
  168. package/dist/config/parsers/enum/enum.parser.d.ts +0 -9
  169. package/dist/config/parsers/enum/enum.parser.js +0 -24
  170. package/dist/config/parsers/enum/enum.parser.js.map +0 -1
  171. package/dist/config/parsers/enum/index.d.ts +0 -1
  172. package/dist/config/parsers/enum/index.js.map +0 -1
  173. package/dist/config/parsers/index.d.ts +0 -11
  174. package/dist/config/parsers/index.js +0 -28
  175. package/dist/config/parsers/index.js.map +0 -1
  176. package/dist/config/parsers/int/index.d.ts +0 -1
  177. package/dist/config/parsers/int/index.js +0 -18
  178. package/dist/config/parsers/int/index.js.map +0 -1
  179. package/dist/config/parsers/int/int.parser.d.ts +0 -6
  180. package/dist/config/parsers/int/int.parser.js +0 -20
  181. package/dist/config/parsers/int/int.parser.js.map +0 -1
  182. package/dist/config/parsers/json/index.d.ts +0 -1
  183. package/dist/config/parsers/json/index.js +0 -18
  184. package/dist/config/parsers/json/index.js.map +0 -1
  185. package/dist/config/parsers/json/json.parser.d.ts +0 -6
  186. package/dist/config/parsers/json/json.parser.js +0 -16
  187. package/dist/config/parsers/json/json.parser.js.map +0 -1
  188. package/dist/config/parsers/number/index.d.ts +0 -1
  189. package/dist/config/parsers/number/index.js +0 -18
  190. package/dist/config/parsers/number/index.js.map +0 -1
  191. package/dist/config/parsers/number/number.parser.d.ts +0 -6
  192. package/dist/config/parsers/number/number.parser.js +0 -23
  193. package/dist/config/parsers/number/number.parser.js.map +0 -1
  194. package/dist/config/parsers/path/fspath.parser.d.ts +0 -8
  195. package/dist/config/parsers/path/fspath.parser.js +0 -59
  196. package/dist/config/parsers/path/fspath.parser.js.map +0 -1
  197. package/dist/config/parsers/path/index.d.ts +0 -1
  198. package/dist/config/parsers/path/index.js +0 -18
  199. package/dist/config/parsers/path/index.js.map +0 -1
  200. package/dist/config/parsers/size/index.d.ts +0 -1
  201. package/dist/config/parsers/size/index.js +0 -18
  202. package/dist/config/parsers/size/index.js.map +0 -1
  203. package/dist/config/parsers/size/size.parser.d.ts +0 -7
  204. package/dist/config/parsers/size/size.parser.js +0 -21
  205. package/dist/config/parsers/size/size.parser.js.map +0 -1
  206. package/dist/config/parsers/string/index.d.ts +0 -1
  207. package/dist/config/parsers/string/index.js +0 -18
  208. package/dist/config/parsers/string/index.js.map +0 -1
  209. package/dist/config/parsers/string/string.parser.d.ts +0 -8
  210. package/dist/config/parsers/string/string.parser.js +0 -29
  211. package/dist/config/parsers/string/string.parser.js.map +0 -1
  212. package/dist/config/parsers/timespan/index.d.ts +0 -1
  213. package/dist/config/parsers/timespan/index.js +0 -18
  214. package/dist/config/parsers/timespan/index.js.map +0 -1
  215. package/dist/config/parsers/timespan/timespan.parser.d.ts +0 -7
  216. package/dist/config/parsers/timespan/timespan.parser.js +0 -21
  217. package/dist/config/parsers/timespan/timespan.parser.js.map +0 -1
  218. package/dist/config/parsers/url/exception.d.ts +0 -7
  219. package/dist/config/parsers/url/exception.js +0 -25
  220. package/dist/config/parsers/url/exception.js.map +0 -1
  221. package/dist/config/parsers/url/index.d.ts +0 -2
  222. package/dist/config/parsers/url/index.js +0 -21
  223. package/dist/config/parsers/url/index.js.map +0 -1
  224. package/dist/config/parsers/url/url.parser.d.ts +0 -9
  225. package/dist/config/parsers/url/url.parser.js +0 -38
  226. package/dist/config/parsers/url/url.parser.js.map +0 -1
  227. package/dist/logging/logger-initializing.module.d.ts +0 -6
  228. package/dist/logging/logger-initializing.module.js.map +0 -1
  229. package/dist/logging/logging.module.js.map +0 -1
  230. package/src/config/parsers/array/array.parser.ts +0 -34
  231. package/src/config/parsers/array/index.ts +0 -1
  232. package/src/config/parsers/boolean/bool.parser.ts +0 -20
  233. package/src/config/parsers/boolean/bool.spec.ts +0 -4
  234. package/src/config/parsers/boolean/index.ts +0 -1
  235. package/src/config/parsers/enum/enum.parser.ts +0 -23
  236. package/src/config/parsers/enum/enum.spec.ts +0 -5
  237. package/src/config/parsers/enum/index.ts +0 -1
  238. package/src/config/parsers/index.ts +0 -11
  239. package/src/config/parsers/int/index.ts +0 -1
  240. package/src/config/parsers/int/int.parser.ts +0 -20
  241. package/src/config/parsers/int/int.spec.ts +0 -5
  242. package/src/config/parsers/json/index.ts +0 -1
  243. package/src/config/parsers/json/json.parser.ts +0 -15
  244. package/src/config/parsers/number/index.ts +0 -1
  245. package/src/config/parsers/number/number.parser.ts +0 -23
  246. package/src/config/parsers/number/number.spec.ts +0 -5
  247. package/src/config/parsers/path/fspath.parser.ts +0 -64
  248. package/src/config/parsers/path/index.ts +0 -1
  249. package/src/config/parsers/size/index.ts +0 -1
  250. package/src/config/parsers/size/size.parser.ts +0 -22
  251. package/src/config/parsers/size/size.spec.ts +0 -4
  252. package/src/config/parsers/string/index.ts +0 -1
  253. package/src/config/parsers/string/string.parser.ts +0 -26
  254. package/src/config/parsers/string/string.spec.ts +0 -10
  255. package/src/config/parsers/timespan/index.ts +0 -1
  256. package/src/config/parsers/timespan/timespan.parser.ts +0 -22
  257. package/src/config/parsers/timespan/timespan.spec.ts +0 -5
  258. package/src/config/parsers/url/exception.ts +0 -21
  259. package/src/config/parsers/url/index.ts +0 -2
  260. package/src/config/parsers/url/url.parser.ts +0 -44
  261. package/src/logging/logger-initializing.module.ts +0 -55
@@ -1,5 +1,3 @@
1
- /* eslint-disable sort-keys */
2
-
3
1
  import type { DynamicModule } from '@nestjs/common';
4
2
  import { Module } from '@nestjs/common';
5
3
  import type { Constructor } from '@rsdk/common';
@@ -15,7 +13,7 @@ import { getLoggerToken } from './helpers';
15
13
  import type { LoggingRsdkMetadata } from './types';
16
14
 
17
15
  @Module({})
18
- export class LoggingModule {
16
+ export class LoggerInstancesModule {
19
17
  static register(
20
18
  target: object,
21
19
  context: string | Constructor,
@@ -73,7 +71,7 @@ export class LoggingModule {
73
71
  ): DynamicModule {
74
72
  return {
75
73
  global: true,
76
- module: LoggingModule,
74
+ module: LoggerInstancesModule,
77
75
  providers: [
78
76
  {
79
77
  provide: token,
@@ -1,14 +1,12 @@
1
- import { DEFAULT_LEVEL, LogLevel } from '@rsdk/logging';
2
-
3
1
  import {
4
2
  ArrayParser,
5
3
  BoolParser,
6
- Config,
7
- ConfigSection,
8
4
  EnumParser,
9
- Property,
10
5
  StringParser,
11
- } from '../config';
6
+ } from '@rsdk/common';
7
+ import { DEFAULT_LEVEL, LogLevel } from '@rsdk/logging';
8
+
9
+ import { Config, ConfigSection, Property } from '../config';
12
10
  import { ConfigTag } from '../config/config.const';
13
11
 
14
12
  @ConfigSection({
@@ -41,4 +39,22 @@ export class LoggingConfig extends Config {
41
39
  description: 'Enable OpenTelemetry exporter',
42
40
  })
43
41
  readonly otelEnabled!: boolean;
42
+
43
+ @Property('LOG_EXCLUDE_ZONES', new ArrayParser(new StringParser()), {
44
+ defaultValue: [],
45
+ description: 'Disable request/response logging for zones',
46
+ })
47
+ readonly excludeZones!: string[];
48
+
49
+ @Property('LOG_REQUEST_BODY', new BoolParser(), {
50
+ description: 'Enable request body (content) logging',
51
+ defaultValue: false,
52
+ })
53
+ readonly logRequestBody!: boolean;
54
+
55
+ @Property('LOG_RESPONSE_BODY', new BoolParser(), {
56
+ description: 'Enable response body (content) logging',
57
+ defaultValue: false,
58
+ })
59
+ readonly logResponseBody!: boolean;
44
60
  }
@@ -0,0 +1,138 @@
1
+ import type {
2
+ CallHandler,
3
+ ExecutionContext,
4
+ NestInterceptor,
5
+ } from '@nestjs/common';
6
+ import { Inject, Injectable } from '@nestjs/common';
7
+ import { ILogger } from '@rsdk/logging';
8
+ import { Zone } from '@rsdk/zones';
9
+ import type { Observable } from 'rxjs';
10
+ import { catchError, tap, throwError } from 'rxjs';
11
+
12
+ import { PipelineException } from '../exceptions';
13
+ import { ProtocolDetector } from '../transport/protocol.detector';
14
+
15
+ import { InjectLogger } from './decorators/inject-logger.decorator';
16
+ import { LOG_FORMATTERS } from './constants';
17
+ import { DefaultLogFormatter, LogFormatter } from './formatters';
18
+ import { LoggingConfig } from './logging.config';
19
+
20
+ /**
21
+ * LOG_LEVEL=
22
+ * LOG_REDACT=
23
+ * LOG_SYNC=
24
+ * LOG_OTEL_ENABLED=
25
+ *
26
+ * 1. Я хочу, чтобы сообщения в логе писались можно было писать
27
+ * с большим или меньшим количество подробностей. В зависимости
28
+ * от уровня логирования.
29
+ *
30
+ * 2. Я хочу, чтобы логирование успешных ответов и логирование ошибок
31
+ * было в принципе унифицировано. Сейчас этим занимаются разные интерцепторы.
32
+ * а мог бы один, отвечающий за логирование.
33
+ *
34
+ * 3. Логирование бинарных данных должны быть исключено.
35
+ * Возможность исключать логи запросов по ApiZone... кроме ошибок.
36
+ *
37
+ * 4. В логе ошибок писать больше о контексте запроса.
38
+ *
39
+ * РАЗОБРАТЬСЯ, ПОЧЕМУ kicker мы не можем сделать контроллером?
40
+ */
41
+
42
+ @Injectable()
43
+ export class LoggingInterceptor implements NestInterceptor {
44
+ private readonly defaultFormatter = new DefaultLogFormatter();
45
+
46
+ constructor(
47
+ @InjectLogger(LoggingInterceptor)
48
+ private readonly logger: ILogger,
49
+ @Inject(LOG_FORMATTERS)
50
+ private readonly formatters: Map<string, LogFormatter>,
51
+ private detector: ProtocolDetector,
52
+ private config: LoggingConfig,
53
+ ) {}
54
+
55
+ intercept(
56
+ context: ExecutionContext,
57
+ next: CallHandler<any>,
58
+ ): Observable<any> {
59
+ const receivedAt = Date.now();
60
+
61
+ const protocol = this.detector.getProtocol(context);
62
+
63
+ const formatter: LogFormatter = protocol
64
+ ? this.getFormatter(protocol)
65
+ : this.defaultFormatter;
66
+
67
+ const shouldLog = formatter.shouldLog?.(context) ?? true;
68
+ if (!shouldLog) {
69
+ return next.handle();
70
+ }
71
+
72
+ const { logRequestBody, logResponseBody, excludeZones, level } =
73
+ this.config;
74
+
75
+ const path = formatter.getPath(context);
76
+ const requestDetails = formatter.formatRequest(context, logRequestBody);
77
+
78
+ const zone = Zone.getForContext(context);
79
+ const isExcluded = !!zone && excludeZones.includes(zone);
80
+
81
+ if (!isExcluded) {
82
+ this.logger.debug(`>>> Received [${protocol.toUpperCase()}] ${path}`, {
83
+ details: requestDetails,
84
+ path,
85
+ zone,
86
+ });
87
+ }
88
+
89
+ return next.handle().pipe(
90
+ catchError((ex: PipelineException) => {
91
+ /**
92
+ * Добавляем параметры запроса, если они не были залогированы ранее.
93
+ */
94
+ const request =
95
+ isExcluded || !['trace', 'debug'].includes(level)
96
+ ? requestDetails
97
+ : '[ALREADY LOGGED]';
98
+
99
+ this.logger.error(`Failed [${protocol.toUpperCase()}] ${path}`, {
100
+ request,
101
+ cause: ex,
102
+ path,
103
+ zone,
104
+ });
105
+
106
+ return throwError(() => ex);
107
+ }),
108
+ tap((body) => {
109
+ if (isExcluded) {
110
+ return;
111
+ }
112
+
113
+ const responseDetails = formatter.formatResponse(
114
+ context,
115
+ logResponseBody ? body : undefined,
116
+ );
117
+
118
+ this.logger.debug(`<<< Handled [${protocol.toUpperCase()}] ${path}`, {
119
+ details: responseDetails,
120
+ executionTime: Date.now() - receivedAt,
121
+ path,
122
+ zone,
123
+ });
124
+ }),
125
+ );
126
+ }
127
+
128
+ private getFormatter(protocol: string): LogFormatter {
129
+ const formatter = this.formatters.get(protocol);
130
+
131
+ if (!formatter) {
132
+ this.logger.warn(`no formatter for protocol <${protocol}>...`);
133
+ return this.defaultFormatter;
134
+ }
135
+
136
+ return formatter;
137
+ }
138
+ }
@@ -1,4 +1,6 @@
1
- import { BoolParser, Config, ConfigSection, Property } from '../config';
1
+ import { BoolParser } from '@rsdk/common';
2
+
3
+ import { Config, ConfigSection, Property } from '../config';
2
4
  import { ConfigTag } from '../config/config.const';
3
5
 
4
6
  @ConfigSection({
@@ -3,7 +3,8 @@ import type { INestApplication } from '@nestjs/common/interfaces';
3
3
  import type { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
4
4
  import type { AbstractHttpAdapter } from '@nestjs/core';
5
5
  import type { Constructor } from '@rsdk/common';
6
- import { LoggerFactory } from '@rsdk/logging';
6
+ import type { ILogger } from '@rsdk/logging';
7
+ import { LoggerFactory, NoopLogger } from '@rsdk/logging';
7
8
  import type { RsdkMetadataProvider } from '@rsdk/metadata';
8
9
  import { groupBy, intersection } from 'lodash';
9
10
 
@@ -39,7 +40,7 @@ import {
39
40
  * Агрегат для хранения опций приложения, а также методы для конфигурации и запуска приложения
40
41
  */
41
42
  export class PlatformContext {
42
- private readonly logger = LoggerFactory.create('App');
43
+ private readonly logger: ILogger;
43
44
  private readonly microservices = new Map<
44
45
  INestMicroservice,
45
46
  IMicroserviceTransport
@@ -68,12 +69,14 @@ export class PlatformContext {
68
69
  // force set appName
69
70
  forceAppName?: string;
70
71
  },
72
+ silent?: boolean,
71
73
  ) {
72
74
  this.assertTransportCompatibility(options);
73
75
  this.assertPluginCompatibility(options);
74
76
 
75
77
  this.httpTransport = options.transports?.find?.(isHttpTransport);
76
78
  this.aggregator = new ContextAggregator(this);
79
+ this.logger = silent ? new NoopLogger() : LoggerFactory.create('App');
77
80
  }
78
81
 
79
82
  get extendedOptions(): PlatformExtendedOptions {
@@ -8,7 +8,8 @@ import { PlatformPluginModule } from './plugin/plugin.module';
8
8
  import { PlatformTransportModule } from './transport/transport.module';
9
9
  import { AppMetadataModule } from './app-metadata';
10
10
  import { PlatformConfigModule } from './config';
11
- import { LoggerInitializingModule } from './logging';
11
+ import { GlobalExceptionsModule } from './exceptions.handling';
12
+ import { LoggingCoreModule } from './logging';
12
13
  import { TracingModule } from './tracing';
13
14
  import type { PlatformAppPlugin, PlatformExtendedOptions } from './types';
14
15
  import { APP_PLUGINS, APP_TRANSPORTS } from './types';
@@ -19,21 +20,41 @@ export class PlatformModule implements NestModule {
19
20
  static forRoot(options: PlatformExtendedOptions): DynamicModule {
20
21
  const imports: (DynamicModule | Constructor)[] = [
21
22
  /**
22
- * Последовательность принципиально важна так как в этом модуле происходит
23
- * инициализация глобального асинхронного контекста (AsyncLocalStorage)
23
+ * Последовательность принципиально важна так как от порядка подключения будет зависеть
24
+ * порядок отработки глобальных интерцепторов
24
25
  */
26
+
27
+ // Interceptor: инициализация асинхронного контекста
25
28
  AsyncContextModule,
29
+
30
+ // Interceptor: Извлечение трассируемых заголовков из запроса
26
31
  TracingModule.forRoot(options),
27
32
 
28
- // Plugins
33
+ // Interceptor: LoggingInterceptor
34
+ LoggingCoreModule.forRoot(options),
35
+
36
+ // Interceptor: Форматирование ошибок
37
+ GlobalExceptionsModule.forRoot(options),
38
+
39
+ // Interceptor: из конкретных реализаций транспортов (если есть)
40
+ PlatformTransportModule.forOptions(options),
41
+
42
+ /**
43
+ * Далее порядок не важен, т. к. интерцепторов нет. Последовательность
44
+ * инициализации провайдеров Nest.js разрулит самостоятельно.
45
+ */
46
+
47
+ // Инициализация плагинов
29
48
  PlatformPluginModule.forOptions(options),
30
49
 
31
- // Infrastructure
50
+ // Метаданные сервиса
32
51
  AppMetadataModule.forRoot(options),
52
+
53
+ // Чтение и валидация конфигурации приложения
33
54
  PlatformConfigModule.forRoot(options),
34
- LoggerInitializingModule,
55
+
56
+ // Прикладные модули
35
57
  ...(options.modules ?? []),
36
- PlatformTransportModule.forOptions(options),
37
58
  ];
38
59
 
39
60
  const providers = [
@@ -1,4 +1,3 @@
1
- import type { TracingOptions } from './tracing.module';
2
1
  import type { TracingHeaderMappings } from './types';
3
2
 
4
3
  /**
@@ -7,13 +6,15 @@ import type { TracingHeaderMappings } from './types';
7
6
  export const HEADER_MAPPINGS = Symbol('HEADER_MAPPINGS');
8
7
 
9
8
  /**
10
- * Default mappings for tracing headers
9
+ * Header extractors injection token
11
10
  */
12
- export const DEFAULT_TRACING_HEADERS: TracingHeaderMappings[] = [
13
- ['requestId', 'X-Request-Id', 'X-Requestid'],
14
- ];
11
+ export const HEADER_EXTRACTORS = Symbol('HEADER_EXTRACTORS');
15
12
 
16
13
  /**
17
- * Default tracing options
14
+ * Default mappings for tracing headers
18
15
  */
19
- export const DEFAULT_TRACING_OPTIONS: TracingOptions = { includeDefault: true };
16
+ export const REQUEST_ID_HEADERS: TracingHeaderMappings = [
17
+ 'requestId',
18
+ 'X-Request-Id',
19
+ 'X-Requestid',
20
+ ];
@@ -2,3 +2,4 @@ export * from './tracing.module';
2
2
  export * from './tracing.actx';
3
3
  export * from './opentelemetry';
4
4
  export * from './types';
5
+ export * from './request-id';
@@ -0,0 +1,4 @@
1
+ export * from './request-id-gen.decorator';
2
+ export * from './metadata.helpers';
3
+ export * from './types';
4
+ export * from './with-prefix.fn';
@@ -0,0 +1,24 @@
1
+ import type { GenerateRequestId } from './types';
2
+
3
+ const REQUEST_ID_GEN_STRATEGY_KEY = Symbol('REQUEST_ID_GEN_STRATEGY');
4
+
5
+ /**
6
+ * Sets the requestId generation strategy for a class
7
+ * @param {object} target - The target object to set the strategy on
8
+ * @param {GenerateRequestId} strategy - The strategy to use for generating requestIds
9
+ */
10
+ export const setStrategy = (
11
+ target: object,
12
+ strategy: GenerateRequestId,
13
+ ): void => {
14
+ Reflect.defineMetadata(REQUEST_ID_GEN_STRATEGY_KEY, strategy, target);
15
+ };
16
+
17
+ /**
18
+ * Gets the requestId generation strategy for a class
19
+ * @param {object} target - The target object to get the strategy from
20
+ * @returns {GenerateRequestId | undefined} The requestId generation strategy for the class
21
+ */
22
+ export const getStrategy = (target: object): GenerateRequestId | undefined => {
23
+ return Reflect.getMetadata(REQUEST_ID_GEN_STRATEGY_KEY, target);
24
+ };
@@ -0,0 +1,16 @@
1
+ import { setStrategy } from './metadata.helpers';
2
+ import type { GenerateRequestId } from './types';
3
+
4
+ /**
5
+ * Decorator that sets the requestId generation strategy for
6
+ * all controller methods
7
+ * @param {GenerateRequestId} strategy - The strategy to use for generating requestIds
8
+ * @returns {ClassDecorator} A decorator that sets the requestId generation strategy for a class
9
+ */
10
+ export const RequestIdGenStrategy = (
11
+ strategy: GenerateRequestId,
12
+ ): ClassDecorator => {
13
+ return (target: object) => {
14
+ setStrategy(target, strategy);
15
+ };
16
+ };
@@ -0,0 +1,6 @@
1
+ import type { ExecutionContext } from '@nestjs/common';
2
+
3
+ export type GenerateRequestId = (
4
+ ctx: ExecutionContext,
5
+ protocol: string,
6
+ ) => string;
@@ -0,0 +1,44 @@
1
+ import { randomBytes } from 'node:crypto';
2
+
3
+ import type { GenerateRequestId } from './types';
4
+
5
+ /**
6
+ * Generates a random hex string of the given length
7
+ * @param {number} length - The length of the random hex string to generate
8
+ * @returns {string} A random hex string of the given length
9
+ */
10
+ export const randomHex = (length: number): string =>
11
+ randomBytes(length).toString('hex');
12
+
13
+ /**
14
+ * Default length of the generated requestId
15
+ * random bytes part
16
+ */
17
+ export const DEFAULT_LENGTH = 8;
18
+
19
+ /**
20
+ * Default prefix of the generated requestId
21
+ */
22
+ export const DEFAULT_PREFIX = 'gen';
23
+
24
+ /**
25
+ * Creates a function that generates a requestId with
26
+ * a static prefix and a random bytes part.
27
+ * Ex: {prefix}:{randomHex(length)}
28
+ *
29
+ * @param {string} [prefix=DEFAULT_PREFIX] - The prefix to use for the generated requestId.
30
+ * @param {number} [length=DEFAULT_LENGTH] - The length of the random bytes part of the requestId.
31
+ * @returns {GenerateRequestId} A function that generates a requestId in the format {prefix}:{randomHex(length)}.
32
+ */
33
+ export const withPrefix =
34
+ (
35
+ prefix: string = DEFAULT_PREFIX,
36
+ length: number = DEFAULT_LENGTH,
37
+ ): GenerateRequestId =>
38
+ () =>
39
+ `${prefix}:${randomHex(length)}`;
40
+
41
+ /**
42
+ * Default requestId generator function
43
+ */
44
+ export const generateDefault = withPrefix();
@@ -0,0 +1,23 @@
1
+ import { BoolParser, text } from '@rsdk/common';
2
+
3
+ import { Config, ConfigSection, Property } from '../config';
4
+ import { ConfigTag } from '../config/config.const';
5
+
6
+ @ConfigSection({ tags: [ConfigTag.tracing] })
7
+ export class TracingConfig extends Config {
8
+ @Property('TRACING_REQUEST_ID', new BoolParser(), {
9
+ description: 'Add requestId (X-Request-ID) tracing',
10
+ defaultValue: true,
11
+ })
12
+ traceRequestId!: boolean;
13
+
14
+ @Property('TRACING_REQUEST_ID_AUTOGENERATE', new BoolParser(), {
15
+ description: text`
16
+ Automatically generate requestId (correlationId) if it
17
+ is not set in the headers. It will be created as
18
+ some random bytes (hex) string with "gen:" prefix.
19
+ `,
20
+ defaultValue: false,
21
+ })
22
+ autogenerate!: boolean;
23
+ }
@@ -9,15 +9,12 @@ import type { Observable } from 'rxjs';
9
9
  import { InternalException } from '../exceptions';
10
10
  import { ILogger, InjectLogger } from '../logging';
11
11
  import { ProtocolDetector } from '../transport/protocol.detector';
12
- import type {
13
- ITransport,
14
- PlatformAppPlugin,
15
- WithGenericHeaders,
16
- } from '../types';
17
- import { APP_PLUGINS, APP_TRANSPORTS } from '../types';
12
+ import type { WithGenericHeaders } from '../types';
18
13
 
19
- import { HEADER_MAPPINGS } from './constants';
14
+ import { HEADER_EXTRACTORS, HEADER_MAPPINGS } from './constants';
15
+ import { generateDefault, getStrategy } from './request-id';
20
16
  import { TracingHeaders } from './tracing.actx';
17
+ import { TracingConfig } from './tracing.config';
21
18
  import type { TracingHeaderMappings } from './types';
22
19
 
23
20
  /**
@@ -26,29 +23,15 @@ import type { TracingHeaderMappings } from './types';
26
23
  */
27
24
  @Injectable()
28
25
  export class TracingInterceptor implements NestInterceptor {
29
- /**
30
- * Extractors can be either transports or additional strategies
31
- * supplied by plugins
32
- */
33
- private readonly extractors = new Map<string, WithGenericHeaders>();
34
-
35
26
  constructor(
27
+ /* eslint-disable prettier/prettier */
36
28
  @InjectLogger(TracingInterceptor) private logger: ILogger,
37
- @Inject(APP_TRANSPORTS) private transports: Set<ITransport>,
38
- @Inject(APP_PLUGINS) private plugins: Set<PlatformAppPlugin>,
39
29
  @Inject(HEADER_MAPPINGS) private mappings: TracingHeaderMappings[],
40
- private detector: ProtocolDetector,
41
- ) {
42
- for (const transport of this.transports) {
43
- this.extractors.set(transport.getProtocol(), transport);
44
- }
45
-
46
- for (const plugin of this.plugins) {
47
- for (const x of plugin.tracingHeadersExtractors?.() ?? []) {
48
- this.extractors.set(x.protocol, x.extractor);
49
- }
50
- }
51
- }
30
+ @Inject(HEADER_EXTRACTORS) private readonly extractors: Map<string, WithGenericHeaders>,
31
+ private readonly detector: ProtocolDetector,
32
+ private readonly config: TracingConfig,
33
+ /* eslint-enable prettier/prettier */
34
+ ) {}
52
35
 
53
36
  intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
54
37
  const protocol = this.detector.getProtocol(ctx) ?? ctx.getType();
@@ -60,6 +43,24 @@ export class TracingInterceptor implements NestInterceptor {
60
43
  );
61
44
  }
62
45
 
46
+ const headers = this.extractHeaders(ctx, extractor);
47
+
48
+ const { traceRequestId, autogenerate } = this.config;
49
+ if (!headers.requestId && traceRequestId && autogenerate) {
50
+ headers.requestId = this.generateRequestId(ctx, protocol);
51
+ }
52
+
53
+ this.logger.trace('Extracted traceable headers', { headers });
54
+
55
+ TracingHeaders.set(headers);
56
+
57
+ return next.handle();
58
+ }
59
+
60
+ private extractHeaders(
61
+ ctx: ExecutionContext,
62
+ extractor: WithGenericHeaders,
63
+ ): Record<string, string> {
63
64
  const headers: Record<string, string> = {};
64
65
 
65
66
  for (const aliases of this.mappings) {
@@ -68,13 +69,17 @@ export class TracingInterceptor implements NestInterceptor {
68
69
  .map((x) => extractor.extractHeaders(ctx).get(x))
69
70
  .find((x) => x);
70
71
 
71
- headers[key] = value || '[missing]';
72
+ if (value) {
73
+ headers[key] = value;
74
+ }
72
75
  }
73
76
 
74
- this.logger.trace('Extracted traceable headers', { headers });
77
+ return headers;
78
+ }
75
79
 
76
- TracingHeaders.set(headers);
80
+ private generateRequestId(ctx: ExecutionContext, protocol: string): string {
81
+ const generate = getStrategy(ctx.getClass()) ?? generateDefault;
77
82
 
78
- return next.handle();
83
+ return generate(ctx, protocol);
79
84
  }
80
85
  }