@vtvlive/interactive-apm 0.0.2

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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +320 -0
  3. package/dist/factories/tracing-provider.factory.d.ts +81 -0
  4. package/dist/factories/tracing-provider.factory.d.ts.map +1 -0
  5. package/dist/factories/tracing-provider.factory.js +93 -0
  6. package/dist/index.d.ts +11 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +35 -0
  9. package/dist/init/elastic-apm-init.d.ts +51 -0
  10. package/dist/init/elastic-apm-init.d.ts.map +1 -0
  11. package/dist/init/elastic-apm-init.js +86 -0
  12. package/dist/init/opentelemetry-init.d.ts +51 -0
  13. package/dist/init/opentelemetry-init.d.ts.map +1 -0
  14. package/dist/init/opentelemetry-init.js +156 -0
  15. package/dist/interfaces/tracing-provider.interface.d.ts +43 -0
  16. package/dist/interfaces/tracing-provider.interface.d.ts.map +1 -0
  17. package/dist/interfaces/tracing-provider.interface.js +2 -0
  18. package/dist/modules/tracing.module.d.ts +96 -0
  19. package/dist/modules/tracing.module.d.ts.map +1 -0
  20. package/dist/modules/tracing.module.js +162 -0
  21. package/dist/providers/elastic-apm.tracing-provider.d.ts +57 -0
  22. package/dist/providers/elastic-apm.tracing-provider.d.ts.map +1 -0
  23. package/dist/providers/elastic-apm.tracing-provider.js +163 -0
  24. package/dist/providers/opentelemetry.tracing-provider.d.ts +68 -0
  25. package/dist/providers/opentelemetry.tracing-provider.d.ts.map +1 -0
  26. package/dist/providers/opentelemetry.tracing-provider.js +288 -0
  27. package/dist/services/tracing.service.d.ts +88 -0
  28. package/dist/services/tracing.service.d.ts.map +1 -0
  29. package/dist/services/tracing.service.js +103 -0
  30. package/dist/types/apm-provider.type.d.ts +47 -0
  31. package/dist/types/apm-provider.type.d.ts.map +1 -0
  32. package/dist/types/apm-provider.type.js +32 -0
  33. package/dist/utils/tracing.helper.d.ts +68 -0
  34. package/dist/utils/tracing.helper.d.ts.map +1 -0
  35. package/dist/utils/tracing.helper.js +115 -0
  36. package/package.json +105 -0
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * Elastic APM Initialization (Standalone)
4
+ *
5
+ * Use this to initialize Elastic APM agent before your application starts.
6
+ * This is useful for non-NestJS applications or when you need manual control.
7
+ *
8
+ * @example
9
+ * import { initElasticApm } from '@vtvlive/interactive-apm';
10
+ *
11
+ * // Initialize at the top of your application
12
+ * initElasticApm({
13
+ * serviceName: 'my-service',
14
+ * serverUrl: 'http://localhost:8200',
15
+ * environment: 'production',
16
+ * });
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.shouldUseElasticApm = shouldUseElasticApm;
20
+ exports.initElasticApm = initElasticApm;
21
+ exports.isElasticApmStarted = isElasticApmStarted;
22
+ exports.getElasticApmAgent = getElasticApmAgent;
23
+ const apm_provider_type_1 = require("../types/apm-provider.type");
24
+ /**
25
+ * Check if APM should use Elastic APM provider based on configuration
26
+ * @returns true if Elastic APM should be used
27
+ */
28
+ function shouldUseElasticApm() {
29
+ const provider = process.env.APM_PROVIDER || apm_provider_type_1.ApmProvider.OPENTELEMETRY;
30
+ return provider === apm_provider_type_1.ApmProvider.ELASTIC_APM || provider === 'elastic-apm';
31
+ }
32
+ /**
33
+ * Initialize Elastic APM agent for standalone usage
34
+ *
35
+ * @param options Configuration options
36
+ * @returns The APM agent instance
37
+ */
38
+ function initElasticApm(options = {}) {
39
+ // @ts-ignore - Optional peer dependency
40
+ const apm = require('elastic-apm-node');
41
+ // If already started, return the instance
42
+ if (apm.isStarted()) {
43
+ return apm;
44
+ }
45
+ // Start the agent
46
+ const agent = apm.start({
47
+ serviceName: options.serviceName || process.env.ELASTIC_APM_SERVICE_NAME || 'interactive-backend',
48
+ serverUrl: options.serverUrl || process.env.ELASTIC_APM_SERVER_URL || 'http://localhost:8200',
49
+ secretToken: options.secretToken || process.env.ELASTIC_APM_SECRET_TOKEN,
50
+ serviceVersion: options.serviceVersion || process.env.npm_package_version || '1.0.0',
51
+ environment: options.environment || process.env.ELASTIC_APM_ENVIRONMENT || 'development',
52
+ logLevel: options.logLevel || 'error',
53
+ });
54
+ console.log(`[ElasticAPM] Service: ${agent.getServiceName()}, Environment: ${agent.conf.environment}`);
55
+ console.log('[ElasticAPM] Initialized');
56
+ return agent;
57
+ }
58
+ /**
59
+ * Check if Elastic APM agent is started
60
+ */
61
+ function isElasticApmStarted() {
62
+ try {
63
+ // @ts-ignore - Optional peer dependency
64
+ const apm = require('elastic-apm-node');
65
+ return apm.isStarted();
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ /**
72
+ * Get the Elastic APM agent instance
73
+ */
74
+ function getElasticApmAgent() {
75
+ try {
76
+ // @ts-ignore - Optional peer dependency
77
+ const apm = require('elastic-apm-node');
78
+ if (apm.isStarted()) {
79
+ return apm;
80
+ }
81
+ return null;
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * OpenTelemetry Initialization (Standalone)
3
+ *
4
+ * Use this to initialize OpenTelemetry SDK for standalone usage.
5
+ * This is useful for non-NestJS applications or when you need manual control.
6
+ *
7
+ * @example
8
+ * import { initOpenTelemetry } from '@vtvlive/interactive-apm';
9
+ *
10
+ * // Initialize at the top of your application
11
+ * const sdk = initOpenTelemetry({
12
+ * serviceName: 'my-service',
13
+ * otlpEndpoint: 'http://localhost:8200/v1/traces',
14
+ * environment: 'production',
15
+ * });
16
+ */
17
+ export interface OpenTelemetryInitOptions {
18
+ /** Service name for APM */
19
+ serviceName?: string;
20
+ /** OTLP endpoint URL */
21
+ otlpEndpoint?: string;
22
+ /** Secret token for authentication */
23
+ secretToken?: string;
24
+ /** OTLP auth token (takes precedence over secretToken for OTLP) */
25
+ otlpAuthToken?: string;
26
+ /** OTLP headers as a record (key-value pairs). If provided, merges with Authorization header when token is set. */
27
+ otlpHeaders?: Record<string, string>;
28
+ /** Service version */
29
+ serviceVersion?: string;
30
+ /** Deployment environment */
31
+ environment?: string;
32
+ /** Enable console exporter for debugging */
33
+ enableConsoleExporter?: boolean;
34
+ /** Enable HTTP instrumentation */
35
+ enableHttpInstrumentation?: boolean;
36
+ /** Enable Express instrumentation */
37
+ enableExpressInstrumentation?: boolean;
38
+ }
39
+ /**
40
+ * Check if APM should use OpenTelemetry provider based on configuration
41
+ * @returns true if OpenTelemetry should be used
42
+ */
43
+ export declare function shouldUseOpenTelemetry(): boolean;
44
+ /**
45
+ * Initialize OpenTelemetry SDK for standalone usage
46
+ *
47
+ * @param options Configuration options
48
+ * @returns The NodeSDK instance
49
+ */
50
+ export declare function initOpenTelemetry(options?: OpenTelemetryInitOptions): Promise<any>;
51
+ //# sourceMappingURL=opentelemetry-init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opentelemetry-init.d.ts","sourceRoot":"","sources":["../../src/init/opentelemetry-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,wBAAwB;IACvC,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mHAAmH;IACnH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kCAAkC;IAClC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,qCAAqC;IACrC,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,GAAG,CAAC,CAyG5F"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * OpenTelemetry Initialization (Standalone)
4
+ *
5
+ * Use this to initialize OpenTelemetry SDK for standalone usage.
6
+ * This is useful for non-NestJS applications or when you need manual control.
7
+ *
8
+ * @example
9
+ * import { initOpenTelemetry } from '@vtvlive/interactive-apm';
10
+ *
11
+ * // Initialize at the top of your application
12
+ * const sdk = initOpenTelemetry({
13
+ * serviceName: 'my-service',
14
+ * otlpEndpoint: 'http://localhost:8200/v1/traces',
15
+ * environment: 'production',
16
+ * });
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.shouldUseOpenTelemetry = shouldUseOpenTelemetry;
53
+ exports.initOpenTelemetry = initOpenTelemetry;
54
+ const apm_provider_type_1 = require("../types/apm-provider.type");
55
+ /**
56
+ * Check if APM should use OpenTelemetry provider based on configuration
57
+ * @returns true if OpenTelemetry should be used
58
+ */
59
+ function shouldUseOpenTelemetry() {
60
+ const provider = process.env.APM_PROVIDER || apm_provider_type_1.ApmProvider.OPENTELEMETRY;
61
+ return provider !== apm_provider_type_1.ApmProvider.ELASTIC_APM && provider !== 'elastic-apm';
62
+ }
63
+ /**
64
+ * Initialize OpenTelemetry SDK for standalone usage
65
+ *
66
+ * @param options Configuration options
67
+ * @returns The NodeSDK instance
68
+ */
69
+ async function initOpenTelemetry(options = {}) {
70
+ // @ts-ignore - Optional peer dependency
71
+ const { NodeSDK } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/sdk-node')));
72
+ // @ts-ignore - Optional peer dependency
73
+ const { resourceFromAttributes } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/resources')));
74
+ // @ts-ignore - Optional peer dependency
75
+ const { OTLPTraceExporter } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/exporter-trace-otlp-http')));
76
+ console.log('[OpenTelemetry] Initializing...');
77
+ const serviceName = options.serviceName || process.env.ELASTIC_APM_SERVICE_NAME || 'interactive-backend';
78
+ const environment = options.environment || process.env.ELASTIC_APM_ENVIRONMENT || 'development';
79
+ const otlpEndpoint = options.otlpEndpoint || process.env.ELASTIC_OTLP_ENDPOINT || 'http://localhost:8200/v1/traces';
80
+ const secretToken = options.secretToken || process.env.ELASTIC_APM_SECRET_TOKEN;
81
+ const otlpAuthToken = options.otlpAuthToken || process.env.ELASTIC_OTLP_AUTH_TOKEN;
82
+ // Build headers: merge options.otlpHeaders with Authorization if token is provided
83
+ const headers = { ...options.otlpHeaders };
84
+ const token = otlpAuthToken || secretToken;
85
+ if (token) {
86
+ headers['Authorization'] = `Bearer ${token}`;
87
+ }
88
+ console.log(`[OpenTelemetry] Service: ${serviceName}, Environment: ${environment}`);
89
+ console.log(`[OpenTelemetry] Endpoint: ${otlpEndpoint}`);
90
+ // Build exporters array
91
+ const exporters = [];
92
+ // OTLP Exporter with detailed logging
93
+ const otlpExporterBase = new OTLPTraceExporter({
94
+ url: otlpEndpoint,
95
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
96
+ });
97
+ // Wrap OTLP exporter - only log errors
98
+ const otlpExporter = {
99
+ export: (spans, resultCallback) => {
100
+ otlpExporterBase.export(spans, (result) => {
101
+ if (result.error) {
102
+ console.error(`[OpenTelemetry] Export failed: ${result.error instanceof Error ? result.error.message : result.error}`);
103
+ }
104
+ resultCallback(result);
105
+ });
106
+ },
107
+ shutdown: async () => {
108
+ await otlpExporterBase.shutdown();
109
+ },
110
+ };
111
+ exporters.push(otlpExporter);
112
+ // Console Exporter for debugging
113
+ if (options.enableConsoleExporter ?? process.env.ELASTIC_OTLP_ENABLE_CONSOLE_EXPORTER === 'true') {
114
+ // @ts-ignore - Optional peer dependency
115
+ const { ConsoleSpanExporter } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/sdk-trace-base')));
116
+ exporters.push(new ConsoleSpanExporter());
117
+ }
118
+ // Build instrumentations array
119
+ const instrumentations = [];
120
+ if (options.enableHttpInstrumentation !== false) {
121
+ // @ts-ignore - Optional peer dependency
122
+ const { HttpInstrumentation } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/instrumentation-http')));
123
+ instrumentations.push(new HttpInstrumentation());
124
+ }
125
+ if (options.enableExpressInstrumentation !== false) {
126
+ // @ts-ignore - Optional peer dependency
127
+ const { ExpressInstrumentation } = await Promise.resolve().then(() => __importStar(require('@opentelemetry/instrumentation-express')));
128
+ instrumentations.push(new ExpressInstrumentation());
129
+ }
130
+ // Resource attributes
131
+ const sdkResource = resourceFromAttributes({
132
+ 'service.name': serviceName,
133
+ 'deployment.environment': environment,
134
+ 'service.version': options.serviceVersion || process.env.npm_package_version || '1.0.0',
135
+ 'service.instance.id': `${process.pid}`,
136
+ 'host.name': require('os').hostname(),
137
+ });
138
+ // Initialize SDK
139
+ const sdk = new NodeSDK({
140
+ serviceName,
141
+ traceExporter: exporters.length === 1 ? exporters[0] : exporters, // Handle single/multiple exporters
142
+ instrumentations,
143
+ resource: sdkResource,
144
+ });
145
+ // Start SDK
146
+ sdk.start();
147
+ console.log('[OpenTelemetry] Initialized');
148
+ // Setup graceful shutdown handlers
149
+ const shutdown = async () => {
150
+ await sdk.shutdown();
151
+ process.exit(0);
152
+ };
153
+ process.on('SIGTERM', shutdown);
154
+ process.on('SIGINT', shutdown);
155
+ return sdk;
156
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Interface chung cho APM Tracing Provider
3
+ * Cho phép switch giữa OpenTelemetry và Elastic APM thông qua DI
4
+ */
5
+ export interface ITracingProvider {
6
+ /**
7
+ * Bắt đầu một span mới để trace operation
8
+ * @param name Tên của span
9
+ * @param attributes Các attributes metadata
10
+ * @param spanKind Loại span (INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER)
11
+ * @returns Span object - cần gọi end() khi hoàn thành
12
+ */
13
+ startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string): any;
14
+ /**
15
+ * Thực thi function với context tracing (auto-close span)
16
+ * @param name Tên của span
17
+ * @param fn Function cần trace
18
+ * @param attributes Các attributes metadata
19
+ * @returns Kết quả của function
20
+ */
21
+ startSpanWithParent<T>(name: string, fn: (span: any) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
22
+ /**
23
+ * Capture error vào active span hiện tại
24
+ * @param error Error object
25
+ */
26
+ captureError(error: Error): void;
27
+ /**
28
+ * Set attribute cho active span hiện tại
29
+ * @param key Tên attribute
30
+ * @param value Giá trị attribute
31
+ */
32
+ setAttribute(key: string, value: string | number): void;
33
+ /**
34
+ * Kết thúc span manually
35
+ * @param span Span cần end (nếu không truyền, sẽ end active span)
36
+ */
37
+ endSpan(span?: any): void;
38
+ /**
39
+ * Flush và shutdown provider (cho graceful shutdown)
40
+ */
41
+ shutdown(): Promise<void>;
42
+ }
43
+ //# sourceMappingURL=tracing-provider.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/tracing-provider.interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAE9F;;;;;;OAMG;IACH,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9H;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEjC;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAExD;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,96 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { ApmProvider } from '../types/apm-provider.type';
3
+ /**
4
+ * Options for configuring TracingModule
5
+ */
6
+ export interface TracingModuleOptions {
7
+ /** Provider type: 'elastic-apm' or 'opentelemetry' (default: from env or 'opentelemetry') */
8
+ provider?: ApmProvider | string;
9
+ /** Service name for APM */
10
+ serviceName?: string;
11
+ /** Deployment environment */
12
+ environment?: string;
13
+ /** Elastic APM server URL (for elastic-apm provider) */
14
+ serverUrl?: string;
15
+ /** Secret token for authentication */
16
+ secretToken?: string;
17
+ /** OTLP endpoint URL (for opentelemetry provider) */
18
+ otlpEndpoint?: string;
19
+ /** Service version */
20
+ serviceVersion?: string;
21
+ /** Auto-initialize the provider on module init */
22
+ autoInit?: boolean;
23
+ }
24
+ /**
25
+ * TracingModule - Module cung cấp APM Tracing functionality cho NestJS
26
+ *
27
+ * Sử dụng decorator @Global để TracingService có thể được inject ở mọi nơi
28
+ * mà không cần import module vào từng module con.
29
+ *
30
+ * @example
31
+ * // Trong app.module.ts - Basic usage (reads from environment)
32
+ * import { TracingModule } from '@vtvlive/interactive-apm';
33
+ *
34
+ * @Module({
35
+ * imports: [
36
+ * TracingModule.registerAsync(),
37
+ * // ... other modules
38
+ * ],
39
+ * })
40
+ * export class AppModule {}
41
+ *
42
+ * @example
43
+ * // Trong app.module.ts - With explicit options
44
+ * @Module({
45
+ * imports: [
46
+ * TracingModule.register({
47
+ * provider: 'opentelemetry',
48
+ * serviceName: 'my-service',
49
+ * otlpEndpoint: 'http://localhost:8200/v1/traces',
50
+ * }),
51
+ * // ... other modules
52
+ * ],
53
+ * })
54
+ * export class AppModule {}
55
+ *
56
+ * @example
57
+ * // Trong controller/service
58
+ * constructor(private readonly tracingService: TracingService) {}
59
+ *
60
+ * async someMethod() {
61
+ * const span = this.tracingService.startSpan('operation', {}, 'SERVER');
62
+ * try {
63
+ * // ... code
64
+ * } finally {
65
+ * span.end();
66
+ * }
67
+ * }
68
+ */
69
+ export declare class TracingModule {
70
+ /**
71
+ * Register module with synchronous options
72
+ */
73
+ static register(options?: TracingModuleOptions): DynamicModule;
74
+ /**
75
+ * Register module with asynchronous options (using ConfigService)
76
+ */
77
+ static registerAsync(options?: TracingModuleAsyncOptions): DynamicModule;
78
+ }
79
+ /**
80
+ * Async options for TracingModule
81
+ */
82
+ export interface TracingModuleAsyncOptions {
83
+ /**
84
+ * Optional list of modules to import for the factory to use
85
+ */
86
+ imports?: any[];
87
+ /**
88
+ * Factory function that returns the module options
89
+ */
90
+ useFactory?: (...args: any[]) => Promise<TracingModuleOptions> | TracingModuleOptions;
91
+ /**
92
+ * Optional list of providers to inject into the factory
93
+ */
94
+ inject?: any[];
95
+ }
96
+ //# sourceMappingURL=tracing.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.module.d.ts","sourceRoot":"","sources":["../../src/modules/tracing.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAChC,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qBAEa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa;IAoBlE;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,OAAO,GAAE,yBAA8B,GAAG,aAAa;CAgC7E;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;IAEtF;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;CAChB"}
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
37
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
38
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.TracingModule = void 0;
42
+ // @ts-ignore - Optional peer dependency
43
+ const common_1 = require("@nestjs/common");
44
+ const tracing_service_1 = require("../services/tracing.service");
45
+ const tracing_provider_factory_1 = require("../factories/tracing-provider.factory");
46
+ /**
47
+ * TracingModule - Module cung cấp APM Tracing functionality cho NestJS
48
+ *
49
+ * Sử dụng decorator @Global để TracingService có thể được inject ở mọi nơi
50
+ * mà không cần import module vào từng module con.
51
+ *
52
+ * @example
53
+ * // Trong app.module.ts - Basic usage (reads from environment)
54
+ * import { TracingModule } from '@vtvlive/interactive-apm';
55
+ *
56
+ * @Module({
57
+ * imports: [
58
+ * TracingModule.registerAsync(),
59
+ * // ... other modules
60
+ * ],
61
+ * })
62
+ * export class AppModule {}
63
+ *
64
+ * @example
65
+ * // Trong app.module.ts - With explicit options
66
+ * @Module({
67
+ * imports: [
68
+ * TracingModule.register({
69
+ * provider: 'opentelemetry',
70
+ * serviceName: 'my-service',
71
+ * otlpEndpoint: 'http://localhost:8200/v1/traces',
72
+ * }),
73
+ * // ... other modules
74
+ * ],
75
+ * })
76
+ * export class AppModule {}
77
+ *
78
+ * @example
79
+ * // Trong controller/service
80
+ * constructor(private readonly tracingService: TracingService) {}
81
+ *
82
+ * async someMethod() {
83
+ * const span = this.tracingService.startSpan('operation', {}, 'SERVER');
84
+ * try {
85
+ * // ... code
86
+ * } finally {
87
+ * span.end();
88
+ * }
89
+ * }
90
+ */
91
+ let TracingModule = (() => {
92
+ let _classDecorators = [(0, common_1.Global)(), (0, common_1.Module)({})];
93
+ let _classDescriptor;
94
+ let _classExtraInitializers = [];
95
+ let _classThis;
96
+ var TracingModule = _classThis = class {
97
+ /**
98
+ * Register module with synchronous options
99
+ */
100
+ static register(options = {}) {
101
+ const tracingProvider = (0, tracing_provider_factory_1.createTracingProvider)(options);
102
+ return {
103
+ module: TracingModule,
104
+ providers: [
105
+ {
106
+ provide: tracing_provider_factory_1.TRACING_PROVIDER_TOKEN,
107
+ useValue: tracingProvider,
108
+ },
109
+ {
110
+ provide: tracing_service_1.TracingService,
111
+ useFactory: (provider) => new tracing_service_1.TracingService(provider),
112
+ inject: [tracing_provider_factory_1.TRACING_PROVIDER_TOKEN],
113
+ },
114
+ ],
115
+ exports: [tracing_service_1.TracingService],
116
+ };
117
+ }
118
+ /**
119
+ * Register module with asynchronous options (using ConfigService)
120
+ */
121
+ static registerAsync(options = {}) {
122
+ return {
123
+ module: TracingModule,
124
+ imports: options.imports || [],
125
+ providers: [
126
+ {
127
+ provide: tracing_provider_factory_1.TRACING_PROVIDER_TOKEN,
128
+ useFactory: async (...args) => {
129
+ const config = options.useFactory ? await options.useFactory(...args) : {};
130
+ const provider = (0, tracing_provider_factory_1.createTracingProvider)(config);
131
+ // Auto-initialize if configured
132
+ if (config.autoInit !== false) {
133
+ // Check if provider has initialize method (not in interface)
134
+ if (provider.initialize && typeof provider.initialize === 'function') {
135
+ await provider.initialize();
136
+ }
137
+ }
138
+ return provider;
139
+ },
140
+ inject: options.inject || [],
141
+ },
142
+ {
143
+ provide: tracing_service_1.TracingService,
144
+ useFactory: (provider) => new tracing_service_1.TracingService(provider),
145
+ inject: [tracing_provider_factory_1.TRACING_PROVIDER_TOKEN],
146
+ },
147
+ ],
148
+ exports: [tracing_service_1.TracingService],
149
+ };
150
+ }
151
+ };
152
+ __setFunctionName(_classThis, "TracingModule");
153
+ (() => {
154
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
155
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
156
+ TracingModule = _classThis = _classDescriptor.value;
157
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
158
+ __runInitializers(_classThis, _classExtraInitializers);
159
+ })();
160
+ return TracingModule = _classThis;
161
+ })();
162
+ exports.TracingModule = TracingModule;
@@ -0,0 +1,57 @@
1
+ import { ITracingProvider } from '../interfaces/tracing-provider.interface';
2
+ /**
3
+ * Elastic APM Tracing Provider Implementation
4
+ * Sử dụng elastic-apm-node agent để gửi traces về Elastic APM server
5
+ */
6
+ export declare class ElasticApmTracingProvider implements ITracingProvider {
7
+ private apm;
8
+ private readonly serviceName;
9
+ private readonly environment;
10
+ constructor(config?: {
11
+ serviceName?: string;
12
+ environment?: string;
13
+ serverUrl?: string;
14
+ secretToken?: string;
15
+ serviceVersion?: string;
16
+ });
17
+ /**
18
+ * Initialize Elastic APM agent
19
+ * Should be called before using the provider
20
+ */
21
+ initialize(config?: {
22
+ serviceName?: string;
23
+ serverUrl?: string;
24
+ secretToken?: string;
25
+ environment?: string;
26
+ serviceVersion?: string;
27
+ }): void;
28
+ /**
29
+ * Bắt đầu một span mới
30
+ */
31
+ startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string): any;
32
+ /**
33
+ * Thực thi function với tracing context
34
+ */
35
+ startSpanWithParent<T>(name: string, fn: (span: any) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
36
+ /**
37
+ * Capture error vào APM
38
+ */
39
+ captureError(error: Error): void;
40
+ /**
41
+ * Set label cho current transaction/span
42
+ */
43
+ setAttribute(key: string, value: string | number): void;
44
+ /**
45
+ * End span manually
46
+ */
47
+ endSpan(span?: any): void;
48
+ /**
49
+ * Flush và shutdown gracefully
50
+ */
51
+ shutdown(): Promise<void>;
52
+ /**
53
+ * Map string span kind to Elastic APM span type
54
+ */
55
+ private mapSpanKindToType;
56
+ }
57
+ //# sourceMappingURL=elastic-apm.tracing-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elastic-apm.tracing-provider.d.ts","sourceRoot":"","sources":["../../src/providers/elastic-apm.tracing-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAE5E;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO;IAK1I;;;OAGG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA6B5I;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,QAAQ,GAAE,MAAmB,GAAG,GAAG;IAkDzG;;OAEG;IACG,mBAAmB,CAAC,CAAC,EACzB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,EAC7B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC;IAmBb;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMhC;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvD;;OAEG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAOzB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAe1B"}