@vtvlive/interactive-apm 0.0.2 → 0.0.4
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 +201 -123
- package/dist/factories/tracing-provider.factory.d.ts +8 -3
- package/dist/factories/tracing-provider.factory.d.ts.map +1 -1
- package/dist/factories/tracing-provider.factory.js +17 -13
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/init/elastic-apm-init.d.ts +25 -3
- package/dist/init/elastic-apm-init.d.ts.map +1 -1
- package/dist/init/elastic-apm-init.js +29 -12
- package/dist/init/opentelemetry-init.d.ts +8 -1
- package/dist/init/opentelemetry-init.d.ts.map +1 -1
- package/dist/init/opentelemetry-init.js +145 -44
- package/dist/interfaces/tracing-provider.interface.d.ts +13 -3
- package/dist/interfaces/tracing-provider.interface.d.ts.map +1 -1
- package/dist/modules/tracing.module.d.ts +5 -5
- package/dist/modules/tracing.module.d.ts.map +1 -1
- package/dist/modules/tracing.module.js +2 -1
- package/dist/providers/elastic-apm.tracing-provider.d.ts +23 -5
- package/dist/providers/elastic-apm.tracing-provider.d.ts.map +1 -1
- package/dist/providers/elastic-apm.tracing-provider.js +127 -28
- package/dist/providers/opentelemetry.tracing-provider.d.ts +12 -4
- package/dist/providers/opentelemetry.tracing-provider.d.ts.map +1 -1
- package/dist/providers/opentelemetry.tracing-provider.js +328 -67
- package/dist/services/tracing.service.d.ts +6 -5
- package/dist/services/tracing.service.d.ts.map +1 -1
- package/dist/services/tracing.service.js +2 -2
- package/dist/types/apm.types.d.ts +162 -0
- package/dist/types/apm.types.d.ts.map +1 -0
- package/dist/types/apm.types.js +37 -0
- package/dist/types/otlp-transport.type.d.ts +14 -0
- package/dist/types/otlp-transport.type.d.ts.map +1 -0
- package/dist/types/otlp-transport.type.js +17 -0
- package/dist/utils/debug-exporter-wrapper.d.ts +36 -0
- package/dist/utils/debug-exporter-wrapper.d.ts.map +1 -0
- package/dist/utils/debug-exporter-wrapper.js +247 -0
- package/dist/utils/debug-logger.d.ts +81 -0
- package/dist/utils/debug-logger.d.ts.map +1 -0
- package/dist/utils/debug-logger.js +236 -0
- package/dist/utils/tracing.helper.d.ts +2 -2
- package/dist/utils/tracing.helper.d.ts.map +1 -1
- package/dist/utils/tracing.helper.js +8 -4
- package/package.json +24 -3
|
@@ -26,7 +26,7 @@ export interface ElasticApmInitOptions {
|
|
|
26
26
|
/** Deployment environment */
|
|
27
27
|
environment?: string;
|
|
28
28
|
/** APM log level */
|
|
29
|
-
logLevel?:
|
|
29
|
+
logLevel?: "trace" | "debug" | "info" | "warn" | "error" | "off";
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Check if APM should use Elastic APM provider based on configuration
|
|
@@ -39,7 +39,18 @@ export declare function shouldUseElasticApm(): boolean;
|
|
|
39
39
|
* @param options Configuration options
|
|
40
40
|
* @returns The APM agent instance
|
|
41
41
|
*/
|
|
42
|
-
export declare function initElasticApm(options?: ElasticApmInitOptions):
|
|
42
|
+
export declare function initElasticApm(options?: ElasticApmInitOptions): {
|
|
43
|
+
isStarted(): boolean;
|
|
44
|
+
startTransaction(name: string, type: string): {
|
|
45
|
+
end(): void;
|
|
46
|
+
} | null;
|
|
47
|
+
startSpan(name: string, type: string): {
|
|
48
|
+
end(): void;
|
|
49
|
+
} | null;
|
|
50
|
+
captureError(error: Error): void;
|
|
51
|
+
setTransactionName(name: string): void;
|
|
52
|
+
flush(): Promise<void>;
|
|
53
|
+
} | null;
|
|
43
54
|
/**
|
|
44
55
|
* Check if Elastic APM agent is started
|
|
45
56
|
*/
|
|
@@ -47,5 +58,16 @@ export declare function isElasticApmStarted(): boolean;
|
|
|
47
58
|
/**
|
|
48
59
|
* Get the Elastic APM agent instance
|
|
49
60
|
*/
|
|
50
|
-
export declare function getElasticApmAgent():
|
|
61
|
+
export declare function getElasticApmAgent(): {
|
|
62
|
+
isStarted(): boolean;
|
|
63
|
+
startTransaction(name: string, type: string): {
|
|
64
|
+
end(): void;
|
|
65
|
+
} | null;
|
|
66
|
+
startSpan(name: string, type: string): {
|
|
67
|
+
end(): void;
|
|
68
|
+
} | null;
|
|
69
|
+
captureError(error: Error): void;
|
|
70
|
+
setTransactionName(name: string): void;
|
|
71
|
+
flush(): Promise<void>;
|
|
72
|
+
} | null;
|
|
51
73
|
//# sourceMappingURL=elastic-apm-init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elastic-apm-init.d.ts","sourceRoot":"","sources":["../../src/init/elastic-apm-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"elastic-apm-init.d.ts","sourceRoot":"","sources":["../../src/init/elastic-apm-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,WAAW,qBAAqB;IACpC,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;CAClE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG;IACnE,SAAS,IAAI,OAAO,CAAC;IACrB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,GAAG,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACrE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,GAAG,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9D,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,GAAG,IAAI,CA6CP;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAQ7C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,SAAS,IAAI,OAAO,CAAC;IACrB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,GAAG,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACrE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,GAAG,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9D,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,GAAG,IAAI,CAWP"}
|
|
@@ -21,13 +21,14 @@ exports.initElasticApm = initElasticApm;
|
|
|
21
21
|
exports.isElasticApmStarted = isElasticApmStarted;
|
|
22
22
|
exports.getElasticApmAgent = getElasticApmAgent;
|
|
23
23
|
const apm_provider_type_1 = require("../types/apm-provider.type");
|
|
24
|
+
const debug_logger_1 = require("../utils/debug-logger");
|
|
24
25
|
/**
|
|
25
26
|
* Check if APM should use Elastic APM provider based on configuration
|
|
26
27
|
* @returns true if Elastic APM should be used
|
|
27
28
|
*/
|
|
28
29
|
function shouldUseElasticApm() {
|
|
29
30
|
const provider = process.env.APM_PROVIDER || apm_provider_type_1.ApmProvider.OPENTELEMETRY;
|
|
30
|
-
return provider === apm_provider_type_1.ApmProvider.ELASTIC_APM || provider ===
|
|
31
|
+
return provider === apm_provider_type_1.ApmProvider.ELASTIC_APM || provider === "elastic-apm";
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* Initialize Elastic APM agent for standalone usage
|
|
@@ -37,22 +38,38 @@ function shouldUseElasticApm() {
|
|
|
37
38
|
*/
|
|
38
39
|
function initElasticApm(options = {}) {
|
|
39
40
|
// @ts-ignore - Optional peer dependency
|
|
40
|
-
const apm = require(
|
|
41
|
+
const apm = require("elastic-apm-node");
|
|
41
42
|
// If already started, return the instance
|
|
42
43
|
if (apm.isStarted()) {
|
|
43
44
|
return apm;
|
|
44
45
|
}
|
|
46
|
+
const serviceName = options.serviceName || process.env.ELASTIC_APM_SERVICE_NAME || "interactive-backend";
|
|
47
|
+
const serverUrl = options.serverUrl || process.env.ELASTIC_APM_SERVER_URL || "http://localhost:8200";
|
|
48
|
+
const secretToken = options.secretToken || process.env.ELASTIC_APM_SECRET_TOKEN;
|
|
49
|
+
const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
|
|
50
|
+
const environment = options.environment || process.env.ELASTIC_APM_ENVIRONMENT || "development";
|
|
51
|
+
// Log initialization details when debug mode is on
|
|
52
|
+
(0, debug_logger_1.logInitialization)("ElasticAPM", {
|
|
53
|
+
serviceName,
|
|
54
|
+
serverUrl,
|
|
55
|
+
hasSecretToken: !!secretToken,
|
|
56
|
+
serviceVersion,
|
|
57
|
+
environment,
|
|
58
|
+
logLevel: options.logLevel || "error",
|
|
59
|
+
});
|
|
45
60
|
// Start the agent
|
|
46
61
|
const agent = apm.start({
|
|
47
|
-
serviceName
|
|
48
|
-
serverUrl
|
|
49
|
-
secretToken
|
|
50
|
-
serviceVersion
|
|
51
|
-
environment
|
|
52
|
-
logLevel: options.logLevel ||
|
|
62
|
+
serviceName,
|
|
63
|
+
serverUrl,
|
|
64
|
+
secretToken,
|
|
65
|
+
serviceVersion,
|
|
66
|
+
environment,
|
|
67
|
+
logLevel: options.logLevel || "error",
|
|
53
68
|
});
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
if ((0, debug_logger_1.isDebugEnabled)()) {
|
|
70
|
+
(0, debug_logger_1.infoLog)(`[ElasticAPM] Service: ${agent.getServiceName()}, Environment: ${agent.conf.environment}`);
|
|
71
|
+
(0, debug_logger_1.infoLog)("[ElasticAPM] Initialized");
|
|
72
|
+
}
|
|
56
73
|
return agent;
|
|
57
74
|
}
|
|
58
75
|
/**
|
|
@@ -61,7 +78,7 @@ function initElasticApm(options = {}) {
|
|
|
61
78
|
function isElasticApmStarted() {
|
|
62
79
|
try {
|
|
63
80
|
// @ts-ignore - Optional peer dependency
|
|
64
|
-
const apm = require(
|
|
81
|
+
const apm = require("elastic-apm-node");
|
|
65
82
|
return apm.isStarted();
|
|
66
83
|
}
|
|
67
84
|
catch {
|
|
@@ -74,7 +91,7 @@ function isElasticApmStarted() {
|
|
|
74
91
|
function getElasticApmAgent() {
|
|
75
92
|
try {
|
|
76
93
|
// @ts-ignore - Optional peer dependency
|
|
77
|
-
const apm = require(
|
|
94
|
+
const apm = require("elastic-apm-node");
|
|
78
95
|
if (apm.isStarted()) {
|
|
79
96
|
return apm;
|
|
80
97
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* environment: 'production',
|
|
15
15
|
* });
|
|
16
16
|
*/
|
|
17
|
+
import { OtlpTransport } from "../types/otlp-transport.type";
|
|
17
18
|
export interface OpenTelemetryInitOptions {
|
|
18
19
|
/** Service name for APM */
|
|
19
20
|
serviceName?: string;
|
|
@@ -35,6 +36,8 @@ export interface OpenTelemetryInitOptions {
|
|
|
35
36
|
enableHttpInstrumentation?: boolean;
|
|
36
37
|
/** Enable Express instrumentation */
|
|
37
38
|
enableExpressInstrumentation?: boolean;
|
|
39
|
+
/** OTLP transport type: 'http' or 'grpc' (default: 'http') */
|
|
40
|
+
otlpTransport?: OtlpTransport | string;
|
|
38
41
|
}
|
|
39
42
|
/**
|
|
40
43
|
* Check if APM should use OpenTelemetry provider based on configuration
|
|
@@ -47,5 +50,9 @@ export declare function shouldUseOpenTelemetry(): boolean;
|
|
|
47
50
|
* @param options Configuration options
|
|
48
51
|
* @returns The NodeSDK instance
|
|
49
52
|
*/
|
|
50
|
-
export declare function initOpenTelemetry(options?: OpenTelemetryInitOptions): Promise<
|
|
53
|
+
export declare function initOpenTelemetry(options?: OpenTelemetryInitOptions): Promise<{
|
|
54
|
+
start(): void;
|
|
55
|
+
shutdown(): Promise<void>;
|
|
56
|
+
flush?(): Promise<void>;
|
|
57
|
+
}>;
|
|
51
58
|
//# sourceMappingURL=opentelemetry-init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opentelemetry-init.d.ts","sourceRoot":"","sources":["../../src/init/opentelemetry-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"opentelemetry-init.d.ts","sourceRoot":"","sources":["../../src/init/opentelemetry-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAgD7D,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;IACvC,8DAA8D;IAC9D,aAAa,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAwCD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC;IACvF,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC,CAwJD"}
|
|
@@ -52,13 +52,81 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
52
52
|
exports.shouldUseOpenTelemetry = shouldUseOpenTelemetry;
|
|
53
53
|
exports.initOpenTelemetry = initOpenTelemetry;
|
|
54
54
|
const apm_provider_type_1 = require("../types/apm-provider.type");
|
|
55
|
+
const otlp_transport_type_1 = require("../types/otlp-transport.type");
|
|
56
|
+
const debug_logger_1 = require("../utils/debug-logger");
|
|
57
|
+
const debug_exporter_wrapper_1 = require("../utils/debug-exporter-wrapper");
|
|
58
|
+
// @ts-ignore - Optional peer dependency
|
|
59
|
+
const api_1 = require("@opentelemetry/api");
|
|
60
|
+
/**
|
|
61
|
+
* Transaction Name Processor for OpenTelemetry
|
|
62
|
+
* Sets transaction names to format: "GET /api/healthcheck/ping"
|
|
63
|
+
*/
|
|
64
|
+
class TransactionNameProcessor {
|
|
65
|
+
onStart(_span) {
|
|
66
|
+
// No-op - moved to onEnd to read final http.route
|
|
67
|
+
}
|
|
68
|
+
forceFlush() {
|
|
69
|
+
return Promise.resolve();
|
|
70
|
+
}
|
|
71
|
+
shutdown() {
|
|
72
|
+
return Promise.resolve();
|
|
73
|
+
}
|
|
74
|
+
onEnd(_span) {
|
|
75
|
+
const span = _span;
|
|
76
|
+
// Only process root spans (SERVER spans without parent)
|
|
77
|
+
if (span.parent || span.kind !== api_1.SpanKind.SERVER) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Get HTTP attributes (http.route is often set after routing completes)
|
|
81
|
+
const method = span.attributes?.["http.method"];
|
|
82
|
+
const route = span.attributes?.["http.route"]; // /api/healthcheck/ping
|
|
83
|
+
const target = span.attributes?.["http.target"]; // fallback
|
|
84
|
+
if (method && (route || target)) {
|
|
85
|
+
// Format: GET /api/healthcheck/ping
|
|
86
|
+
const fullName = `${method} ${route || target}`;
|
|
87
|
+
span.updateName?.(fullName);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
55
91
|
/**
|
|
56
92
|
* Check if APM should use OpenTelemetry provider based on configuration
|
|
57
93
|
* @returns true if OpenTelemetry should be used
|
|
58
94
|
*/
|
|
59
95
|
function shouldUseOpenTelemetry() {
|
|
60
96
|
const provider = process.env.APM_PROVIDER || apm_provider_type_1.ApmProvider.OPENTELEMETRY;
|
|
61
|
-
return provider !== apm_provider_type_1.ApmProvider.ELASTIC_APM && provider !==
|
|
97
|
+
return provider !== apm_provider_type_1.ApmProvider.ELASTIC_APM && provider !== "elastic-apm";
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Normalize OTLP endpoint URL to ensure consistent format
|
|
101
|
+
* - Ensure port is included
|
|
102
|
+
* - Remove trailing slashes
|
|
103
|
+
* - For gRPC, don't add /v1/traces (it uses different path)
|
|
104
|
+
*/
|
|
105
|
+
function normalizeEndpoint(endpoint, isGrpc) {
|
|
106
|
+
try {
|
|
107
|
+
const url = new URL(endpoint);
|
|
108
|
+
// Ensure port is specified
|
|
109
|
+
if (!url.port) {
|
|
110
|
+
const defaultPort = url.protocol === "https:" ? "443" : "80";
|
|
111
|
+
url.port = defaultPort;
|
|
112
|
+
}
|
|
113
|
+
// Remove trailing slash
|
|
114
|
+
let pathname = url.pathname.replace(/\/+$/, "");
|
|
115
|
+
// For gRPC, remove /v1/traces as it uses different path
|
|
116
|
+
if (isGrpc && pathname.endsWith("/v1/traces")) {
|
|
117
|
+
pathname = pathname.replace("/v1/traces", "");
|
|
118
|
+
}
|
|
119
|
+
// For HTTP/PROTO, ensure /v1/traces path exists
|
|
120
|
+
if (!isGrpc && !pathname.endsWith("/v1/traces")) {
|
|
121
|
+
pathname = pathname.endsWith("/") ? pathname + "v1/traces" : pathname + "/v1/traces";
|
|
122
|
+
}
|
|
123
|
+
url.pathname = pathname;
|
|
124
|
+
return url.toString();
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// If URL parsing fails, return as-is
|
|
128
|
+
return endpoint;
|
|
129
|
+
}
|
|
62
130
|
}
|
|
63
131
|
/**
|
|
64
132
|
* Initialize OpenTelemetry SDK for standalone usage
|
|
@@ -68,89 +136,122 @@ function shouldUseOpenTelemetry() {
|
|
|
68
136
|
*/
|
|
69
137
|
async function initOpenTelemetry(options = {}) {
|
|
70
138
|
// @ts-ignore - Optional peer dependency
|
|
71
|
-
const { NodeSDK } = await Promise.resolve().then(() => __importStar(require(
|
|
139
|
+
const { NodeSDK } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/sdk-node")));
|
|
72
140
|
// @ts-ignore - Optional peer dependency
|
|
73
|
-
const { resourceFromAttributes } = await Promise.resolve().then(() => __importStar(require(
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
141
|
+
const { resourceFromAttributes } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/resources")));
|
|
142
|
+
const serviceName = options.serviceName || process.env.ELASTIC_APM_SERVICE_NAME || "interactive-backend";
|
|
143
|
+
const environment = options.environment || process.env.ELASTIC_APM_ENVIRONMENT || "development";
|
|
144
|
+
// Determine transport type (HTTP, gRPC, or PROTO)
|
|
145
|
+
const transportType = (options.otlpTransport ||
|
|
146
|
+
process.env.ELASTIC_OTLP_TRANSPORT ||
|
|
147
|
+
otlp_transport_type_1.OtlpTransport.HTTP).toLowerCase();
|
|
148
|
+
const isGrpc = transportType === otlp_transport_type_1.OtlpTransport.GRPC || transportType === "grpc";
|
|
149
|
+
const isProto = transportType === otlp_transport_type_1.OtlpTransport.PROTO || transportType === "proto";
|
|
150
|
+
// Get endpoint from config or env (same endpoint for both transports)
|
|
151
|
+
const otlpEndpoint = options.otlpEndpoint || process.env.ELASTIC_OTLP_ENDPOINT || "http://localhost:8200/v1/traces";
|
|
152
|
+
// Validate and normalize endpoint
|
|
153
|
+
const normalizedEndpoint = normalizeEndpoint(otlpEndpoint, isGrpc);
|
|
80
154
|
const secretToken = options.secretToken || process.env.ELASTIC_APM_SECRET_TOKEN;
|
|
81
155
|
const otlpAuthToken = options.otlpAuthToken || process.env.ELASTIC_OTLP_AUTH_TOKEN;
|
|
82
156
|
// Build headers: merge options.otlpHeaders with Authorization if token is provided
|
|
83
157
|
const headers = { ...options.otlpHeaders };
|
|
84
158
|
const token = otlpAuthToken || secretToken;
|
|
85
159
|
if (token) {
|
|
86
|
-
headers[
|
|
160
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
87
161
|
}
|
|
88
|
-
|
|
89
|
-
|
|
162
|
+
// Log initialization details when debug mode is on
|
|
163
|
+
(0, debug_logger_1.logInitialization)("OpenTelemetry", {
|
|
164
|
+
serviceName,
|
|
165
|
+
environment,
|
|
166
|
+
otlpEndpoint: normalizedEndpoint,
|
|
167
|
+
transport: isGrpc ? "gRPC" : isProto ? "PROTO (protobuf over HTTP)" : "HTTP",
|
|
168
|
+
hasToken: !!token,
|
|
169
|
+
enableConsoleExporter: options.enableConsoleExporter ?? process.env.ELASTIC_OTLP_ENABLE_CONSOLE_EXPORTER === "true",
|
|
170
|
+
enableHttpInstrumentation: options.enableHttpInstrumentation !== false,
|
|
171
|
+
enableExpressInstrumentation: options.enableExpressInstrumentation !== false,
|
|
172
|
+
});
|
|
173
|
+
const transportLabel = isGrpc ? "gRPC" : isProto ? "PROTO" : "HTTP";
|
|
174
|
+
(0, debug_logger_1.infoLog)(`[OpenTelemetry] Initializing with ${transportLabel} transport...`);
|
|
90
175
|
// Build exporters array
|
|
91
176
|
const exporters = [];
|
|
92
|
-
// OTLP
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
177
|
+
// Create OTLP exporter based on transport type
|
|
178
|
+
let otlpExporterBase;
|
|
179
|
+
if (isGrpc) {
|
|
180
|
+
// @ts-ignore - Optional peer dependency
|
|
181
|
+
const { OTLPTraceExporter } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/exporter-trace-otlp-grpc")));
|
|
182
|
+
otlpExporterBase = new OTLPTraceExporter({
|
|
183
|
+
url: normalizedEndpoint,
|
|
184
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else if (isProto) {
|
|
188
|
+
// @ts-ignore - Optional peer dependency
|
|
189
|
+
const { OTLPTraceExporter } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/exporter-trace-otlp-proto")));
|
|
190
|
+
otlpExporterBase = new OTLPTraceExporter({
|
|
191
|
+
url: normalizedEndpoint,
|
|
192
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// @ts-ignore - Optional peer dependency
|
|
197
|
+
const { OTLPTraceExporter } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/exporter-trace-otlp-http")));
|
|
198
|
+
otlpExporterBase = new OTLPTraceExporter({
|
|
199
|
+
url: normalizedEndpoint,
|
|
200
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
// Wrap with debug exporter for detailed request/response logging
|
|
204
|
+
const otlpExporter = (0, debug_exporter_wrapper_1.createDebugExporter)(otlpExporterBase, normalizedEndpoint);
|
|
111
205
|
exporters.push(otlpExporter);
|
|
112
206
|
// Console Exporter for debugging
|
|
113
|
-
if (options.enableConsoleExporter ??
|
|
207
|
+
if (options.enableConsoleExporter ??
|
|
208
|
+
process.env.ELASTIC_OTLP_ENABLE_CONSOLE_EXPORTER === "true") {
|
|
114
209
|
// @ts-ignore - Optional peer dependency
|
|
115
|
-
const { ConsoleSpanExporter } = await Promise.resolve().then(() => __importStar(require(
|
|
210
|
+
const { ConsoleSpanExporter } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/sdk-trace-base")));
|
|
116
211
|
exporters.push(new ConsoleSpanExporter());
|
|
117
212
|
}
|
|
118
213
|
// Build instrumentations array
|
|
119
214
|
const instrumentations = [];
|
|
120
215
|
if (options.enableHttpInstrumentation !== false) {
|
|
121
216
|
// @ts-ignore - Optional peer dependency
|
|
122
|
-
const { HttpInstrumentation } = await Promise.resolve().then(() => __importStar(require(
|
|
217
|
+
const { HttpInstrumentation } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/instrumentation-http")));
|
|
123
218
|
instrumentations.push(new HttpInstrumentation());
|
|
124
219
|
}
|
|
125
220
|
if (options.enableExpressInstrumentation !== false) {
|
|
126
221
|
// @ts-ignore - Optional peer dependency
|
|
127
|
-
const { ExpressInstrumentation } = await Promise.resolve().then(() => __importStar(require(
|
|
222
|
+
const { ExpressInstrumentation } = await Promise.resolve().then(() => __importStar(require("@opentelemetry/instrumentation-express")));
|
|
128
223
|
instrumentations.push(new ExpressInstrumentation());
|
|
129
224
|
}
|
|
130
225
|
// Resource attributes
|
|
131
226
|
const sdkResource = resourceFromAttributes({
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
227
|
+
"service.name": serviceName,
|
|
228
|
+
"deployment.environment": environment,
|
|
229
|
+
"service.version": options.serviceVersion || process.env.npm_package_version || "1.0.0",
|
|
230
|
+
"service.instance.id": `${process.pid}`,
|
|
231
|
+
"host.name": require("os").hostname(),
|
|
137
232
|
});
|
|
138
233
|
// Initialize SDK
|
|
139
234
|
const sdk = new NodeSDK({
|
|
140
235
|
serviceName,
|
|
141
236
|
traceExporter: exporters.length === 1 ? exporters[0] : exporters, // Handle single/multiple exporters
|
|
142
|
-
instrumentations,
|
|
237
|
+
instrumentations: instrumentations,
|
|
143
238
|
resource: sdkResource,
|
|
239
|
+
spanProcessor: new TransactionNameProcessor(),
|
|
144
240
|
});
|
|
145
241
|
// Start SDK
|
|
146
242
|
sdk.start();
|
|
147
|
-
|
|
243
|
+
// Install HTTP interceptor for debug mode
|
|
244
|
+
const interceptor = (0, debug_exporter_wrapper_1.createHttpRequestInterceptor)();
|
|
245
|
+
if (interceptor) {
|
|
246
|
+
interceptor.install();
|
|
247
|
+
}
|
|
248
|
+
(0, debug_logger_1.infoLog)("[OpenTelemetry] Initialized");
|
|
148
249
|
// Setup graceful shutdown handlers
|
|
149
250
|
const shutdown = async () => {
|
|
150
251
|
await sdk.shutdown();
|
|
151
252
|
process.exit(0);
|
|
152
253
|
};
|
|
153
|
-
process.on(
|
|
154
|
-
process.on(
|
|
254
|
+
process.on("SIGTERM", shutdown);
|
|
255
|
+
process.on("SIGINT", shutdown);
|
|
155
256
|
return sdk;
|
|
156
257
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { ISpan } from "../types/apm.types";
|
|
1
2
|
/**
|
|
2
3
|
* Interface chung cho APM Tracing Provider
|
|
3
4
|
* Cho phép switch giữa OpenTelemetry và Elastic APM thông qua DI
|
|
4
5
|
*/
|
|
5
6
|
export interface ITracingProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Initialize the provider
|
|
9
|
+
* @param config Optional configuration
|
|
10
|
+
*/
|
|
11
|
+
initialize?(config?: unknown): Promise<void>;
|
|
6
12
|
/**
|
|
7
13
|
* Bắt đầu một span mới để trace operation
|
|
8
14
|
* @param name Tên của span
|
|
@@ -10,7 +16,7 @@ export interface ITracingProvider {
|
|
|
10
16
|
* @param spanKind Loại span (INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER)
|
|
11
17
|
* @returns Span object - cần gọi end() khi hoàn thành
|
|
12
18
|
*/
|
|
13
|
-
startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string):
|
|
19
|
+
startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string): ISpan | null;
|
|
14
20
|
/**
|
|
15
21
|
* Thực thi function với context tracing (auto-close span)
|
|
16
22
|
* @param name Tên của span
|
|
@@ -18,7 +24,7 @@ export interface ITracingProvider {
|
|
|
18
24
|
* @param attributes Các attributes metadata
|
|
19
25
|
* @returns Kết quả của function
|
|
20
26
|
*/
|
|
21
|
-
startSpanWithParent<T>(name: string, fn: (span:
|
|
27
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
|
|
22
28
|
/**
|
|
23
29
|
* Capture error vào active span hiện tại
|
|
24
30
|
* @param error Error object
|
|
@@ -30,11 +36,15 @@ export interface ITracingProvider {
|
|
|
30
36
|
* @param value Giá trị attribute
|
|
31
37
|
*/
|
|
32
38
|
setAttribute(key: string, value: string | number): void;
|
|
39
|
+
/**
|
|
40
|
+
* Force flush all pending spans
|
|
41
|
+
*/
|
|
42
|
+
forceFlush?(): Promise<void>;
|
|
33
43
|
/**
|
|
34
44
|
* Kết thúc span manually
|
|
35
45
|
* @param span Span cần end (nếu không truyền, sẽ end active span)
|
|
36
46
|
*/
|
|
37
|
-
endSpan(span?:
|
|
47
|
+
endSpan(span?: ISpan | null): void;
|
|
38
48
|
/**
|
|
39
49
|
* Flush và shutdown provider (cho graceful shutdown)
|
|
40
50
|
*/
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"tracing-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/tracing-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;;;;OAMG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC5C,QAAQ,CAAC,EAAE,MAAM,GAChB,KAAK,GAAG,IAAI,CAAC;IAEhB;;;;;;OAMG;IACH,mBAAmB,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;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;;OAEG;IACH,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;IAEnC;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DynamicModule } from
|
|
2
|
-
import { ApmProvider } from
|
|
1
|
+
import { DynamicModule, Type, ForwardReference } from "@nestjs/common";
|
|
2
|
+
import { ApmProvider } from "../types/apm-provider.type";
|
|
3
3
|
/**
|
|
4
4
|
* Options for configuring TracingModule
|
|
5
5
|
*/
|
|
@@ -83,14 +83,14 @@ export interface TracingModuleAsyncOptions {
|
|
|
83
83
|
/**
|
|
84
84
|
* Optional list of modules to import for the factory to use
|
|
85
85
|
*/
|
|
86
|
-
imports?:
|
|
86
|
+
imports?: Array<Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference<unknown>>;
|
|
87
87
|
/**
|
|
88
88
|
* Factory function that returns the module options
|
|
89
89
|
*/
|
|
90
|
-
useFactory?: (...args:
|
|
90
|
+
useFactory?: (...args: unknown[]) => Promise<TracingModuleOptions> | TracingModuleOptions;
|
|
91
91
|
/**
|
|
92
92
|
* Optional list of providers to inject into the factory
|
|
93
93
|
*/
|
|
94
|
-
inject?:
|
|
94
|
+
inject?: (Type<object> | string | symbol)[];
|
|
95
95
|
}
|
|
96
96
|
//# sourceMappingURL=tracing.module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.module.d.ts","sourceRoot":"","sources":["../../src/modules/tracing.module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tracing.module.d.ts","sourceRoot":"","sources":["../../src/modules/tracing.module.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,aAAa,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMvF,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGzD;;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,KAAK,CACb,IAAI,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC,CACnF,CAAC;IAEF;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;IAE1F;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CAC7C"}
|
|
@@ -40,6 +40,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.TracingModule = void 0;
|
|
42
42
|
// @ts-ignore - Optional peer dependency
|
|
43
|
+
// @ts-ignore - Optional peer dependency
|
|
43
44
|
const common_1 = require("@nestjs/common");
|
|
44
45
|
const tracing_service_1 = require("../services/tracing.service");
|
|
45
46
|
const tracing_provider_factory_1 = require("../factories/tracing-provider.factory");
|
|
@@ -131,7 +132,7 @@ let TracingModule = (() => {
|
|
|
131
132
|
// Auto-initialize if configured
|
|
132
133
|
if (config.autoInit !== false) {
|
|
133
134
|
// Check if provider has initialize method (not in interface)
|
|
134
|
-
if (
|
|
135
|
+
if ("initialize" in provider && typeof provider.initialize === "function") {
|
|
135
136
|
await provider.initialize();
|
|
136
137
|
}
|
|
137
138
|
}
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import { ITracingProvider } from
|
|
1
|
+
import { ITracingProvider } from "../interfaces/tracing-provider.interface";
|
|
2
|
+
import { ISpan } from "../types/apm.types";
|
|
3
|
+
/**
|
|
4
|
+
* Elastic APM specific span interface
|
|
5
|
+
*/
|
|
6
|
+
export interface IElasticApmSpan extends ISpan {
|
|
7
|
+
/** Set a label on the span */
|
|
8
|
+
setLabel(key: string, value: string): void;
|
|
9
|
+
/** Set the span type */
|
|
10
|
+
setType(type: string): void;
|
|
11
|
+
/** Set the outcome (success, failure) */
|
|
12
|
+
outcome?: string;
|
|
13
|
+
/** End the span */
|
|
14
|
+
end(): void;
|
|
15
|
+
}
|
|
2
16
|
/**
|
|
3
17
|
* Elastic APM Tracing Provider Implementation
|
|
4
18
|
* Sử dụng elastic-apm-node agent để gửi traces về Elastic APM server
|
|
@@ -24,15 +38,15 @@ export declare class ElasticApmTracingProvider implements ITracingProvider {
|
|
|
24
38
|
secretToken?: string;
|
|
25
39
|
environment?: string;
|
|
26
40
|
serviceVersion?: string;
|
|
27
|
-
}): void
|
|
41
|
+
}): Promise<void>;
|
|
28
42
|
/**
|
|
29
43
|
* Bắt đầu một span mới
|
|
30
44
|
*/
|
|
31
|
-
startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string):
|
|
45
|
+
startSpan(name: string, attributes?: Record<string, string | number>, spanKind?: string): IElasticApmSpan | null;
|
|
32
46
|
/**
|
|
33
47
|
* Thực thi function với tracing context
|
|
34
48
|
*/
|
|
35
|
-
startSpanWithParent<T>(name: string, fn: (span:
|
|
49
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
|
|
36
50
|
/**
|
|
37
51
|
* Capture error vào APM
|
|
38
52
|
*/
|
|
@@ -44,7 +58,7 @@ export declare class ElasticApmTracingProvider implements ITracingProvider {
|
|
|
44
58
|
/**
|
|
45
59
|
* End span manually
|
|
46
60
|
*/
|
|
47
|
-
endSpan(span?:
|
|
61
|
+
endSpan(span?: ISpan | null): void;
|
|
48
62
|
/**
|
|
49
63
|
* Flush và shutdown gracefully
|
|
50
64
|
*/
|
|
@@ -53,5 +67,9 @@ export declare class ElasticApmTracingProvider implements ITracingProvider {
|
|
|
53
67
|
* Map string span kind to Elastic APM span type
|
|
54
68
|
*/
|
|
55
69
|
private mapSpanKindToType;
|
|
70
|
+
/**
|
|
71
|
+
* Map string span kind to numeric value (for logging)
|
|
72
|
+
*/
|
|
73
|
+
private mapSpanKindToNumber;
|
|
56
74
|
}
|
|
57
75
|
//# sourceMappingURL=elastic-apm.tracing-provider.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAS3C;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,KAAK;IAC5C,8BAA8B;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3C,wBAAwB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,mBAAmB;IACnB,GAAG,IAAI,IAAI,CAAC;CACb;AA0BD;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,OAAO,CAAC,GAAG,CAAiC;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAGnC,MAAM,GAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;KACpB;IAOR;;;OAGG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDjB;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC5C,QAAQ,GAAE,MAAmB,GAC5B,eAAe,GAAG,IAAI;IAiHzB;;OAEG;IACG,mBAAmB,CAAC,CAAC,EACzB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC;IAsBb;;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,KAAK,GAAG,IAAI,GAAG,IAAI;IAOlC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAe5B"}
|