nestjs-ddd-cli 2.2.1 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -408
- package/ddd.schema.json +111 -0
- package/dist/commands/aggregate-validator.d.ts +9 -0
- package/dist/commands/aggregate-validator.js +953 -0
- package/dist/commands/aggregate-validator.js.map +1 -0
- package/dist/commands/ai-assist.d.ts +8 -0
- package/dist/commands/ai-assist.js +337 -0
- package/dist/commands/ai-assist.js.map +1 -0
- package/dist/commands/api-contracts.d.ts +9 -0
- package/dist/commands/api-contracts.js +1368 -0
- package/dist/commands/api-contracts.js.map +1 -0
- package/dist/commands/api-docs.d.ts +8 -0
- package/dist/commands/api-docs.js +408 -0
- package/dist/commands/api-docs.js.map +1 -0
- package/dist/commands/api-versioning.d.ts +11 -0
- package/dist/commands/api-versioning.js +643 -0
- package/dist/commands/api-versioning.js.map +1 -0
- package/dist/commands/audit-logging.d.ts +9 -0
- package/dist/commands/audit-logging.js +1129 -0
- package/dist/commands/audit-logging.js.map +1 -0
- package/dist/commands/batch-generate.d.ts +10 -0
- package/dist/commands/batch-generate.js +405 -0
- package/dist/commands/batch-generate.js.map +1 -0
- package/dist/commands/caching-strategies.d.ts +9 -0
- package/dist/commands/caching-strategies.js +874 -0
- package/dist/commands/caching-strategies.js.map +1 -0
- package/dist/commands/code-analyzer.d.ts +42 -0
- package/dist/commands/code-analyzer.js +474 -0
- package/dist/commands/code-analyzer.js.map +1 -0
- package/dist/commands/database-seeding.d.ts +6 -0
- package/dist/commands/database-seeding.js +621 -0
- package/dist/commands/database-seeding.js.map +1 -0
- package/dist/commands/db-optimization.d.ts +7 -0
- package/dist/commands/db-optimization.js +687 -0
- package/dist/commands/db-optimization.js.map +1 -0
- package/dist/commands/dependency-graph.d.ts +6 -0
- package/dist/commands/dependency-graph.js +329 -0
- package/dist/commands/dependency-graph.js.map +1 -0
- package/dist/commands/doctor-enhanced.d.ts +22 -0
- package/dist/commands/doctor-enhanced.js +543 -0
- package/dist/commands/doctor-enhanced.js.map +1 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +151 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/env-manager.d.ts +6 -0
- package/dist/commands/env-manager.js +419 -0
- package/dist/commands/env-manager.js.map +1 -0
- package/dist/commands/event-sourcing-full.d.ts +10 -0
- package/dist/commands/event-sourcing-full.js +1107 -0
- package/dist/commands/event-sourcing-full.js.map +1 -0
- package/dist/commands/feature-flags.d.ts +9 -0
- package/dist/commands/feature-flags.js +824 -0
- package/dist/commands/feature-flags.js.map +1 -0
- package/dist/commands/filter-dsl.d.ts +10 -0
- package/dist/commands/filter-dsl.js +1407 -0
- package/dist/commands/filter-dsl.js.map +1 -0
- package/dist/commands/generate-all.js +485 -32
- package/dist/commands/generate-all.js.map +1 -1
- package/dist/commands/generate-deployment.d.ts +8 -0
- package/dist/commands/generate-deployment.js +746 -0
- package/dist/commands/generate-deployment.js.map +1 -0
- package/dist/commands/generate-domain-service.d.ts +14 -0
- package/dist/commands/generate-domain-service.js +796 -0
- package/dist/commands/generate-domain-service.js.map +1 -0
- package/dist/commands/generate-entity.js +82 -24
- package/dist/commands/generate-entity.js.map +1 -1
- package/dist/commands/generate-from-schema.d.ts +56 -0
- package/dist/commands/generate-from-schema.js +222 -0
- package/dist/commands/generate-from-schema.js.map +1 -0
- package/dist/commands/generate-orchestrator.d.ts +14 -0
- package/dist/commands/generate-orchestrator.js +887 -0
- package/dist/commands/generate-orchestrator.js.map +1 -0
- package/dist/commands/generate-repository.d.ts +14 -0
- package/dist/commands/generate-repository.js +1019 -0
- package/dist/commands/generate-repository.js.map +1 -0
- package/dist/commands/generate-shared.d.ts +4 -0
- package/dist/commands/generate-shared.js +388 -0
- package/dist/commands/generate-shared.js.map +1 -0
- package/dist/commands/generate-value-object.d.ts +32 -0
- package/dist/commands/generate-value-object.js +700 -0
- package/dist/commands/generate-value-object.js.map +1 -0
- package/dist/commands/graphql-subscriptions.d.ts +6 -0
- package/dist/commands/graphql-subscriptions.js +607 -0
- package/dist/commands/graphql-subscriptions.js.map +1 -0
- package/dist/commands/graphql-types.d.ts +5 -0
- package/dist/commands/graphql-types.js +423 -0
- package/dist/commands/graphql-types.js.map +1 -0
- package/dist/commands/health-probes-advanced.d.ts +6 -0
- package/dist/commands/health-probes-advanced.js +655 -0
- package/dist/commands/health-probes-advanced.js.map +1 -0
- package/dist/commands/i18n-setup.d.ts +10 -0
- package/dist/commands/i18n-setup.js +677 -0
- package/dist/commands/i18n-setup.js.map +1 -0
- package/dist/commands/init-config.d.ts +6 -0
- package/dist/commands/init-config.js +370 -0
- package/dist/commands/init-config.js.map +1 -0
- package/dist/commands/init-project.js +56 -6
- package/dist/commands/init-project.js.map +1 -1
- package/dist/commands/interactive-scaffold.d.ts +5 -0
- package/dist/commands/interactive-scaffold.js +271 -0
- package/dist/commands/interactive-scaffold.js.map +1 -0
- package/dist/commands/metrics-prometheus.d.ts +6 -0
- package/dist/commands/metrics-prometheus.js +681 -0
- package/dist/commands/metrics-prometheus.js.map +1 -0
- package/dist/commands/migration-engine.d.ts +6 -0
- package/dist/commands/migration-engine.js +446 -0
- package/dist/commands/migration-engine.js.map +1 -0
- package/dist/commands/migration.d.ts +12 -0
- package/dist/commands/migration.js +484 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/monorepo.d.ts +8 -0
- package/dist/commands/monorepo.js +483 -0
- package/dist/commands/monorepo.js.map +1 -0
- package/dist/commands/multi-database.d.ts +5 -0
- package/dist/commands/multi-database.js +439 -0
- package/dist/commands/multi-database.js.map +1 -0
- package/dist/commands/observability-tracing.d.ts +10 -0
- package/dist/commands/observability-tracing.js +740 -0
- package/dist/commands/observability-tracing.js.map +1 -0
- package/dist/commands/openapi-export.d.ts +8 -0
- package/dist/commands/openapi-export.js +359 -0
- package/dist/commands/openapi-export.js.map +1 -0
- package/dist/commands/perf-analyzer.d.ts +8 -0
- package/dist/commands/perf-analyzer.js +423 -0
- package/dist/commands/perf-analyzer.js.map +1 -0
- package/dist/commands/rate-limiting.d.ts +10 -0
- package/dist/commands/rate-limiting.js +953 -0
- package/dist/commands/rate-limiting.js.map +1 -0
- package/dist/commands/recipe-plugin.d.ts +56 -0
- package/dist/commands/recipe-plugin.js +315 -0
- package/dist/commands/recipe-plugin.js.map +1 -0
- package/dist/commands/recipe.d.ts +6 -0
- package/dist/commands/recipe.js +3941 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
- package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
- package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
- package/dist/commands/recipes/index.d.ts +7 -0
- package/dist/commands/recipes/index.js +24 -0
- package/dist/commands/recipes/index.js.map +1 -0
- package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
- package/dist/commands/recipes/message-queue.recipe.js +706 -0
- package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
- package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
- package/dist/commands/recipes/middleware.recipe.js +383 -0
- package/dist/commands/recipes/middleware.recipe.js.map +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2.recipe.js +472 -0
- package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
- package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
- package/dist/commands/recipes/websocket.recipe.js +453 -0
- package/dist/commands/recipes/websocket.recipe.js.map +1 -0
- package/dist/commands/resilience-patterns.d.ts +13 -0
- package/dist/commands/resilience-patterns.js +1029 -0
- package/dist/commands/resilience-patterns.js.map +1 -0
- package/dist/commands/security-patterns.d.ts +11 -0
- package/dist/commands/security-patterns.js +2233 -0
- package/dist/commands/security-patterns.js.map +1 -0
- package/dist/commands/template-debug.d.ts +27 -0
- package/dist/commands/template-debug.js +388 -0
- package/dist/commands/template-debug.js.map +1 -0
- package/dist/commands/test-factory-full.d.ts +9 -0
- package/dist/commands/test-factory-full.js +1570 -0
- package/dist/commands/test-factory-full.js.map +1 -0
- package/dist/commands/test-scaffold.d.ts +7 -0
- package/dist/commands/test-scaffold.js +621 -0
- package/dist/commands/test-scaffold.js.map +1 -0
- package/dist/index.js +1088 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
- package/dist/templates/ai-context/conventions.md.hbs +154 -0
- package/dist/templates/command/create-command.hbs +6 -14
- package/dist/templates/command/delete-command.hbs +19 -0
- package/dist/templates/command/update-command.hbs +24 -0
- package/dist/templates/controller/controller.hbs +64 -17
- package/dist/templates/dto/create-dto.hbs +29 -5
- package/dist/templates/dto/filter-dto.hbs +52 -0
- package/dist/templates/dto/filter-query.dto.hbs +148 -0
- package/dist/templates/dto/paginated-response.dto.hbs +29 -0
- package/dist/templates/dto/pagination-query.dto.hbs +30 -0
- package/dist/templates/dto/response-dto.hbs +38 -0
- package/dist/templates/dto/update-dto.hbs +11 -0
- package/dist/templates/entity/entity.hbs +32 -1
- package/dist/templates/event/domain-event.hbs +33 -7
- package/dist/templates/event/event-handler.hbs +40 -0
- package/dist/templates/exception/base-exceptions.hbs +69 -0
- package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
- package/dist/templates/mapper/mapper.hbs +49 -24
- package/dist/templates/module/module.hbs +34 -10
- package/dist/templates/orm-entity/orm-entity.hbs +63 -12
- package/dist/templates/prisma/prisma-mapper.hbs +71 -0
- package/dist/templates/prisma/prisma-repository.hbs +114 -0
- package/dist/templates/prisma/prisma-schema.hbs +20 -0
- package/dist/templates/prisma/prisma-service.hbs +51 -0
- package/dist/templates/query/get-all.query.hbs +50 -0
- package/dist/templates/query/get-by-id.query.hbs +31 -0
- package/dist/templates/repository/repository.hbs +55 -13
- package/dist/templates/resolver/graphql-input.hbs +54 -0
- package/dist/templates/resolver/graphql-type.hbs +58 -0
- package/dist/templates/resolver/pagination-args.hbs +33 -0
- package/dist/templates/resolver/resolver.hbs +62 -0
- package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
- package/dist/templates/shared/query-builder.util.hbs +218 -0
- package/dist/templates/test/controller.spec.hbs +124 -0
- package/dist/templates/test/repository.spec.hbs +158 -0
- package/dist/templates/test/usecase.spec.hbs +116 -0
- package/dist/templates/usecase/create-usecase.hbs +19 -7
- package/dist/templates/usecase/delete-usecase.hbs +17 -0
- package/dist/templates/usecase/update-usecase.hbs +31 -0
- package/dist/utils/config.utils.d.ts +45 -0
- package/dist/utils/config.utils.js +211 -0
- package/dist/utils/config.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +145 -0
- package/dist/utils/error.utils.js +422 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/field.utils.d.ts +54 -0
- package/dist/utils/field.utils.js +389 -0
- package/dist/utils/field.utils.js.map +1 -0
- package/dist/utils/file.utils.d.ts +19 -8
- package/dist/utils/file.utils.js +135 -4
- package/dist/utils/file.utils.js.map +1 -1
- package/dist/utils/idempotency.utils.d.ts +123 -0
- package/dist/utils/idempotency.utils.js +444 -0
- package/dist/utils/idempotency.utils.js.map +1 -0
- package/dist/utils/naming.utils.js +24 -5
- package/dist/utils/naming.utils.js.map +1 -1
- package/dist/utils/performance.utils.d.ts +37 -0
- package/dist/utils/performance.utils.js +158 -0
- package/dist/utils/performance.utils.js.map +1 -0
- package/dist/utils/relation.utils.d.ts +92 -0
- package/dist/utils/relation.utils.js +388 -0
- package/dist/utils/relation.utils.js.map +1 -0
- package/dist/utils/rollback.utils.d.ts +49 -0
- package/dist/utils/rollback.utils.js +306 -0
- package/dist/utils/rollback.utils.js.map +1 -0
- package/dist/utils/schema.utils.d.ts +123 -0
- package/dist/utils/schema.utils.js +419 -0
- package/dist/utils/schema.utils.js.map +1 -0
- package/dist/utils/security.utils.d.ts +57 -0
- package/dist/utils/security.utils.js +315 -0
- package/dist/utils/security.utils.js.map +1 -0
- package/dist/utils/template-engine.utils.d.ts +80 -0
- package/dist/utils/template-engine.utils.js +463 -0
- package/dist/utils/template-engine.utils.js.map +1 -0
- package/dist/utils/validation-registry.utils.d.ts +160 -0
- package/dist/utils/validation-registry.utils.js +526 -0
- package/dist/utils/validation-registry.utils.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,740 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Distributed Tracing & Observability Generator
|
|
4
|
+
* OpenTelemetry integration for microservices
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.setupObservability = setupObservability;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
47
|
+
async function setupObservability(basePath, options = {}) {
|
|
48
|
+
console.log(chalk_1.default.bold.blue('\n📊 Setting up Observability & Tracing\n'));
|
|
49
|
+
const sharedPath = path.join(basePath, 'src/shared/observability');
|
|
50
|
+
if (!fs.existsSync(sharedPath)) {
|
|
51
|
+
fs.mkdirSync(sharedPath, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
// Generate tracing setup
|
|
54
|
+
fs.writeFileSync(path.join(sharedPath, 'tracing.setup.ts'), generateTracingSetup(options));
|
|
55
|
+
console.log(chalk_1.default.green(` ✓ Created tracing setup`));
|
|
56
|
+
// Generate span decorator
|
|
57
|
+
fs.writeFileSync(path.join(sharedPath, 'span.decorator.ts'), generateSpanDecorator());
|
|
58
|
+
console.log(chalk_1.default.green(` ✓ Created span decorator`));
|
|
59
|
+
// Generate trace interceptor
|
|
60
|
+
fs.writeFileSync(path.join(sharedPath, 'trace.interceptor.ts'), generateTraceInterceptor());
|
|
61
|
+
console.log(chalk_1.default.green(` ✓ Created trace interceptor`));
|
|
62
|
+
// Generate context propagation
|
|
63
|
+
fs.writeFileSync(path.join(sharedPath, 'trace-context.ts'), generateTraceContext());
|
|
64
|
+
console.log(chalk_1.default.green(` ✓ Created trace context`));
|
|
65
|
+
// Generate metrics collector
|
|
66
|
+
fs.writeFileSync(path.join(sharedPath, 'metrics.ts'), generateMetrics());
|
|
67
|
+
console.log(chalk_1.default.green(` ✓ Created metrics`));
|
|
68
|
+
// Generate observability module
|
|
69
|
+
fs.writeFileSync(path.join(sharedPath, 'observability.module.ts'), generateObservabilityModule());
|
|
70
|
+
console.log(chalk_1.default.green(` ✓ Created observability module`));
|
|
71
|
+
console.log(chalk_1.default.bold.green('\n✅ Observability & tracing ready!\n'));
|
|
72
|
+
}
|
|
73
|
+
function generateTracingSetup(options) {
|
|
74
|
+
const provider = options.provider || 'otlp';
|
|
75
|
+
const serviceName = options.serviceName || 'my-service';
|
|
76
|
+
return `/**
|
|
77
|
+
* OpenTelemetry Tracing Setup
|
|
78
|
+
* Initialize distributed tracing for the application
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
82
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
83
|
+
import { Resource } from '@opentelemetry/resources';
|
|
84
|
+
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
85
|
+
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
86
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
87
|
+
import { trace, context, SpanKind, SpanStatusCode, Span } from '@opentelemetry/api';
|
|
88
|
+
|
|
89
|
+
export interface TracingConfig {
|
|
90
|
+
serviceName: string;
|
|
91
|
+
serviceVersion?: string;
|
|
92
|
+
environment?: string;
|
|
93
|
+
exporterUrl?: string;
|
|
94
|
+
samplingRatio?: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const DEFAULT_CONFIG: TracingConfig = {
|
|
98
|
+
serviceName: '${serviceName}',
|
|
99
|
+
serviceVersion: '1.0.0',
|
|
100
|
+
environment: process.env.NODE_ENV || 'development',
|
|
101
|
+
exporterUrl: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces',
|
|
102
|
+
samplingRatio: 1.0,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
let sdk: NodeSDK | null = null;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Initialize OpenTelemetry tracing
|
|
109
|
+
*/
|
|
110
|
+
export async function initTracing(config: Partial<TracingConfig> = {}): Promise<void> {
|
|
111
|
+
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
112
|
+
|
|
113
|
+
const exporter = new OTLPTraceExporter({
|
|
114
|
+
url: finalConfig.exporterUrl,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
sdk = new NodeSDK({
|
|
118
|
+
resource: new Resource({
|
|
119
|
+
[SemanticResourceAttributes.SERVICE_NAME]: finalConfig.serviceName,
|
|
120
|
+
[SemanticResourceAttributes.SERVICE_VERSION]: finalConfig.serviceVersion,
|
|
121
|
+
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: finalConfig.environment,
|
|
122
|
+
}),
|
|
123
|
+
spanProcessor: new BatchSpanProcessor(exporter),
|
|
124
|
+
instrumentations: [
|
|
125
|
+
getNodeAutoInstrumentations({
|
|
126
|
+
'@opentelemetry/instrumentation-fs': { enabled: false },
|
|
127
|
+
}),
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await sdk.start();
|
|
132
|
+
console.log('Tracing initialized for', finalConfig.serviceName);
|
|
133
|
+
|
|
134
|
+
// Graceful shutdown
|
|
135
|
+
process.on('SIGTERM', async () => {
|
|
136
|
+
await sdk?.shutdown();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Shutdown tracing
|
|
142
|
+
*/
|
|
143
|
+
export async function shutdownTracing(): Promise<void> {
|
|
144
|
+
await sdk?.shutdown();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get the tracer
|
|
149
|
+
*/
|
|
150
|
+
export function getTracer(name: string = 'default') {
|
|
151
|
+
return trace.getTracer(name);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Create a new span
|
|
156
|
+
*/
|
|
157
|
+
export function createSpan(
|
|
158
|
+
name: string,
|
|
159
|
+
options: {
|
|
160
|
+
kind?: SpanKind;
|
|
161
|
+
attributes?: Record<string, string | number | boolean>;
|
|
162
|
+
} = {},
|
|
163
|
+
): Span {
|
|
164
|
+
const tracer = getTracer();
|
|
165
|
+
return tracer.startSpan(name, {
|
|
166
|
+
kind: options.kind || SpanKind.INTERNAL,
|
|
167
|
+
attributes: options.attributes,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Run a function within a span
|
|
173
|
+
*/
|
|
174
|
+
export async function withSpan<T>(
|
|
175
|
+
name: string,
|
|
176
|
+
fn: (span: Span) => Promise<T>,
|
|
177
|
+
options: {
|
|
178
|
+
kind?: SpanKind;
|
|
179
|
+
attributes?: Record<string, string | number | boolean>;
|
|
180
|
+
} = {},
|
|
181
|
+
): Promise<T> {
|
|
182
|
+
const tracer = getTracer();
|
|
183
|
+
const span = tracer.startSpan(name, {
|
|
184
|
+
kind: options.kind || SpanKind.INTERNAL,
|
|
185
|
+
attributes: options.attributes,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const result = await context.with(trace.setSpan(context.active(), span), () => fn(span));
|
|
190
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
191
|
+
return result;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
span.setStatus({
|
|
194
|
+
code: SpanStatusCode.ERROR,
|
|
195
|
+
message: (error as Error).message,
|
|
196
|
+
});
|
|
197
|
+
span.recordException(error as Error);
|
|
198
|
+
throw error;
|
|
199
|
+
} finally {
|
|
200
|
+
span.end();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get current span
|
|
206
|
+
*/
|
|
207
|
+
export function getCurrentSpan(): Span | undefined {
|
|
208
|
+
return trace.getSpan(context.active());
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Add attributes to current span
|
|
213
|
+
*/
|
|
214
|
+
export function addSpanAttributes(attributes: Record<string, string | number | boolean>): void {
|
|
215
|
+
const span = getCurrentSpan();
|
|
216
|
+
if (span) {
|
|
217
|
+
span.setAttributes(attributes);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Record an event on current span
|
|
223
|
+
*/
|
|
224
|
+
export function recordSpanEvent(name: string, attributes?: Record<string, string | number | boolean>): void {
|
|
225
|
+
const span = getCurrentSpan();
|
|
226
|
+
if (span) {
|
|
227
|
+
span.addEvent(name, attributes);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
function generateSpanDecorator() {
|
|
233
|
+
return `/**
|
|
234
|
+
* Span Decorator
|
|
235
|
+
* Automatically create spans for methods
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
import { trace, SpanKind, SpanStatusCode, context } from '@opentelemetry/api';
|
|
239
|
+
|
|
240
|
+
export interface SpanOptions {
|
|
241
|
+
name?: string;
|
|
242
|
+
kind?: SpanKind;
|
|
243
|
+
attributes?: Record<string, string | number | boolean>;
|
|
244
|
+
recordArgs?: boolean;
|
|
245
|
+
recordResult?: boolean;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Span decorator for automatic span creation
|
|
250
|
+
*/
|
|
251
|
+
export function Span(options: SpanOptions = {}): MethodDecorator {
|
|
252
|
+
return function (
|
|
253
|
+
target: any,
|
|
254
|
+
propertyKey: string | symbol,
|
|
255
|
+
descriptor: PropertyDescriptor,
|
|
256
|
+
) {
|
|
257
|
+
const originalMethod = descriptor.value;
|
|
258
|
+
const className = target.constructor.name;
|
|
259
|
+
const methodName = String(propertyKey);
|
|
260
|
+
const spanName = options.name || \`\${className}.\${methodName}\`;
|
|
261
|
+
|
|
262
|
+
descriptor.value = async function (...args: any[]) {
|
|
263
|
+
const tracer = trace.getTracer('application');
|
|
264
|
+
const span = tracer.startSpan(spanName, {
|
|
265
|
+
kind: options.kind || SpanKind.INTERNAL,
|
|
266
|
+
attributes: {
|
|
267
|
+
'code.function': methodName,
|
|
268
|
+
'code.namespace': className,
|
|
269
|
+
...options.attributes,
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
if (options.recordArgs) {
|
|
274
|
+
try {
|
|
275
|
+
span.setAttribute('args', JSON.stringify(args));
|
|
276
|
+
} catch {
|
|
277
|
+
// Ignore serialization errors
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
const result = await context.with(
|
|
283
|
+
trace.setSpan(context.active(), span),
|
|
284
|
+
() => originalMethod.apply(this, args),
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
if (options.recordResult) {
|
|
288
|
+
try {
|
|
289
|
+
span.setAttribute('result', JSON.stringify(result));
|
|
290
|
+
} catch {
|
|
291
|
+
// Ignore serialization errors
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
296
|
+
return result;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
span.setStatus({
|
|
299
|
+
code: SpanStatusCode.ERROR,
|
|
300
|
+
message: (error as Error).message,
|
|
301
|
+
});
|
|
302
|
+
span.recordException(error as Error);
|
|
303
|
+
throw error;
|
|
304
|
+
} finally {
|
|
305
|
+
span.end();
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
return descriptor;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Trace incoming requests
|
|
315
|
+
*/
|
|
316
|
+
export function TraceIncoming(options: SpanOptions = {}): MethodDecorator {
|
|
317
|
+
return Span({ ...options, kind: SpanKind.SERVER });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Trace outgoing requests
|
|
322
|
+
*/
|
|
323
|
+
export function TraceOutgoing(options: SpanOptions = {}): MethodDecorator {
|
|
324
|
+
return Span({ ...options, kind: SpanKind.CLIENT });
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Trace internal operations
|
|
329
|
+
*/
|
|
330
|
+
export function TraceInternal(options: SpanOptions = {}): MethodDecorator {
|
|
331
|
+
return Span({ ...options, kind: SpanKind.INTERNAL });
|
|
332
|
+
}
|
|
333
|
+
`;
|
|
334
|
+
}
|
|
335
|
+
function generateTraceInterceptor() {
|
|
336
|
+
return `/**
|
|
337
|
+
* Trace Interceptor
|
|
338
|
+
* Automatically trace all HTTP requests
|
|
339
|
+
*/
|
|
340
|
+
|
|
341
|
+
import {
|
|
342
|
+
Injectable,
|
|
343
|
+
NestInterceptor,
|
|
344
|
+
ExecutionContext,
|
|
345
|
+
CallHandler,
|
|
346
|
+
} from '@nestjs/common';
|
|
347
|
+
import { Observable } from 'rxjs';
|
|
348
|
+
import { tap } from 'rxjs/operators';
|
|
349
|
+
import { trace, SpanKind, SpanStatusCode, context } from '@opentelemetry/api';
|
|
350
|
+
|
|
351
|
+
@Injectable()
|
|
352
|
+
export class TraceInterceptor implements NestInterceptor {
|
|
353
|
+
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
|
|
354
|
+
const request = ctx.switchToHttp().getRequest();
|
|
355
|
+
const response = ctx.switchToHttp().getResponse();
|
|
356
|
+
const tracer = trace.getTracer('http');
|
|
357
|
+
|
|
358
|
+
const span = tracer.startSpan(\`HTTP \${request.method} \${request.route?.path || request.path}\`, {
|
|
359
|
+
kind: SpanKind.SERVER,
|
|
360
|
+
attributes: {
|
|
361
|
+
'http.method': request.method,
|
|
362
|
+
'http.url': request.url,
|
|
363
|
+
'http.route': request.route?.path,
|
|
364
|
+
'http.user_agent': request.headers['user-agent'],
|
|
365
|
+
'http.client_ip': request.ip,
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// Add trace headers for propagation
|
|
370
|
+
const traceId = span.spanContext().traceId;
|
|
371
|
+
const spanId = span.spanContext().spanId;
|
|
372
|
+
response.setHeader('X-Trace-Id', traceId);
|
|
373
|
+
response.setHeader('X-Span-Id', spanId);
|
|
374
|
+
|
|
375
|
+
return context.with(trace.setSpan(context.active(), span), () => {
|
|
376
|
+
return next.handle().pipe(
|
|
377
|
+
tap({
|
|
378
|
+
next: () => {
|
|
379
|
+
span.setAttribute('http.status_code', response.statusCode);
|
|
380
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
381
|
+
},
|
|
382
|
+
error: (error) => {
|
|
383
|
+
span.setAttribute('http.status_code', error.status || 500);
|
|
384
|
+
span.setStatus({
|
|
385
|
+
code: SpanStatusCode.ERROR,
|
|
386
|
+
message: error.message,
|
|
387
|
+
});
|
|
388
|
+
span.recordException(error);
|
|
389
|
+
},
|
|
390
|
+
complete: () => {
|
|
391
|
+
span.end();
|
|
392
|
+
},
|
|
393
|
+
}),
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Trace context middleware
|
|
401
|
+
*/
|
|
402
|
+
export function traceContextMiddleware(req: any, res: any, next: () => void): void {
|
|
403
|
+
const tracer = trace.getTracer('http');
|
|
404
|
+
const span = tracer.startSpan(\`\${req.method} \${req.path}\`, {
|
|
405
|
+
kind: SpanKind.SERVER,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
req.span = span;
|
|
409
|
+
req.traceId = span.spanContext().traceId;
|
|
410
|
+
|
|
411
|
+
res.on('finish', () => {
|
|
412
|
+
span.setAttribute('http.status_code', res.statusCode);
|
|
413
|
+
span.end();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
context.with(trace.setSpan(context.active(), span), next);
|
|
417
|
+
}
|
|
418
|
+
`;
|
|
419
|
+
}
|
|
420
|
+
function generateTraceContext() {
|
|
421
|
+
return `/**
|
|
422
|
+
* Trace Context Propagation
|
|
423
|
+
* Handle trace context across service boundaries
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
import { trace, context, propagation, SpanContext } from '@opentelemetry/api';
|
|
427
|
+
|
|
428
|
+
export interface TraceHeaders {
|
|
429
|
+
'traceparent'?: string;
|
|
430
|
+
'tracestate'?: string;
|
|
431
|
+
'x-trace-id'?: string;
|
|
432
|
+
'x-span-id'?: string;
|
|
433
|
+
'x-request-id'?: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Extract trace context from headers
|
|
438
|
+
*/
|
|
439
|
+
export function extractTraceContext(headers: Record<string, string | string[] | undefined>): void {
|
|
440
|
+
const carrier: Record<string, string> = {};
|
|
441
|
+
|
|
442
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
443
|
+
if (typeof value === 'string') {
|
|
444
|
+
carrier[key.toLowerCase()] = value;
|
|
445
|
+
} else if (Array.isArray(value) && value.length > 0) {
|
|
446
|
+
carrier[key.toLowerCase()] = value[0];
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
propagation.extract(context.active(), carrier);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Inject trace context into headers
|
|
455
|
+
*/
|
|
456
|
+
export function injectTraceContext(headers: Record<string, string> = {}): Record<string, string> {
|
|
457
|
+
propagation.inject(context.active(), headers);
|
|
458
|
+
return headers;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Get current trace ID
|
|
463
|
+
*/
|
|
464
|
+
export function getCurrentTraceId(): string | undefined {
|
|
465
|
+
const span = trace.getSpan(context.active());
|
|
466
|
+
return span?.spanContext().traceId;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Get current span ID
|
|
471
|
+
*/
|
|
472
|
+
export function getCurrentSpanId(): string | undefined {
|
|
473
|
+
const span = trace.getSpan(context.active());
|
|
474
|
+
return span?.spanContext().spanId;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Create trace headers for outgoing requests
|
|
479
|
+
*/
|
|
480
|
+
export function createTraceHeaders(): TraceHeaders {
|
|
481
|
+
const headers: TraceHeaders = {};
|
|
482
|
+
injectTraceContext(headers as any);
|
|
483
|
+
|
|
484
|
+
const traceId = getCurrentTraceId();
|
|
485
|
+
const spanId = getCurrentSpanId();
|
|
486
|
+
|
|
487
|
+
if (traceId) headers['x-trace-id'] = traceId;
|
|
488
|
+
if (spanId) headers['x-span-id'] = spanId;
|
|
489
|
+
|
|
490
|
+
return headers;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Correlation ID manager
|
|
495
|
+
*/
|
|
496
|
+
export class CorrelationIdManager {
|
|
497
|
+
private static readonly CORRELATION_ID_KEY = 'correlation-id';
|
|
498
|
+
|
|
499
|
+
static get(): string | undefined {
|
|
500
|
+
const span = trace.getSpan(context.active());
|
|
501
|
+
return span?.spanContext().traceId;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
static set(id: string): void {
|
|
505
|
+
const span = trace.getSpan(context.active());
|
|
506
|
+
span?.setAttribute(this.CORRELATION_ID_KEY, id);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
static generate(): string {
|
|
510
|
+
return \`\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}\`;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Request context for passing trace info
|
|
516
|
+
*/
|
|
517
|
+
export class RequestContext {
|
|
518
|
+
private static readonly storage = new Map<string, any>();
|
|
519
|
+
|
|
520
|
+
static set(key: string, value: any): void {
|
|
521
|
+
const traceId = getCurrentTraceId() || 'default';
|
|
522
|
+
const contextKey = \`\${traceId}:\${key}\`;
|
|
523
|
+
this.storage.set(contextKey, value);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
static get<T>(key: string): T | undefined {
|
|
527
|
+
const traceId = getCurrentTraceId() || 'default';
|
|
528
|
+
const contextKey = \`\${traceId}:\${key}\`;
|
|
529
|
+
return this.storage.get(contextKey) as T;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
static clear(): void {
|
|
533
|
+
const traceId = getCurrentTraceId() || 'default';
|
|
534
|
+
for (const key of this.storage.keys()) {
|
|
535
|
+
if (key.startsWith(\`\${traceId}:\`)) {
|
|
536
|
+
this.storage.delete(key);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
`;
|
|
542
|
+
}
|
|
543
|
+
function generateMetrics() {
|
|
544
|
+
return `/**
|
|
545
|
+
* Metrics Collection
|
|
546
|
+
* Custom metrics for observability
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
import { metrics, Counter, Histogram, UpDownCounter, Gauge } from '@opentelemetry/api';
|
|
550
|
+
|
|
551
|
+
export interface MetricLabels {
|
|
552
|
+
[key: string]: string | number;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Metrics registry
|
|
557
|
+
*/
|
|
558
|
+
export class MetricsRegistry {
|
|
559
|
+
private readonly meter = metrics.getMeter('application');
|
|
560
|
+
private readonly counters = new Map<string, Counter>();
|
|
561
|
+
private readonly histograms = new Map<string, Histogram>();
|
|
562
|
+
private readonly gauges = new Map<string, any>();
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Get or create a counter
|
|
566
|
+
*/
|
|
567
|
+
counter(name: string, description?: string): Counter {
|
|
568
|
+
let counter = this.counters.get(name);
|
|
569
|
+
if (!counter) {
|
|
570
|
+
counter = this.meter.createCounter(name, { description });
|
|
571
|
+
this.counters.set(name, counter);
|
|
572
|
+
}
|
|
573
|
+
return counter;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Get or create a histogram
|
|
578
|
+
*/
|
|
579
|
+
histogram(name: string, description?: string): Histogram {
|
|
580
|
+
let histogram = this.histograms.get(name);
|
|
581
|
+
if (!histogram) {
|
|
582
|
+
histogram = this.meter.createHistogram(name, { description });
|
|
583
|
+
this.histograms.set(name, histogram);
|
|
584
|
+
}
|
|
585
|
+
return histogram;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Increment a counter
|
|
590
|
+
*/
|
|
591
|
+
increment(name: string, value: number = 1, labels?: MetricLabels): void {
|
|
592
|
+
this.counter(name).add(value, labels);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Record a histogram value
|
|
597
|
+
*/
|
|
598
|
+
record(name: string, value: number, labels?: MetricLabels): void {
|
|
599
|
+
this.histogram(name).record(value, labels);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Time a function execution
|
|
604
|
+
*/
|
|
605
|
+
async time<T>(name: string, fn: () => Promise<T>, labels?: MetricLabels): Promise<T> {
|
|
606
|
+
const start = Date.now();
|
|
607
|
+
try {
|
|
608
|
+
return await fn();
|
|
609
|
+
} finally {
|
|
610
|
+
this.record(name, Date.now() - start, labels);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Default metrics registry
|
|
617
|
+
*/
|
|
618
|
+
export const metricsRegistry = new MetricsRegistry();
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Metric decorator
|
|
622
|
+
*/
|
|
623
|
+
export function Metric(name: string, type: 'counter' | 'histogram' = 'histogram'): MethodDecorator {
|
|
624
|
+
return function (
|
|
625
|
+
target: any,
|
|
626
|
+
propertyKey: string | symbol,
|
|
627
|
+
descriptor: PropertyDescriptor,
|
|
628
|
+
) {
|
|
629
|
+
const originalMethod = descriptor.value;
|
|
630
|
+
|
|
631
|
+
descriptor.value = async function (...args: any[]) {
|
|
632
|
+
const labels = {
|
|
633
|
+
class: target.constructor.name,
|
|
634
|
+
method: String(propertyKey),
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
if (type === 'counter') {
|
|
638
|
+
metricsRegistry.increment(name, 1, labels);
|
|
639
|
+
return originalMethod.apply(this, args);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return metricsRegistry.time(\`\${name}_duration_ms\`, () => originalMethod.apply(this, args), labels);
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
return descriptor;
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Common application metrics
|
|
651
|
+
*/
|
|
652
|
+
export const AppMetrics = {
|
|
653
|
+
httpRequestsTotal: (method: string, path: string, status: number) => {
|
|
654
|
+
metricsRegistry.increment('http_requests_total', 1, { method, path, status: String(status) });
|
|
655
|
+
},
|
|
656
|
+
|
|
657
|
+
httpRequestDuration: (method: string, path: string, durationMs: number) => {
|
|
658
|
+
metricsRegistry.record('http_request_duration_ms', durationMs, { method, path });
|
|
659
|
+
},
|
|
660
|
+
|
|
661
|
+
dbQueryDuration: (operation: string, table: string, durationMs: number) => {
|
|
662
|
+
metricsRegistry.record('db_query_duration_ms', durationMs, { operation, table });
|
|
663
|
+
},
|
|
664
|
+
|
|
665
|
+
externalCallDuration: (service: string, operation: string, durationMs: number) => {
|
|
666
|
+
metricsRegistry.record('external_call_duration_ms', durationMs, { service, operation });
|
|
667
|
+
},
|
|
668
|
+
|
|
669
|
+
errorCount: (type: string, service: string) => {
|
|
670
|
+
metricsRegistry.increment('errors_total', 1, { type, service });
|
|
671
|
+
},
|
|
672
|
+
|
|
673
|
+
cacheHit: (cache: string) => {
|
|
674
|
+
metricsRegistry.increment('cache_hits_total', 1, { cache });
|
|
675
|
+
},
|
|
676
|
+
|
|
677
|
+
cacheMiss: (cache: string) => {
|
|
678
|
+
metricsRegistry.increment('cache_misses_total', 1, { cache });
|
|
679
|
+
},
|
|
680
|
+
};
|
|
681
|
+
`;
|
|
682
|
+
}
|
|
683
|
+
function generateObservabilityModule() {
|
|
684
|
+
return `import { Module, Global, DynamicModule, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
685
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
686
|
+
import { TraceInterceptor } from './trace.interceptor';
|
|
687
|
+
import { initTracing, shutdownTracing, TracingConfig } from './tracing.setup';
|
|
688
|
+
import { MetricsRegistry, metricsRegistry } from './metrics';
|
|
689
|
+
|
|
690
|
+
export interface ObservabilityModuleOptions {
|
|
691
|
+
tracing?: Partial<TracingConfig>;
|
|
692
|
+
enableHttpTracing?: boolean;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
@Global()
|
|
696
|
+
@Module({})
|
|
697
|
+
export class ObservabilityModule implements OnModuleInit, OnModuleDestroy {
|
|
698
|
+
static options: ObservabilityModuleOptions = {};
|
|
699
|
+
|
|
700
|
+
static forRoot(options: ObservabilityModuleOptions = {}): DynamicModule {
|
|
701
|
+
this.options = options;
|
|
702
|
+
|
|
703
|
+
const providers: any[] = [
|
|
704
|
+
{
|
|
705
|
+
provide: 'OBSERVABILITY_OPTIONS',
|
|
706
|
+
useValue: options,
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
provide: MetricsRegistry,
|
|
710
|
+
useValue: metricsRegistry,
|
|
711
|
+
},
|
|
712
|
+
];
|
|
713
|
+
|
|
714
|
+
if (options.enableHttpTracing !== false) {
|
|
715
|
+
providers.push({
|
|
716
|
+
provide: APP_INTERCEPTOR,
|
|
717
|
+
useClass: TraceInterceptor,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
return {
|
|
722
|
+
module: ObservabilityModule,
|
|
723
|
+
providers,
|
|
724
|
+
exports: [MetricsRegistry],
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
async onModuleInit() {
|
|
729
|
+
if (ObservabilityModule.options.tracing) {
|
|
730
|
+
await initTracing(ObservabilityModule.options.tracing);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
async onModuleDestroy() {
|
|
735
|
+
await shutdownTracing();
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
`;
|
|
739
|
+
}
|
|
740
|
+
//# sourceMappingURL=observability-tracing.js.map
|