@rsdk/core 4.0.0-next.13 → 4.0.0-next.14
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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/tracing/active-span.module.d.ts +5 -0
- package/dist/tracing/active-span.module.js +25 -0
- package/dist/tracing/active-span.module.js.map +1 -0
- package/dist/tracing/constants.d.ts +7 -1
- package/dist/tracing/constants.js +8 -2
- package/dist/tracing/constants.js.map +1 -1
- package/dist/tracing/decorators/span.decorator.d.ts +1 -1
- package/dist/tracing/decorators/span.decorator.js +13 -1
- package/dist/tracing/decorators/span.decorator.js.map +1 -1
- package/dist/tracing/index.d.ts +7 -0
- package/dist/tracing/index.js +7 -0
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/request-metadata.module.d.ts +5 -0
- package/dist/tracing/request-metadata.module.js +25 -0
- package/dist/tracing/request-metadata.module.js.map +1 -0
- package/dist/tracing/services/active-span.storage.d.ts +17 -0
- package/dist/tracing/services/active-span.storage.js +46 -0
- package/dist/tracing/services/active-span.storage.js.map +1 -0
- package/dist/tracing/services/index.d.ts +0 -1
- package/dist/tracing/services/index.js +0 -1
- package/dist/tracing/services/index.js.map +1 -1
- package/dist/tracing/services/instrumentation.service.d.ts +2 -8
- package/dist/tracing/services/instrumentation.service.js +9 -114
- package/dist/tracing/services/instrumentation.service.js.map +1 -1
- package/dist/tracing/services/request-metadata.injector.d.ts +6 -0
- package/dist/tracing/services/request-metadata.injector.js +122 -0
- package/dist/tracing/services/request-metadata.injector.js.map +1 -0
- package/dist/tracing/services/request-metadata.storage.d.ts +32 -0
- package/dist/tracing/services/request-metadata.storage.js +64 -0
- package/dist/tracing/services/request-metadata.storage.js.map +1 -0
- package/dist/tracing/services/trace.injector.d.ts +1 -1
- package/dist/tracing/services/trace.injector.js +213 -18
- package/dist/tracing/services/trace.injector.js.map +1 -1
- package/dist/tracing/tracing.interceptor.d.ts +9 -0
- package/dist/tracing/tracing.interceptor.js +24 -0
- package/dist/tracing/tracing.interceptor.js.map +1 -0
- package/dist/tracing/tracing.module.d.ts +1 -1
- package/dist/tracing/tracing.module.js +15 -16
- package/dist/tracing/tracing.module.js.map +1 -1
- package/dist/tracing/utils/create-span.d.ts +10 -0
- package/dist/tracing/utils/create-span.js +20 -0
- package/dist/tracing/utils/create-span.js.map +1 -0
- package/dist/tracing/utils/save-async-hooks-context.d.ts +19 -0
- package/dist/tracing/utils/save-async-hooks-context.js +59 -0
- package/dist/tracing/utils/save-async-hooks-context.js.map +1 -0
- package/package.json +10 -10
- package/src/index.ts +20 -1
- package/src/tracing/active-span.module.ts +13 -0
- package/src/tracing/constants.ts +8 -1
- package/src/tracing/decorators/span.decorator.ts +18 -5
- package/src/tracing/index.ts +7 -0
- package/src/tracing/request-metadata.module.ts +13 -0
- package/src/tracing/services/active-span.storage.ts +32 -0
- package/src/tracing/services/index.ts +0 -1
- package/src/tracing/services/instrumentation.service.ts +16 -130
- package/src/tracing/services/request-metadata.injector.ts +153 -0
- package/src/tracing/services/request-metadata.storage.ts +69 -0
- package/src/tracing/services/trace.injector.ts +268 -19
- package/src/tracing/tracing.interceptor.ts +18 -0
- package/src/tracing/tracing.module.ts +14 -14
- package/src/tracing/utils/create-span.ts +20 -0
- package/src/tracing/utils/save-async-hooks-context.ts +62 -0
- package/dist/tracing/services/metadata.scanner.d.ts +0 -11
- package/dist/tracing/services/metadata.scanner.js +0 -50
- package/dist/tracing/services/metadata.scanner.js.map +0 -1
- package/src/tracing/services/metadata.scanner.ts +0 -40
|
@@ -15,20 +15,21 @@ var TracingModule_1;
|
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.TracingModule = void 0;
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
|
+
const core_1 = require("@nestjs/core");
|
|
18
19
|
const api_1 = require("@opentelemetry/api");
|
|
19
20
|
const context_async_hooks_1 = require("@opentelemetry/context-async-hooks");
|
|
20
|
-
const core_1 = require("@opentelemetry/core");
|
|
21
21
|
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
22
|
-
const propagator_b3_1 = require("@opentelemetry/propagator-b3");
|
|
23
22
|
const resources_1 = require("@opentelemetry/resources");
|
|
24
23
|
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
25
24
|
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
26
25
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
27
26
|
const logging_1 = require("@rsdk/logging");
|
|
28
27
|
const logging_2 = require("../logging");
|
|
29
|
-
const
|
|
30
|
-
const
|
|
28
|
+
const active_span_module_1 = require("./active-span.module");
|
|
29
|
+
const request_metadata_module_1 = require("./request-metadata.module");
|
|
30
|
+
const services_1 = require("./services");
|
|
31
31
|
const tracing_config_1 = require("./tracing.config");
|
|
32
|
+
const tracing_interceptor_1 = require("./tracing.interceptor");
|
|
32
33
|
let TracingModule = TracingModule_1 = class TracingModule {
|
|
33
34
|
logger;
|
|
34
35
|
instrumentations;
|
|
@@ -43,10 +44,14 @@ let TracingModule = TracingModule_1 = class TracingModule {
|
|
|
43
44
|
static forRoot(options) {
|
|
44
45
|
return {
|
|
45
46
|
module: TracingModule_1,
|
|
47
|
+
imports: [request_metadata_module_1.RequestMetadataModule, active_span_module_1.ActiveSpanModule],
|
|
46
48
|
providers: [
|
|
47
|
-
|
|
48
|
-
instrumentation_service_1.InstrumentationService,
|
|
49
|
+
services_1.InstrumentationService,
|
|
49
50
|
this.createSDKProvider(options),
|
|
51
|
+
/**
|
|
52
|
+
* Глобальный интерцептор для проброса входящих traceId, spanId и requestId из заголовков и метадаты в активный AsyncLocalStorage запроса
|
|
53
|
+
*/
|
|
54
|
+
{ provide: core_1.APP_INTERCEPTOR, useClass: tracing_interceptor_1.TracingInterceptor },
|
|
50
55
|
],
|
|
51
56
|
};
|
|
52
57
|
}
|
|
@@ -69,20 +74,14 @@ let TracingModule = TracingModule_1 = class TracingModule {
|
|
|
69
74
|
[semantic_conventions_1.SemanticResourceAttributes.SERVICE_NAME]: options.appName,
|
|
70
75
|
}),
|
|
71
76
|
spanProcessor: processor,
|
|
72
|
-
textMapPropagator: new core_1.CompositePropagator({
|
|
73
|
-
propagators: [
|
|
74
|
-
new propagator_b3_1.B3Propagator(),
|
|
75
|
-
new propagator_b3_1.B3Propagator({
|
|
76
|
-
injectEncoding: propagator_b3_1.B3InjectEncoding.MULTI_HEADER,
|
|
77
|
-
}),
|
|
78
|
-
],
|
|
79
|
-
}),
|
|
80
77
|
});
|
|
81
78
|
},
|
|
82
79
|
};
|
|
83
80
|
}
|
|
84
81
|
// Можно добавить включение и выключение при изменении конфига.
|
|
85
82
|
async onModuleInit() {
|
|
83
|
+
this.logger.debug('Injecting request-metadata storage...');
|
|
84
|
+
this.instrumentations.injectWrapRequestMetadataInjector();
|
|
86
85
|
if (!this.config.enabled) {
|
|
87
86
|
this.logger.info('Tracing is disabled');
|
|
88
87
|
return;
|
|
@@ -91,7 +90,7 @@ let TracingModule = TracingModule_1 = class TracingModule {
|
|
|
91
90
|
this.logger.debug('Starting Open Telemetry SDK...');
|
|
92
91
|
await this.sdk.start();
|
|
93
92
|
this.logger.debug('Instrumenting nest.js entities...');
|
|
94
|
-
this.instrumentations.
|
|
93
|
+
this.instrumentations.injectWrapTraceInjector();
|
|
95
94
|
this.logger.debug('Attaching log messages to spans...');
|
|
96
95
|
logging_1.LoggerFactory.onMessage((level, msg) => {
|
|
97
96
|
const span = api_1.trace.getSpan(api_1.context.active());
|
|
@@ -107,7 +106,7 @@ exports.TracingModule = TracingModule;
|
|
|
107
106
|
exports.TracingModule = TracingModule = TracingModule_1 = __decorate([
|
|
108
107
|
(0, common_1.Module)({}),
|
|
109
108
|
__param(0, (0, logging_2.InjectLogger)(TracingModule)),
|
|
110
|
-
__metadata("design:paramtypes", [Object,
|
|
109
|
+
__metadata("design:paramtypes", [Object, services_1.InstrumentationService,
|
|
111
110
|
sdk_node_1.NodeSDK,
|
|
112
111
|
tracing_config_1.TracingModuleConfig])
|
|
113
112
|
], TracingModule);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.module.js","sourceRoot":"","sources":["../../src/tracing/tracing.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,2CAAwC;AACxC,4CAAoD;AACpD,4EAAqF;AACrF,
|
|
1
|
+
{"version":3,"file":"tracing.module.js","sourceRoot":"","sources":["../../src/tracing/tracing.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Функция для генерации корректного рандомного traceId и spanId
|
|
3
|
+
* алгоритм взят из: https://github.com/openzipkin/zipkin-js/blob/ec89188cf6a07e184ab886c1dfb6c9dc276ddfa4/packages/zipkin/src/tracer/randomTraceId.js
|
|
4
|
+
* спецификация по traceId: https://www.w3.org/TR/trace-context/#considerations-for-trace-id-field-generation
|
|
5
|
+
* @returns {traceId, spanId}
|
|
6
|
+
*/
|
|
7
|
+
export declare function createSpan(): {
|
|
8
|
+
traceId: string;
|
|
9
|
+
spanId: string;
|
|
10
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSpan = void 0;
|
|
4
|
+
const common_1 = require("@rsdk/common");
|
|
5
|
+
/**
|
|
6
|
+
* Функция для генерации корректного рандомного traceId и spanId
|
|
7
|
+
* алгоритм взят из: https://github.com/openzipkin/zipkin-js/blob/ec89188cf6a07e184ab886c1dfb6c9dc276ddfa4/packages/zipkin/src/tracer/randomTraceId.js
|
|
8
|
+
* спецификация по traceId: https://www.w3.org/TR/trace-context/#considerations-for-trace-id-field-generation
|
|
9
|
+
* @returns {traceId, spanId}
|
|
10
|
+
*/
|
|
11
|
+
function createSpan() {
|
|
12
|
+
const rootSpanId = (0, common_1.getRandomBytes)(16);
|
|
13
|
+
const traceId = (0, common_1.getRandomBytes)(16) + rootSpanId;
|
|
14
|
+
return {
|
|
15
|
+
traceId,
|
|
16
|
+
spanId: rootSpanId,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
exports.createSpan = createSpan;
|
|
20
|
+
//# sourceMappingURL=create-span.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-span.js","sourceRoot":"","sources":["../../../src/tracing/utils/create-span.ts"],"names":[],"mappings":";;;AAAA,yCAA8C;AAE9C;;;;;GAKG;AACH,SAAgB,UAAU;IAIxB,MAAM,UAAU,GAAG,IAAA,uBAAc,EAAC,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAA,uBAAc,EAAC,EAAE,CAAC,GAAG,UAAU,CAAC;IAEhD,OAAO;QACL,OAAO;QACP,MAAM,EAAE,UAAU;KACnB,CAAC;AACJ,CAAC;AAXD,gCAWC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Проблема: при передаче управления в rxjs теряется контекст асинк локал стораджа
|
|
3
|
+
*
|
|
4
|
+
* Решение: Утилита для проброса инфы из асинк локал стораджа в тело пайпа rxjs
|
|
5
|
+
* поиском "observableToAsyncIterable" можно найти тесты в которых есть пример использования
|
|
6
|
+
*
|
|
7
|
+
* Тут есть часть логик трейсер декоратора, суть простая:
|
|
8
|
+
* мы - находясь в контексте с актуальным асинк Metadata запускаем создание боди для пайпа rx и тем самым мы передаем контекст работы туда
|
|
9
|
+
* ```
|
|
10
|
+
* return this.booksStream.pipe(
|
|
11
|
+
* concatMap(
|
|
12
|
+
* saveAsyncHooksContext(async (book) => {
|
|
13
|
+
* return { book: { ...book, pages: request.limit } };
|
|
14
|
+
* }),
|
|
15
|
+
* ),
|
|
16
|
+
* );
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveAsyncHooksContext<T>(fn: (...args: any[]) => Promise<T>): (...args: any[]) => Promise<T>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.saveAsyncHooksContext = void 0;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
6
|
+
const services_1 = require("../services");
|
|
7
|
+
const active_span_storage_1 = require("../services/active-span.storage");
|
|
8
|
+
/**
|
|
9
|
+
* Проблема: при передаче управления в rxjs теряется контекст асинк локал стораджа
|
|
10
|
+
*
|
|
11
|
+
* Решение: Утилита для проброса инфы из асинк локал стораджа в тело пайпа rxjs
|
|
12
|
+
* поиском "observableToAsyncIterable" можно найти тесты в которых есть пример использования
|
|
13
|
+
*
|
|
14
|
+
* Тут есть часть логик трейсер декоратора, суть простая:
|
|
15
|
+
* мы - находясь в контексте с актуальным асинк Metadata запускаем создание боди для пайпа rx и тем самым мы передаем контекст работы туда
|
|
16
|
+
* ```
|
|
17
|
+
* return this.booksStream.pipe(
|
|
18
|
+
* concatMap(
|
|
19
|
+
* saveAsyncHooksContext(async (book) => {
|
|
20
|
+
* return { book: { ...book, pages: request.limit } };
|
|
21
|
+
* }),
|
|
22
|
+
* ),
|
|
23
|
+
* );
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
function saveAsyncHooksContext(fn) {
|
|
27
|
+
const span = active_span_storage_1.ActiveSpanStorage.getInstance()?.getActiveSpan();
|
|
28
|
+
return async function (...args) {
|
|
29
|
+
const activeSpan = active_span_storage_1.ActiveSpanStorage.getInstance()?.getActiveSpan();
|
|
30
|
+
if (activeSpan) {
|
|
31
|
+
Object.assign(activeSpan.spanContext(), span?.spanContext());
|
|
32
|
+
return fn(...args);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
if (!span) {
|
|
36
|
+
return fn(...args);
|
|
37
|
+
}
|
|
38
|
+
const spanContext = sdk_node_1.api.trace.setSpan(sdk_node_1.api.context.active(), span);
|
|
39
|
+
return sdk_node_1.api.context.with(spanContext, async () => fn(...args)
|
|
40
|
+
.then(async (result) => {
|
|
41
|
+
span.setAttribute('response', services_1.TraceInjector.toAttribute(result));
|
|
42
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
43
|
+
span.end();
|
|
44
|
+
return result;
|
|
45
|
+
})
|
|
46
|
+
.catch(async (error) => {
|
|
47
|
+
span.recordException(error);
|
|
48
|
+
span.setStatus({
|
|
49
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
50
|
+
message: error.message,
|
|
51
|
+
});
|
|
52
|
+
span.end();
|
|
53
|
+
throw error;
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
exports.saveAsyncHooksContext = saveAsyncHooksContext;
|
|
59
|
+
//# sourceMappingURL=save-async-hooks-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save-async-hooks-context.js","sourceRoot":"","sources":["../../../src/tracing/utils/save-async-hooks-context.ts"],"names":[],"mappings":";;;AAAA,4CAAoD;AACpD,sDAA8C;AAG9C,0CAA4C;AAC5C,yEAAoE;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,qBAAqB,CACnC,EAAkC;IAElC,MAAM,IAAI,GAAG,uCAAiB,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,CAAC;IAE9D,OAAO,KAAK,WAAW,GAAG,IAAI;QAC5B,MAAM,UAAU,GAAG,uCAAiB,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,CAAC;QACpE,IAAI,UAAU,EAAE;YACd,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAC7D,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;SACpB;aAAM;YACL,IAAI,CAAC,IAAI,EAAE;gBACT,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;aACpB;YACD,MAAM,WAAW,GAAG,cAAG,CAAC,KAAK,CAAC,OAAO,CAAC,cAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;YAElE,OAAO,cAAG,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAC9C,EAAE,CAAC,GAAG,IAAI,CAAC;iBACR,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBACrB,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,wBAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;gBACjE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,oBAAc,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,OAAO,MAAM,CAAC;YAChB,CAAC,CAAC;iBACD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACrB,IAAI,CAAC,eAAe,CAAC,KAAkB,CAAC,CAAC;gBACzC,IAAI,CAAC,SAAS,CAAC;oBACb,IAAI,EAAE,oBAAc,CAAC,KAAK;oBAC1B,OAAO,EAAG,KAAmB,CAAC,OAAO;iBACtC,CAAC,CAAC;gBACH,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,MAAM,KAAK,CAAC;YACd,CAAC,CAAC,CACL,CAAC;SACH;IACH,CAAC,CAAC;AACJ,CAAC;AApCD,sDAoCC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsdk/core",
|
|
3
|
-
"version": "4.0.0-next.
|
|
3
|
+
"version": "4.0.0-next.14",
|
|
4
4
|
"description": "Nestjs based microservice chassis",
|
|
5
5
|
"license": "Apache License 2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -31,18 +31,18 @@
|
|
|
31
31
|
"@nestjs/common": "^10.0.0",
|
|
32
32
|
"@nestjs/core": "^10.0.0",
|
|
33
33
|
"@nestjs/microservices": "^10.0.0",
|
|
34
|
-
"@rsdk/autodoc.protocol": "^4.0.0-next.
|
|
35
|
-
"@rsdk/common": "^4.0.0-next.
|
|
36
|
-
"@rsdk/common.nestjs": "^4.0.0-next.
|
|
37
|
-
"@rsdk/common.node": "^4.0.0-next.
|
|
38
|
-
"@rsdk/decorators": "^4.0.0-next.
|
|
39
|
-
"@rsdk/logging": "^4.0.0-next.
|
|
40
|
-
"@rsdk/metadata": "^4.0.0-next.
|
|
41
|
-
"@rsdk/nest-tools": "^4.0.0-next.
|
|
34
|
+
"@rsdk/autodoc.protocol": "^4.0.0-next.14",
|
|
35
|
+
"@rsdk/common": "^4.0.0-next.14",
|
|
36
|
+
"@rsdk/common.nestjs": "^4.0.0-next.14",
|
|
37
|
+
"@rsdk/common.node": "^4.0.0-next.14",
|
|
38
|
+
"@rsdk/decorators": "^4.0.0-next.14",
|
|
39
|
+
"@rsdk/logging": "^4.0.0-next.14",
|
|
40
|
+
"@rsdk/metadata": "^4.0.0-next.14",
|
|
41
|
+
"@rsdk/nest-tools": "^4.0.0-next.14",
|
|
42
42
|
"axios": "^1.1.3",
|
|
43
43
|
"pino": "^8.16.1",
|
|
44
44
|
"reflect-metadata": "^0.1.13",
|
|
45
45
|
"rxjs": "^7.0.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "567e6d331c4caa6fdadbe0329f91c471b877f7a4"
|
|
48
48
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import './unhandled-rejection.handler';
|
|
2
2
|
|
|
3
|
+
export { X_REQUEST_ID } from './tracing/constants';
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
RequestMetadata,
|
|
7
|
+
RequestMetadataStorage,
|
|
8
|
+
TracingModule,
|
|
9
|
+
saveAsyncHooksContext,
|
|
10
|
+
createSpan,
|
|
11
|
+
ActiveSpanModule,
|
|
12
|
+
ActiveSpanStorage,
|
|
13
|
+
Span,
|
|
14
|
+
} from './tracing';
|
|
15
|
+
|
|
3
16
|
export {
|
|
4
17
|
FileSystemCheckOptions,
|
|
5
18
|
FileSystemIndicator,
|
|
@@ -36,9 +49,9 @@ export {
|
|
|
36
49
|
Counter,
|
|
37
50
|
Gauge,
|
|
38
51
|
Histogram,
|
|
39
|
-
Summary,
|
|
40
52
|
Metric,
|
|
41
53
|
MetricsModule,
|
|
54
|
+
Summary,
|
|
42
55
|
register,
|
|
43
56
|
} from './metrics';
|
|
44
57
|
|
|
@@ -49,3 +62,9 @@ export * from './types';
|
|
|
49
62
|
export * from './app-metadata/decorators';
|
|
50
63
|
|
|
51
64
|
export * from './app-metadata/app-metadata.const';
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
X_B3_PARENT_SPAN_ID,
|
|
68
|
+
X_B3_SPAN_ID,
|
|
69
|
+
X_B3_TRACE_ID,
|
|
70
|
+
} from '@opentelemetry/propagator-b3';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Global, Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { ActiveSpanStorage } from './services/active-span.storage';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Модуль для получения данных активного спана
|
|
7
|
+
*/
|
|
8
|
+
@Global()
|
|
9
|
+
@Module({
|
|
10
|
+
providers: [ActiveSpanStorage],
|
|
11
|
+
exports: [ActiveSpanStorage],
|
|
12
|
+
})
|
|
13
|
+
export class ActiveSpanModule {}
|
package/src/tracing/constants.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import { Size } from '@rsdk/common';
|
|
2
|
+
|
|
1
3
|
export enum Constants {
|
|
2
4
|
TRACE_METADATA_ACTIVE = 'OPEN_TELEMETRY_TRACE_METADATA_ACTIVE',
|
|
5
|
+
REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE = 'REQUEST_METADATA_ASYNC_LOCAL_STORAGE_ACTIVE',
|
|
3
6
|
NO_SPAN_METADATA = 'NO_SPAN_METADATA',
|
|
4
7
|
}
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Ид запроса - нужен для фильтрации запросов при поиске проблем от конкретного клиента
|
|
11
|
+
*/
|
|
12
|
+
export const X_REQUEST_ID = 'x-requestid';
|
|
13
|
+
export const MAX_BYTES = new Size(100, 'kb');
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
+
import { MetadataScanner } from '@nestjs/core';
|
|
2
|
+
|
|
1
3
|
import { SymbolKeyDecorationException } from '../../exceptions';
|
|
2
4
|
import { TraceInjector } from '../services';
|
|
3
5
|
|
|
6
|
+
const metadataScanner = new MetadataScanner();
|
|
7
|
+
|
|
4
8
|
/**
|
|
5
9
|
* Explicitly adds instrumentation to method (don't work for classes!).
|
|
6
10
|
* Use for classes that you instantiate manually.
|
|
7
11
|
* NOTE: Is redundant for injectables and other nest.js stuff
|
|
8
12
|
*/
|
|
9
|
-
export const Span = (): MethodDecorator =>
|
|
13
|
+
export const Span = (): MethodDecorator & ClassDecorator =>
|
|
10
14
|
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
11
15
|
function (
|
|
12
16
|
target: object,
|
|
13
|
-
methodName
|
|
14
|
-
descriptor
|
|
15
|
-
) {
|
|
17
|
+
methodName?: string | symbol,
|
|
18
|
+
descriptor?: TypedPropertyDescriptor<any>,
|
|
19
|
+
): any {
|
|
16
20
|
if (typeof methodName === 'symbol') {
|
|
17
21
|
throw new SymbolKeyDecorationException();
|
|
18
22
|
}
|
|
23
|
+
if (methodName && descriptor) {
|
|
24
|
+
TraceInjector.wrap(target, descriptor.value, descriptor);
|
|
25
|
+
} else {
|
|
26
|
+
const prototype = (target as any).prototype ?? target;
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
for (const name of metadataScanner.getAllMethodNames(prototype)) {
|
|
29
|
+
if (name) {
|
|
30
|
+
TraceInjector.wrap(prototype, prototype[name]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
21
34
|
};
|
package/src/tracing/index.ts
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
+
export * from './active-span.module';
|
|
2
|
+
export * from './request-metadata.module';
|
|
3
|
+
export * from './services/active-span.storage';
|
|
4
|
+
export * from './services/request-metadata.storage';
|
|
1
5
|
export * from './tracing.module';
|
|
6
|
+
export * from './utils/create-span';
|
|
7
|
+
export * from './utils/save-async-hooks-context';
|
|
8
|
+
export * from './decorators';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Global, Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { RequestMetadataStorage } from './services/request-metadata.storage';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Модуль для хранения и получения данных из аскин локал стораджа
|
|
7
|
+
*/
|
|
8
|
+
@Global()
|
|
9
|
+
@Module({
|
|
10
|
+
providers: [RequestMetadataStorage],
|
|
11
|
+
exports: [RequestMetadataStorage],
|
|
12
|
+
})
|
|
13
|
+
export class RequestMetadataModule {}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import type { Span } from '@opentelemetry/api';
|
|
3
|
+
import { api } from '@opentelemetry/sdk-node';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Обертка вокруг `api.trace.getActiveSpan()`
|
|
7
|
+
*/
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class ActiveSpanStorage {
|
|
10
|
+
/**
|
|
11
|
+
* Так как этот сервис используется в разных местах, чтобы не усложнять существующий код путем проксирования модулей и сервисов
|
|
12
|
+
* после создания ложим инстанс в эту статик переменную
|
|
13
|
+
*/
|
|
14
|
+
private static instance: ActiveSpanStorage | undefined;
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
if (!ActiveSpanStorage.instance) {
|
|
18
|
+
ActiveSpanStorage.instance = this;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static getInstance(): ActiveSpanStorage | undefined {
|
|
23
|
+
return ActiveSpanStorage.instance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Получает новое значение в контекст
|
|
28
|
+
*/
|
|
29
|
+
getActiveSpan(): Span | undefined {
|
|
30
|
+
return api.trace.getActiveSpan();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,145 +1,31 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
-
import {
|
|
3
|
-
EXCEPTION_FILTERS_METADATA,
|
|
4
|
-
GUARDS_METADATA,
|
|
5
|
-
INTERCEPTORS_METADATA,
|
|
6
|
-
PIPES_METADATA,
|
|
7
|
-
} from '@nestjs/common/constants';
|
|
8
|
-
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
|
9
|
-
import { ILogger } from '@rsdk/logging';
|
|
10
2
|
|
|
11
|
-
import {
|
|
3
|
+
import { TracingInterceptor } from '../tracing.interceptor';
|
|
12
4
|
|
|
13
|
-
import {
|
|
5
|
+
import { RequestMetadataInjector } from './request-metadata.injector';
|
|
14
6
|
import { TraceInjector } from './trace.injector';
|
|
15
7
|
|
|
16
|
-
const types = [
|
|
17
|
-
EXCEPTION_FILTERS_METADATA,
|
|
18
|
-
GUARDS_METADATA,
|
|
19
|
-
INTERCEPTORS_METADATA,
|
|
20
|
-
PIPES_METADATA,
|
|
21
|
-
] as const;
|
|
22
|
-
|
|
23
8
|
@Injectable()
|
|
24
9
|
export class InstrumentationService {
|
|
25
|
-
|
|
26
|
-
@InjectLogger(InstrumentationService) private readonly logger: ILogger,
|
|
27
|
-
protected readonly scanner: ExtendedMetadataScanner,
|
|
28
|
-
) {}
|
|
29
|
-
|
|
30
|
-
public inject(): void {
|
|
31
|
-
/**
|
|
32
|
-
* Для каждого контроллера
|
|
33
|
-
*/
|
|
34
|
-
for (const controller of this.scanner.getControllers()) {
|
|
35
|
-
/**
|
|
36
|
-
* Перебираем методы контроллера и оборачиваем их.
|
|
37
|
-
*/
|
|
38
|
-
this.wrapMethods(controller.metatype.prototype);
|
|
39
|
-
|
|
40
|
-
this.wrapAugmentations(controller.metatype);
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Для каждого метода контроллера
|
|
44
|
-
*/
|
|
45
|
-
for (const name of this.scanner.getMethods(
|
|
46
|
-
controller.metatype.prototype,
|
|
47
|
-
)) {
|
|
48
|
-
/**
|
|
49
|
-
* Во вложенном цикле находим все гарды, интерцепторы, пайпы и фильтры,
|
|
50
|
-
* привязанные к методу.
|
|
51
|
-
* Уровни вложенности, как в цикле выше
|
|
52
|
-
*/
|
|
53
|
-
const method = controller.metatype.prototype[name];
|
|
54
|
-
|
|
55
|
-
this.wrapAugmentations(method);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Глобальные гарды, интерцепторы, пайпы и фильтры находятся
|
|
61
|
-
* в общем списке провайдеров по injection-токенам.
|
|
62
|
-
*/
|
|
63
|
-
for (const { metatype, token } of this.scanner.getProviders()) {
|
|
64
|
-
if (typeof token !== 'string') {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
token.includes(APP_GUARD) ||
|
|
70
|
-
token.includes(APP_PIPE) ||
|
|
71
|
-
token.includes(APP_INTERCEPTOR) ||
|
|
72
|
-
token.includes(APP_FILTER)
|
|
73
|
-
) {
|
|
74
|
-
this.wrapMethods(metatype.prototype);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
10
|
+
public injectWrapRequestMetadataInjector(): void {
|
|
78
11
|
/**
|
|
79
|
-
*
|
|
80
|
-
* в общем списке провайдеров по injection-токенам.
|
|
12
|
+
* Оборачиваем интерцептор в логику которая несет с собою асинк локал сторадж с requestId
|
|
81
13
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
name === 'ModuleRef' ||
|
|
91
|
-
name === 'Reflector' ||
|
|
92
|
-
name === 'OrphanedReferenceRegistry' ||
|
|
93
|
-
name === 'TypeFieldsAccessor' ||
|
|
94
|
-
name === 'TypeMapperSevice' ||
|
|
95
|
-
name === 'TypeDefinitionsStorage' ||
|
|
96
|
-
name === 'FileSystemHelper' ||
|
|
97
|
-
name === 'TypeDefinitionsGenerator' ||
|
|
98
|
-
name === 'GraphQLSchemaFactory' ||
|
|
99
|
-
name === 'AstDefinitionNodeFactory' ||
|
|
100
|
-
name === 'UnionDefinitionFactory' ||
|
|
101
|
-
name === 'SubscriptionTypeFactory' ||
|
|
102
|
-
name === 'RootTypeFactory' ||
|
|
103
|
-
name === 'ResolveTypeFactory' ||
|
|
104
|
-
name === 'QueryTypeFactory' ||
|
|
105
|
-
name === 'OrphanedTypesFactory' ||
|
|
106
|
-
name === 'OutputTypeFactory' ||
|
|
107
|
-
name === 'ObjectTypeDefinitionFactory' ||
|
|
108
|
-
name === 'MutationTypeFactory' ||
|
|
109
|
-
name === 'InterfaceDefinitionFactory' ||
|
|
110
|
-
name === 'InputTypeFactory' ||
|
|
111
|
-
name === 'ArgsFactory' ||
|
|
112
|
-
name === 'InputTypeDefinitionFactory' ||
|
|
113
|
-
name === 'EnumDefinitionFactory'
|
|
114
|
-
) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this.wrapMethods(prototype);
|
|
119
|
-
}
|
|
14
|
+
RequestMetadataInjector.wrap(
|
|
15
|
+
TracingInterceptor.prototype,
|
|
16
|
+
TracingInterceptor.prototype['intercept'],
|
|
17
|
+
);
|
|
120
18
|
}
|
|
121
19
|
|
|
122
|
-
|
|
20
|
+
public injectWrapTraceInjector(): void {
|
|
123
21
|
/**
|
|
124
|
-
*
|
|
125
|
-
* повешенные на переданный прототип (metatype).
|
|
126
|
-
* 1-й уровень - типы сущностей: интерцепторы, гарды, пайпы, фильтры
|
|
127
|
-
* 2-й уровень - методы сущностей
|
|
22
|
+
* Оборачиваем интерцептор в логику которая несет с собою асинк локал сторадж с traceId, spanId
|
|
128
23
|
*/
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
private wrapMethods(obj: any): void {
|
|
137
|
-
const prototype = obj.prototype ?? obj;
|
|
138
|
-
|
|
139
|
-
this.logger.trace(`Wrapping methods of ${prototype.constructor.name}...`);
|
|
140
|
-
|
|
141
|
-
for (const name of this.scanner.getMethods(prototype)) {
|
|
142
|
-
TraceInjector.wrap(prototype, prototype[name]);
|
|
143
|
-
}
|
|
24
|
+
TraceInjector.wrap(
|
|
25
|
+
TracingInterceptor.prototype,
|
|
26
|
+
TracingInterceptor.prototype['intercept'],
|
|
27
|
+
undefined,
|
|
28
|
+
true,
|
|
29
|
+
);
|
|
144
30
|
}
|
|
145
31
|
}
|