@vtvlive/interactive-apm 0.0.13 → 0.0.15
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/dist/interfaces/tracing-provider.interface.d.ts +10 -4
- package/dist/interfaces/tracing-provider.interface.d.ts.map +1 -1
- package/dist/providers/elastic-apm.tracing-provider.d.ts +12 -6
- package/dist/providers/elastic-apm.tracing-provider.d.ts.map +1 -1
- package/dist/providers/elastic-apm.tracing-provider.js +29 -4
- package/dist/providers/opentelemetry.tracing-provider.d.ts +9 -4
- package/dist/providers/opentelemetry.tracing-provider.d.ts.map +1 -1
- package/dist/providers/opentelemetry.tracing-provider.js +60 -11
- package/dist/services/tracing.service.d.ts +10 -4
- package/dist/services/tracing.service.d.ts.map +1 -1
- package/dist/services/tracing.service.js +8 -0
- package/dist/types/apm.types.d.ts +4 -2
- package/dist/types/apm.types.d.ts.map +1 -1
- package/dist/utils/opentelemetry-transaction-context.d.ts +4 -0
- package/dist/utils/opentelemetry-transaction-context.d.ts.map +1 -0
- package/dist/utils/opentelemetry-transaction-context.js +19 -0
- package/dist/utils/tracing.helper.d.ts +13 -6
- package/dist/utils/tracing.helper.d.ts.map +1 -1
- package/dist/utils/tracing.helper.js +98 -22
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISpan, SpanKind } from "../types/apm.types";
|
|
1
|
+
import { ISpan, SpanAttributes, SpanAttributeValue, SpanKind } from "../types/apm.types";
|
|
2
2
|
/**
|
|
3
3
|
* Interface chung cho APM Tracing Provider
|
|
4
4
|
* Cho phép switch giữa OpenTelemetry và Elastic APM thông qua DI
|
|
@@ -16,7 +16,7 @@ export interface ITracingProvider {
|
|
|
16
16
|
* @param spanKind Loại span (INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER, WEBSOCKET, OTHER)
|
|
17
17
|
* @returns Span object - cần gọi end() khi hoàn thành
|
|
18
18
|
*/
|
|
19
|
-
startSpan(name: string, attributes?:
|
|
19
|
+
startSpan(name: string, attributes?: SpanAttributes, spanKind?: SpanKind): ISpan | null;
|
|
20
20
|
/**
|
|
21
21
|
* Thực thi function với context tracing (auto-close span)
|
|
22
22
|
* @param name Tên của span
|
|
@@ -24,7 +24,7 @@ export interface ITracingProvider {
|
|
|
24
24
|
* @param attributes Các attributes metadata
|
|
25
25
|
* @returns Kết quả của function
|
|
26
26
|
*/
|
|
27
|
-
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?:
|
|
27
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: SpanAttributes): Promise<T>;
|
|
28
28
|
/**
|
|
29
29
|
* Capture error vào active span hiện tại
|
|
30
30
|
* @param error Error object
|
|
@@ -35,7 +35,13 @@ export interface ITracingProvider {
|
|
|
35
35
|
* @param key Tên attribute
|
|
36
36
|
* @param value Giá trị attribute
|
|
37
37
|
*/
|
|
38
|
-
setAttribute(key: string, value:
|
|
38
|
+
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
39
|
+
/**
|
|
40
|
+
* Set label/attribute cho active transaction hiện tại
|
|
41
|
+
* @param key Tên label
|
|
42
|
+
* @param value Giá trị label
|
|
43
|
+
*/
|
|
44
|
+
setTransactionLabel(key: string, value: SpanAttributeValue): void;
|
|
39
45
|
/**
|
|
40
46
|
* Force flush all pending spans
|
|
41
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/tracing-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"tracing-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/tracing-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzF;;;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,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAC;IAExF;;;;;;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,cAAc,GAC1B,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,kBAAkB,GAAG,IAAI,CAAC;IAE3D;;;;OAIG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAElE;;OAEG;IACH,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { SpanKind } from "../types/apm-provider.type";
|
|
2
2
|
import { ITracingProvider } from "../interfaces/tracing-provider.interface";
|
|
3
|
-
import { ISpan } from "../types/apm.types";
|
|
3
|
+
import { ISpan, SpanAttributes, SpanAttributeValue } from "../types/apm.types";
|
|
4
4
|
/**
|
|
5
5
|
* Elastic APM specific span interface
|
|
6
6
|
*/
|
|
7
7
|
export interface IElasticApmSpan extends ISpan {
|
|
8
8
|
/** Set a label on the span */
|
|
9
|
-
setLabel(key: string, value: string): void;
|
|
9
|
+
setLabel(key: string, value: string | number | boolean, stringify?: boolean): void;
|
|
10
10
|
/** Set the span type */
|
|
11
11
|
setType(type: string): void;
|
|
12
12
|
/** Set the outcome (success, failure) */
|
|
@@ -22,6 +22,8 @@ export declare class ElasticApmTracingProvider implements ITracingProvider {
|
|
|
22
22
|
private apm;
|
|
23
23
|
private readonly serviceName;
|
|
24
24
|
private readonly environment;
|
|
25
|
+
private static isElasticLabelValue;
|
|
26
|
+
private static setElasticLabel;
|
|
25
27
|
constructor(config?: {
|
|
26
28
|
serviceName?: string;
|
|
27
29
|
environment?: string;
|
|
@@ -43,19 +45,23 @@ export declare class ElasticApmTracingProvider implements ITracingProvider {
|
|
|
43
45
|
/**
|
|
44
46
|
* Bắt đầu một span mới
|
|
45
47
|
*/
|
|
46
|
-
startSpan(name: string, attributes?:
|
|
48
|
+
startSpan(name: string, attributes?: SpanAttributes, spanKind?: SpanKind): IElasticApmSpan | null;
|
|
47
49
|
/**
|
|
48
50
|
* Thực thi function với tracing context
|
|
49
51
|
*/
|
|
50
|
-
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?:
|
|
52
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: SpanAttributes): Promise<T>;
|
|
51
53
|
/**
|
|
52
54
|
* Capture error vào APM
|
|
53
55
|
*/
|
|
54
56
|
captureError(error: Error): void;
|
|
55
57
|
/**
|
|
56
|
-
* Set label cho current
|
|
58
|
+
* Set label cho current span
|
|
57
59
|
*/
|
|
58
|
-
setAttribute(key: string, value:
|
|
60
|
+
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
61
|
+
/**
|
|
62
|
+
* Set label cho current transaction
|
|
63
|
+
*/
|
|
64
|
+
setTransactionLabel(key: string, value: SpanAttributeValue): void;
|
|
59
65
|
/**
|
|
60
66
|
* End span manually
|
|
61
67
|
*/
|
|
@@ -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,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,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,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAU/E;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,KAAK;IAC5C,8BAA8B;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEnF,wBAAwB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,mBAAmB;IACnB,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B;AA2BD;;;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;IAErC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAMlC,OAAO,CAAC,MAAM,CAAC,eAAe;gBAkB5B,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,cAAc,EAC3B,QAAQ,GAAE,QAA4B,GACrC,eAAe,GAAG,IAAI;IAoHzB;;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,cAAc,GAC1B,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,kBAAkB,GAAG,IAAI;IAO1D;;OAEG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAOjE;;OAEG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAOpD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAe5B"}
|
|
@@ -9,6 +9,19 @@ const elastic_apm_compat_1 = require("../utils/elastic-apm-compat");
|
|
|
9
9
|
* Sử dụng elastic-apm-node agent để gửi traces về Elastic APM server
|
|
10
10
|
*/
|
|
11
11
|
class ElasticApmTracingProvider {
|
|
12
|
+
static isElasticLabelValue(value) {
|
|
13
|
+
return value !== undefined && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
static setElasticLabel(target, key, value) {
|
|
16
|
+
if (!ElasticApmTracingProvider.isElasticLabelValue(value)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
20
|
+
target.setLabel(key, value, false);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
target.setLabel(key, value);
|
|
24
|
+
}
|
|
12
25
|
constructor(config = {}) {
|
|
13
26
|
this.apm = null;
|
|
14
27
|
this.serviceName =
|
|
@@ -93,7 +106,7 @@ class ElasticApmTracingProvider {
|
|
|
93
106
|
// Set labels từ attributes
|
|
94
107
|
if (attributes) {
|
|
95
108
|
for (const [key, value] of Object.entries(attributes)) {
|
|
96
|
-
|
|
109
|
+
ElasticApmTracingProvider.setElasticLabel(span, key, value);
|
|
97
110
|
}
|
|
98
111
|
}
|
|
99
112
|
// Set span type dựa trên kind
|
|
@@ -112,7 +125,10 @@ class ElasticApmTracingProvider {
|
|
|
112
125
|
}
|
|
113
126
|
return;
|
|
114
127
|
}
|
|
115
|
-
|
|
128
|
+
if (!ElasticApmTracingProvider.isElasticLabelValue(value)) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
ElasticApmTracingProvider.setElasticLabel({ setLabel: originalSetLabel }, key, value);
|
|
116
132
|
};
|
|
117
133
|
// Override setAttribute (if it exists, maps to setLabel)
|
|
118
134
|
if (typeof span.setAttribute === "function") {
|
|
@@ -188,12 +204,21 @@ class ElasticApmTracingProvider {
|
|
|
188
204
|
}
|
|
189
205
|
}
|
|
190
206
|
/**
|
|
191
|
-
* Set label cho current
|
|
207
|
+
* Set label cho current span
|
|
192
208
|
*/
|
|
193
209
|
setAttribute(key, value) {
|
|
194
210
|
const span = this.apm?.currentSpan;
|
|
195
211
|
if (span) {
|
|
196
|
-
|
|
212
|
+
ElasticApmTracingProvider.setElasticLabel(span, key, value);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Set label cho current transaction
|
|
217
|
+
*/
|
|
218
|
+
setTransactionLabel(key, value) {
|
|
219
|
+
const transaction = this.apm?.currentTransaction;
|
|
220
|
+
if (transaction) {
|
|
221
|
+
ElasticApmTracingProvider.setElasticLabel(transaction, key, value);
|
|
197
222
|
}
|
|
198
223
|
}
|
|
199
224
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ITracingProvider } from "../interfaces/tracing-provider.interface";
|
|
2
2
|
import { OtlpTransport } from "../types/otlp-transport.type";
|
|
3
|
-
import { ISpan, SpanKind } from "../types/apm.types";
|
|
3
|
+
import { ISpan, SpanAttributes, SpanAttributeValue, SpanKind } from "../types/apm.types";
|
|
4
4
|
/**
|
|
5
5
|
* OpenTelemetry Tracing Provider Implementation
|
|
6
6
|
* Sử dụng OpenTelemetry SDK với OTLP exporter để gửi traces về Elastic APM
|
|
@@ -40,14 +40,15 @@ export declare class OpenTelemetryTracingProvider implements ITracingProvider {
|
|
|
40
40
|
enableConsoleExporter?: boolean;
|
|
41
41
|
environment?: string;
|
|
42
42
|
}): Promise<void>;
|
|
43
|
+
private getTransactionSpanFromContext;
|
|
43
44
|
/**
|
|
44
45
|
* Bắt đầu một span mới
|
|
45
46
|
*/
|
|
46
|
-
startSpan(name: string, attributes?:
|
|
47
|
+
startSpan(name: string, attributes?: SpanAttributes, spanKind?: SpanKind): ISpan | null;
|
|
47
48
|
/**
|
|
48
49
|
* Thực thi function với tracing context
|
|
49
50
|
*/
|
|
50
|
-
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?:
|
|
51
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: SpanAttributes): Promise<T>;
|
|
51
52
|
/**
|
|
52
53
|
* Capture error vào active span
|
|
53
54
|
*/
|
|
@@ -55,7 +56,11 @@ export declare class OpenTelemetryTracingProvider implements ITracingProvider {
|
|
|
55
56
|
/**
|
|
56
57
|
* Set attribute cho active span
|
|
57
58
|
*/
|
|
58
|
-
setAttribute(key: string, value:
|
|
59
|
+
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
60
|
+
/**
|
|
61
|
+
* Set transaction label on the root request span when available
|
|
62
|
+
*/
|
|
63
|
+
setTransactionLabel(key: string, value: SpanAttributeValue): void;
|
|
59
64
|
/**
|
|
60
65
|
* Force flush all pending spans
|
|
61
66
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opentelemetry.tracing-provider.d.ts","sourceRoot":"","sources":["../../src/providers/opentelemetry.tracing-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"opentelemetry.tracing-provider.d.ts","sourceRoot":"","sources":["../../src/providers/opentelemetry.tracing-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA8GzF;;;GAGG;AACH,qBAAa,4BAA6B,YAAW,gBAAgB;IACnE,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IACrD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAU;IAChD,OAAO,CAAC,WAAW,CAAS;gBAG1B,MAAM,GAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;QACvC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;KAC5B;IA6BR;;;OAGG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+NjB,OAAO,CAAC,6BAA6B;IAuBrC;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,cAAc,EAC3B,QAAQ,GAAE,QAA4B,GACrC,KAAK,GAAG,IAAI;IA4If;;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,cAAc,GAC1B,OAAO,CAAC,CAAC,CAAC;IA4Cb;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAiBhC;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAa1D;;OAEG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAWjE;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC;;OAEG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAapD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;OAEG;IACH,OAAO,CAAC,WAAW;CAmBpB"}
|
|
@@ -38,6 +38,7 @@ const otlp_transport_type_1 = require("../types/otlp-transport.type");
|
|
|
38
38
|
const apm_types_1 = require("../types/apm.types");
|
|
39
39
|
const debug_logger_1 = require("../utils/debug-logger");
|
|
40
40
|
const debug_exporter_wrapper_1 = require("../utils/debug-exporter-wrapper");
|
|
41
|
+
const opentelemetry_transaction_context_1 = require("../utils/opentelemetry-transaction-context");
|
|
41
42
|
/**
|
|
42
43
|
* Transaction Name Processor for OpenTelemetry
|
|
43
44
|
* Sets transaction names to format: "GET /api/healthcheck/ping"
|
|
@@ -339,6 +340,20 @@ class OpenTelemetryTracingProvider {
|
|
|
339
340
|
throw error;
|
|
340
341
|
}
|
|
341
342
|
}
|
|
343
|
+
getTransactionSpanFromContext() {
|
|
344
|
+
// @ts-ignore - Optional peer dependency
|
|
345
|
+
const { context, trace } = require("@opentelemetry/api");
|
|
346
|
+
const activeContext = context.active();
|
|
347
|
+
const transactionSpan = activeContext?.getValue?.(opentelemetry_transaction_context_1.transactionSpanContextKey);
|
|
348
|
+
if (transactionSpan) {
|
|
349
|
+
return transactionSpan;
|
|
350
|
+
}
|
|
351
|
+
const activeSpan = trace.getActiveSpan();
|
|
352
|
+
if (activeSpan?.[opentelemetry_transaction_context_1.transactionSpanRef]) {
|
|
353
|
+
return activeSpan[opentelemetry_transaction_context_1.transactionSpanRef] ?? null;
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
342
357
|
/**
|
|
343
358
|
* Bắt đầu một span mới
|
|
344
359
|
*/
|
|
@@ -350,8 +365,10 @@ class OpenTelemetryTracingProvider {
|
|
|
350
365
|
return null;
|
|
351
366
|
}
|
|
352
367
|
// @ts-ignore - Optional peer dependency
|
|
353
|
-
const { context } = require("@opentelemetry/api");
|
|
368
|
+
const { context, trace } = require("@opentelemetry/api");
|
|
354
369
|
const tracer = this.tracer;
|
|
370
|
+
const activeContext = context.active();
|
|
371
|
+
const activeTransactionSpan = this.getTransactionSpanFromContext();
|
|
355
372
|
const span = tracer.startSpan(name, {
|
|
356
373
|
attributes,
|
|
357
374
|
kind: this.mapSpanKind(spanKind),
|
|
@@ -360,6 +377,21 @@ class OpenTelemetryTracingProvider {
|
|
|
360
377
|
if (span) {
|
|
361
378
|
const spanForLog = { name, kind: this.mapSpanKind(spanKind) };
|
|
362
379
|
(0, debug_logger_1.logSpan)("OpenTelemetry", spanForLog);
|
|
380
|
+
const transactionSpan = spanKind === apm_types_1.SpanKind.SERVER ? span : activeTransactionSpan;
|
|
381
|
+
if (transactionSpan) {
|
|
382
|
+
span[opentelemetry_transaction_context_1.transactionSpanRef] = transactionSpan;
|
|
383
|
+
let transactionContext;
|
|
384
|
+
if (typeof activeContext.setValue === "function") {
|
|
385
|
+
transactionContext = activeContext.setValue(opentelemetry_transaction_context_1.transactionSpanContextKey, transactionSpan);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
if ((0, debug_logger_1.isDebugEnabled)()) {
|
|
389
|
+
console.warn("[OpenTelemetry] activeContext.setValue is unavailable; falling back to trace.setSpan for transaction span propagation");
|
|
390
|
+
}
|
|
391
|
+
transactionContext = trace.setSpan(context.active(), transactionSpan);
|
|
392
|
+
}
|
|
393
|
+
span[opentelemetry_transaction_context_1.spanExecutionContextRef] = transactionContext;
|
|
394
|
+
}
|
|
363
395
|
}
|
|
364
396
|
// Add end protection to prevent operations on ended span
|
|
365
397
|
if (span) {
|
|
@@ -412,7 +444,7 @@ class OpenTelemetryTracingProvider {
|
|
|
412
444
|
// Override end to prevent duplicate ends
|
|
413
445
|
if (typeof span.end === "function") {
|
|
414
446
|
const originalEnd = span.end.bind(span);
|
|
415
|
-
span.end = () => {
|
|
447
|
+
span.end = (result) => {
|
|
416
448
|
if (isEnded) {
|
|
417
449
|
if ((0, debug_logger_1.isDebugEnabled)()) {
|
|
418
450
|
console.warn(`[OpenTelemetry] Span "${name}" has already been ended. Ignoring duplicate end().`);
|
|
@@ -420,7 +452,7 @@ class OpenTelemetryTracingProvider {
|
|
|
420
452
|
return;
|
|
421
453
|
}
|
|
422
454
|
isEnded = true;
|
|
423
|
-
originalEnd();
|
|
455
|
+
originalEnd(result);
|
|
424
456
|
};
|
|
425
457
|
}
|
|
426
458
|
}
|
|
@@ -432,16 +464,21 @@ class OpenTelemetryTracingProvider {
|
|
|
432
464
|
async startSpanWithParent(name, fn, attributes) {
|
|
433
465
|
// @ts-ignore - Optional peer dependency
|
|
434
466
|
const { context, trace, SpanStatusCode } = require("@opentelemetry/api");
|
|
435
|
-
|
|
436
|
-
|
|
467
|
+
const span = this.startSpan(name, attributes);
|
|
468
|
+
const spanContext = span?.[opentelemetry_transaction_context_1.spanExecutionContextRef] ??
|
|
469
|
+
context.active();
|
|
470
|
+
const executionContext = span ? trace.setSpan(spanContext, span) : spanContext;
|
|
471
|
+
return context.with(executionContext, async () => {
|
|
472
|
+
const activeSpan = trace.getActiveSpan();
|
|
473
|
+
const currentSpan = activeSpan ?? span;
|
|
437
474
|
try {
|
|
438
|
-
const result = await fn(
|
|
475
|
+
const result = await fn(currentSpan);
|
|
439
476
|
return result;
|
|
440
477
|
}
|
|
441
478
|
catch (error) {
|
|
442
|
-
if (
|
|
443
|
-
|
|
444
|
-
|
|
479
|
+
if (currentSpan) {
|
|
480
|
+
currentSpan.recordException(error);
|
|
481
|
+
currentSpan.setStatus({
|
|
445
482
|
code: SpanStatusCode.ERROR,
|
|
446
483
|
message: error.message,
|
|
447
484
|
});
|
|
@@ -452,7 +489,7 @@ class OpenTelemetryTracingProvider {
|
|
|
452
489
|
throw error;
|
|
453
490
|
}
|
|
454
491
|
finally {
|
|
455
|
-
|
|
492
|
+
currentSpan?.end();
|
|
456
493
|
}
|
|
457
494
|
});
|
|
458
495
|
}
|
|
@@ -478,7 +515,7 @@ class OpenTelemetryTracingProvider {
|
|
|
478
515
|
* Set attribute cho active span
|
|
479
516
|
*/
|
|
480
517
|
setAttribute(key, value) {
|
|
481
|
-
if (!this.initialized) {
|
|
518
|
+
if (!this.initialized || value === undefined) {
|
|
482
519
|
return;
|
|
483
520
|
}
|
|
484
521
|
// @ts-ignore - Optional peer dependency
|
|
@@ -488,6 +525,18 @@ class OpenTelemetryTracingProvider {
|
|
|
488
525
|
span.setAttribute(key, value);
|
|
489
526
|
}
|
|
490
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Set transaction label on the root request span when available
|
|
530
|
+
*/
|
|
531
|
+
setTransactionLabel(key, value) {
|
|
532
|
+
if (!this.initialized || value === undefined || Array.isArray(value)) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const transactionSpan = this.getTransactionSpanFromContext();
|
|
536
|
+
if (transactionSpan) {
|
|
537
|
+
transactionSpan.setAttribute(key, value);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
491
540
|
/**
|
|
492
541
|
* Force flush all pending spans
|
|
493
542
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ITracingProvider } from "../interfaces/tracing-provider.interface";
|
|
2
|
-
import { ISpan, SpanKind } from "../types/apm.types";
|
|
2
|
+
import { ISpan, SpanAttributes, SpanAttributeValue, SpanKind } from "../types/apm.types";
|
|
3
3
|
/**
|
|
4
4
|
* Tracing Service - Wrapper cho ITracingProvider
|
|
5
5
|
* Service này được inject vào controllers/services để sử dụng tracing
|
|
@@ -47,7 +47,7 @@ export declare class TracingService {
|
|
|
47
47
|
* span.end();
|
|
48
48
|
* }
|
|
49
49
|
*/
|
|
50
|
-
startSpan(name: string, attributes?:
|
|
50
|
+
startSpan(name: string, attributes?: SpanAttributes, spanKind?: SpanKind): ISpan | null;
|
|
51
51
|
/**
|
|
52
52
|
* Thực thi function với context tracing (auto-close span)
|
|
53
53
|
* @param name Tên của span
|
|
@@ -64,7 +64,7 @@ export declare class TracingService {
|
|
|
64
64
|
* }
|
|
65
65
|
* );
|
|
66
66
|
*/
|
|
67
|
-
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?:
|
|
67
|
+
startSpanWithParent<T>(name: string, fn: (span: ISpan | null) => Promise<T>, attributes?: SpanAttributes): Promise<T>;
|
|
68
68
|
/**
|
|
69
69
|
* Capture error vào active span hiện tại
|
|
70
70
|
* @param error Error object
|
|
@@ -75,7 +75,13 @@ export declare class TracingService {
|
|
|
75
75
|
* @param key Tên attribute
|
|
76
76
|
* @param value Giá trị attribute
|
|
77
77
|
*/
|
|
78
|
-
setAttribute(key: string, value:
|
|
78
|
+
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
79
|
+
/**
|
|
80
|
+
* Set label/attribute cho active transaction hiện tại
|
|
81
|
+
* @param key Tên label
|
|
82
|
+
* @param value Giá trị label
|
|
83
|
+
*/
|
|
84
|
+
setTransactionLabel(key: string, value: SpanAttributeValue): void;
|
|
79
85
|
/**
|
|
80
86
|
* Kết thúc span manually
|
|
81
87
|
* @param span Span cần end (nếu không truyền, sẽ end active span)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.service.d.ts","sourceRoot":"","sources":["../../src/services/tracing.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"tracing.service.d.ts","sourceRoot":"","sources":["../../src/services/tracing.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,gBAAgB;IAEvD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,cAAc,EAC3B,QAAQ,GAAE,QAA4B,GACrC,KAAK,GAAG,IAAI;IAIf;;;;;;;;;;;;;;;OAeG;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,cAAc,GAC1B,OAAO,CAAC,CAAC,CAAC;IAIb;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIhC;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAI1D;;;;OAIG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAIjE;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAI7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
|
|
@@ -87,6 +87,14 @@ class TracingService {
|
|
|
87
87
|
setAttribute(key, value) {
|
|
88
88
|
this.provider.setAttribute(key, value);
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Set label/attribute cho active transaction hiện tại
|
|
92
|
+
* @param key Tên label
|
|
93
|
+
* @param value Giá trị label
|
|
94
|
+
*/
|
|
95
|
+
setTransactionLabel(key, value) {
|
|
96
|
+
this.provider.setTransactionLabel(key, value);
|
|
97
|
+
}
|
|
90
98
|
/**
|
|
91
99
|
* Kết thúc span manually
|
|
92
100
|
* @param span Span cần end (nếu không truyền, sẽ end active span)
|
|
@@ -10,13 +10,15 @@ export { ApmProvider, type ApmProviderType, SpanKind, OtlpTransport, type OtlpTr
|
|
|
10
10
|
/**
|
|
11
11
|
* Common Span interface - works with both Elastic APM and OpenTelemetry
|
|
12
12
|
*/
|
|
13
|
+
export type SpanAttributeValue = string | number | boolean | string[] | undefined;
|
|
14
|
+
export type SpanAttributes = Record<string, SpanAttributeValue>;
|
|
13
15
|
export interface ISpan {
|
|
14
16
|
/** Span name */
|
|
15
17
|
name: string;
|
|
16
18
|
/** End the span */
|
|
17
19
|
end(result?: unknown): void;
|
|
18
20
|
/** Set an attribute on the span */
|
|
19
|
-
setAttribute(key: string, value:
|
|
21
|
+
setAttribute(key: string, value: SpanAttributeValue): void;
|
|
20
22
|
/** Add an event to the span */
|
|
21
23
|
addEvent?(name: string, attributes?: Record<string, unknown>): void;
|
|
22
24
|
/** Set the span status */
|
|
@@ -47,7 +49,7 @@ export interface ITracer {
|
|
|
47
49
|
*/
|
|
48
50
|
export interface SpanOptions {
|
|
49
51
|
/** Span attributes */
|
|
50
|
-
attributes?:
|
|
52
|
+
attributes?: SpanAttributes;
|
|
51
53
|
/** Span kind (server, client, internal, etc.) */
|
|
52
54
|
kind?: SpanKind;
|
|
53
55
|
/** Parent span context */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apm.types.d.ts","sourceRoot":"","sources":["../../src/types/apm.types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG9E,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,CAAC;AAE9F;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,mBAAmB;IACnB,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAE5B,mCAAmC;IACnC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"apm.types.d.ts","sourceRoot":"","sources":["../../src/types/apm.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opentelemetry-transaction-context.d.ts","sourceRoot":"","sources":["../../src/utils/opentelemetry-transaction-context.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,yBAAyB,QAErC,CAAC;AAEF,eAAO,MAAM,kBAAkB,eAAiD,CAAC;AACjF,eAAO,MAAM,uBAAuB,eAA8C,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.spanExecutionContextRef = exports.transactionSpanRef = exports.transactionSpanContextKey = void 0;
|
|
4
|
+
const resolveCreateContextKey = () => {
|
|
5
|
+
try {
|
|
6
|
+
// @ts-ignore - Optional peer dependency
|
|
7
|
+
const { createContextKey } = require("@opentelemetry/api");
|
|
8
|
+
if (typeof createContextKey === "function") {
|
|
9
|
+
return createContextKey;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// Ignore when optional dependency is unavailable
|
|
14
|
+
}
|
|
15
|
+
return (description) => Symbol(description);
|
|
16
|
+
};
|
|
17
|
+
exports.transactionSpanContextKey = resolveCreateContextKey()("interactive-apm.transaction-span");
|
|
18
|
+
exports.transactionSpanRef = Symbol("interactive-apm.transaction-span-ref");
|
|
19
|
+
exports.spanExecutionContextRef = Symbol("interactive-apm.execution-context");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ISpan, SpanAttributes, SpanAttributeValue } from "../types/apm.types";
|
|
2
2
|
import { SpanKind } from "../types/apm-provider.type";
|
|
3
3
|
/**
|
|
4
4
|
* TracingHelper - Static utility class for unified APM usage
|
|
@@ -19,10 +19,13 @@ import { SpanKind } from "../types/apm-provider.type";
|
|
|
19
19
|
export declare class TracingHelper {
|
|
20
20
|
private static tracer;
|
|
21
21
|
private static apmProvider;
|
|
22
|
+
private static isElasticLabelValue;
|
|
23
|
+
private static setElasticLabel;
|
|
22
24
|
/**
|
|
23
25
|
* Get the current APM provider (cached)
|
|
24
26
|
*/
|
|
25
27
|
private static getProvider;
|
|
28
|
+
private static getTransactionSpanFromContext;
|
|
26
29
|
/**
|
|
27
30
|
* Reset cached provider (useful for testing)
|
|
28
31
|
*/
|
|
@@ -34,7 +37,7 @@ export declare class TracingHelper {
|
|
|
34
37
|
* @param spanKind Loại span (mặc định: INTERNAL). Dùng SERVER cho API endpoints
|
|
35
38
|
* @returns Span object
|
|
36
39
|
*/
|
|
37
|
-
static startSpan(name: string, attributes?:
|
|
40
|
+
static startSpan(name: string, attributes?: SpanAttributes, spanKind?: SpanKind): ISpan;
|
|
38
41
|
private static mapSpanKindToOtlpSpanKind;
|
|
39
42
|
/**
|
|
40
43
|
* Start span using OpenTelemetry API
|
|
@@ -63,7 +66,7 @@ export declare class TracingHelper {
|
|
|
63
66
|
* @param attributes Các attributes metadata
|
|
64
67
|
* @returns Kết quả của function
|
|
65
68
|
*/
|
|
66
|
-
static startSpanWithParent<T>(name: string, fn: (span:
|
|
69
|
+
static startSpanWithParent<T>(name: string, fn: (span: ISpan | undefined) => Promise<T>, attributes?: SpanAttributes): Promise<T>;
|
|
67
70
|
/**
|
|
68
71
|
* Capture error vào active span hiện tại
|
|
69
72
|
* @param error Error object
|
|
@@ -74,17 +77,21 @@ export declare class TracingHelper {
|
|
|
74
77
|
* @param key Tên attribute
|
|
75
78
|
* @param value Giá trị attribute
|
|
76
79
|
*/
|
|
77
|
-
static setAttribute(key: string, value:
|
|
80
|
+
static setAttribute(key: string, value: SpanAttributeValue): void;
|
|
81
|
+
/**
|
|
82
|
+
* Set label/attribute cho active transaction hiện tại
|
|
83
|
+
*/
|
|
84
|
+
static setTransactionLabel(key: string, value: SpanAttributeValue): void;
|
|
78
85
|
/**
|
|
79
86
|
* Kết thúc span manually
|
|
80
87
|
* @param span Span cần end
|
|
81
88
|
*/
|
|
82
|
-
static endSpan(span?:
|
|
89
|
+
static endSpan(span?: ISpan, result?: unknown): void;
|
|
83
90
|
/**
|
|
84
91
|
* Get the current active span
|
|
85
92
|
* @returns The active span or undefined
|
|
86
93
|
*/
|
|
87
|
-
static getActiveSpan():
|
|
94
|
+
static getActiveSpan(): ISpan | undefined;
|
|
88
95
|
/**
|
|
89
96
|
* Get the current trace ID
|
|
90
97
|
* @returns The trace ID or undefined
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAkDtD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAsC;IAC3D,OAAO,CAAC,MAAM,CAAC,WAAW,CAAoD;IAE9E,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAMlC,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAO1B,OAAO,CAAC,MAAM,CAAC,6BAA6B;IAqB5C;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,IAAI;IAIjC;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,cAAc,EAC3B,QAAQ,GAAE,QAA4B,GACrC,KAAK;IAWR,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAiBxC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAmCrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAgGlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAqB3C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAsBpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAoB7B;;;;;;OAMG;WACU,mBAAmB,CAAC,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3C,UAAU,CAAC,EAAE,cAAc,GAC1B,OAAO,CAAC,CAAC,CAAC;IAyDb;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAsBvC;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAwBjE;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IA2BxE;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IA2BpD;;;OAGG;IACH,MAAM,CAAC,aAAa,IAAI,KAAK,GAAG,SAAS;IAqBzC;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,GAAG,SAAS;CAqBxC"}
|
|
@@ -4,6 +4,7 @@ exports.TracingHelper = void 0;
|
|
|
4
4
|
// @ts-ignore - Optional peer dependency
|
|
5
5
|
const api_1 = require("@opentelemetry/api");
|
|
6
6
|
const apm_provider_type_1 = require("../types/apm-provider.type");
|
|
7
|
+
const opentelemetry_transaction_context_1 = require("./opentelemetry-transaction-context");
|
|
7
8
|
/**
|
|
8
9
|
* Get the current APM provider type
|
|
9
10
|
*/
|
|
@@ -52,6 +53,19 @@ function getApmProvider() {
|
|
|
52
53
|
* }
|
|
53
54
|
*/
|
|
54
55
|
class TracingHelper {
|
|
56
|
+
static isElasticLabelValue(value) {
|
|
57
|
+
return value !== undefined && !Array.isArray(value);
|
|
58
|
+
}
|
|
59
|
+
static setElasticLabel(target, key, value) {
|
|
60
|
+
if (!TracingHelper.isElasticLabelValue(value)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
64
|
+
target.setLabel(key, value, false);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
target.setLabel(key, value);
|
|
68
|
+
}
|
|
55
69
|
/**
|
|
56
70
|
* Get the current APM provider (cached)
|
|
57
71
|
*/
|
|
@@ -61,6 +75,18 @@ class TracingHelper {
|
|
|
61
75
|
}
|
|
62
76
|
return this.apmProvider;
|
|
63
77
|
}
|
|
78
|
+
static getTransactionSpanFromContext() {
|
|
79
|
+
const activeContext = api_1.context.active();
|
|
80
|
+
const transactionSpan = activeContext?.getValue?.(opentelemetry_transaction_context_1.transactionSpanContextKey);
|
|
81
|
+
if (transactionSpan) {
|
|
82
|
+
return transactionSpan;
|
|
83
|
+
}
|
|
84
|
+
const activeSpan = api_1.trace.getActiveSpan();
|
|
85
|
+
if (activeSpan?.[opentelemetry_transaction_context_1.transactionSpanRef]) {
|
|
86
|
+
return activeSpan[opentelemetry_transaction_context_1.transactionSpanRef] ?? null;
|
|
87
|
+
}
|
|
88
|
+
return activeSpan ?? null;
|
|
89
|
+
}
|
|
64
90
|
/**
|
|
65
91
|
* Reset cached provider (useful for testing)
|
|
66
92
|
*/
|
|
@@ -102,10 +128,18 @@ class TracingHelper {
|
|
|
102
128
|
* Start span using OpenTelemetry API
|
|
103
129
|
*/
|
|
104
130
|
static startSpanOpenTelemetry(name, attributes, spanKind = apm_provider_type_1.SpanKind.INTERNAL) {
|
|
131
|
+
const activeContext = api_1.context.active();
|
|
132
|
+
const activeTransactionSpan = this.getTransactionSpanFromContext();
|
|
105
133
|
const span = this.tracer.startSpan(name, {
|
|
106
134
|
attributes,
|
|
107
135
|
kind: this.mapSpanKindToOtlpSpanKind(spanKind),
|
|
108
136
|
}, api_1.context.active());
|
|
137
|
+
const transactionSpan = spanKind === apm_provider_type_1.SpanKind.SERVER ? span : activeTransactionSpan;
|
|
138
|
+
if (transactionSpan) {
|
|
139
|
+
span[opentelemetry_transaction_context_1.transactionSpanRef] = transactionSpan;
|
|
140
|
+
const transactionContext = activeContext.setValue?.(opentelemetry_transaction_context_1.transactionSpanContextKey, transactionSpan);
|
|
141
|
+
span[opentelemetry_transaction_context_1.spanExecutionContextRef] = transactionContext ?? api_1.context.active();
|
|
142
|
+
}
|
|
109
143
|
return span;
|
|
110
144
|
}
|
|
111
145
|
/**
|
|
@@ -139,7 +173,7 @@ class TracingHelper {
|
|
|
139
173
|
// Set attributes as labels
|
|
140
174
|
if (attributes) {
|
|
141
175
|
for (const [key, value] of Object.entries(attributes)) {
|
|
142
|
-
|
|
176
|
+
TracingHelper.setElasticLabel(apmSpan, key, value);
|
|
143
177
|
}
|
|
144
178
|
}
|
|
145
179
|
// Set span type
|
|
@@ -153,14 +187,14 @@ class TracingHelper {
|
|
|
153
187
|
// Add setAttribute method that maps to setLabel
|
|
154
188
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
189
|
span.setAttribute = (key, value) => {
|
|
156
|
-
originalSetLabel
|
|
190
|
+
TracingHelper.setElasticLabel({ setLabel: originalSetLabel }, key, value);
|
|
157
191
|
return span; // Return span for chaining
|
|
158
192
|
};
|
|
159
193
|
// Add setAttributes method for batch setting
|
|
160
194
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
161
195
|
span.setAttributes = (attrs) => {
|
|
162
196
|
for (const [k, v] of Object.entries(attrs)) {
|
|
163
|
-
originalSetLabel
|
|
197
|
+
TracingHelper.setElasticLabel({ setLabel: originalSetLabel }, k, v);
|
|
164
198
|
}
|
|
165
199
|
return span; // Return span for chaining
|
|
166
200
|
};
|
|
@@ -235,18 +269,23 @@ class TracingHelper {
|
|
|
235
269
|
* Create a no-op span that does nothing
|
|
236
270
|
*/
|
|
237
271
|
static createNoOpSpan(name) {
|
|
238
|
-
|
|
272
|
+
const noOpSpan = {
|
|
239
273
|
name,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
274
|
+
setAttribute: function () {
|
|
275
|
+
return this;
|
|
276
|
+
},
|
|
277
|
+
addEvent: function () {
|
|
278
|
+
return this;
|
|
279
|
+
},
|
|
280
|
+
recordException: function () {
|
|
281
|
+
return this;
|
|
282
|
+
},
|
|
283
|
+
setStatus: function () {
|
|
284
|
+
return this;
|
|
285
|
+
},
|
|
286
|
+
end: () => { },
|
|
249
287
|
};
|
|
288
|
+
return noOpSpan;
|
|
250
289
|
}
|
|
251
290
|
/**
|
|
252
291
|
* Thực thi function với context tracing (auto-close span)
|
|
@@ -271,23 +310,33 @@ class TracingHelper {
|
|
|
271
310
|
}
|
|
272
311
|
}
|
|
273
312
|
// OpenTelemetry with context propagation
|
|
274
|
-
|
|
275
|
-
|
|
313
|
+
const span = TracingHelper.startSpan(name, attributes);
|
|
314
|
+
const spanContext = span?.[opentelemetry_transaction_context_1.spanExecutionContextRef] ??
|
|
315
|
+
api_1.context.active();
|
|
316
|
+
const executionContext = span
|
|
317
|
+
? api_1.trace.setSpan(spanContext, span)
|
|
318
|
+
: api_1.context.active();
|
|
319
|
+
return api_1.context.with(executionContext, async () => {
|
|
320
|
+
const activeSpan = api_1.trace.getActiveSpan();
|
|
321
|
+
const currentSpan = activeSpan ?? span;
|
|
276
322
|
// If no active span, throw an error - this should not happen if the span was just started
|
|
277
|
-
if (!
|
|
323
|
+
if (!currentSpan) {
|
|
278
324
|
throw new Error(`Failed to get active span for "${name}". The OpenTelemetry context may not be properly initialized.`);
|
|
279
325
|
}
|
|
280
326
|
try {
|
|
281
|
-
const result = await fn(
|
|
327
|
+
const result = await fn(currentSpan);
|
|
282
328
|
return result;
|
|
283
329
|
}
|
|
284
330
|
catch (error) {
|
|
285
|
-
|
|
286
|
-
|
|
331
|
+
currentSpan.recordException(error);
|
|
332
|
+
currentSpan.setStatus({
|
|
333
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
334
|
+
message: error.message,
|
|
335
|
+
});
|
|
287
336
|
throw error;
|
|
288
337
|
}
|
|
289
338
|
finally {
|
|
290
|
-
|
|
339
|
+
currentSpan.end();
|
|
291
340
|
}
|
|
292
341
|
});
|
|
293
342
|
}
|
|
@@ -328,7 +377,7 @@ class TracingHelper {
|
|
|
328
377
|
const apm = require("elastic-apm-node");
|
|
329
378
|
const span = apm.currentSpan;
|
|
330
379
|
if (span) {
|
|
331
|
-
|
|
380
|
+
TracingHelper.setElasticLabel(span, key, value);
|
|
332
381
|
}
|
|
333
382
|
}
|
|
334
383
|
catch {
|
|
@@ -338,10 +387,37 @@ class TracingHelper {
|
|
|
338
387
|
}
|
|
339
388
|
// OpenTelemetry
|
|
340
389
|
const span = api_1.trace.getActiveSpan();
|
|
341
|
-
if (span) {
|
|
390
|
+
if (span && value !== undefined) {
|
|
342
391
|
span.setAttribute(key, value);
|
|
343
392
|
}
|
|
344
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* Set label/attribute cho active transaction hiện tại
|
|
396
|
+
*/
|
|
397
|
+
static setTransactionLabel(key, value) {
|
|
398
|
+
const provider = this.getProvider();
|
|
399
|
+
if (provider === "elastic-apm") {
|
|
400
|
+
try {
|
|
401
|
+
// @ts-ignore - Optional dependency
|
|
402
|
+
const apm = require("elastic-apm-node");
|
|
403
|
+
const transaction = apm.currentTransaction;
|
|
404
|
+
if (transaction) {
|
|
405
|
+
TracingHelper.setElasticLabel(transaction, key, value);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// Ignore if elastic-apm is not available
|
|
410
|
+
}
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (value === undefined || Array.isArray(value)) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const transactionSpan = this.getTransactionSpanFromContext();
|
|
417
|
+
if (transactionSpan) {
|
|
418
|
+
transactionSpan.setAttribute(key, value);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
345
421
|
/**
|
|
346
422
|
* Kết thúc span manually
|
|
347
423
|
* @param span Span cần end
|
package/package.json
CHANGED