@ryanzeng/nest-observe 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/dist/index.d.mts +44 -17
- package/dist/index.d.ts +44 -17
- package/dist/index.js +353 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +359 -43
- package/dist/index.mjs.map +1 -1
- package/dist/register.js +312 -43
- package/dist/register.js.map +1 -1
- package/dist/register.mjs +312 -43
- package/dist/register.mjs.map +1 -1
- package/package.json +19 -9
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(index_exports, {
|
|
|
32
32
|
CompatibleNestInstrumentation: () => CompatibleNestInstrumentation,
|
|
33
33
|
HttpRequestMetrics: () => HttpRequestMetrics,
|
|
34
34
|
IgnoreTrace: () => IgnoreTrace,
|
|
35
|
+
NestHttpMetricsInterceptor: () => NestHttpMetricsInterceptor,
|
|
35
36
|
NestLoggerInstrumentation: () => NestLoggerInstrumentation,
|
|
36
37
|
NestMethodInstrumenter: () => NestMethodInstrumenter,
|
|
37
38
|
OBSERVE_HANDLE: () => OBSERVE_HANDLE,
|
|
@@ -139,7 +140,9 @@ function resolveObserveConfig(options = {}, env = process.env) {
|
|
|
139
140
|
allowedHeaders,
|
|
140
141
|
exportTimeoutMillis: positiveInteger(options.exportTimeoutMillis ?? env.OTEL_EXPORTER_OTLP_TIMEOUT, 1e4),
|
|
141
142
|
metricExportIntervalMillis: positiveInteger(options.metricExportIntervalMillis ?? env.OTEL_METRIC_EXPORT_INTERVAL, 6e4),
|
|
142
|
-
resourceAttributes
|
|
143
|
+
resourceAttributes,
|
|
144
|
+
diagnosticLogging: booleanValue(options.diagnosticLogging, true),
|
|
145
|
+
failFast: booleanValue(options.failFast, false)
|
|
143
146
|
};
|
|
144
147
|
if (options.exporters) result.exporters = options.exporters;
|
|
145
148
|
return result;
|
|
@@ -230,6 +233,11 @@ function invokeWithSpan(tracer, spanName, attributes, invoke, onFinish) {
|
|
|
230
233
|
}
|
|
231
234
|
|
|
232
235
|
// src/decorators/trace.decorator.ts
|
|
236
|
+
function copyOwnMetadata(source, target) {
|
|
237
|
+
for (const metadataKey of Reflect.getOwnMetadataKeys(source)) {
|
|
238
|
+
Reflect.defineMetadata(metadataKey, Reflect.getOwnMetadata(metadataKey, source), target);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
233
241
|
function decorateMethod(target, propertyKey, descriptor, options) {
|
|
234
242
|
const original = descriptor.value;
|
|
235
243
|
if (typeof original !== "function" || isTraceIgnored(original, target.constructor))
|
|
@@ -254,6 +262,7 @@ function decorateMethod(target, propertyKey, descriptor, options) {
|
|
|
254
262
|
value: original.name,
|
|
255
263
|
configurable: true
|
|
256
264
|
});
|
|
265
|
+
copyOwnMetadata(original, wrapped);
|
|
257
266
|
markTraceDecorated(wrapped);
|
|
258
267
|
descriptor.value = wrapped;
|
|
259
268
|
}
|
|
@@ -334,7 +343,8 @@ var SEVERITY = {
|
|
|
334
343
|
fatal: "FATAL"
|
|
335
344
|
};
|
|
336
345
|
function bodyValue(message) {
|
|
337
|
-
if (message instanceof Error)
|
|
346
|
+
if (message instanceof Error)
|
|
347
|
+
return redactText(message.stack ?? `${message.name}: ${message.message}`);
|
|
338
348
|
return redact(message);
|
|
339
349
|
}
|
|
340
350
|
var NestLoggerInstrumentation = class {
|
|
@@ -379,7 +389,8 @@ var NestLoggerInstrumentation = class {
|
|
|
379
389
|
disable() {
|
|
380
390
|
if (!this.enabled) return;
|
|
381
391
|
const prototype = import_common.ConsoleLogger.prototype;
|
|
382
|
-
for (const [method, original] of this.originals)
|
|
392
|
+
for (const [method, original] of this.originals)
|
|
393
|
+
prototype[method] = original;
|
|
383
394
|
this.originals.clear();
|
|
384
395
|
this.enabled = false;
|
|
385
396
|
}
|
|
@@ -455,7 +466,7 @@ var NestMethodInstrumenter = class {
|
|
|
455
466
|
if (!descriptor || typeof original !== "function" || isTraceIgnored(original, type) || isTraceDecorated(original)) continue;
|
|
456
467
|
const existing = Reflect.get(target, methodName);
|
|
457
468
|
if (typeof existing === "function" && existing !== original && isTraceDecorated(existing)) continue;
|
|
458
|
-
const name = componentName
|
|
469
|
+
const name = typeof componentName === "symbol" ? String(componentName) : typeof componentName === "string" && componentName ? componentName : type.name || "Anonymous";
|
|
459
470
|
const attributes = {
|
|
460
471
|
[`nestjs.${kind}`]: name,
|
|
461
472
|
"nestjs.method": methodName
|
|
@@ -508,7 +519,7 @@ var CompatibleNestInstrumentation = class extends import_instrumentation_nestjs_
|
|
|
508
519
|
const instance = await original.apply(this, args);
|
|
509
520
|
try {
|
|
510
521
|
const wrapper = args[1];
|
|
511
|
-
if (!instance || typeof instance !== "object" || !wrapper?.metatype) return instance;
|
|
522
|
+
if (!instance || typeof instance !== "object" || !wrapper?.metatype || wrapper.inject !== void 0) return instance;
|
|
512
523
|
if (["InternalCoreModule", "ObserveModule", "DiscoveryModule"].includes(wrapper.host?.name ?? "")) {
|
|
513
524
|
return instance;
|
|
514
525
|
}
|
|
@@ -569,9 +580,14 @@ var HttpRequestMetrics = class {
|
|
|
569
580
|
errorCount;
|
|
570
581
|
startedAt = /* @__PURE__ */ new WeakMap();
|
|
571
582
|
start(request) {
|
|
583
|
+
if (this.startedAt.has(request)) return false;
|
|
572
584
|
this.startedAt.set(request, process.hrtime.bigint());
|
|
585
|
+
return true;
|
|
573
586
|
}
|
|
574
587
|
record(request, response) {
|
|
588
|
+
const started = this.startedAt.get(request);
|
|
589
|
+
if (started === void 0) return false;
|
|
590
|
+
this.startedAt.delete(request);
|
|
575
591
|
const statusCode = Number.isFinite(response.statusCode) ? response.statusCode : 0;
|
|
576
592
|
const attributes = {
|
|
577
593
|
"service.name": this.serviceName,
|
|
@@ -580,12 +596,9 @@ var HttpRequestMetrics = class {
|
|
|
580
596
|
"http.response.status_code": statusCode
|
|
581
597
|
};
|
|
582
598
|
this.requestCount.add(1, attributes);
|
|
583
|
-
|
|
584
|
-
if (started !== void 0) {
|
|
585
|
-
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
586
|
-
this.startedAt.delete(request);
|
|
587
|
-
}
|
|
599
|
+
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
588
600
|
if (statusCode >= 500) this.errorCount.add(1, attributes);
|
|
601
|
+
return true;
|
|
589
602
|
}
|
|
590
603
|
};
|
|
591
604
|
|
|
@@ -674,6 +687,7 @@ var RuntimeMetrics = class {
|
|
|
674
687
|
var import_common2 = require("@nestjs/common");
|
|
675
688
|
var import_core = require("@nestjs/core");
|
|
676
689
|
var import_api7 = require("@opentelemetry/api");
|
|
690
|
+
var import_rxjs2 = require("rxjs");
|
|
677
691
|
|
|
678
692
|
// src/sdk.ts
|
|
679
693
|
var import_api_logs2 = require("@opentelemetry/api-logs");
|
|
@@ -689,6 +703,113 @@ var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
|
|
689
703
|
var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
|
690
704
|
var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
|
|
691
705
|
|
|
706
|
+
// src/diagnostics.ts
|
|
707
|
+
function toError(value) {
|
|
708
|
+
if (value instanceof Error) return value;
|
|
709
|
+
if (typeof value === "string") return new Error(value);
|
|
710
|
+
try {
|
|
711
|
+
return new Error(JSON.stringify(value));
|
|
712
|
+
} catch {
|
|
713
|
+
return new Error(String(value));
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
function sanitizeError(error) {
|
|
717
|
+
const sanitized = new Error(redactText(error.message));
|
|
718
|
+
sanitized.name = error.name;
|
|
719
|
+
if (error.stack) sanitized.stack = redactText(error.stack);
|
|
720
|
+
return sanitized;
|
|
721
|
+
}
|
|
722
|
+
var ObserveDiagnostics = class {
|
|
723
|
+
constructor(logging, onError) {
|
|
724
|
+
this.logging = logging;
|
|
725
|
+
this.onError = onError;
|
|
726
|
+
}
|
|
727
|
+
logging;
|
|
728
|
+
onError;
|
|
729
|
+
currentStatus = "starting";
|
|
730
|
+
currentError;
|
|
731
|
+
failedSignals = /* @__PURE__ */ new Set();
|
|
732
|
+
reported = /* @__PURE__ */ new Set();
|
|
733
|
+
get status() {
|
|
734
|
+
return this.currentStatus;
|
|
735
|
+
}
|
|
736
|
+
get lastError() {
|
|
737
|
+
return this.currentError;
|
|
738
|
+
}
|
|
739
|
+
activate() {
|
|
740
|
+
if (this.currentStatus === "starting") this.currentStatus = "active";
|
|
741
|
+
}
|
|
742
|
+
inactive() {
|
|
743
|
+
this.currentStatus = "inactive";
|
|
744
|
+
}
|
|
745
|
+
stop() {
|
|
746
|
+
this.currentStatus = "stopped";
|
|
747
|
+
}
|
|
748
|
+
success(signal) {
|
|
749
|
+
this.failedSignals.delete(signal);
|
|
750
|
+
for (const fingerprint of this.reported) {
|
|
751
|
+
if (fingerprint.startsWith(`${signal}\0`)) this.reported.delete(fingerprint);
|
|
752
|
+
}
|
|
753
|
+
if (this.currentStatus === "degraded" && this.failedSignals.size === 0) {
|
|
754
|
+
this.currentStatus = "active";
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
failure(signal, stage, value) {
|
|
758
|
+
const error = sanitizeError(toError(value));
|
|
759
|
+
const event = { signal, stage, error, timestamp: Date.now() };
|
|
760
|
+
this.currentError = event;
|
|
761
|
+
this.failedSignals.add(signal);
|
|
762
|
+
if (this.currentStatus !== "inactive" && this.currentStatus !== "stopped") {
|
|
763
|
+
this.currentStatus = "degraded";
|
|
764
|
+
}
|
|
765
|
+
const fingerprint = `${signal}\0${stage}\0${error.name}\0${error.message}`;
|
|
766
|
+
if (this.reported.has(fingerprint)) return;
|
|
767
|
+
this.reported.add(fingerprint);
|
|
768
|
+
try {
|
|
769
|
+
this.onError?.(event);
|
|
770
|
+
} catch {
|
|
771
|
+
}
|
|
772
|
+
if (!this.logging) return;
|
|
773
|
+
try {
|
|
774
|
+
process.stderr.write(
|
|
775
|
+
`[nest-observe] ${signal} ${stage} failed: ${redactText(error.message)}
|
|
776
|
+
`
|
|
777
|
+
);
|
|
778
|
+
} catch {
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
function withExporterDiagnostics(exporter, signal, diagnostics) {
|
|
783
|
+
const delegate = exporter;
|
|
784
|
+
return new Proxy(exporter, {
|
|
785
|
+
get(target, property) {
|
|
786
|
+
if (property === "export") {
|
|
787
|
+
return (items, callback) => {
|
|
788
|
+
try {
|
|
789
|
+
delegate.export.call(target, items, (result) => {
|
|
790
|
+
if (result.code === 0) {
|
|
791
|
+
diagnostics.success(signal);
|
|
792
|
+
} else {
|
|
793
|
+
diagnostics.failure(
|
|
794
|
+
signal,
|
|
795
|
+
"export",
|
|
796
|
+
result.error ?? new Error(`${signal} export failed`)
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
callback(result);
|
|
800
|
+
});
|
|
801
|
+
} catch (error) {
|
|
802
|
+
diagnostics.failure(signal, "export", error);
|
|
803
|
+
throw error;
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
const value = Reflect.get(target, property, target);
|
|
808
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
692
813
|
// src/exceptions/process-exception-capture.ts
|
|
693
814
|
var import_api5 = require("@opentelemetry/api");
|
|
694
815
|
function asError(value) {
|
|
@@ -738,8 +859,118 @@ var ProcessExceptionCapture = class {
|
|
|
738
859
|
// src/resource.ts
|
|
739
860
|
var import_resources = require("@opentelemetry/resources");
|
|
740
861
|
var import_node_os2 = require("os");
|
|
741
|
-
|
|
742
|
-
|
|
862
|
+
|
|
863
|
+
// package.json
|
|
864
|
+
var package_default = {
|
|
865
|
+
name: "@ryanzeng/nest-observe",
|
|
866
|
+
version: "0.1.3",
|
|
867
|
+
description: "Zero-config, vendor-neutral OpenTelemetry observability for NestJS",
|
|
868
|
+
keywords: [
|
|
869
|
+
"nestjs",
|
|
870
|
+
"opentelemetry",
|
|
871
|
+
"observability",
|
|
872
|
+
"otlp",
|
|
873
|
+
"tracing",
|
|
874
|
+
"metrics",
|
|
875
|
+
"logging"
|
|
876
|
+
],
|
|
877
|
+
license: "MIT",
|
|
878
|
+
homepage: "https://github.com/ryanzen9/nest-observe#readme",
|
|
879
|
+
bugs: {
|
|
880
|
+
url: "https://github.com/ryanzen9/nest-observe/issues"
|
|
881
|
+
},
|
|
882
|
+
repository: {
|
|
883
|
+
type: "git",
|
|
884
|
+
url: "git+https://github.com/ryanzen9/nest-observe.git"
|
|
885
|
+
},
|
|
886
|
+
packageManager: "pnpm@10.13.1",
|
|
887
|
+
sideEffects: [
|
|
888
|
+
"./dist/register.js",
|
|
889
|
+
"./dist/register.mjs"
|
|
890
|
+
],
|
|
891
|
+
main: "./dist/index.js",
|
|
892
|
+
module: "./dist/index.mjs",
|
|
893
|
+
types: "./dist/index.d.ts",
|
|
894
|
+
exports: {
|
|
895
|
+
".": {
|
|
896
|
+
import: {
|
|
897
|
+
types: "./dist/index.d.mts",
|
|
898
|
+
default: "./dist/index.mjs"
|
|
899
|
+
},
|
|
900
|
+
require: {
|
|
901
|
+
types: "./dist/index.d.ts",
|
|
902
|
+
default: "./dist/index.js"
|
|
903
|
+
}
|
|
904
|
+
},
|
|
905
|
+
"./register": {
|
|
906
|
+
import: {
|
|
907
|
+
types: "./dist/register.d.mts",
|
|
908
|
+
default: "./dist/register.mjs"
|
|
909
|
+
},
|
|
910
|
+
require: {
|
|
911
|
+
types: "./dist/register.d.ts",
|
|
912
|
+
default: "./dist/register.js"
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
files: [
|
|
917
|
+
"dist",
|
|
918
|
+
"README.md",
|
|
919
|
+
"CHANGELOG.md",
|
|
920
|
+
"LICENSE"
|
|
921
|
+
],
|
|
922
|
+
scripts: {
|
|
923
|
+
build: "tsup",
|
|
924
|
+
test: "vitest run",
|
|
925
|
+
"test:watch": "vitest",
|
|
926
|
+
typecheck: "tsc --noEmit",
|
|
927
|
+
check: "pnpm typecheck && pnpm test && pnpm build"
|
|
928
|
+
},
|
|
929
|
+
engines: {
|
|
930
|
+
node: ">=20"
|
|
931
|
+
},
|
|
932
|
+
peerDependencies: {
|
|
933
|
+
"@nestjs/common": ">=10 <13",
|
|
934
|
+
"@nestjs/core": ">=10 <13",
|
|
935
|
+
"reflect-metadata": ">=0.1.12 <1",
|
|
936
|
+
rxjs: "^7.1.0"
|
|
937
|
+
},
|
|
938
|
+
dependencies: {
|
|
939
|
+
"@opentelemetry/api": "^1.9.0",
|
|
940
|
+
"@opentelemetry/api-logs": "^0.221.0",
|
|
941
|
+
"@opentelemetry/exporter-logs-otlp-proto": "^0.221.0",
|
|
942
|
+
"@opentelemetry/exporter-metrics-otlp-proto": "^0.221.0",
|
|
943
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.221.0",
|
|
944
|
+
"@opentelemetry/instrumentation": "^0.221.0",
|
|
945
|
+
"@opentelemetry/instrumentation-http": "^0.221.0",
|
|
946
|
+
"@opentelemetry/instrumentation-nestjs-core": "^0.67.0",
|
|
947
|
+
"@opentelemetry/resources": "^2.10.0",
|
|
948
|
+
"@opentelemetry/sdk-logs": "^0.221.0",
|
|
949
|
+
"@opentelemetry/sdk-metrics": "^2.10.0",
|
|
950
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
951
|
+
"@opentelemetry/sdk-trace-node": "^2.10.0",
|
|
952
|
+
"@prisma/instrumentation": "^7.10.0"
|
|
953
|
+
},
|
|
954
|
+
devDependencies: {
|
|
955
|
+
"@nestjs/common": "^12.0.1",
|
|
956
|
+
"@nestjs/core": "^12.0.1",
|
|
957
|
+
"@nestjs/testing": "^12.0.1",
|
|
958
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
959
|
+
"@types/node": "^24.0.0",
|
|
960
|
+
"reflect-metadata": "^0.2.2",
|
|
961
|
+
rxjs: "^7.8.2",
|
|
962
|
+
tsup: "^8.5.1",
|
|
963
|
+
typescript: "^5.9.3",
|
|
964
|
+
vitest: "^4.1.11"
|
|
965
|
+
},
|
|
966
|
+
publishConfig: {
|
|
967
|
+
access: "public"
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
// src/resource.ts
|
|
972
|
+
var SDK_NAME = package_default.name;
|
|
973
|
+
var SDK_VERSION = package_default.version;
|
|
743
974
|
function createObserveResource(config) {
|
|
744
975
|
return (0, import_resources.defaultResource)().merge(
|
|
745
976
|
(0, import_resources.resourceFromAttributes)({
|
|
@@ -796,14 +1027,23 @@ var SpanRedactionProcessor = class {
|
|
|
796
1027
|
|
|
797
1028
|
// src/sdk.ts
|
|
798
1029
|
var InactiveObserveHandle = class {
|
|
799
|
-
constructor(config) {
|
|
1030
|
+
constructor(config, diagnostics) {
|
|
800
1031
|
this.config = config;
|
|
1032
|
+
this.diagnostics = diagnostics;
|
|
801
1033
|
}
|
|
802
1034
|
config;
|
|
1035
|
+
diagnostics;
|
|
803
1036
|
started = false;
|
|
804
1037
|
tracerProvider = void 0;
|
|
805
1038
|
meterProvider = void 0;
|
|
806
1039
|
loggerProvider = void 0;
|
|
1040
|
+
httpRequestMetrics = void 0;
|
|
1041
|
+
get status() {
|
|
1042
|
+
return this.diagnostics.status;
|
|
1043
|
+
}
|
|
1044
|
+
get lastError() {
|
|
1045
|
+
return this.diagnostics.lastError;
|
|
1046
|
+
}
|
|
807
1047
|
forceFlush() {
|
|
808
1048
|
return Promise.resolve();
|
|
809
1049
|
}
|
|
@@ -812,52 +1052,73 @@ var InactiveObserveHandle = class {
|
|
|
812
1052
|
}
|
|
813
1053
|
};
|
|
814
1054
|
var ActiveObserveHandle = class {
|
|
815
|
-
constructor(config, tracerProvider, meterProvider, loggerProvider, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations) {
|
|
1055
|
+
constructor(config, tracerProvider, meterProvider, loggerProvider, httpRequestMetrics, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations, diagnostics) {
|
|
816
1056
|
this.config = config;
|
|
817
1057
|
this.tracerProvider = tracerProvider;
|
|
818
1058
|
this.meterProvider = meterProvider;
|
|
819
1059
|
this.loggerProvider = loggerProvider;
|
|
1060
|
+
this.httpRequestMetrics = httpRequestMetrics;
|
|
820
1061
|
this.runtimeMetrics = runtimeMetrics;
|
|
821
1062
|
this.loggerInstrumentation = loggerInstrumentation;
|
|
822
1063
|
this.exceptionCapture = exceptionCapture;
|
|
823
1064
|
this.instrumentations = instrumentations;
|
|
1065
|
+
this.diagnostics = diagnostics;
|
|
824
1066
|
}
|
|
825
1067
|
config;
|
|
826
1068
|
tracerProvider;
|
|
827
1069
|
meterProvider;
|
|
828
1070
|
loggerProvider;
|
|
1071
|
+
httpRequestMetrics;
|
|
829
1072
|
runtimeMetrics;
|
|
830
1073
|
loggerInstrumentation;
|
|
831
1074
|
exceptionCapture;
|
|
832
1075
|
instrumentations;
|
|
1076
|
+
diagnostics;
|
|
833
1077
|
started = true;
|
|
834
1078
|
stopped = false;
|
|
1079
|
+
get status() {
|
|
1080
|
+
return this.diagnostics.status;
|
|
1081
|
+
}
|
|
1082
|
+
get lastError() {
|
|
1083
|
+
return this.diagnostics.lastError;
|
|
1084
|
+
}
|
|
835
1085
|
async forceFlush() {
|
|
836
|
-
await
|
|
837
|
-
this.tracerProvider
|
|
838
|
-
this.meterProvider
|
|
839
|
-
this.loggerProvider
|
|
840
|
-
]
|
|
1086
|
+
await this.runSafely("forceFlush", [
|
|
1087
|
+
...this.config.traces && this.tracerProvider ? [["traces", () => this.tracerProvider.forceFlush()]] : [],
|
|
1088
|
+
...this.config.metrics && this.meterProvider ? [["metrics", () => this.meterProvider.forceFlush()]] : [],
|
|
1089
|
+
...this.config.logs && this.loggerProvider ? [["logs", () => this.loggerProvider.forceFlush({ timeoutMillis: this.config.exportTimeoutMillis })]] : []
|
|
1090
|
+
]);
|
|
841
1091
|
}
|
|
842
1092
|
async shutdown() {
|
|
843
1093
|
if (this.stopped) return;
|
|
844
1094
|
this.stopped = true;
|
|
845
1095
|
this.loggerInstrumentation?.disable();
|
|
846
|
-
this.runtimeMetrics?.stop();
|
|
847
1096
|
this.exceptionCapture.stop();
|
|
848
1097
|
for (const instrumentation of this.instrumentations) {
|
|
849
1098
|
try {
|
|
850
1099
|
instrumentation.disable();
|
|
851
|
-
} catch {
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
this.diagnostics.failure("sdk", "shutdown", error);
|
|
852
1102
|
}
|
|
853
1103
|
}
|
|
854
1104
|
await this.forceFlush();
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
this.
|
|
858
|
-
this.
|
|
859
|
-
|
|
1105
|
+
this.runtimeMetrics?.stop();
|
|
1106
|
+
await this.runSafely("shutdown", [
|
|
1107
|
+
...this.tracerProvider ? [["traces", () => this.tracerProvider.shutdown()]] : [],
|
|
1108
|
+
...this.meterProvider ? [["metrics", () => this.meterProvider.shutdown()]] : [],
|
|
1109
|
+
...this.loggerProvider ? [["logs", () => this.loggerProvider.shutdown()]] : []
|
|
1110
|
+
]);
|
|
860
1111
|
if (activeRuntime === this) activeRuntime = void 0;
|
|
1112
|
+
this.diagnostics.stop();
|
|
1113
|
+
}
|
|
1114
|
+
async runSafely(stage, operations) {
|
|
1115
|
+
await Promise.all(operations.map(async ([signal, operation]) => {
|
|
1116
|
+
try {
|
|
1117
|
+
await operation();
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
this.diagnostics.failure(signal, stage, error);
|
|
1120
|
+
}
|
|
1121
|
+
}));
|
|
861
1122
|
}
|
|
862
1123
|
};
|
|
863
1124
|
var activeRuntime;
|
|
@@ -868,12 +1129,16 @@ function exporterConfig(url, config) {
|
|
|
868
1129
|
timeoutMillis: config.exportTimeoutMillis
|
|
869
1130
|
};
|
|
870
1131
|
}
|
|
871
|
-
function createTraceProvider(config, resource) {
|
|
1132
|
+
function createTraceProvider(config, resource, diagnostics) {
|
|
872
1133
|
if (!config.traces && !config.metrics) return void 0;
|
|
873
1134
|
const spanProcessors = [new SpanRedactionProcessor()];
|
|
874
1135
|
if (config.traces) {
|
|
875
1136
|
const exporter = config.exporters?.span ?? new import_exporter_trace_otlp_proto.OTLPTraceExporter(exporterConfig(config.endpoints.traces, config));
|
|
876
|
-
spanProcessors.push(new import_sdk_trace_base.BatchSpanProcessor(
|
|
1137
|
+
spanProcessors.push(new import_sdk_trace_base.BatchSpanProcessor(withExporterDiagnostics(
|
|
1138
|
+
exporter,
|
|
1139
|
+
"traces",
|
|
1140
|
+
diagnostics
|
|
1141
|
+
), {
|
|
877
1142
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
878
1143
|
maxQueueSize: 2048,
|
|
879
1144
|
maxExportBatchSize: 512
|
|
@@ -888,14 +1153,18 @@ function createTraceProvider(config, resource) {
|
|
|
888
1153
|
provider.register();
|
|
889
1154
|
return provider;
|
|
890
1155
|
}
|
|
891
|
-
function createMeterProvider(config, resource) {
|
|
1156
|
+
function createMeterProvider(config, resource, diagnostics) {
|
|
892
1157
|
if (!config.metrics) return void 0;
|
|
893
1158
|
let reader;
|
|
894
1159
|
if (config.exporters?.metricReader) {
|
|
895
1160
|
reader = config.exporters.metricReader;
|
|
896
1161
|
} else {
|
|
897
1162
|
reader = new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
898
|
-
exporter:
|
|
1163
|
+
exporter: withExporterDiagnostics(
|
|
1164
|
+
new import_exporter_metrics_otlp_proto.OTLPMetricExporter(exporterConfig(config.endpoints.metrics, config)),
|
|
1165
|
+
"metrics",
|
|
1166
|
+
diagnostics
|
|
1167
|
+
),
|
|
899
1168
|
exportIntervalMillis: config.metricExportIntervalMillis,
|
|
900
1169
|
exportTimeoutMillis: Math.min(config.exportTimeoutMillis, config.metricExportIntervalMillis),
|
|
901
1170
|
cardinalityLimits: { default: 2e3, histogram: 2e3 }
|
|
@@ -913,13 +1182,13 @@ function createMeterProvider(config, resource) {
|
|
|
913
1182
|
import_api6.metrics.setGlobalMeterProvider(provider);
|
|
914
1183
|
return provider;
|
|
915
1184
|
}
|
|
916
|
-
function createLoggerProvider(config, resource) {
|
|
1185
|
+
function createLoggerProvider(config, resource, diagnostics) {
|
|
917
1186
|
if (!config.logs) return void 0;
|
|
918
1187
|
const exporter = config.exporters?.log ?? new import_exporter_logs_otlp_proto.OTLPLogExporter(exporterConfig(config.endpoints.logs, config));
|
|
919
1188
|
const provider = new import_sdk_logs.LoggerProvider({
|
|
920
1189
|
resource,
|
|
921
1190
|
processors: [new import_sdk_logs.BatchLogRecordProcessor({
|
|
922
|
-
exporter,
|
|
1191
|
+
exporter: withExporterDiagnostics(exporter, "logs", diagnostics),
|
|
923
1192
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
924
1193
|
maxQueueSize: 2048,
|
|
925
1194
|
maxExportBatchSize: 512
|
|
@@ -931,7 +1200,11 @@ function createLoggerProvider(config, resource) {
|
|
|
931
1200
|
function observe(options = {}) {
|
|
932
1201
|
if (activeRuntime?.started) return activeRuntime;
|
|
933
1202
|
const config = resolveObserveConfig(options);
|
|
934
|
-
|
|
1203
|
+
const diagnostics = new ObserveDiagnostics(config.diagnosticLogging, options.onError);
|
|
1204
|
+
if (!config.enabled) {
|
|
1205
|
+
diagnostics.inactive();
|
|
1206
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
1207
|
+
}
|
|
935
1208
|
let tracerProvider;
|
|
936
1209
|
let meterProvider;
|
|
937
1210
|
let loggerProvider;
|
|
@@ -941,10 +1214,11 @@ function observe(options = {}) {
|
|
|
941
1214
|
const instrumentations = [];
|
|
942
1215
|
try {
|
|
943
1216
|
const resource = createObserveResource(config);
|
|
944
|
-
meterProvider = createMeterProvider(config, resource);
|
|
1217
|
+
meterProvider = createMeterProvider(config, resource, diagnostics);
|
|
945
1218
|
const meter = meterProvider?.getMeter(SDK_NAME, SDK_VERSION);
|
|
946
|
-
|
|
947
|
-
|
|
1219
|
+
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
1220
|
+
tracerProvider = createTraceProvider(config, resource, diagnostics);
|
|
1221
|
+
loggerProvider = createLoggerProvider(config, resource, diagnostics);
|
|
948
1222
|
runtimeMetrics = meter ? new RuntimeMetrics(meter) : void 0;
|
|
949
1223
|
runtimeMetrics?.start();
|
|
950
1224
|
const otelLogger = loggerProvider?.getLogger(SDK_NAME, SDK_VERSION);
|
|
@@ -959,7 +1233,6 @@ function observe(options = {}) {
|
|
|
959
1233
|
exceptionCapture.start();
|
|
960
1234
|
if (config.traces || config.metrics) {
|
|
961
1235
|
const safeHeaders = config.allowedHeaders.filter((header) => !isSensitiveKey(header));
|
|
962
|
-
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
963
1236
|
instrumentations.push(new import_instrumentation_http.HttpInstrumentation({
|
|
964
1237
|
requireParentforOutgoingSpans: false,
|
|
965
1238
|
headersToSpanAttributes: {
|
|
@@ -1003,14 +1276,18 @@ function observe(options = {}) {
|
|
|
1003
1276
|
tracerProvider,
|
|
1004
1277
|
meterProvider,
|
|
1005
1278
|
loggerProvider,
|
|
1279
|
+
httpRequestMetrics,
|
|
1006
1280
|
runtimeMetrics,
|
|
1007
1281
|
loggerInstrumentation,
|
|
1008
1282
|
exceptionCapture,
|
|
1009
|
-
instrumentations
|
|
1283
|
+
instrumentations,
|
|
1284
|
+
diagnostics
|
|
1010
1285
|
);
|
|
1286
|
+
diagnostics.activate();
|
|
1011
1287
|
activeRuntime = runtime;
|
|
1012
1288
|
return runtime;
|
|
1013
|
-
} catch {
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
diagnostics.failure("sdk", "initialization", error);
|
|
1014
1291
|
loggerInstrumentation?.disable();
|
|
1015
1292
|
runtimeMetrics?.stop();
|
|
1016
1293
|
exceptionCapture?.stop();
|
|
@@ -1025,7 +1302,9 @@ function observe(options = {}) {
|
|
|
1025
1302
|
meterProvider?.shutdown(),
|
|
1026
1303
|
loggerProvider?.shutdown()
|
|
1027
1304
|
].filter((item) => Boolean(item)));
|
|
1028
|
-
|
|
1305
|
+
diagnostics.inactive();
|
|
1306
|
+
if (config.failFast) throw toError(error);
|
|
1307
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
1029
1308
|
}
|
|
1030
1309
|
}
|
|
1031
1310
|
function getObserveRuntime() {
|
|
@@ -1035,6 +1314,37 @@ function getObserveRuntime() {
|
|
|
1035
1314
|
// src/nest/observe.module.ts
|
|
1036
1315
|
var OBSERVE_OPTIONS = /* @__PURE__ */ Symbol("OBSERVE_OPTIONS");
|
|
1037
1316
|
var OBSERVE_HANDLE = /* @__PURE__ */ Symbol("OBSERVE_HANDLE");
|
|
1317
|
+
var NestHttpMetricsInterceptor = class {
|
|
1318
|
+
constructor(handle) {
|
|
1319
|
+
this.handle = handle;
|
|
1320
|
+
}
|
|
1321
|
+
handle;
|
|
1322
|
+
intercept(context3, next) {
|
|
1323
|
+
if (context3.getType() !== "http" || !this.handle.started || !this.handle.httpRequestMetrics) {
|
|
1324
|
+
return next.handle();
|
|
1325
|
+
}
|
|
1326
|
+
const http = context3.switchToHttp();
|
|
1327
|
+
const request = http.getRequest();
|
|
1328
|
+
const response = http.getResponse();
|
|
1329
|
+
const started = this.handle.httpRequestMetrics.start(request);
|
|
1330
|
+
const result = next.handle();
|
|
1331
|
+
if (!started) return result;
|
|
1332
|
+
const responseEventSource = response.raw ?? response;
|
|
1333
|
+
if (typeof responseEventSource.once === "function") {
|
|
1334
|
+
responseEventSource.once("finish", () => {
|
|
1335
|
+
this.handle.httpRequestMetrics?.record(request, response);
|
|
1336
|
+
});
|
|
1337
|
+
return result;
|
|
1338
|
+
}
|
|
1339
|
+
return result.pipe((0, import_rxjs2.finalize)(() => {
|
|
1340
|
+
this.handle.httpRequestMetrics?.record(request, response);
|
|
1341
|
+
}));
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1344
|
+
NestHttpMetricsInterceptor = __decorateClass([
|
|
1345
|
+
(0, import_common2.Injectable)(),
|
|
1346
|
+
__decorateParam(0, (0, import_common2.Inject)(OBSERVE_HANDLE))
|
|
1347
|
+
], NestHttpMetricsInterceptor);
|
|
1038
1348
|
var NestObserveExplorer = class {
|
|
1039
1349
|
constructor(discovery, options, handle) {
|
|
1040
1350
|
this.discovery = discovery;
|
|
@@ -1059,7 +1369,7 @@ var NestObserveExplorer = class {
|
|
|
1059
1369
|
}
|
|
1060
1370
|
instrument(wrappers, instrumenter, kind) {
|
|
1061
1371
|
for (const wrapper of wrappers) {
|
|
1062
|
-
if (!wrapper.metatype) continue;
|
|
1372
|
+
if (!wrapper.metatype || wrapper.inject !== void 0) continue;
|
|
1063
1373
|
if (["ObserveModule", "DiscoveryModule", "InternalCoreModule"].includes(wrapper.host?.name ?? "")) continue;
|
|
1064
1374
|
if (wrapper.metatype === NestObserveExplorer) continue;
|
|
1065
1375
|
if (wrapper.instance) {
|
|
@@ -1088,6 +1398,7 @@ var ObserveModule = class {
|
|
|
1088
1398
|
providers: [
|
|
1089
1399
|
{ provide: OBSERVE_OPTIONS, useValue: options },
|
|
1090
1400
|
{ provide: OBSERVE_HANDLE, useFactory: () => observe(options) },
|
|
1401
|
+
{ provide: import_core.APP_INTERCEPTOR, useClass: NestHttpMetricsInterceptor },
|
|
1091
1402
|
NestObserveExplorer
|
|
1092
1403
|
],
|
|
1093
1404
|
exports: [OBSERVE_HANDLE]
|
|
@@ -1103,6 +1414,7 @@ ObserveModule = __decorateClass([
|
|
|
1103
1414
|
CompatibleNestInstrumentation,
|
|
1104
1415
|
HttpRequestMetrics,
|
|
1105
1416
|
IgnoreTrace,
|
|
1417
|
+
NestHttpMetricsInterceptor,
|
|
1106
1418
|
NestLoggerInstrumentation,
|
|
1107
1419
|
NestMethodInstrumenter,
|
|
1108
1420
|
OBSERVE_HANDLE,
|