@dumanarge/xssrv-shared-lib 1.0.3 → 1.0.5
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/auth/tenant.middleware.d.ts +6 -1
- package/dist/auth/tenant.middleware.js +10 -3
- package/dist/auth/tenant.middleware.js.map +1 -1
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.js +11 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/observability-context.d.ts +23 -0
- package/dist/context/observability-context.js +71 -0
- package/dist/context/observability-context.js.map +1 -0
- package/dist/context/observability.interceptor.d.ts +5 -0
- package/dist/context/observability.interceptor.js +72 -0
- package/dist/context/observability.interceptor.js.map +1 -0
- package/dist/context/observability.middleware.d.ts +5 -0
- package/dist/context/observability.middleware.js +36 -0
- package/dist/context/observability.middleware.js.map +1 -0
- package/dist/errors/app-error.d.ts +22 -0
- package/dist/errors/app-error.js +94 -0
- package/dist/errors/app-error.js.map +1 -0
- package/dist/errors/app-error.types.d.ts +44 -0
- package/dist/errors/app-error.types.js +3 -0
- package/dist/errors/app-error.types.js.map +1 -0
- package/dist/errors/error-category.d.ts +22 -0
- package/dist/errors/error-category.js +42 -0
- package/dist/errors/error-category.js.map +1 -0
- package/dist/errors/error-registry.d.ts +5 -0
- package/dist/errors/error-registry.js +26 -0
- package/dist/errors/error-registry.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +14 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/filters/grpc-app-exception.filter.d.ts +11 -0
- package/dist/filters/grpc-app-exception.filter.js +177 -0
- package/dist/filters/grpc-app-exception.filter.js.map +1 -0
- package/dist/filters/http-app-exception.filter.d.ts +7 -0
- package/dist/filters/http-app-exception.filter.js +196 -0
- package/dist/filters/http-app-exception.filter.js.map +1 -0
- package/dist/filters/index.d.ts +3 -0
- package/dist/filters/index.js +13 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/severity.d.ts +7 -0
- package/dist/filters/severity.js +51 -0
- package/dist/filters/severity.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/http-exception.filter.d.ts +1 -0
- package/dist/logging/http-exception.filter.js +6 -0
- package/dist/logging/http-exception.filter.js.map +1 -0
- package/dist/logging/logging.module.d.ts +22 -5
- package/dist/logging/logging.module.js +39 -10
- package/dist/logging/logging.module.js.map +1 -1
- package/dist/logging/request-logging.interceptor.d.ts +5 -0
- package/dist/logging/request-logging.interceptor.js +59 -0
- package/dist/logging/request-logging.interceptor.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -0
- package/dist/metrics/index.js +9 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/metrics.d.ts +17 -0
- package/dist/metrics/metrics.js +31 -0
- package/dist/metrics/metrics.js.map +1 -0
- package/dist/observability/error-observability.d.ts +32 -0
- package/dist/observability/error-observability.js +146 -0
- package/dist/observability/error-observability.js.map +1 -0
- package/dist/observability/otel-log-emitter.d.ts +10 -0
- package/dist/observability/otel-log-emitter.js +47 -0
- package/dist/observability/otel-log-emitter.js.map +1 -0
- package/dist/observability/request-context.d.ts +12 -0
- package/dist/observability/request-context.js +49 -0
- package/dist/observability/request-context.js.map +1 -0
- package/dist/tracing/tracing.js +22 -0
- package/dist/tracing/tracing.js.map +1 -1
- package/package.json +24 -1
|
@@ -17,7 +17,11 @@ export declare const PINO_LOGGER_CONFIG: {
|
|
|
17
17
|
url: any;
|
|
18
18
|
headers: {
|
|
19
19
|
'x-request-id': any;
|
|
20
|
+
'x-correlation-id': any;
|
|
20
21
|
'x-tenant-id': any;
|
|
22
|
+
'x-user-id': any;
|
|
23
|
+
'x-account-id': any;
|
|
24
|
+
'x-user-email': any;
|
|
21
25
|
'user-agent': any;
|
|
22
26
|
};
|
|
23
27
|
};
|
|
@@ -25,14 +29,27 @@ export declare const PINO_LOGGER_CONFIG: {
|
|
|
25
29
|
statusCode: any;
|
|
26
30
|
};
|
|
27
31
|
};
|
|
28
|
-
customProps: () => {
|
|
32
|
+
customProps: (req: any) => {
|
|
33
|
+
requestId: any;
|
|
34
|
+
correlationId: any;
|
|
35
|
+
tenantId: string;
|
|
36
|
+
userId: string;
|
|
37
|
+
accountId: string;
|
|
38
|
+
userEmail: string;
|
|
39
|
+
origin: "http" | "grpc" | "rabbitmq" | "cron" | "system";
|
|
40
|
+
operation: string;
|
|
41
|
+
} | {
|
|
29
42
|
traceId: string;
|
|
30
43
|
spanId: string;
|
|
31
44
|
traceFlags: number;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
requestId: any;
|
|
46
|
+
correlationId: any;
|
|
47
|
+
tenantId: string;
|
|
48
|
+
userId: string;
|
|
49
|
+
accountId: string;
|
|
50
|
+
userEmail: string;
|
|
51
|
+
origin: "http" | "grpc" | "rabbitmq" | "cron" | "system";
|
|
52
|
+
operation: string;
|
|
36
53
|
};
|
|
37
54
|
redact: {
|
|
38
55
|
paths: string[];
|
|
@@ -10,6 +10,19 @@ exports.LoggingModule = exports.PINO_LOGGER_CONFIG = void 0;
|
|
|
10
10
|
const common_1 = require("@nestjs/common");
|
|
11
11
|
const nestjs_pino_1 = require("nestjs-pino");
|
|
12
12
|
const api_1 = require("@opentelemetry/api");
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const observability_context_1 = require("../context/observability-context");
|
|
15
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
16
|
+
const redactPaths = [
|
|
17
|
+
'req.headers.authorization',
|
|
18
|
+
'req.headers.cookie',
|
|
19
|
+
'req.body.password',
|
|
20
|
+
'req.body.secret',
|
|
21
|
+
'req.body.token',
|
|
22
|
+
];
|
|
23
|
+
if (isProduction) {
|
|
24
|
+
redactPaths.push('req.headers.x-user-email', 'req.body.email', 'email', 'user.email');
|
|
25
|
+
}
|
|
13
26
|
exports.PINO_LOGGER_CONFIG = {
|
|
14
27
|
pinoHttp: {
|
|
15
28
|
level: process.env.LOG_LEVEL || 'info',
|
|
@@ -27,7 +40,11 @@ exports.PINO_LOGGER_CONFIG = {
|
|
|
27
40
|
url: req.url,
|
|
28
41
|
headers: {
|
|
29
42
|
'x-request-id': req.headers['x-request-id'],
|
|
43
|
+
'x-correlation-id': req.headers['x-correlation-id'],
|
|
30
44
|
'x-tenant-id': req.headers['x-tenant-id'],
|
|
45
|
+
'x-user-id': req.headers['x-user-id'],
|
|
46
|
+
'x-account-id': req.headers['x-account-id'],
|
|
47
|
+
'x-user-email': req.headers['x-user-email'],
|
|
31
48
|
'user-agent': req.headers['user-agent'],
|
|
32
49
|
},
|
|
33
50
|
}),
|
|
@@ -35,30 +52,42 @@ exports.PINO_LOGGER_CONFIG = {
|
|
|
35
52
|
statusCode: res.statusCode,
|
|
36
53
|
}),
|
|
37
54
|
},
|
|
38
|
-
customProps: () => {
|
|
55
|
+
customProps: (req) => {
|
|
39
56
|
const activeSpan = api_1.trace.getActiveSpan();
|
|
57
|
+
const contextData = observability_context_1.ObservabilityContext.get();
|
|
58
|
+
const requestId = contextData?.requestId ?? req?.id ?? req?.headers?.['x-request-id'];
|
|
59
|
+
const correlationId = contextData?.correlationId ?? req?.headers?.['x-correlation-id'] ?? requestId;
|
|
60
|
+
const baseProps = {
|
|
61
|
+
requestId,
|
|
62
|
+
correlationId,
|
|
63
|
+
tenantId: contextData?.tenantId,
|
|
64
|
+
userId: contextData?.userId,
|
|
65
|
+
accountId: contextData?.accountId,
|
|
66
|
+
userEmail: contextData?.userEmail,
|
|
67
|
+
origin: contextData?.origin,
|
|
68
|
+
operation: contextData?.operation,
|
|
69
|
+
};
|
|
40
70
|
if (activeSpan) {
|
|
41
71
|
const spanContext = activeSpan.spanContext();
|
|
72
|
+
observability_context_1.ObservabilityContext.set({
|
|
73
|
+
traceId: spanContext.traceId,
|
|
74
|
+
spanId: spanContext.spanId,
|
|
75
|
+
});
|
|
42
76
|
return {
|
|
77
|
+
...baseProps,
|
|
43
78
|
traceId: spanContext.traceId,
|
|
44
79
|
spanId: spanContext.spanId,
|
|
45
80
|
traceFlags: spanContext.traceFlags,
|
|
46
81
|
};
|
|
47
82
|
}
|
|
48
|
-
return
|
|
83
|
+
return baseProps;
|
|
49
84
|
},
|
|
50
85
|
redact: {
|
|
51
|
-
paths:
|
|
52
|
-
'req.headers.authorization',
|
|
53
|
-
'req.headers.cookie',
|
|
54
|
-
'req.body.password',
|
|
55
|
-
'req.body.secret',
|
|
56
|
-
'req.body.token',
|
|
57
|
-
],
|
|
86
|
+
paths: redactPaths,
|
|
58
87
|
censor: '[REDACTED]',
|
|
59
88
|
},
|
|
60
89
|
genReqId: (req) => {
|
|
61
|
-
return req.headers['x-request-id'] ||
|
|
90
|
+
return req.headers['x-request-id'] || (0, crypto_1.randomUUID)();
|
|
62
91
|
},
|
|
63
92
|
},
|
|
64
93
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.module.js","sourceRoot":"","sources":["../../src/logging/logging.module.ts"],"names":[],"mappings":";;;;;;;;;AAUA,2CAAwC;AACxC,6CAA+D;AAC/D,
|
|
1
|
+
{"version":3,"file":"logging.module.js","sourceRoot":"","sources":["../../src/logging/logging.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
export declare class RequestLoggingInterceptor implements NestInterceptor {
|
|
4
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RequestLoggingInterceptor = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const crypto_1 = require("crypto");
|
|
12
|
+
const rxjs_1 = require("rxjs");
|
|
13
|
+
const request_context_1 = require("../observability/request-context");
|
|
14
|
+
const metrics_1 = require("../metrics");
|
|
15
|
+
let RequestLoggingInterceptor = class RequestLoggingInterceptor {
|
|
16
|
+
intercept(context, next) {
|
|
17
|
+
if (context.getType() !== 'http') {
|
|
18
|
+
return next.handle();
|
|
19
|
+
}
|
|
20
|
+
const http = context.switchToHttp();
|
|
21
|
+
const request = http.getRequest();
|
|
22
|
+
const response = http.getResponse();
|
|
23
|
+
const ctx = (0, request_context_1.createHttpObservabilityContext)(request);
|
|
24
|
+
const requestId = ctx.requestId ?? request.id ?? (0, crypto_1.randomUUID)();
|
|
25
|
+
const correlationId = ctx.correlationId ?? requestId;
|
|
26
|
+
const startedAt = Date.now();
|
|
27
|
+
request.__requestStartedAt = startedAt;
|
|
28
|
+
if (response.setHeader) {
|
|
29
|
+
response.setHeader('x-request-id', requestId);
|
|
30
|
+
response.setHeader('x-correlation-id', correlationId);
|
|
31
|
+
}
|
|
32
|
+
return new rxjs_1.Observable((subscriber) => {
|
|
33
|
+
request_context_1.ObservabilityContextStorage.run({
|
|
34
|
+
...ctx,
|
|
35
|
+
requestId,
|
|
36
|
+
correlationId,
|
|
37
|
+
}, () => {
|
|
38
|
+
next.handle().subscribe({
|
|
39
|
+
next: (value) => subscriber.next(value),
|
|
40
|
+
error: (error) => subscriber.error(error),
|
|
41
|
+
complete: () => {
|
|
42
|
+
(0, metrics_1.recordRequestDurationMetric)(Date.now() - startedAt, {
|
|
43
|
+
service: process.env.SERVICE_NAME ?? 'unknown-service',
|
|
44
|
+
transport: 'http',
|
|
45
|
+
operation: String(request.url ?? 'unknown'),
|
|
46
|
+
statusCode: response.statusCode,
|
|
47
|
+
});
|
|
48
|
+
subscriber.complete();
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.RequestLoggingInterceptor = RequestLoggingInterceptor;
|
|
56
|
+
exports.RequestLoggingInterceptor = RequestLoggingInterceptor = __decorate([
|
|
57
|
+
(0, common_1.Injectable)()
|
|
58
|
+
], RequestLoggingInterceptor);
|
|
59
|
+
//# sourceMappingURL=request-logging.interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-logging.interceptor.js","sourceRoot":"","sources":["../../src/logging/request-logging.interceptor.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAKwB;AACxB,mCAAoC;AACpC,+BAAkC;AAClC,sEAG0C;AAC1C,wCAAyD;AAGlD,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IACpC,SAAS,CAAC,OAAyB,EAAE,IAAiB;QACpD,IAAI,OAAO,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAI3B,CAAC;QACL,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAwD,CAAC;QAE1F,MAAM,GAAG,GAAG,IAAA,gDAA8B,EAAC,OAAO,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,EAAE,IAAI,IAAA,mBAAU,GAAE,CAAC;QAC9D,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,OAAmC,CAAC,kBAAkB,GAAG,SAAS,CAAC;QAEpE,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACvB,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;YAC9C,QAAQ,CAAC,SAAS,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,iBAAU,CAAC,CAAC,UAAU,EAAE,EAAE;YACnC,6CAA2B,CAAC,GAAG,CAC7B;gBACE,GAAG,GAAG;gBACN,SAAS;gBACT,aAAa;aACd,EACD,GAAG,EAAE;gBACH,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC;oBACtB,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;oBACvC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,GAAG,EAAE;wBACb,IAAA,qCAA2B,EAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE;4BAClD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,iBAAiB;4BACtD,SAAS,EAAE,MAAM;4BACjB,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,SAAS,CAAC;4BAC3C,UAAU,EAAG,QAAoC,CAAC,UAAgC;yBACnF,CAAC,CAAC;wBACH,UAAU,CAAC,QAAQ,EAAE,CAAC;oBACxB,CAAC;iBACF,CAAC,CAAC;YACL,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAlDY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;GACA,yBAAyB,CAkDrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { appErrorsCounter, requestDurationHistogram, recordAppErrorMetric, recordRequestDurationMetric, type AppMetricSeverity, type AppErrorMetricInput, type RequestDurationMetricInput, } from './metrics';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordRequestDurationMetric = exports.recordAppErrorMetric = exports.requestDurationHistogram = exports.appErrorsCounter = void 0;
|
|
4
|
+
var metrics_1 = require("./metrics");
|
|
5
|
+
Object.defineProperty(exports, "appErrorsCounter", { enumerable: true, get: function () { return metrics_1.appErrorsCounter; } });
|
|
6
|
+
Object.defineProperty(exports, "requestDurationHistogram", { enumerable: true, get: function () { return metrics_1.requestDurationHistogram; } });
|
|
7
|
+
Object.defineProperty(exports, "recordAppErrorMetric", { enumerable: true, get: function () { return metrics_1.recordAppErrorMetric; } });
|
|
8
|
+
Object.defineProperty(exports, "recordRequestDurationMetric", { enumerable: true, get: function () { return metrics_1.recordRequestDurationMetric; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":";;;AAAA,qCAQmB;AAPjB,2GAAA,gBAAgB,OAAA;AAChB,mHAAA,wBAAwB,OAAA;AACxB,+GAAA,oBAAoB,OAAA;AACpB,sHAAA,2BAA2B,OAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type AppMetricSeverity = 'info' | 'warn' | 'error' | 'fatal';
|
|
2
|
+
export interface AppErrorMetricInput {
|
|
3
|
+
service: string;
|
|
4
|
+
category: string;
|
|
5
|
+
code: string;
|
|
6
|
+
severity: AppMetricSeverity;
|
|
7
|
+
}
|
|
8
|
+
export interface RequestDurationMetricInput {
|
|
9
|
+
service: string;
|
|
10
|
+
transport: 'http' | 'grpc' | 'rabbitmq' | 'system';
|
|
11
|
+
operation: string;
|
|
12
|
+
statusCode?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare const appErrorsCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
15
|
+
export declare const requestDurationHistogram: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
16
|
+
export declare function recordAppErrorMetric(input: AppErrorMetricInput): void;
|
|
17
|
+
export declare function recordRequestDurationMetric(durationMs: number, input: RequestDurationMetricInput): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requestDurationHistogram = exports.appErrorsCounter = void 0;
|
|
4
|
+
exports.recordAppErrorMetric = recordAppErrorMetric;
|
|
5
|
+
exports.recordRequestDurationMetric = recordRequestDurationMetric;
|
|
6
|
+
const api_1 = require("@opentelemetry/api");
|
|
7
|
+
const meter = api_1.metrics.getMeter('xenonsmart-backend');
|
|
8
|
+
exports.appErrorsCounter = meter.createCounter('app_errors_total', {
|
|
9
|
+
description: 'Total application errors by service/category/code/severity',
|
|
10
|
+
});
|
|
11
|
+
exports.requestDurationHistogram = meter.createHistogram('app_request_duration_ms', {
|
|
12
|
+
description: 'Application request duration in milliseconds',
|
|
13
|
+
unit: 'ms',
|
|
14
|
+
});
|
|
15
|
+
function recordAppErrorMetric(input) {
|
|
16
|
+
exports.appErrorsCounter.add(1, {
|
|
17
|
+
service: input.service,
|
|
18
|
+
category: input.category,
|
|
19
|
+
code: input.code,
|
|
20
|
+
severity: input.severity,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function recordRequestDurationMetric(durationMs, input) {
|
|
24
|
+
exports.requestDurationHistogram.record(durationMs, {
|
|
25
|
+
service: input.service,
|
|
26
|
+
transport: input.transport,
|
|
27
|
+
operation: input.operation,
|
|
28
|
+
status_code: input.statusCode ? String(input.statusCode) : 'unknown',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/metrics/metrics.ts"],"names":[],"mappings":";;;AA6BA,oDAOC;AAED,kEAUC;AAhDD,4CAA6C;AAkB7C,MAAM,KAAK,GAAG,aAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAExC,QAAA,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAC,kBAAkB,EAAE;IACtE,WAAW,EAAE,4DAA4D;CAC1E,CAAC,CAAC;AAEU,QAAA,wBAAwB,GAAG,KAAK,CAAC,eAAe,CAAC,yBAAyB,EAAE;IACvF,WAAW,EAAE,8CAA8C;IAC3D,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,SAAgB,oBAAoB,CAAC,KAA0B;IAC7D,wBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,2BAA2B,CACzC,UAAkB,EAClB,KAAiC;IAEjC,gCAAwB,CAAC,MAAM,CAAC,UAAU,EAAE;QAC1C,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;KACrE,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type AppErrorSeverity = 'info' | 'warn' | 'error';
|
|
2
|
+
export type AppErrorLogPayload = {
|
|
3
|
+
service: string;
|
|
4
|
+
transport: 'http' | 'grpc' | 'rabbitmq' | 'system';
|
|
5
|
+
errorKey: string;
|
|
6
|
+
messageKey?: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
retryable?: boolean;
|
|
9
|
+
httpCode?: number;
|
|
10
|
+
grpcCode?: number;
|
|
11
|
+
requestId?: string;
|
|
12
|
+
userId?: string;
|
|
13
|
+
accountId?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
details?: Record<string, unknown>;
|
|
16
|
+
fields?: Array<{
|
|
17
|
+
field?: string;
|
|
18
|
+
code?: string;
|
|
19
|
+
message?: string;
|
|
20
|
+
}>;
|
|
21
|
+
timestamp?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function resolveErrorSeverity(payload: AppErrorLogPayload): AppErrorSeverity;
|
|
24
|
+
export declare function emitAppErrorObservability(payload: AppErrorLogPayload, options?: {
|
|
25
|
+
logger?: {
|
|
26
|
+
error?: (payload: unknown, message?: string) => void;
|
|
27
|
+
warn?: (payload: unknown, message?: string) => void;
|
|
28
|
+
info?: (payload: unknown, message?: string) => void;
|
|
29
|
+
log?: (payload: unknown, message?: string) => void;
|
|
30
|
+
};
|
|
31
|
+
severity?: AppErrorSeverity;
|
|
32
|
+
}): AppErrorSeverity;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveErrorSeverity = resolveErrorSeverity;
|
|
4
|
+
exports.emitAppErrorObservability = emitAppErrorObservability;
|
|
5
|
+
const api_1 = require("@opentelemetry/api");
|
|
6
|
+
const meter = api_1.metrics.getMeter('xssrv-shared-observability');
|
|
7
|
+
const appErrorLogCounter = meter.createCounter('app_error_log_total', {
|
|
8
|
+
description: 'Application error logs grouped by severity and error identity.',
|
|
9
|
+
});
|
|
10
|
+
function normalizeHttpCode(httpCode) {
|
|
11
|
+
if (typeof httpCode !== 'number' || Number.isNaN(httpCode)) {
|
|
12
|
+
return 'unknown';
|
|
13
|
+
}
|
|
14
|
+
return String(httpCode);
|
|
15
|
+
}
|
|
16
|
+
function readString(input) {
|
|
17
|
+
if (typeof input !== 'string') {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
const value = input.trim();
|
|
21
|
+
return value.length > 0 ? value : undefined;
|
|
22
|
+
}
|
|
23
|
+
function firstValidationField(fields) {
|
|
24
|
+
if (!Array.isArray(fields) || fields.length === 0) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const first = fields[0];
|
|
28
|
+
if (!first) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
field: readString(first.field),
|
|
33
|
+
code: readString(first.code),
|
|
34
|
+
message: readString(first.message),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function firstDetailsValidation(details) {
|
|
38
|
+
const validationErrors = details
|
|
39
|
+
?.validationErrors;
|
|
40
|
+
if (!Array.isArray(validationErrors) || validationErrors.length === 0) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const first = validationErrors[0];
|
|
44
|
+
if (!first) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const field = readString(first.property);
|
|
48
|
+
const constraints = first.constraints;
|
|
49
|
+
const constraintKey = constraints ? Object.keys(constraints)[0] : undefined;
|
|
50
|
+
const rule = readString(constraintKey);
|
|
51
|
+
const message = constraints && constraintKey ? readString(constraints[constraintKey]) : undefined;
|
|
52
|
+
return { field, rule, message };
|
|
53
|
+
}
|
|
54
|
+
function resolveErrorSeverity(payload) {
|
|
55
|
+
const category = payload.category?.toUpperCase();
|
|
56
|
+
const httpCode = payload.httpCode;
|
|
57
|
+
const grpcCode = payload.grpcCode;
|
|
58
|
+
if (httpCode === 503 || httpCode === 504) {
|
|
59
|
+
return 'warn';
|
|
60
|
+
}
|
|
61
|
+
if (typeof httpCode === 'number' && httpCode >= 500) {
|
|
62
|
+
return 'error';
|
|
63
|
+
}
|
|
64
|
+
if (grpcCode === 14 || grpcCode === 4) {
|
|
65
|
+
return 'warn';
|
|
66
|
+
}
|
|
67
|
+
if (grpcCode === 13 || grpcCode === 2 || grpcCode === 15) {
|
|
68
|
+
return 'error';
|
|
69
|
+
}
|
|
70
|
+
if (category === 'UNAVAILABLE' || category === 'TIMEOUT' || category === 'DEPENDENCY') {
|
|
71
|
+
return 'warn';
|
|
72
|
+
}
|
|
73
|
+
if (category === 'INTERNAL') {
|
|
74
|
+
return 'error';
|
|
75
|
+
}
|
|
76
|
+
return 'info';
|
|
77
|
+
}
|
|
78
|
+
function emitAppErrorObservability(payload, options) {
|
|
79
|
+
const severity = options?.severity ?? resolveErrorSeverity(payload);
|
|
80
|
+
const details = payload.details ?? {};
|
|
81
|
+
const validationField = firstValidationField(payload.fields);
|
|
82
|
+
const detailsValidation = firstDetailsValidation(details);
|
|
83
|
+
const source = details;
|
|
84
|
+
const targetService = readString(source.unavailableService) ??
|
|
85
|
+
readString(source.dependency) ??
|
|
86
|
+
readString(source.source);
|
|
87
|
+
const operation = readString(source.operation);
|
|
88
|
+
appErrorLogCounter.add(1, {
|
|
89
|
+
service: payload.service,
|
|
90
|
+
level: severity,
|
|
91
|
+
error_key: payload.errorKey,
|
|
92
|
+
category: payload.category ?? 'UNKNOWN',
|
|
93
|
+
transport: payload.transport,
|
|
94
|
+
http_code: normalizeHttpCode(payload.httpCode),
|
|
95
|
+
});
|
|
96
|
+
const logPayload = {
|
|
97
|
+
event: 'app_error',
|
|
98
|
+
level: severity,
|
|
99
|
+
service: payload.service,
|
|
100
|
+
sourceService: payload.service,
|
|
101
|
+
targetService,
|
|
102
|
+
operation,
|
|
103
|
+
transport: payload.transport,
|
|
104
|
+
errorKey: payload.errorKey,
|
|
105
|
+
messageKey: payload.messageKey,
|
|
106
|
+
category: payload.category,
|
|
107
|
+
retryable: payload.retryable,
|
|
108
|
+
status: {
|
|
109
|
+
http: payload.httpCode,
|
|
110
|
+
grpc: payload.grpcCode,
|
|
111
|
+
},
|
|
112
|
+
validation: validationField || detailsValidation
|
|
113
|
+
? {
|
|
114
|
+
field: validationField?.field ?? detailsValidation?.field,
|
|
115
|
+
code: validationField?.code,
|
|
116
|
+
rule: detailsValidation?.rule,
|
|
117
|
+
message: validationField?.message ?? detailsValidation?.message,
|
|
118
|
+
}
|
|
119
|
+
: undefined,
|
|
120
|
+
user: {
|
|
121
|
+
userId: payload.userId,
|
|
122
|
+
accountId: payload.accountId,
|
|
123
|
+
email: payload.email,
|
|
124
|
+
},
|
|
125
|
+
requestId: payload.requestId,
|
|
126
|
+
details: payload.details,
|
|
127
|
+
timestamp: payload.timestamp ?? new Date().toISOString(),
|
|
128
|
+
};
|
|
129
|
+
const logger = options?.logger;
|
|
130
|
+
if (severity === 'error') {
|
|
131
|
+
logger?.error?.(logPayload, 'Application error observed');
|
|
132
|
+
}
|
|
133
|
+
else if (severity === 'warn') {
|
|
134
|
+
logger?.warn?.(logPayload, 'Application warning observed');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
if (logger?.info) {
|
|
138
|
+
logger.info(logPayload, 'Application info observed');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
logger?.log?.(logPayload, 'Application info observed');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return severity;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=error-observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-observability.js","sourceRoot":"","sources":["../../src/observability/error-observability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type OTelSeverity = 'info' | 'warn' | 'error' | 'fatal';
|
|
2
|
+
type OTelLogInput = {
|
|
3
|
+
service: string;
|
|
4
|
+
severity: OTelSeverity;
|
|
5
|
+
message: string;
|
|
6
|
+
attributes?: Record<string, unknown>;
|
|
7
|
+
body?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
export declare function emitOtelLog(input: OTelLogInput): void;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitOtelLog = emitOtelLog;
|
|
4
|
+
let cachedLogger;
|
|
5
|
+
function toSeverityNumber(level) {
|
|
6
|
+
switch (level) {
|
|
7
|
+
case 'fatal':
|
|
8
|
+
return 21;
|
|
9
|
+
case 'error':
|
|
10
|
+
return 17;
|
|
11
|
+
case 'warn':
|
|
12
|
+
return 13;
|
|
13
|
+
default:
|
|
14
|
+
return 9;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function getLogger() {
|
|
18
|
+
if (cachedLogger !== undefined) {
|
|
19
|
+
return cachedLogger;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const apiLogs = require('@opentelemetry/api-logs');
|
|
23
|
+
cachedLogger = apiLogs.logs.getLogger('xenonsmart-backend');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
cachedLogger = null;
|
|
27
|
+
}
|
|
28
|
+
return cachedLogger;
|
|
29
|
+
}
|
|
30
|
+
function emitOtelLog(input) {
|
|
31
|
+
const logger = getLogger();
|
|
32
|
+
if (!logger) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const severityText = input.severity.toUpperCase();
|
|
36
|
+
logger.emit({
|
|
37
|
+
severityNumber: toSeverityNumber(input.severity),
|
|
38
|
+
severityText,
|
|
39
|
+
body: input.body ?? { message: input.message },
|
|
40
|
+
attributes: {
|
|
41
|
+
service: input.service,
|
|
42
|
+
severity: input.severity,
|
|
43
|
+
...input.attributes,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=otel-log-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel-log-emitter.js","sourceRoot":"","sources":["../../src/observability/otel-log-emitter.ts"],"names":[],"mappings":";;AAmDA,kCAkBC;AAlDD,IAAI,YAA+C,CAAC;AAEpD,SAAS,gBAAgB,CAAC,KAAmB;IAC3C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,EAAE,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,EAAE,CAAC;QACZ;YACE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,yBAAyB,CAEhD,CAAC;QACF,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAgB,WAAW,CAAC,KAAmB;IAC7C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAElD,MAAM,CAAC,IAAI,CAAC;QACV,cAAc,EAAE,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAChD,YAAY;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;QAC9C,UAAU,EAAE;YACV,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,KAAK,CAAC,UAAU;SACpB;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createHttpObservabilityContext, type ObservabilityContextData as BaseObservabilityContextData } from '../context/observability-context';
|
|
2
|
+
export interface ObservabilityContextData extends BaseObservabilityContextData {
|
|
3
|
+
email?: string;
|
|
4
|
+
source?: BaseObservabilityContextData['origin'];
|
|
5
|
+
}
|
|
6
|
+
export declare class ObservabilityContextStorage {
|
|
7
|
+
static run<T>(context: ObservabilityContextData, callback: () => T): T;
|
|
8
|
+
static get(): ObservabilityContextData | undefined;
|
|
9
|
+
static patch(input: Partial<ObservabilityContextData>): void;
|
|
10
|
+
static toLogMeta(): Record<string, string | undefined>;
|
|
11
|
+
}
|
|
12
|
+
export { createHttpObservabilityContext };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHttpObservabilityContext = exports.ObservabilityContextStorage = void 0;
|
|
4
|
+
const observability_context_1 = require("../context/observability-context");
|
|
5
|
+
Object.defineProperty(exports, "createHttpObservabilityContext", { enumerable: true, get: function () { return observability_context_1.createHttpObservabilityContext; } });
|
|
6
|
+
class ObservabilityContextStorage {
|
|
7
|
+
static run(context, callback) {
|
|
8
|
+
return observability_context_1.ObservabilityContext.run({
|
|
9
|
+
...context,
|
|
10
|
+
userEmail: context.userEmail ?? context.email,
|
|
11
|
+
origin: context.origin ?? context.source,
|
|
12
|
+
}, callback);
|
|
13
|
+
}
|
|
14
|
+
static get() {
|
|
15
|
+
const current = observability_context_1.ObservabilityContext.get();
|
|
16
|
+
if (!current) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
...current,
|
|
21
|
+
email: current.userEmail,
|
|
22
|
+
source: current.origin,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
static patch(input) {
|
|
26
|
+
observability_context_1.ObservabilityContext.set({
|
|
27
|
+
...input,
|
|
28
|
+
userEmail: input.userEmail ?? input.email,
|
|
29
|
+
origin: input.origin ?? input.source,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
static toLogMeta() {
|
|
33
|
+
const context = ObservabilityContextStorage.get();
|
|
34
|
+
return {
|
|
35
|
+
requestId: context?.requestId,
|
|
36
|
+
correlationId: context?.correlationId,
|
|
37
|
+
tenantId: context?.tenantId,
|
|
38
|
+
userId: context?.userId,
|
|
39
|
+
accountId: context?.accountId,
|
|
40
|
+
email: context?.email,
|
|
41
|
+
source: context?.source,
|
|
42
|
+
operation: context?.operation,
|
|
43
|
+
traceId: context?.traceId,
|
|
44
|
+
spanId: context?.spanId,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ObservabilityContextStorage = ObservabilityContextStorage;
|
|
49
|
+
//# sourceMappingURL=request-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/observability/request-context.ts"],"names":[],"mappings":";;;AAAA,4EAI0C;AAwDjC,+GA3DP,sDAA8B,OA2DO;AAjDvC,MAAa,2BAA2B;IACtC,MAAM,CAAC,GAAG,CAAI,OAAiC,EAAE,QAAiB;QAChE,OAAO,4CAAoB,CAAC,GAAG,CAC7B;YACE,GAAG,OAAO;YACV,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,KAAK;YAC7C,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM;SACzC,EACD,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG;QACR,MAAM,OAAO,GAAG,4CAAoB,CAAC,GAAG,EAAE,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO;YACL,GAAG,OAAO;YACV,KAAK,EAAE,OAAO,CAAC,SAAS;YACxB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,KAAwC;QACnD,4CAAoB,CAAC,GAAG,CAAC;YACvB,GAAG,KAAK;YACR,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK;YACzC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM;SACrC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,SAAS;QACd,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,EAAE,CAAC;QAClD,OAAO;YACL,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,aAAa,EAAE,OAAO,EAAE,aAAa;YACrC,QAAQ,EAAE,OAAO,EAAE,QAAQ;YAC3B,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,OAAO,EAAE,OAAO,EAAE,OAAO;YACzB,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC;IACJ,CAAC;CACF;AA/CD,kEA+CC"}
|
package/dist/tracing/tracing.js
CHANGED
|
@@ -28,6 +28,24 @@ const metricReader = new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
|
28
28
|
exporter: new exporter_metrics_otlp_grpc_1.OTLPMetricExporter({ url: otelEndpoint }),
|
|
29
29
|
exportIntervalMillis: 15000,
|
|
30
30
|
});
|
|
31
|
+
let logProvider = null;
|
|
32
|
+
function setupOtelLogs() {
|
|
33
|
+
try {
|
|
34
|
+
const sdkLogs = require('@opentelemetry/sdk-logs');
|
|
35
|
+
const exporterLogs = require('@opentelemetry/exporter-logs-otlp-grpc');
|
|
36
|
+
const apiLogs = require('@opentelemetry/api-logs');
|
|
37
|
+
const provider = new sdkLogs.LoggerProvider({ resource });
|
|
38
|
+
const exporter = new exporterLogs.OTLPLogExporter({ url: otelEndpoint });
|
|
39
|
+
provider.addLogRecordProcessor(new sdkLogs.BatchLogRecordProcessor(exporter));
|
|
40
|
+
apiLogs.logs.setGlobalLoggerProvider(provider);
|
|
41
|
+
logProvider = provider;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (process.env.OTEL_DEBUG === 'true') {
|
|
45
|
+
console.warn('OpenTelemetry logs SDK is not available. Install @opentelemetry/sdk-logs, @opentelemetry/api-logs and @opentelemetry/exporter-logs-otlp-grpc.', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
31
49
|
const sdk = new sdk_node_1.NodeSDK({
|
|
32
50
|
resource,
|
|
33
51
|
traceExporter,
|
|
@@ -46,10 +64,14 @@ const sdk = new sdk_node_1.NodeSDK({
|
|
|
46
64
|
],
|
|
47
65
|
});
|
|
48
66
|
exports.sdk = sdk;
|
|
67
|
+
setupOtelLogs();
|
|
49
68
|
sdk.start();
|
|
50
69
|
const shutdown = async () => {
|
|
51
70
|
try {
|
|
52
71
|
await sdk.shutdown();
|
|
72
|
+
if (logProvider) {
|
|
73
|
+
await logProvider.shutdown();
|
|
74
|
+
}
|
|
53
75
|
console.log('OpenTelemetry SDK shut down successfully');
|
|
54
76
|
}
|
|
55
77
|
catch (err) {
|