@application-kit/observability 0.8.3 → 0.10.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 (41) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +39 -3
  3. package/dist/cjs/http/first-header-value.d.ts +1 -0
  4. package/dist/cjs/http/first-header-value.js +9 -0
  5. package/dist/cjs/http/index.d.ts +2 -0
  6. package/dist/cjs/http/index.js +2 -0
  7. package/dist/cjs/http/resolve-client-ip.js +3 -6
  8. package/dist/cjs/http/resolve-request-facts.d.ts +7 -0
  9. package/dist/cjs/http/resolve-request-facts.js +14 -0
  10. package/dist/cjs/logging/nest/application-logger.d.ts +5 -0
  11. package/dist/cjs/logging/nest/application-logger.js +59 -0
  12. package/dist/cjs/logging/nest/index.d.ts +1 -0
  13. package/dist/cjs/logging/nest/index.js +17 -0
  14. package/dist/cjs/nest/index.d.ts +3 -0
  15. package/dist/cjs/nest/index.js +19 -0
  16. package/dist/cjs/nest/observability-root-module-options.interface.d.ts +5 -0
  17. package/dist/cjs/nest/observability-root-module-options.interface.js +2 -0
  18. package/dist/cjs/nest/observability-root.module.d.ts +5 -0
  19. package/dist/cjs/nest/observability-root.module.js +37 -0
  20. package/dist/cjs/nest/observability-web.module.d.ts +5 -0
  21. package/dist/cjs/nest/observability-web.module.js +24 -0
  22. package/dist/esm/http/first-header-value.d.ts +1 -0
  23. package/dist/esm/http/first-header-value.js +5 -0
  24. package/dist/esm/http/index.d.ts +2 -0
  25. package/dist/esm/http/index.js +2 -0
  26. package/dist/esm/http/resolve-client-ip.js +2 -5
  27. package/dist/esm/http/resolve-request-facts.d.ts +7 -0
  28. package/dist/esm/http/resolve-request-facts.js +10 -0
  29. package/dist/esm/logging/nest/application-logger.d.ts +5 -0
  30. package/dist/esm/logging/nest/application-logger.js +23 -0
  31. package/dist/esm/logging/nest/index.d.ts +1 -0
  32. package/dist/esm/logging/nest/index.js +1 -0
  33. package/dist/esm/nest/index.d.ts +3 -0
  34. package/dist/esm/nest/index.js +3 -0
  35. package/dist/esm/nest/observability-root-module-options.interface.d.ts +5 -0
  36. package/dist/esm/nest/observability-root-module-options.interface.js +1 -0
  37. package/dist/esm/nest/observability-root.module.d.ts +5 -0
  38. package/dist/esm/nest/observability-root.module.js +34 -0
  39. package/dist/esm/nest/observability-web.module.d.ts +5 -0
  40. package/dist/esm/nest/observability-web.module.js +21 -0
  41. package/package.json +22 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @application-kit/observability
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3a17e1a: Корень наблюдаемости одним вызовом: вход `/nest` — `ObservabilityRootModule.forRoot({ imports, resolveClientIp })` (pino, логгер приложения под `OBSERVABILITY_LOGGER`, ядро health-чека) и `ObservabilityWebModule.forRoot({ publicRoute })` (HTTP-носители `/health` и `/metrics`). Вход `/logging/nest` — класс `ApplicationLogger`.
8
+
9
+ ## 0.9.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 504f068: Вход `/http`: `resolveRequestFacts(request, { trustedHeaders })` отдаёт `{ ip, userAgent }`, не определившийся факт — `null`. `firstHeaderValue(value)` теперь в экспорте: первое значение повторяющегося заголовка без краевых пробелов, `null` у отсутствующего или пустого. `resolveClientIp` работает как раньше.
14
+
3
15
  ## 0.8.3
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -21,13 +21,37 @@ Peer-зависимости: `@nestjs/common`, `@prometheus-io/client`; оста
21
21
  | `@application-kit/observability/health` | состав чека, пробы `/health/live` и `/health/ready`, `GET /health` | `@nestjs/terminus`, `@nestjs/typeorm`, `typeorm`, `@application-kit/typeorm`, `class-validator`, `class-transformer` |
22
22
  | `@application-kit/observability/health/graphql` | `query { health { status } }` | `/health` + `@nestjs/graphql` |
23
23
  | `@application-kit/observability/health/cli` | CLI-команда `<группа> health` | `/health` + `nestjs-console` |
24
- | `@application-kit/observability/http` | `resolveClientIp` — IP клиента за прокси | ничего |
24
+ | `@application-kit/observability/http` | `resolveClientIp`, `resolveRequestFacts`, `firstHeaderValue` — IP клиента за прокси и факты запроса | ничего |
25
25
  | `@application-kit/observability/logging` | опции nestjs-pino, request-id, support-id, служебные пути, токен логгера | `@opentelemetry/api`, `class-validator`, `class-transformer`; типы — `nestjs-pino`, `pino` |
26
+ | `@application-kit/observability/logging/nest` | `ApplicationLogger` — `PinoLogger` с контекстом приложения | `@nestjs/common`, `nestjs-pino` |
26
27
  | `@application-kit/observability/metrics` | реестр, гистограммы HTTP и GraphQL, `GET /metrics`, хуки Fastify, сервер `/metrics` | `@nestjs/common`, `@prometheus-io/client`; типы — `fastify`, `@nestjs/platform-fastify` |
28
+ | `@application-kit/observability/nest` | `ObservabilityRootModule`, `ObservabilityWebModule` — сборка логирования, health и метрик | `nestjs-pino`, `pino` + зависимости `/health`, `/logging`, `/metrics` |
27
29
  | `@application-kit/observability/tracing` | `startTracing` — OpenTelemetry NodeSDK для `node --import`, только ESM | `@opentelemetry/sdk-node`, `@opentelemetry/instrumentation`, `@opentelemetry/instrumentation-http`, `@opentelemetry/exporter-trace-otlp-grpc`, `@opentelemetry/semantic-conventions` |
28
30
 
29
31
  Корневого входа нет: каждый вход несёт свои peer-зависимости, и лишнего потребитель не ставит.
30
32
 
33
+ ## Сборка процесса (`/nest`)
34
+
35
+ `ObservabilityRootModule.forRoot` — глобальный корень на процесс: `LoggerModule` nestjs-pino, `ApplicationLogger` под
36
+ `OBSERVABILITY_LOGGER`, ядро health-чека с логгером pino в terminus. `ObservabilityWebModule.forRoot` — только в
37
+ web-графе: HTTP-носители `/health` и `/metrics`. `HealthGraphqlModule` подключается отдельно: его вход требует `@nestjs/graphql`.
38
+
39
+ ```ts
40
+ @Module({
41
+ imports: [
42
+ ObservabilityRootModule.forRoot({
43
+ imports: [healthConfigsModule, loggerConfigsModule],
44
+ resolveClientIp: resolveRequestClientIp,
45
+ }),
46
+ ObservabilityWebModule.forRoot({ publicRoute: Public() }),
47
+ HealthGraphqlModule.forRoot({ publicRoute: Public() }),
48
+ ],
49
+ })
50
+ export class WebModule {}
51
+ ```
52
+
53
+ `resolveClientIp` необязателен: дефолт и доверенные заголовки — раздел «IP клиента за прокси».
54
+
31
55
  ## Метрики
32
56
 
33
57
  - `MetricsRegistry` — провайдер с собственным `Registry` (не глобальным: экземпляры независимы) и метриками процесса
@@ -109,7 +133,7 @@ export class AppModule {}
109
133
 
110
134
  ## Health-чек (`/health`)
111
135
 
112
- `HealthModule.forRoot({ imports, logger })` — глобальное ядро процесса: terminus и `HealthChecks` (ping БД, heap, RSS,
136
+ `HealthModule.forRoot({ imports, terminus })` — глобальное ядро процесса: terminus и `HealthChecks` (ping БД, heap, RSS,
113
137
  диск по корню; пороги — `HealthConfig`/`HealthEnvironment`). Носители подключаются там, где нужны, и берут состав
114
138
  отсюда — вердикт не зависит от того, каким путём спросили:
115
139
 
@@ -125,7 +149,7 @@ export class AppModule {}
125
149
  ```ts
126
150
  @Module({
127
151
  imports: [
128
- HealthModule.forRoot({ imports: [healthConfigsModule], logger: Logger }),
152
+ HealthModule.forRoot({ imports: [healthConfigsModule], terminus: { logger: Logger } }),
129
153
  HealthHttpModule.forRoot({ publicRoute: Public() }),
130
154
  HealthGraphqlModule.forRoot({ publicRoute: Public() }),
131
155
  ],
@@ -146,6 +170,18 @@ export class WebModule {}
146
170
  const clientIp = resolveClientIp(request, { trustedHeaders: ['cf-connecting-ip'] })
147
171
  ```
148
172
 
173
+ ## Факты запроса
174
+
175
+ `resolveRequestFacts(request, { trustedHeaders })` — `{ ip, userAgent }` для строки сессии или журнала: адрес берётся из
176
+ `resolveClientIp` с теми же опциями, не определившийся факт — `null`. `firstHeaderValue(value)` — значение заголовка одной
177
+ строкой: первое у повторяющегося, без краевых пробелов, `null` у отсутствующего или пустого.
178
+
179
+ Где лежит текущий запрос и что ещё считать фактами (актор, роль), функция не знает: это решает приложение.
180
+
181
+ ```ts
182
+ const facts = resolveRequestFacts(request, { trustedHeaders: ['cf-connecting-ip'] })
183
+ ```
184
+
149
185
  ## Трейсинг (`/tracing`)
150
186
 
151
187
  `startTracing({ esmHookedModules, instrumentations, resolveClientIp })` поднимает OpenTelemetry NodeSDK: OTLP gRPC-экспортёр,
@@ -0,0 +1 @@
1
+ export declare const firstHeaderValue: (value: string | string[] | undefined) => null | string;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.firstHeaderValue = void 0;
4
+ const firstHeaderValue = (value) => {
5
+ const single = Array.isArray(value) ? value[0] : value;
6
+ const trimmed = (single ?? '').trim();
7
+ return trimmed === '' ? null : trimmed;
8
+ };
9
+ exports.firstHeaderValue = firstHeaderValue;
@@ -1,2 +1,4 @@
1
1
  export * from './client-ip-options.interface.js';
2
+ export * from './first-header-value.js';
2
3
  export * from './resolve-client-ip.js';
4
+ export * from './resolve-request-facts.js';
@@ -15,4 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./client-ip-options.interface.js"), exports);
18
+ __exportStar(require("./first-header-value.js"), exports);
18
19
  __exportStar(require("./resolve-client-ip.js"), exports);
20
+ __exportStar(require("./resolve-request-facts.js"), exports);
@@ -1,13 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveClientIp = void 0;
4
- const firstHeaderValue = (value) => {
5
- const single = Array.isArray(value) ? value[0] : value;
6
- return (single ?? '').trim();
7
- };
4
+ const first_header_value_js_1 = require("./first-header-value.js");
8
5
  const trustedHeaderIp = (request, trustedHeaders) => {
9
- const values = trustedHeaders?.map((header) => firstHeaderValue(request.headers?.[header]));
10
- return values?.find((value) => value !== '') ?? '';
6
+ const values = trustedHeaders?.map((header) => (0, first_header_value_js_1.firstHeaderValue)(request.headers?.[header]));
7
+ return values?.find((value) => value !== null) ?? '';
11
8
  };
12
9
  const rawSocketIp = (request) => request.raw?.socket?.remoteAddress ?? '';
13
10
  const socketIp = (request) => request.socket?.remoteAddress ?? rawSocketIp(request);
@@ -0,0 +1,7 @@
1
+ import type { ClientIpOptionsInterface } from './client-ip-options.interface.js';
2
+ import type { ClientIpSourceInterface } from './resolve-client-ip.js';
3
+ export interface RequestFactsInterface {
4
+ ip: null | string;
5
+ userAgent: null | string;
6
+ }
7
+ export declare const resolveRequestFacts: (request: ClientIpSourceInterface, options?: ClientIpOptionsInterface) => RequestFactsInterface;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRequestFacts = void 0;
4
+ const first_header_value_js_1 = require("./first-header-value.js");
5
+ const resolve_client_ip_js_1 = require("./resolve-client-ip.js");
6
+ const USER_AGENT_HEADER = 'user-agent';
7
+ const resolveRequestFacts = (request, options = {}) => {
8
+ const ip = (0, resolve_client_ip_js_1.resolveClientIp)(request, options);
9
+ return {
10
+ ip: ip === '' ? null : ip,
11
+ userAgent: (0, first_header_value_js_1.firstHeaderValue)(request.headers?.[USER_AGENT_HEADER]),
12
+ };
13
+ };
14
+ exports.resolveRequestFacts = resolveRequestFacts;
@@ -0,0 +1,5 @@
1
+ import * as nestjsPino from 'nestjs-pino';
2
+ import type { ObservabilityLoggerInterface } from '../observability-logger.interface.js';
3
+ export declare class ApplicationLogger extends nestjsPino.PinoLogger implements ObservabilityLoggerInterface {
4
+ constructor(options: nestjsPino.Params);
5
+ }
@@ -0,0 +1,59 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var ApplicationLogger_1;
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.ApplicationLogger = void 0;
47
+ const common_1 = require("@nestjs/common");
48
+ const nestjsPino = __importStar(require("nestjs-pino"));
49
+ let ApplicationLogger = ApplicationLogger_1 = class ApplicationLogger extends nestjsPino.PinoLogger {
50
+ constructor(options) {
51
+ super(options);
52
+ this.setContext(ApplicationLogger_1.name);
53
+ }
54
+ };
55
+ exports.ApplicationLogger = ApplicationLogger;
56
+ exports.ApplicationLogger = ApplicationLogger = ApplicationLogger_1 = __decorate([
57
+ (0, common_1.Injectable)(),
58
+ __metadata("design:paramtypes", [Object])
59
+ ], ApplicationLogger);
@@ -0,0 +1 @@
1
+ export * from './application-logger.js';
@@ -0,0 +1,17 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./application-logger.js"), exports);
@@ -0,0 +1,3 @@
1
+ export * from './observability-root-module-options.interface.js';
2
+ export * from './observability-root.module.js';
3
+ export * from './observability-web.module.js';
@@ -0,0 +1,19 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./observability-root-module-options.interface.js"), exports);
18
+ __exportStar(require("./observability-root.module.js"), exports);
19
+ __exportStar(require("./observability-web.module.js"), exports);
@@ -0,0 +1,5 @@
1
+ import type { ModuleMetadata } from '@nestjs/common';
2
+ import type { PinoLoggerOptionsInterface } from '../logging/pino-logger-options.interface.js';
3
+ export interface ObservabilityRootModuleOptionsInterface extends PinoLoggerOptionsInterface {
4
+ readonly imports: NonNullable<ModuleMetadata['imports']>;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { ObservabilityRootModuleOptionsInterface } from './observability-root-module-options.interface.js';
3
+ export declare class ObservabilityRootModule {
4
+ static forRoot({ imports, ...loggerOptions }: ObservabilityRootModuleOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ObservabilityRootModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const nestjs_pino_1 = require("nestjs-pino");
12
+ const health_module_js_1 = require("../health/health.module.js");
13
+ const constants_js_1 = require("../logging/constants.js");
14
+ const application_logger_js_1 = require("../logging/nest/application-logger.js");
15
+ const pino_logger_config_js_1 = require("../logging/pino-logger.config.js");
16
+ let ObservabilityRootModule = class ObservabilityRootModule {
17
+ static forRoot({ imports, ...loggerOptions }) {
18
+ return {
19
+ exports: [application_logger_js_1.ApplicationLogger, constants_js_1.OBSERVABILITY_LOGGER],
20
+ global: true,
21
+ imports: [
22
+ nestjs_pino_1.LoggerModule.forRootAsync({
23
+ imports,
24
+ inject: [pino_logger_config_js_1.PinoLoggerConfig],
25
+ useFactory: (config) => config.createOptions(loggerOptions),
26
+ }),
27
+ health_module_js_1.HealthModule.forRoot({ imports, terminus: { logger: nestjs_pino_1.Logger } }),
28
+ ],
29
+ module: this,
30
+ providers: [application_logger_js_1.ApplicationLogger, { provide: constants_js_1.OBSERVABILITY_LOGGER, useExisting: application_logger_js_1.ApplicationLogger }],
31
+ };
32
+ }
33
+ };
34
+ exports.ObservabilityRootModule = ObservabilityRootModule;
35
+ exports.ObservabilityRootModule = ObservabilityRootModule = __decorate([
36
+ (0, common_1.Module)({})
37
+ ], ObservabilityRootModule);
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { HealthCarrierOptionsInterface } from '../health/health-module-options.interface.js';
3
+ export declare class ObservabilityWebModule {
4
+ static forRoot(options?: HealthCarrierOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ObservabilityWebModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const health_http_module_js_1 = require("../health/health-http.module.js");
12
+ const metrics_http_module_js_1 = require("../metrics/metrics-http.module.js");
13
+ let ObservabilityWebModule = class ObservabilityWebModule {
14
+ static forRoot(options = {}) {
15
+ return {
16
+ imports: [health_http_module_js_1.HealthHttpModule.forRoot(options), metrics_http_module_js_1.MetricsHttpModule.forRoot(options)],
17
+ module: this,
18
+ };
19
+ }
20
+ };
21
+ exports.ObservabilityWebModule = ObservabilityWebModule;
22
+ exports.ObservabilityWebModule = ObservabilityWebModule = __decorate([
23
+ (0, common_1.Module)({})
24
+ ], ObservabilityWebModule);
@@ -0,0 +1 @@
1
+ export declare const firstHeaderValue: (value: string | string[] | undefined) => null | string;
@@ -0,0 +1,5 @@
1
+ export const firstHeaderValue = (value) => {
2
+ const single = Array.isArray(value) ? value[0] : value;
3
+ const trimmed = (single ?? '').trim();
4
+ return trimmed === '' ? null : trimmed;
5
+ };
@@ -1,2 +1,4 @@
1
1
  export * from './client-ip-options.interface.js';
2
+ export * from './first-header-value.js';
2
3
  export * from './resolve-client-ip.js';
4
+ export * from './resolve-request-facts.js';
@@ -1,2 +1,4 @@
1
1
  export * from './client-ip-options.interface.js';
2
+ export * from './first-header-value.js';
2
3
  export * from './resolve-client-ip.js';
4
+ export * from './resolve-request-facts.js';
@@ -1,10 +1,7 @@
1
- const firstHeaderValue = (value) => {
2
- const single = Array.isArray(value) ? value[0] : value;
3
- return (single ?? '').trim();
4
- };
1
+ import { firstHeaderValue } from './first-header-value.js';
5
2
  const trustedHeaderIp = (request, trustedHeaders) => {
6
3
  const values = trustedHeaders?.map((header) => firstHeaderValue(request.headers?.[header]));
7
- return values?.find((value) => value !== '') ?? '';
4
+ return values?.find((value) => value !== null) ?? '';
8
5
  };
9
6
  const rawSocketIp = (request) => request.raw?.socket?.remoteAddress ?? '';
10
7
  const socketIp = (request) => request.socket?.remoteAddress ?? rawSocketIp(request);
@@ -0,0 +1,7 @@
1
+ import type { ClientIpOptionsInterface } from './client-ip-options.interface.js';
2
+ import type { ClientIpSourceInterface } from './resolve-client-ip.js';
3
+ export interface RequestFactsInterface {
4
+ ip: null | string;
5
+ userAgent: null | string;
6
+ }
7
+ export declare const resolveRequestFacts: (request: ClientIpSourceInterface, options?: ClientIpOptionsInterface) => RequestFactsInterface;
@@ -0,0 +1,10 @@
1
+ import { firstHeaderValue } from './first-header-value.js';
2
+ import { resolveClientIp } from './resolve-client-ip.js';
3
+ const USER_AGENT_HEADER = 'user-agent';
4
+ export const resolveRequestFacts = (request, options = {}) => {
5
+ const ip = resolveClientIp(request, options);
6
+ return {
7
+ ip: ip === '' ? null : ip,
8
+ userAgent: firstHeaderValue(request.headers?.[USER_AGENT_HEADER]),
9
+ };
10
+ };
@@ -0,0 +1,5 @@
1
+ import * as nestjsPino from 'nestjs-pino';
2
+ import type { ObservabilityLoggerInterface } from '../observability-logger.interface.js';
3
+ export declare class ApplicationLogger extends nestjsPino.PinoLogger implements ObservabilityLoggerInterface {
4
+ constructor(options: nestjsPino.Params);
5
+ }
@@ -0,0 +1,23 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var ApplicationLogger_1;
11
+ import { Injectable } from '@nestjs/common';
12
+ import * as nestjsPino from 'nestjs-pino';
13
+ let ApplicationLogger = ApplicationLogger_1 = class ApplicationLogger extends nestjsPino.PinoLogger {
14
+ constructor(options) {
15
+ super(options);
16
+ this.setContext(ApplicationLogger_1.name);
17
+ }
18
+ };
19
+ ApplicationLogger = ApplicationLogger_1 = __decorate([
20
+ Injectable(),
21
+ __metadata("design:paramtypes", [Object])
22
+ ], ApplicationLogger);
23
+ export { ApplicationLogger };
@@ -0,0 +1 @@
1
+ export * from './application-logger.js';
@@ -0,0 +1 @@
1
+ export * from './application-logger.js';
@@ -0,0 +1,3 @@
1
+ export * from './observability-root-module-options.interface.js';
2
+ export * from './observability-root.module.js';
3
+ export * from './observability-web.module.js';
@@ -0,0 +1,3 @@
1
+ export * from './observability-root-module-options.interface.js';
2
+ export * from './observability-root.module.js';
3
+ export * from './observability-web.module.js';
@@ -0,0 +1,5 @@
1
+ import type { ModuleMetadata } from '@nestjs/common';
2
+ import type { PinoLoggerOptionsInterface } from '../logging/pino-logger-options.interface.js';
3
+ export interface ObservabilityRootModuleOptionsInterface extends PinoLoggerOptionsInterface {
4
+ readonly imports: NonNullable<ModuleMetadata['imports']>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { ObservabilityRootModuleOptionsInterface } from './observability-root-module-options.interface.js';
3
+ export declare class ObservabilityRootModule {
4
+ static forRoot({ imports, ...loggerOptions }: ObservabilityRootModuleOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,34 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Module } from '@nestjs/common';
8
+ import { Logger, LoggerModule } from 'nestjs-pino';
9
+ import { HealthModule } from '../health/health.module.js';
10
+ import { OBSERVABILITY_LOGGER } from '../logging/constants.js';
11
+ import { ApplicationLogger } from '../logging/nest/application-logger.js';
12
+ import { PinoLoggerConfig } from '../logging/pino-logger.config.js';
13
+ let ObservabilityRootModule = class ObservabilityRootModule {
14
+ static forRoot({ imports, ...loggerOptions }) {
15
+ return {
16
+ exports: [ApplicationLogger, OBSERVABILITY_LOGGER],
17
+ global: true,
18
+ imports: [
19
+ LoggerModule.forRootAsync({
20
+ imports,
21
+ inject: [PinoLoggerConfig],
22
+ useFactory: (config) => config.createOptions(loggerOptions),
23
+ }),
24
+ HealthModule.forRoot({ imports, terminus: { logger: Logger } }),
25
+ ],
26
+ module: this,
27
+ providers: [ApplicationLogger, { provide: OBSERVABILITY_LOGGER, useExisting: ApplicationLogger }],
28
+ };
29
+ }
30
+ };
31
+ ObservabilityRootModule = __decorate([
32
+ Module({})
33
+ ], ObservabilityRootModule);
34
+ export { ObservabilityRootModule };
@@ -0,0 +1,5 @@
1
+ import type { DynamicModule } from '@nestjs/common';
2
+ import type { HealthCarrierOptionsInterface } from '../health/health-module-options.interface.js';
3
+ export declare class ObservabilityWebModule {
4
+ static forRoot(options?: HealthCarrierOptionsInterface): DynamicModule;
5
+ }
@@ -0,0 +1,21 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Module } from '@nestjs/common';
8
+ import { HealthHttpModule } from '../health/health-http.module.js';
9
+ import { MetricsHttpModule } from '../metrics/metrics-http.module.js';
10
+ let ObservabilityWebModule = class ObservabilityWebModule {
11
+ static forRoot(options = {}) {
12
+ return {
13
+ imports: [HealthHttpModule.forRoot(options), MetricsHttpModule.forRoot(options)],
14
+ module: this,
15
+ };
16
+ }
17
+ };
18
+ ObservabilityWebModule = __decorate([
19
+ Module({})
20
+ ], ObservabilityWebModule);
21
+ export { ObservabilityWebModule };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@application-kit/observability",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "description": "Наблюдаемость NestJS-процесса: метрики Prometheus и RED-гистограммы, health-чеки и пробы, опции pino с request-id и trace-контекстом, логирование CQRS-шин, реальный IP клиента за прокси, трейсинг OpenTelemetry",
5
5
  "keywords": [
6
6
  "cqrs",
@@ -89,6 +89,16 @@
89
89
  "default": "./dist/cjs/logging/index.js"
90
90
  }
91
91
  },
92
+ "./logging/nest": {
93
+ "import": {
94
+ "types": "./dist/esm/logging/nest/index.d.ts",
95
+ "default": "./dist/esm/logging/nest/index.js"
96
+ },
97
+ "require": {
98
+ "types": "./dist/cjs/logging/nest/index.d.ts",
99
+ "default": "./dist/cjs/logging/nest/index.js"
100
+ }
101
+ },
92
102
  "./metric-names.json": "./metric-names.json",
93
103
  "./metrics": {
94
104
  "import": {
@@ -100,6 +110,16 @@
100
110
  "default": "./dist/cjs/metrics/index.js"
101
111
  }
102
112
  },
113
+ "./nest": {
114
+ "import": {
115
+ "types": "./dist/esm/nest/index.d.ts",
116
+ "default": "./dist/esm/nest/index.js"
117
+ },
118
+ "require": {
119
+ "types": "./dist/cjs/nest/index.d.ts",
120
+ "default": "./dist/cjs/nest/index.js"
121
+ }
122
+ },
103
123
  "./package.json": "./package.json",
104
124
  "./tracing": {
105
125
  "import": {
@@ -116,7 +136,7 @@
116
136
  "metric-names.json"
117
137
  ],
118
138
  "scripts": {
119
- "build": "rm -rf ./dist && node ../../scripts/barrels.mjs create ./src/cqrs && node ../../scripts/barrels.mjs create ./src/health --entry-only=cli,graphql && node ../../scripts/barrels.mjs create ./src/http && node ../../scripts/barrels.mjs create ./src/logging && node ../../scripts/barrels.mjs create ./src/metrics && node ../../scripts/barrels.mjs create ./src/tracing && tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json && node ../../scripts/barrels.mjs clean ./src && node ../../scripts/mark-cjs.mjs ./dist/cjs",
139
+ "build": "rm -rf ./dist && node ../../scripts/barrels.mjs create ./src/cqrs && node ../../scripts/barrels.mjs create ./src/health --entry-only=cli,graphql && node ../../scripts/barrels.mjs create ./src/http && node ../../scripts/barrels.mjs create ./src/logging --entry-only=nest && node ../../scripts/barrels.mjs create ./src/metrics && node ../../scripts/barrels.mjs create ./src/nest && node ../../scripts/barrels.mjs create ./src/tracing && tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json && node ../../scripts/barrels.mjs clean ./src && node ../../scripts/mark-cjs.mjs ./dist/cjs",
120
140
  "lint:tsc": "tsc --noEmit --pretty --project .",
121
141
  "test:mutation": "stryker run",
122
142
  "test:unit": "vitest run"