@generazioneai/telemetry 0.0.0-stage → 0.1.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 (55) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +44 -2
  3. package/dist/attributes.d.ts +13 -0
  4. package/dist/attributes.d.ts.map +1 -0
  5. package/dist/attributes.js +115 -0
  6. package/dist/attributes.js.map +1 -0
  7. package/dist/config.d.ts +20 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +39 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/index.d.ts +16 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +43 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/log-context.d.ts +8 -0
  16. package/dist/log-context.d.ts.map +1 -0
  17. package/dist/log-context.js +13 -0
  18. package/dist/log-context.js.map +1 -0
  19. package/dist/logger/index.d.ts +10 -0
  20. package/dist/logger/index.d.ts.map +1 -0
  21. package/dist/logger/index.js +23 -0
  22. package/dist/logger/index.js.map +1 -0
  23. package/dist/logger/json-logger.d.ts +39 -0
  24. package/dist/logger/json-logger.d.ts.map +1 -0
  25. package/dist/logger/json-logger.js +127 -0
  26. package/dist/logger/json-logger.js.map +1 -0
  27. package/dist/nats.interceptor.d.ts +18 -0
  28. package/dist/nats.interceptor.d.ts.map +1 -0
  29. package/dist/nats.interceptor.js +124 -0
  30. package/dist/nats.interceptor.js.map +1 -0
  31. package/dist/propagation.d.ts +18 -0
  32. package/dist/propagation.d.ts.map +1 -0
  33. package/dist/propagation.js +37 -0
  34. package/dist/propagation.js.map +1 -0
  35. package/dist/redaction.d.ts +13 -0
  36. package/dist/redaction.d.ts.map +1 -0
  37. package/dist/redaction.js +133 -0
  38. package/dist/redaction.js.map +1 -0
  39. package/dist/register.d.ts +2 -0
  40. package/dist/register.d.ts.map +1 -0
  41. package/dist/register.js +10 -0
  42. package/dist/register.js.map +1 -0
  43. package/dist/sanitizing-exporter.d.ts +13 -0
  44. package/dist/sanitizing-exporter.d.ts.map +1 -0
  45. package/dist/sanitizing-exporter.js +45 -0
  46. package/dist/sanitizing-exporter.js.map +1 -0
  47. package/dist/sdk.d.ts +18 -0
  48. package/dist/sdk.d.ts.map +1 -0
  49. package/dist/sdk.js +94 -0
  50. package/dist/sdk.js.map +1 -0
  51. package/dist/telemetry.module.d.ts +26 -0
  52. package/dist/telemetry.module.d.ts.map +1 -0
  53. package/dist/telemetry.module.js +78 -0
  54. package/dist/telemetry.module.js.map +1 -0
  55. package/package.json +94 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog — @generazioneai/telemetry
2
+
3
+ ## 0.1.0 — 2026-10-25
4
+ Prima versione (treno 3+4, O1; ADR-013, spec «Fondamenta enterprise» §5.2, decisioni 31, 32, 35).
5
+ - `@generazioneai/telemetry/register`: SDK OpenTelemetry Node (tracce e metriche OTLP/HTTP; HTTP, pg, ioredis, Prisma), spento di serie (`TELEMETRY_MODE=off`).
6
+ - `TelemetryModule.forRoot({ service })`: interceptor `nats.server <cmd>`, hook `traceparent` per `setNatsHeadersHook` di authz ≥ 0.7 (opzionale), spegnimento.
7
+ - `@generazioneai/telemetry/logger`: `JsonLogger` (`level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId`), `createLogger` (`LOG_FORMAT`).
8
+ - Attributi a lista bianca, esportatore che ripulisce gli span, redazione di corpi, `Authorization`, cookie, email, nomi, codici fiscali, IBAN, JWT.
package/README.md CHANGED
@@ -1,3 +1,45 @@
1
- # Temporary Holding Version
1
+ # @generazioneai/telemetry
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Osservabilità comune dei servizi Node (ADR-013, spec «Fondamenta enterprise» §5): tracce e metriche OpenTelemetry verso il collector, log JSON con `trace_id`, span dei comandi NATS, nessun dato personale.
4
+
5
+ ```bash
6
+ npm i @generazioneai/telemetry
7
+ ```
8
+
9
+ ## Uso
10
+ ```ts
11
+ // main.ts — PRIMA riga
12
+ import '@generazioneai/telemetry/register';
13
+ import { createLogger } from '@generazioneai/telemetry/logger';
14
+
15
+ const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
16
+
17
+ // app.module.ts
18
+ TelemetryModule.forRoot({ service: 'hr' })
19
+ ```
20
+
21
+ | Variabile | Valori | Di serie |
22
+ |---|---|---|
23
+ | `TELEMETRY_MODE` | `off` \| `on` | `off`: il processo non carica l'SDK, nessuna connessione |
24
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | base OTLP/HTTP | `http://otel-collector.observability:4318`; **vuota = spento** |
25
+ | `OTEL_SERVICE_NAME` | nome | `name` del `package.json` (senza scope) |
26
+ | `SKILLERA_ENV` | | → `deployment.environment` |
27
+ | `LOG_FORMAT` | `text` \| `json` | `text` |
28
+ | `APP_LOGGER_LEVEL` | `log,error,warn,debug,verbose` \| `none` | `log,error,warn` (`fatal` segue `error`) |
29
+ | `TELEMETRY_SAMPLE_RATIO` | 0..1 | `1` (il campionamento in coda è del collector) |
30
+ | `OTEL_METRIC_EXPORT_INTERVAL` | ms | `60000` |
31
+
32
+ Impostare `OTEL_SERVICE_NAME` nei manifest: `register` parte prima di Nest e non conosce l'opzione `service` del modulo.
33
+
34
+ ## Cosa fa
35
+ - **`/register`**: Node SDK con OTLP/HTTP per tracce e metriche; strumentazioni HTTP (senza `health`/`metrics`), `pg`, `ioredis`, Prisma (le ultime tre opzionali). Nessun gestore di SIGTERM: lo spegnimento ordinato lo fa `TelemetryModule` (o `beforeExit`).
36
+ - **NATS**: l'interceptor globale (solo contesto `rpc`) apre `nats.server <cmd>` (kind consumer) come figlio del `traceparent` negli header, mette `cmd` e `juridicalId` nel contesto dei log, conta `nats_server_requests_total{cmd,outcome}` e `nats_server_request_duration_seconds{cmd}`. `juridicalId` viene dall'header `Gen-Tenant` o da `auth.juridicalId`/`auth.tenantId`/`dto.juridicalId`, solo se è un UUID.
37
+ - **Invio**: `traceparentHeadersHook` scrive `traceparent` negli header. `TelemetryModule.forRoot` lo registra con `setNatsHeadersHook` di `@generazioneai/authz` ≥ 0.7 se c'è (altrimenti nulla); si può passare il modulo con `authz: …` o spegnere con `authz: false`. Per gli eventi di JetStream ci pensa `@generazioneai/events` con `injectTraceContext`/`extractTraceContext`.
38
+ - **Log** (`JsonLogger`): `level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId` (+ `context`, `err`, campi del messaggio-oggetto, mai in conflitto con quelli del contratto).
39
+ - **Dati personali** (decisione 35): gli span escono da `SanitizingSpanExporter`, che tiene solo gli attributi della **lista bianca** (`ALLOWED_ATTRIBUTES`: metodo, rotta come modello, comando, esito, durata, dimensioni, id di azienda UUID, `db.statement` senza letterali, redis solo il comando), stato senza messaggio, IP solo come hash (`client.ip_hash`). `redact()`/`maskString()` (usate dal logger) azzerano i valori di chiavi come `authorization`, `cookie`, `body`, `dto`, `email`, `*name`, `fiscalCode`, `iban`, `password`, `*token` e mascherano nel testo email, codici fiscali (anche omocodici), IBAN, JWT, `Bearer …`.
40
+
41
+ ## Compatibilità delle versioni OpenTelemetry
42
+ Le strumentazioni sono fissate alla famiglia `0.219` con `@opentelemetry/api` 1.9 (la `0.300` richiede api ≥ 1.10, che gli SDK 2.x non accettano ancora). Il servizio **non** deve avere un proprio `@opentelemetry/api` diverso.
43
+
44
+ ## Prove
45
+ `npm test`. La prova dell'SDK acceso gira in un processo Node figlio (le strumentazioni usano `import()` dinamici, che Jest non esegue) e costruisce il pacchetto in `.test-dist/`.
@@ -0,0 +1,13 @@
1
+ import type { Attributes } from '@opentelemetry/api';
2
+ /**
3
+ * Lista bianca degli attributi di un span (decisione 35): metodo, rotta come modello, comando, esito, durata, dimensione,
4
+ * id di azienda. Tutto il resto cade, anche se un'instrumentation lo scrive (`http.url`, `url.query`, intestazioni,
5
+ * `exception.message`, `db.query.parameter.*`…).
6
+ */
7
+ export declare const ALLOWED_ATTRIBUTES: ReadonlySet<string>;
8
+ export declare function hashIp(ip: string, salt?: string): string;
9
+ /** Toglie dal testo SQL stringhe e numeri letterali: restano struttura e segnaposto `$1`. */
10
+ export declare function sanitizeStatement(sql: string): string;
11
+ /** Copia degli attributi con solo quelli ammessi e ripuliti. */
12
+ export declare function sanitizeAttributes(attrs: Attributes | undefined): Attributes;
13
+ //# sourceMappingURL=attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAGrE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAgDjD,CAAC;AAMH,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,SAAsC,GAAG,MAAM,CAErF;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD;AAOD,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CA2B5E"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALLOWED_ATTRIBUTES = void 0;
4
+ exports.hashIp = hashIp;
5
+ exports.sanitizeStatement = sanitizeStatement;
6
+ exports.sanitizeAttributes = sanitizeAttributes;
7
+ const crypto_1 = require("crypto");
8
+ const redaction_1 = require("./redaction");
9
+ /**
10
+ * Lista bianca degli attributi di un span (decisione 35): metodo, rotta come modello, comando, esito, durata, dimensione,
11
+ * id di azienda. Tutto il resto cade, anche se un'instrumentation lo scrive (`http.url`, `url.query`, intestazioni,
12
+ * `exception.message`, `db.query.parameter.*`…).
13
+ */
14
+ exports.ALLOWED_ATTRIBUTES = new Set([
15
+ 'http.request.method',
16
+ 'http.method',
17
+ 'http.route',
18
+ 'http.response.status_code',
19
+ 'http.status_code',
20
+ 'http.request.body.size',
21
+ 'http.response.body.size',
22
+ 'http.request_content_length',
23
+ 'http.response_content_length',
24
+ 'network.protocol.name',
25
+ 'network.protocol.version',
26
+ 'network.transport',
27
+ 'url.scheme',
28
+ 'server.address',
29
+ 'server.port',
30
+ 'net.peer.name',
31
+ 'net.peer.port',
32
+ 'messaging.system',
33
+ 'messaging.operation',
34
+ 'messaging.operation.name',
35
+ 'messaging.operation.type',
36
+ 'messaging.destination.name',
37
+ 'messaging.message.body.size',
38
+ 'rpc.system',
39
+ 'rpc.method',
40
+ 'cmd',
41
+ 'outcome',
42
+ 'error.type',
43
+ 'exception.type',
44
+ 'db.system',
45
+ 'db.system.name',
46
+ 'db.operation',
47
+ 'db.operation.name',
48
+ 'db.namespace',
49
+ 'db.name',
50
+ 'db.sql.table',
51
+ 'db.collection.name',
52
+ 'db.statement',
53
+ 'db.query.text',
54
+ 'db.redis.database_index',
55
+ 'duration_ms',
56
+ 'size_bytes',
57
+ 'juridicalId',
58
+ 'gen.juridical_id',
59
+ 'job',
60
+ 'consumer',
61
+ 'event.subject',
62
+ ]);
63
+ const IP_KEYS = new Set(['client.address', 'net.sock.peer.addr', 'net.peer.ip', 'http.client_ip', 'net.sock.host.addr']);
64
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
65
+ const ID_KEYS = new Set(['juridicalId', 'gen.juridical_id']);
66
+ function hashIp(ip, salt = process.env.TELEMETRY_IP_SALT ?? '') {
67
+ return (0, crypto_1.createHash)('sha256').update(`${salt}${ip}`).digest('hex').slice(0, 16);
68
+ }
69
+ /** Toglie dal testo SQL stringhe e numeri letterali: restano struttura e segnaposto `$1`. */
70
+ function sanitizeStatement(sql) {
71
+ return sql
72
+ .replace(/'(?:[^']|'')*'/g, '?')
73
+ .replace(/(?<![\w$])\d+(?:\.\d+)?(?![\w$])/g, '?')
74
+ .slice(0, 1000);
75
+ }
76
+ function scalar(value) {
77
+ if (value === undefined || value === null || Array.isArray(value))
78
+ return undefined;
79
+ return value;
80
+ }
81
+ /** Copia degli attributi con solo quelli ammessi e ripuliti. */
82
+ function sanitizeAttributes(attrs) {
83
+ const out = {};
84
+ if (!attrs)
85
+ return out;
86
+ for (const [key, raw] of Object.entries(attrs)) {
87
+ const value = scalar(raw);
88
+ if (value === undefined)
89
+ continue;
90
+ if (IP_KEYS.has(key)) {
91
+ if (typeof value === 'string')
92
+ out['client.ip_hash'] = hashIp(value);
93
+ continue;
94
+ }
95
+ if (!exports.ALLOWED_ATTRIBUTES.has(key))
96
+ continue;
97
+ if (ID_KEYS.has(key)) {
98
+ if (typeof value === 'string' && UUID.test(value))
99
+ out[key] = value;
100
+ continue;
101
+ }
102
+ if (typeof value !== 'string') {
103
+ out[key] = value;
104
+ continue;
105
+ }
106
+ if (key === 'db.statement' || key === 'db.query.text') {
107
+ // Redis: solo il comando, mai chiavi e valori.
108
+ out[key] = attrs['db.system'] === 'redis' || attrs['db.system.name'] === 'redis' ? value.split(/\s+/)[0] : (0, redaction_1.maskString)(sanitizeStatement(value));
109
+ continue;
110
+ }
111
+ out[key] = (0, redaction_1.maskString)(value);
112
+ }
113
+ return out;
114
+ }
115
+ //# sourceMappingURL=attributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export declare const DEFAULT_OTLP_ENDPOINT = "http://otel-collector.observability:4318";
2
+ export interface TelemetryConfig {
3
+ enabled: boolean;
4
+ endpoint: string;
5
+ serviceName: string;
6
+ environment?: string;
7
+ serviceVersion?: string;
8
+ sampleRatio: number;
9
+ metricIntervalMs: number;
10
+ }
11
+ /**
12
+ * - `TELEMETRY_MODE=on` accende (di serie `off`: il processo non carica nulla, non apre connessioni);
13
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`: base OTLP/HTTP (di serie quella del collector nel cluster); **vuota = spento**;
14
+ * - `OTEL_SERVICE_NAME`, altrimenti il `name` del `package.json` del processo;
15
+ * - `SKILLERA_ENV` → `deployment.environment`;
16
+ * - `TELEMETRY_SAMPLE_RATIO` (0..1, di serie 1: il campionamento in coda lo fa il collector);
17
+ * - `OTEL_METRIC_EXPORT_INTERVAL` (ms, di serie 60000).
18
+ */
19
+ export declare function readConfig(env?: NodeJS.ProcessEnv): TelemetryConfig;
20
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,6CAA6C,CAAC;AAEhF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAWD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,eAAe,CAahF"}
package/dist/config.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_OTLP_ENDPOINT = void 0;
4
+ exports.readConfig = readConfig;
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ exports.DEFAULT_OTLP_ENDPOINT = 'http://otel-collector.observability:4318';
8
+ function packageName() {
9
+ try {
10
+ const name = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'package.json'), 'utf8')).name;
11
+ return name?.replace(/^@[^/]+\//, '');
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ }
17
+ /**
18
+ * - `TELEMETRY_MODE=on` accende (di serie `off`: il processo non carica nulla, non apre connessioni);
19
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`: base OTLP/HTTP (di serie quella del collector nel cluster); **vuota = spento**;
20
+ * - `OTEL_SERVICE_NAME`, altrimenti il `name` del `package.json` del processo;
21
+ * - `SKILLERA_ENV` → `deployment.environment`;
22
+ * - `TELEMETRY_SAMPLE_RATIO` (0..1, di serie 1: il campionamento in coda lo fa il collector);
23
+ * - `OTEL_METRIC_EXPORT_INTERVAL` (ms, di serie 60000).
24
+ */
25
+ function readConfig(env = process.env) {
26
+ const rawEndpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
27
+ const endpoint = (rawEndpoint === undefined ? exports.DEFAULT_OTLP_ENDPOINT : rawEndpoint).trim().replace(/\/+$/, '');
28
+ const ratio = Number(env.TELEMETRY_SAMPLE_RATIO ?? '1');
29
+ return {
30
+ enabled: (env.TELEMETRY_MODE ?? 'off').toLowerCase() === 'on' && endpoint !== '',
31
+ endpoint,
32
+ serviceName: env.OTEL_SERVICE_NAME?.trim() || packageName() || 'unknown-service',
33
+ environment: env.SKILLERA_ENV,
34
+ serviceVersion: env.npm_package_version,
35
+ sampleRatio: Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1,
36
+ metricIntervalMs: Number(env.OTEL_METRIC_EXPORT_INTERVAL) > 0 ? Number(env.OTEL_METRIC_EXPORT_INTERVAL) : 60_000,
37
+ };
38
+ }
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAgCA,gCAaC;AA7CD,2BAAkC;AAClC,+BAA4B;AAEf,QAAA,qBAAqB,GAAG,0CAA0C,CAAC;AAYhF,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAA0B,CAAC;QAC9G,OAAO,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,WAAW,GAAG,GAAG,CAAC,2BAA2B,CAAC;IACpD,MAAM,QAAQ,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,6BAAqB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9G,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,sBAAsB,IAAI,GAAG,CAAC,CAAC;IACxD,OAAO;QACL,OAAO,EAAE,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE;QAChF,QAAQ;QACR,WAAW,EAAE,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,IAAI,iBAAiB;QAChF,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,cAAc,EAAE,GAAG,CAAC,mBAAmB;QACvC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,MAAM;KACjH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ export { TelemetryModule, TelemetryService, TELEMETRY_OPTIONS } from './telemetry.module';
2
+ export type { TelemetryModuleOptions } from './telemetry.module';
3
+ export { NatsTelemetryInterceptor, resolveCmd, pickJuridicalId } from './nats.interceptor';
4
+ export { injectTraceContext, extractTraceContext, traceparentHeadersHook } from './propagation';
5
+ export type { NatsHeadersHook, HeadersLike, ReadableHeadersLike } from './propagation';
6
+ export { redact, maskString, isSensitiveKey, REDACTED } from './redaction';
7
+ export { sanitizeAttributes, sanitizeStatement, ALLOWED_ATTRIBUTES, hashIp } from './attributes';
8
+ export { SanitizingSpanExporter, sanitizeSpan } from './sanitizing-exporter';
9
+ export { runWithLogContext, getLogContext } from './log-context';
10
+ export type { LogContext } from './log-context';
11
+ export { startTelemetry, shutdownTelemetry, getTelemetry } from './sdk';
12
+ export type { TelemetryHandle } from './sdk';
13
+ export { readConfig, DEFAULT_OTLP_ENDPOINT } from './config';
14
+ export type { TelemetryConfig } from './config';
15
+ export { JsonLogger, createLogger, parseLogLevels } from './logger';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAChG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACxE,YAAY,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLogLevels = exports.createLogger = exports.JsonLogger = exports.DEFAULT_OTLP_ENDPOINT = exports.readConfig = exports.getTelemetry = exports.shutdownTelemetry = exports.startTelemetry = exports.getLogContext = exports.runWithLogContext = exports.sanitizeSpan = exports.SanitizingSpanExporter = exports.hashIp = exports.ALLOWED_ATTRIBUTES = exports.sanitizeStatement = exports.sanitizeAttributes = exports.REDACTED = exports.isSensitiveKey = exports.maskString = exports.redact = exports.traceparentHeadersHook = exports.extractTraceContext = exports.injectTraceContext = exports.pickJuridicalId = exports.resolveCmd = exports.NatsTelemetryInterceptor = exports.TELEMETRY_OPTIONS = exports.TelemetryService = exports.TelemetryModule = void 0;
4
+ var telemetry_module_1 = require("./telemetry.module");
5
+ Object.defineProperty(exports, "TelemetryModule", { enumerable: true, get: function () { return telemetry_module_1.TelemetryModule; } });
6
+ Object.defineProperty(exports, "TelemetryService", { enumerable: true, get: function () { return telemetry_module_1.TelemetryService; } });
7
+ Object.defineProperty(exports, "TELEMETRY_OPTIONS", { enumerable: true, get: function () { return telemetry_module_1.TELEMETRY_OPTIONS; } });
8
+ var nats_interceptor_1 = require("./nats.interceptor");
9
+ Object.defineProperty(exports, "NatsTelemetryInterceptor", { enumerable: true, get: function () { return nats_interceptor_1.NatsTelemetryInterceptor; } });
10
+ Object.defineProperty(exports, "resolveCmd", { enumerable: true, get: function () { return nats_interceptor_1.resolveCmd; } });
11
+ Object.defineProperty(exports, "pickJuridicalId", { enumerable: true, get: function () { return nats_interceptor_1.pickJuridicalId; } });
12
+ var propagation_1 = require("./propagation");
13
+ Object.defineProperty(exports, "injectTraceContext", { enumerable: true, get: function () { return propagation_1.injectTraceContext; } });
14
+ Object.defineProperty(exports, "extractTraceContext", { enumerable: true, get: function () { return propagation_1.extractTraceContext; } });
15
+ Object.defineProperty(exports, "traceparentHeadersHook", { enumerable: true, get: function () { return propagation_1.traceparentHeadersHook; } });
16
+ var redaction_1 = require("./redaction");
17
+ Object.defineProperty(exports, "redact", { enumerable: true, get: function () { return redaction_1.redact; } });
18
+ Object.defineProperty(exports, "maskString", { enumerable: true, get: function () { return redaction_1.maskString; } });
19
+ Object.defineProperty(exports, "isSensitiveKey", { enumerable: true, get: function () { return redaction_1.isSensitiveKey; } });
20
+ Object.defineProperty(exports, "REDACTED", { enumerable: true, get: function () { return redaction_1.REDACTED; } });
21
+ var attributes_1 = require("./attributes");
22
+ Object.defineProperty(exports, "sanitizeAttributes", { enumerable: true, get: function () { return attributes_1.sanitizeAttributes; } });
23
+ Object.defineProperty(exports, "sanitizeStatement", { enumerable: true, get: function () { return attributes_1.sanitizeStatement; } });
24
+ Object.defineProperty(exports, "ALLOWED_ATTRIBUTES", { enumerable: true, get: function () { return attributes_1.ALLOWED_ATTRIBUTES; } });
25
+ Object.defineProperty(exports, "hashIp", { enumerable: true, get: function () { return attributes_1.hashIp; } });
26
+ var sanitizing_exporter_1 = require("./sanitizing-exporter");
27
+ Object.defineProperty(exports, "SanitizingSpanExporter", { enumerable: true, get: function () { return sanitizing_exporter_1.SanitizingSpanExporter; } });
28
+ Object.defineProperty(exports, "sanitizeSpan", { enumerable: true, get: function () { return sanitizing_exporter_1.sanitizeSpan; } });
29
+ var log_context_1 = require("./log-context");
30
+ Object.defineProperty(exports, "runWithLogContext", { enumerable: true, get: function () { return log_context_1.runWithLogContext; } });
31
+ Object.defineProperty(exports, "getLogContext", { enumerable: true, get: function () { return log_context_1.getLogContext; } });
32
+ var sdk_1 = require("./sdk");
33
+ Object.defineProperty(exports, "startTelemetry", { enumerable: true, get: function () { return sdk_1.startTelemetry; } });
34
+ Object.defineProperty(exports, "shutdownTelemetry", { enumerable: true, get: function () { return sdk_1.shutdownTelemetry; } });
35
+ Object.defineProperty(exports, "getTelemetry", { enumerable: true, get: function () { return sdk_1.getTelemetry; } });
36
+ var config_1 = require("./config");
37
+ Object.defineProperty(exports, "readConfig", { enumerable: true, get: function () { return config_1.readConfig; } });
38
+ Object.defineProperty(exports, "DEFAULT_OTLP_ENDPOINT", { enumerable: true, get: function () { return config_1.DEFAULT_OTLP_ENDPOINT; } });
39
+ var logger_1 = require("./logger");
40
+ Object.defineProperty(exports, "JsonLogger", { enumerable: true, get: function () { return logger_1.JsonLogger; } });
41
+ Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return logger_1.createLogger; } });
42
+ Object.defineProperty(exports, "parseLogLevels", { enumerable: true, get: function () { return logger_1.parseLogLevels; } });
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAA0F;AAAjF,mHAAA,eAAe,OAAA;AAAE,oHAAA,gBAAgB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE7D,uDAA2F;AAAlF,4HAAA,wBAAwB,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,mHAAA,eAAe,OAAA;AAC9D,6CAAgG;AAAvF,iHAAA,kBAAkB,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AAExE,yCAA2E;AAAlE,mGAAA,MAAM,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,qGAAA,QAAQ,OAAA;AACrD,2CAAiG;AAAxF,gHAAA,kBAAkB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AAAE,gHAAA,kBAAkB,OAAA;AAAE,oGAAA,MAAM,OAAA;AAC1E,6DAA6E;AAApE,6HAAA,sBAAsB,OAAA;AAAE,mHAAA,YAAY,OAAA;AAC7C,6CAAiE;AAAxD,gHAAA,iBAAiB,OAAA;AAAE,4GAAA,aAAa,OAAA;AAEzC,6BAAwE;AAA/D,qGAAA,cAAc,OAAA;AAAE,wGAAA,iBAAiB,OAAA;AAAE,mGAAA,YAAY,OAAA;AAExD,mCAA6D;AAApD,oGAAA,UAAU,OAAA;AAAE,+GAAA,qBAAqB,OAAA;AAE1C,mCAAoE;AAA3D,oGAAA,UAAU,OAAA;AAAE,sGAAA,YAAY,OAAA;AAAE,wGAAA,cAAc,OAAA"}
@@ -0,0 +1,8 @@
1
+ /** Campi che ogni riga di log dello stesso comando eredita (`cmd`, `juridicalId`). */
2
+ export interface LogContext {
3
+ cmd?: string;
4
+ juridicalId?: string;
5
+ }
6
+ export declare function runWithLogContext<T>(ctx: LogContext, fn: () => T): T;
7
+ export declare function getLogContext(): LogContext;
8
+ //# sourceMappingURL=log-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-context.d.ts","sourceRoot":"","sources":["../src/log-context.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEpE;AAED,wBAAgB,aAAa,IAAI,UAAU,CAE1C"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runWithLogContext = runWithLogContext;
4
+ exports.getLogContext = getLogContext;
5
+ const async_hooks_1 = require("async_hooks");
6
+ const storage = new async_hooks_1.AsyncLocalStorage();
7
+ function runWithLogContext(ctx, fn) {
8
+ return storage.run({ ...storage.getStore(), ...ctx }, fn);
9
+ }
10
+ function getLogContext() {
11
+ return storage.getStore() ?? {};
12
+ }
13
+ //# sourceMappingURL=log-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-context.js","sourceRoot":"","sources":["../src/log-context.ts"],"names":[],"mappings":";;AAUA,8CAEC;AAED,sCAEC;AAhBD,6CAAgD;AAQhD,MAAM,OAAO,GAAG,IAAI,+BAAiB,EAAc,CAAC;AAEpD,SAAgB,iBAAiB,CAAI,GAAe,EAAE,EAAW;IAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAgB,aAAa;IAC3B,OAAO,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type LoggerService } from '@nestjs/common';
2
+ export { JsonLogger, parseLogLevels, DEFAULT_LOG_LEVELS } from './json-logger';
3
+ export type { JsonLoggerOptions } from './json-logger';
4
+ /**
5
+ * Il logger di `main.ts`: `LOG_FORMAT=json` → `JsonLogger`, altrimenti (di serie, `text`) il logger di testo di Nest.
6
+ *
7
+ * const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
8
+ */
9
+ export declare function createLogger(service: string, env?: NodeJS.ProcessEnv): LoggerService;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,aAAa,CAMjG"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_LOG_LEVELS = exports.parseLogLevels = exports.JsonLogger = void 0;
4
+ exports.createLogger = createLogger;
5
+ const common_1 = require("@nestjs/common");
6
+ const json_logger_1 = require("./json-logger");
7
+ var json_logger_2 = require("./json-logger");
8
+ Object.defineProperty(exports, "JsonLogger", { enumerable: true, get: function () { return json_logger_2.JsonLogger; } });
9
+ Object.defineProperty(exports, "parseLogLevels", { enumerable: true, get: function () { return json_logger_2.parseLogLevels; } });
10
+ Object.defineProperty(exports, "DEFAULT_LOG_LEVELS", { enumerable: true, get: function () { return json_logger_2.DEFAULT_LOG_LEVELS; } });
11
+ /**
12
+ * Il logger di `main.ts`: `LOG_FORMAT=json` → `JsonLogger`, altrimenti (di serie, `text`) il logger di testo di Nest.
13
+ *
14
+ * const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
15
+ */
16
+ function createLogger(service, env = process.env) {
17
+ json_logger_1.JsonLogger.defaultService = service;
18
+ if ((env.LOG_FORMAT ?? 'text').toLowerCase() === 'json') {
19
+ return new json_logger_1.JsonLogger({ service, levels: (0, json_logger_1.parseLogLevels)(env.APP_LOGGER_LEVEL) });
20
+ }
21
+ return new common_1.ConsoleLogger({ logLevels: (0, json_logger_1.parseLogLevels)(env.APP_LOGGER_LEVEL) });
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":";;;AAWA,oCAMC;AAjBD,2CAAmE;AACnE,+CAA2D;AAE3D,6CAA+E;AAAtE,yGAAA,UAAU,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAGvD;;;;GAIG;AACH,SAAgB,YAAY,CAAC,OAAe,EAAE,MAAyB,OAAO,CAAC,GAAG;IAChF,wBAAU,CAAC,cAAc,GAAG,OAAO,CAAC;IACpC,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QACxD,OAAO,IAAI,wBAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAA,4BAAc,EAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,sBAAa,CAAC,EAAE,SAAS,EAAE,IAAA,4BAAc,EAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { LogLevel, LoggerService } from '@nestjs/common';
2
+ type Write = (line: string) => void;
3
+ export declare const DEFAULT_LOG_LEVELS: readonly LogLevel[];
4
+ /** `APP_LOGGER_LEVEL`: elenco separato da virgole (`log,error,warn`), `none` per spegnere. */
5
+ export declare function parseLogLevels(raw: string | undefined, fallback?: readonly LogLevel[]): LogLevel[];
6
+ export interface JsonLoggerOptions {
7
+ /** Nome del servizio nel campo `service`. Di serie `OTEL_SERVICE_NAME` o `unknown`. */
8
+ service?: string;
9
+ levels?: readonly LogLevel[];
10
+ write?: Write;
11
+ clock?: () => Date;
12
+ }
13
+ /**
14
+ * Una riga JSON per evento su stdout, con gli stessi campi in tutti i servizi Node:
15
+ * `level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId` (solo id), più `context` (nome del logger di Nest)
16
+ * ed eventuali campi di un messaggio-oggetto. Ogni stringa e ogni oggetto passano dalla redazione: niente email, codici
17
+ * fiscali, IBAN, token, né i valori di chiavi come `password`, `authorization`, `body`.
18
+ * `trace_id`/`span_id` vengono dallo span attivo; `cmd`/`juridicalId` dal contesto del comando NATS in corso.
19
+ */
20
+ export declare class JsonLogger implements LoggerService {
21
+ /** Impostato da `TelemetryModule.forRoot({ service })`. */
22
+ static defaultService: string | undefined;
23
+ private levels;
24
+ private readonly service?;
25
+ private readonly write;
26
+ private readonly clock;
27
+ constructor(options?: JsonLoggerOptions);
28
+ setLogLevels(levels: LogLevel[]): void;
29
+ log(message: unknown, ...rest: unknown[]): void;
30
+ error(message: unknown, ...rest: unknown[]): void;
31
+ warn(message: unknown, ...rest: unknown[]): void;
32
+ debug(message: unknown, ...rest: unknown[]): void;
33
+ verbose(message: unknown, ...rest: unknown[]): void;
34
+ fatal(message: unknown, ...rest: unknown[]): void;
35
+ private emit;
36
+ private build;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=json-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-logger.d.ts","sourceRoot":"","sources":["../../src/logger/json-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAGpC,eAAO,MAAM,kBAAkB,EAAE,SAAS,QAAQ,EAAsC,CAAC;AASzF,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAE,SAAS,QAAQ,EAAuB,GAAG,QAAQ,EAAE,CAUtH;AAED,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC9C,2DAA2D;IAC3D,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAEvB,OAAO,GAAE,iBAAsB;IAO3C,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI;IAItC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAG/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGjD,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGhD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGjD,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGnD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIjD,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,KAAK;CA2Cd"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonLogger = exports.DEFAULT_LOG_LEVELS = void 0;
4
+ exports.parseLogLevels = parseLogLevels;
5
+ const api_1 = require("@opentelemetry/api");
6
+ const log_context_1 = require("../log-context");
7
+ const redaction_1 = require("../redaction");
8
+ const ALL_LEVELS = ['fatal', 'error', 'warn', 'log', 'debug', 'verbose'];
9
+ exports.DEFAULT_LOG_LEVELS = ['log', 'error', 'warn', 'fatal'];
10
+ /** Livello scritto nella riga: `log` di Nest = `info`. */
11
+ const LEVEL_NAME = { fatal: 'fatal', error: 'error', warn: 'warn', log: 'info', debug: 'debug', verbose: 'trace' };
12
+ function withFatal(levels) {
13
+ return levels.includes('error') && !levels.includes('fatal') ? [...levels, 'fatal'] : levels;
14
+ }
15
+ /** `APP_LOGGER_LEVEL`: elenco separato da virgole (`log,error,warn`), `none` per spegnere. */
16
+ function parseLogLevels(raw, fallback = exports.DEFAULT_LOG_LEVELS) {
17
+ const value = raw?.trim();
18
+ if (!value)
19
+ return withFatal([...fallback]);
20
+ if (value === 'none')
21
+ return [];
22
+ return withFatal(value
23
+ .split(',')
24
+ .map((l) => l.trim())
25
+ .filter((l) => ALL_LEVELS.includes(l)));
26
+ }
27
+ /**
28
+ * Una riga JSON per evento su stdout, con gli stessi campi in tutti i servizi Node:
29
+ * `level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId` (solo id), più `context` (nome del logger di Nest)
30
+ * ed eventuali campi di un messaggio-oggetto. Ogni stringa e ogni oggetto passano dalla redazione: niente email, codici
31
+ * fiscali, IBAN, token, né i valori di chiavi come `password`, `authorization`, `body`.
32
+ * `trace_id`/`span_id` vengono dallo span attivo; `cmd`/`juridicalId` dal contesto del comando NATS in corso.
33
+ */
34
+ class JsonLogger {
35
+ constructor(options = {}) {
36
+ this.levels = new Set(options.levels ?? parseLogLevels(process.env.APP_LOGGER_LEVEL));
37
+ this.service = options.service;
38
+ this.write = options.write ?? ((line) => process.stdout.write(`${line}\n`));
39
+ this.clock = options.clock ?? (() => new Date());
40
+ }
41
+ setLogLevels(levels) {
42
+ this.levels = new Set(levels);
43
+ }
44
+ log(message, ...rest) {
45
+ this.emit('log', message, rest);
46
+ }
47
+ error(message, ...rest) {
48
+ this.emit('error', message, rest);
49
+ }
50
+ warn(message, ...rest) {
51
+ this.emit('warn', message, rest);
52
+ }
53
+ debug(message, ...rest) {
54
+ this.emit('debug', message, rest);
55
+ }
56
+ verbose(message, ...rest) {
57
+ this.emit('verbose', message, rest);
58
+ }
59
+ fatal(message, ...rest) {
60
+ this.emit('fatal', message, rest);
61
+ }
62
+ emit(level, message, rest) {
63
+ if (!this.levels.has(level))
64
+ return;
65
+ try {
66
+ this.write(JSON.stringify(this.build(level, message, rest)));
67
+ }
68
+ catch {
69
+ /* un log non deve mai far cadere il servizio */
70
+ }
71
+ }
72
+ build(level, message, rest) {
73
+ // Convenzione di Nest: l'ultimo argomento stringa è il contesto; per `error` il penultimo può essere lo stack.
74
+ const args = [...rest];
75
+ let context;
76
+ if (args.length && typeof args[args.length - 1] === 'string' && !(level === 'error' && args.length === 1 && looksLikeStack(args[0]))) {
77
+ context = args.pop();
78
+ }
79
+ let stack;
80
+ if (args.length && typeof args[0] === 'string' && looksLikeStack(args[0]))
81
+ stack = args.shift();
82
+ const span = api_1.trace.getActiveSpan()?.spanContext();
83
+ const ctx = (0, log_context_1.getLogContext)();
84
+ const line = {
85
+ level: LEVEL_NAME[level],
86
+ ts: this.clock().toISOString(),
87
+ service: this.service ?? JsonLogger.defaultService ?? process.env.OTEL_SERVICE_NAME ?? 'unknown',
88
+ msg: '',
89
+ trace_id: span?.traceId,
90
+ span_id: span?.spanId,
91
+ cmd: ctx.cmd,
92
+ juridicalId: ctx.juridicalId,
93
+ };
94
+ if (context)
95
+ line.context = (0, redaction_1.maskString)(context);
96
+ if (message instanceof Error) {
97
+ line.msg = (0, redaction_1.maskString)(message.message);
98
+ line.err = (0, redaction_1.redact)(message);
99
+ }
100
+ else if (message !== null && typeof message === 'object') {
101
+ const { message: inner, msg: inner2, ...fields } = message;
102
+ line.msg = typeof (inner ?? inner2) === 'string' ? (0, redaction_1.maskString)((inner ?? inner2)) : '';
103
+ const extra = (0, redaction_1.redact)(fields);
104
+ // I campi del contratto non si sovrascrivono da un messaggio-oggetto.
105
+ for (const [k, v] of Object.entries(extra))
106
+ if (!(k in line) || line[k] === undefined)
107
+ line[k] = v;
108
+ }
109
+ else {
110
+ line.msg = (0, redaction_1.maskString)(String(message));
111
+ }
112
+ if (stack)
113
+ line.stack = (0, redaction_1.maskString)(stack);
114
+ for (const extra of args) {
115
+ if (extra instanceof Error)
116
+ line.err = (0, redaction_1.redact)(extra);
117
+ else if (extra && typeof extra === 'object')
118
+ line.extra = (0, redaction_1.redact)(extra);
119
+ }
120
+ return line;
121
+ }
122
+ }
123
+ exports.JsonLogger = JsonLogger;
124
+ function looksLikeStack(s) {
125
+ return /\n\s+at /.test(s) || /^\w*Error: .*\n/.test(s);
126
+ }
127
+ //# sourceMappingURL=json-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-logger.js","sourceRoot":"","sources":["../../src/logger/json-logger.ts"],"names":[],"mappings":";;;AAkBA,wCAUC;AA3BD,4CAA2C;AAC3C,gDAA+C;AAC/C,4CAAkD;AAIlD,MAAM,UAAU,GAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AACjF,QAAA,kBAAkB,GAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzF,0DAA0D;AAC1D,MAAM,UAAU,GAA6B,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAE7I,SAAS,SAAS,CAAC,MAAkB;IACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/F,CAAC;AAED,8FAA8F;AAC9F,SAAgB,cAAc,CAAC,GAAuB,EAAE,WAAgC,0BAAkB;IACxG,MAAM,KAAK,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,SAAS,CACd,KAAK;SACF,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAE,UAAgC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAC/E,CAAC;AACJ,CAAC;AAUD;;;;;;GAMG;AACH,MAAa,UAAU;IASrB,YAAY,UAA6B,EAAE;QACzC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,YAAY,CAAC,MAAkB;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,GAAG,CAAC,OAAgB,EAAE,GAAG,IAAe;QACtC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IACD,KAAK,CAAC,OAAgB,EAAE,GAAG,IAAe;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,OAAgB,EAAE,GAAG,IAAe;QACvC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,OAAgB,EAAE,GAAG,IAAe;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,CAAC,OAAgB,EAAE,GAAG,IAAe;QAC1C,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,KAAK,CAAC,OAAgB,EAAE,GAAG,IAAe;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAEO,IAAI,CAAC,KAAe,EAAE,OAAgB,EAAE,IAAe;QAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO;QACpC,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,KAAe,EAAE,OAAgB,EAAE,IAAe;QAC9D,+GAA+G;QAC/G,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACvB,IAAI,OAA2B,CAAC;QAChC,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC,EAAE,CAAC;YAC/I,OAAO,GAAG,IAAI,CAAC,GAAG,EAAY,CAAC;QACjC,CAAC;QACD,IAAI,KAAyB,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,GAAG,IAAI,CAAC,KAAK,EAAY,CAAC;QAE1G,MAAM,IAAI,GAAG,WAAK,CAAC,aAAa,EAAE,EAAE,WAAW,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,IAAA,2BAAa,GAAE,CAAC;QAC5B,MAAM,IAAI,GAA4B;YACpC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC;YACxB,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE;YAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,SAAS;YAChG,GAAG,EAAE,EAAE;YACP,QAAQ,EAAE,IAAI,EAAE,OAAO;YACvB,OAAO,EAAE,IAAI,EAAE,MAAM;YACrB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC;QACF,IAAI,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,IAAA,sBAAU,EAAC,OAAO,CAAC,CAAC;QAEhD,IAAI,OAAO,YAAY,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,GAAG,IAAA,sBAAU,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,CAAC,GAAG,GAAG,IAAA,kBAAM,EAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC3D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,OAAkC,CAAC;YACtF,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAA,sBAAU,EAAC,CAAC,KAAK,IAAI,MAAM,CAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChG,MAAM,KAAK,GAAG,IAAA,kBAAM,EAAC,MAAM,CAA4B,CAAC;YACxD,sEAAsE;YACtE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;oBAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,GAAG,IAAA,sBAAU,EAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,IAAA,sBAAU,EAAC,KAAK,CAAC,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;YACzB,IAAI,KAAK,YAAY,KAAK;gBAAE,IAAI,CAAC,GAAG,GAAG,IAAA,kBAAM,EAAC,KAAK,CAAC,CAAC;iBAChD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,IAAI,CAAC,KAAK,GAAG,IAAA,kBAAM,EAAC,KAAK,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA3FD,gCA2FC;AAED,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,18 @@
1
+ import 'reflect-metadata';
2
+ import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
3
+ import { Observable } from 'rxjs';
4
+ import { type ReadableHeadersLike } from './propagation';
5
+ /** Il nome del comando di un handler `@MessagePattern({ cmd: 'x.y' })` (o `@EventPattern`), altrimenti il subject NATS. */
6
+ export declare function resolveCmd(handler: unknown, subject?: string): string;
7
+ /** L'azienda del messaggio, solo se è un UUID: dall'intestazione `Gen-Tenant` o dall'`auth`/dal payload. Mai altri campi. */
8
+ export declare function pickJuridicalId(headers: ReadableHeadersLike | undefined, data: unknown): string | undefined;
9
+ /**
10
+ * Lato servizio: per ogni messaggio NATS apre lo span `nats.server <cmd>` figlio del `traceparent` negli header, mette `cmd`
11
+ * e `juridicalId` nel contesto dei log del comando e conta durata ed esito. Non tocca mai il payload: negli span entrano
12
+ * solo gli attributi a lista bianca. Gli altri tipi di contesto (HTTP) passano senza cambiamenti.
13
+ */
14
+ export declare class NatsTelemetryInterceptor implements NestInterceptor {
15
+ private readonly tracer;
16
+ intercept(execution: ExecutionContext, next: CallHandler): Observable<unknown>;
17
+ }
18
+ //# sourceMappingURL=nats.interceptor.d.ts.map