@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.mjs
CHANGED
|
@@ -89,7 +89,9 @@ function resolveObserveConfig(options = {}, env = process.env) {
|
|
|
89
89
|
allowedHeaders,
|
|
90
90
|
exportTimeoutMillis: positiveInteger(options.exportTimeoutMillis ?? env.OTEL_EXPORTER_OTLP_TIMEOUT, 1e4),
|
|
91
91
|
metricExportIntervalMillis: positiveInteger(options.metricExportIntervalMillis ?? env.OTEL_METRIC_EXPORT_INTERVAL, 6e4),
|
|
92
|
-
resourceAttributes
|
|
92
|
+
resourceAttributes,
|
|
93
|
+
diagnosticLogging: booleanValue(options.diagnosticLogging, true),
|
|
94
|
+
failFast: booleanValue(options.failFast, false)
|
|
93
95
|
};
|
|
94
96
|
if (options.exporters) result.exporters = options.exporters;
|
|
95
97
|
return result;
|
|
@@ -180,6 +182,11 @@ function invokeWithSpan(tracer, spanName, attributes, invoke, onFinish) {
|
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
// src/decorators/trace.decorator.ts
|
|
185
|
+
function copyOwnMetadata(source, target) {
|
|
186
|
+
for (const metadataKey of Reflect.getOwnMetadataKeys(source)) {
|
|
187
|
+
Reflect.defineMetadata(metadataKey, Reflect.getOwnMetadata(metadataKey, source), target);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
183
190
|
function decorateMethod(target, propertyKey, descriptor, options) {
|
|
184
191
|
const original = descriptor.value;
|
|
185
192
|
if (typeof original !== "function" || isTraceIgnored(original, target.constructor))
|
|
@@ -204,6 +211,7 @@ function decorateMethod(target, propertyKey, descriptor, options) {
|
|
|
204
211
|
value: original.name,
|
|
205
212
|
configurable: true
|
|
206
213
|
});
|
|
214
|
+
copyOwnMetadata(original, wrapped);
|
|
207
215
|
markTraceDecorated(wrapped);
|
|
208
216
|
descriptor.value = wrapped;
|
|
209
217
|
}
|
|
@@ -284,7 +292,8 @@ var SEVERITY = {
|
|
|
284
292
|
fatal: "FATAL"
|
|
285
293
|
};
|
|
286
294
|
function bodyValue(message) {
|
|
287
|
-
if (message instanceof Error)
|
|
295
|
+
if (message instanceof Error)
|
|
296
|
+
return redactText(message.stack ?? `${message.name}: ${message.message}`);
|
|
288
297
|
return redact(message);
|
|
289
298
|
}
|
|
290
299
|
var NestLoggerInstrumentation = class {
|
|
@@ -329,7 +338,8 @@ var NestLoggerInstrumentation = class {
|
|
|
329
338
|
disable() {
|
|
330
339
|
if (!this.enabled) return;
|
|
331
340
|
const prototype = ConsoleLogger.prototype;
|
|
332
|
-
for (const [method, original] of this.originals)
|
|
341
|
+
for (const [method, original] of this.originals)
|
|
342
|
+
prototype[method] = original;
|
|
333
343
|
this.originals.clear();
|
|
334
344
|
this.enabled = false;
|
|
335
345
|
}
|
|
@@ -408,7 +418,7 @@ var NestMethodInstrumenter = class {
|
|
|
408
418
|
if (!descriptor || typeof original !== "function" || isTraceIgnored(original, type) || isTraceDecorated(original)) continue;
|
|
409
419
|
const existing = Reflect.get(target, methodName);
|
|
410
420
|
if (typeof existing === "function" && existing !== original && isTraceDecorated(existing)) continue;
|
|
411
|
-
const name = componentName
|
|
421
|
+
const name = typeof componentName === "symbol" ? String(componentName) : typeof componentName === "string" && componentName ? componentName : type.name || "Anonymous";
|
|
412
422
|
const attributes = {
|
|
413
423
|
[`nestjs.${kind}`]: name,
|
|
414
424
|
"nestjs.method": methodName
|
|
@@ -461,7 +471,7 @@ var CompatibleNestInstrumentation = class extends NestInstrumentation {
|
|
|
461
471
|
const instance = await original.apply(this, args);
|
|
462
472
|
try {
|
|
463
473
|
const wrapper = args[1];
|
|
464
|
-
if (!instance || typeof instance !== "object" || !wrapper?.metatype) return instance;
|
|
474
|
+
if (!instance || typeof instance !== "object" || !wrapper?.metatype || wrapper.inject !== void 0) return instance;
|
|
465
475
|
if (["InternalCoreModule", "ObserveModule", "DiscoveryModule"].includes(wrapper.host?.name ?? "")) {
|
|
466
476
|
return instance;
|
|
467
477
|
}
|
|
@@ -522,9 +532,14 @@ var HttpRequestMetrics = class {
|
|
|
522
532
|
errorCount;
|
|
523
533
|
startedAt = /* @__PURE__ */ new WeakMap();
|
|
524
534
|
start(request) {
|
|
535
|
+
if (this.startedAt.has(request)) return false;
|
|
525
536
|
this.startedAt.set(request, process.hrtime.bigint());
|
|
537
|
+
return true;
|
|
526
538
|
}
|
|
527
539
|
record(request, response) {
|
|
540
|
+
const started = this.startedAt.get(request);
|
|
541
|
+
if (started === void 0) return false;
|
|
542
|
+
this.startedAt.delete(request);
|
|
528
543
|
const statusCode = Number.isFinite(response.statusCode) ? response.statusCode : 0;
|
|
529
544
|
const attributes = {
|
|
530
545
|
"service.name": this.serviceName,
|
|
@@ -533,12 +548,9 @@ var HttpRequestMetrics = class {
|
|
|
533
548
|
"http.response.status_code": statusCode
|
|
534
549
|
};
|
|
535
550
|
this.requestCount.add(1, attributes);
|
|
536
|
-
|
|
537
|
-
if (started !== void 0) {
|
|
538
|
-
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
539
|
-
this.startedAt.delete(request);
|
|
540
|
-
}
|
|
551
|
+
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
541
552
|
if (statusCode >= 500) this.errorCount.add(1, attributes);
|
|
553
|
+
return true;
|
|
542
554
|
}
|
|
543
555
|
};
|
|
544
556
|
|
|
@@ -624,9 +636,15 @@ var RuntimeMetrics = class {
|
|
|
624
636
|
};
|
|
625
637
|
|
|
626
638
|
// src/nest/observe.module.ts
|
|
627
|
-
import {
|
|
628
|
-
|
|
639
|
+
import {
|
|
640
|
+
Global,
|
|
641
|
+
Inject,
|
|
642
|
+
Injectable,
|
|
643
|
+
Module
|
|
644
|
+
} from "@nestjs/common";
|
|
645
|
+
import { APP_INTERCEPTOR, DiscoveryModule, DiscoveryService } from "@nestjs/core";
|
|
629
646
|
import { metrics as metrics2, trace as trace5 } from "@opentelemetry/api";
|
|
647
|
+
import { finalize as finalize2 } from "rxjs";
|
|
630
648
|
|
|
631
649
|
// src/sdk.ts
|
|
632
650
|
import { logs as logs2 } from "@opentelemetry/api-logs";
|
|
@@ -642,6 +660,113 @@ import { AggregationType, MeterProvider, PeriodicExportingMetricReader } from "@
|
|
|
642
660
|
import { AlwaysOffSampler, BatchSpanProcessor, ParentBasedSampler, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
|
|
643
661
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
644
662
|
|
|
663
|
+
// src/diagnostics.ts
|
|
664
|
+
function toError(value) {
|
|
665
|
+
if (value instanceof Error) return value;
|
|
666
|
+
if (typeof value === "string") return new Error(value);
|
|
667
|
+
try {
|
|
668
|
+
return new Error(JSON.stringify(value));
|
|
669
|
+
} catch {
|
|
670
|
+
return new Error(String(value));
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function sanitizeError(error) {
|
|
674
|
+
const sanitized = new Error(redactText(error.message));
|
|
675
|
+
sanitized.name = error.name;
|
|
676
|
+
if (error.stack) sanitized.stack = redactText(error.stack);
|
|
677
|
+
return sanitized;
|
|
678
|
+
}
|
|
679
|
+
var ObserveDiagnostics = class {
|
|
680
|
+
constructor(logging, onError) {
|
|
681
|
+
this.logging = logging;
|
|
682
|
+
this.onError = onError;
|
|
683
|
+
}
|
|
684
|
+
logging;
|
|
685
|
+
onError;
|
|
686
|
+
currentStatus = "starting";
|
|
687
|
+
currentError;
|
|
688
|
+
failedSignals = /* @__PURE__ */ new Set();
|
|
689
|
+
reported = /* @__PURE__ */ new Set();
|
|
690
|
+
get status() {
|
|
691
|
+
return this.currentStatus;
|
|
692
|
+
}
|
|
693
|
+
get lastError() {
|
|
694
|
+
return this.currentError;
|
|
695
|
+
}
|
|
696
|
+
activate() {
|
|
697
|
+
if (this.currentStatus === "starting") this.currentStatus = "active";
|
|
698
|
+
}
|
|
699
|
+
inactive() {
|
|
700
|
+
this.currentStatus = "inactive";
|
|
701
|
+
}
|
|
702
|
+
stop() {
|
|
703
|
+
this.currentStatus = "stopped";
|
|
704
|
+
}
|
|
705
|
+
success(signal) {
|
|
706
|
+
this.failedSignals.delete(signal);
|
|
707
|
+
for (const fingerprint of this.reported) {
|
|
708
|
+
if (fingerprint.startsWith(`${signal}\0`)) this.reported.delete(fingerprint);
|
|
709
|
+
}
|
|
710
|
+
if (this.currentStatus === "degraded" && this.failedSignals.size === 0) {
|
|
711
|
+
this.currentStatus = "active";
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
failure(signal, stage, value) {
|
|
715
|
+
const error = sanitizeError(toError(value));
|
|
716
|
+
const event = { signal, stage, error, timestamp: Date.now() };
|
|
717
|
+
this.currentError = event;
|
|
718
|
+
this.failedSignals.add(signal);
|
|
719
|
+
if (this.currentStatus !== "inactive" && this.currentStatus !== "stopped") {
|
|
720
|
+
this.currentStatus = "degraded";
|
|
721
|
+
}
|
|
722
|
+
const fingerprint = `${signal}\0${stage}\0${error.name}\0${error.message}`;
|
|
723
|
+
if (this.reported.has(fingerprint)) return;
|
|
724
|
+
this.reported.add(fingerprint);
|
|
725
|
+
try {
|
|
726
|
+
this.onError?.(event);
|
|
727
|
+
} catch {
|
|
728
|
+
}
|
|
729
|
+
if (!this.logging) return;
|
|
730
|
+
try {
|
|
731
|
+
process.stderr.write(
|
|
732
|
+
`[nest-observe] ${signal} ${stage} failed: ${redactText(error.message)}
|
|
733
|
+
`
|
|
734
|
+
);
|
|
735
|
+
} catch {
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
function withExporterDiagnostics(exporter, signal, diagnostics) {
|
|
740
|
+
const delegate = exporter;
|
|
741
|
+
return new Proxy(exporter, {
|
|
742
|
+
get(target, property) {
|
|
743
|
+
if (property === "export") {
|
|
744
|
+
return (items, callback) => {
|
|
745
|
+
try {
|
|
746
|
+
delegate.export.call(target, items, (result) => {
|
|
747
|
+
if (result.code === 0) {
|
|
748
|
+
diagnostics.success(signal);
|
|
749
|
+
} else {
|
|
750
|
+
diagnostics.failure(
|
|
751
|
+
signal,
|
|
752
|
+
"export",
|
|
753
|
+
result.error ?? new Error(`${signal} export failed`)
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
callback(result);
|
|
757
|
+
});
|
|
758
|
+
} catch (error) {
|
|
759
|
+
diagnostics.failure(signal, "export", error);
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
const value = Reflect.get(target, property, target);
|
|
765
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
|
|
645
770
|
// src/exceptions/process-exception-capture.ts
|
|
646
771
|
import { trace as trace3, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
|
|
647
772
|
function asError(value) {
|
|
@@ -694,8 +819,118 @@ import {
|
|
|
694
819
|
resourceFromAttributes
|
|
695
820
|
} from "@opentelemetry/resources";
|
|
696
821
|
import { hostname } from "os";
|
|
697
|
-
|
|
698
|
-
|
|
822
|
+
|
|
823
|
+
// package.json
|
|
824
|
+
var package_default = {
|
|
825
|
+
name: "@ryanzeng/nest-observe",
|
|
826
|
+
version: "0.1.3",
|
|
827
|
+
description: "Zero-config, vendor-neutral OpenTelemetry observability for NestJS",
|
|
828
|
+
keywords: [
|
|
829
|
+
"nestjs",
|
|
830
|
+
"opentelemetry",
|
|
831
|
+
"observability",
|
|
832
|
+
"otlp",
|
|
833
|
+
"tracing",
|
|
834
|
+
"metrics",
|
|
835
|
+
"logging"
|
|
836
|
+
],
|
|
837
|
+
license: "MIT",
|
|
838
|
+
homepage: "https://github.com/ryanzen9/nest-observe#readme",
|
|
839
|
+
bugs: {
|
|
840
|
+
url: "https://github.com/ryanzen9/nest-observe/issues"
|
|
841
|
+
},
|
|
842
|
+
repository: {
|
|
843
|
+
type: "git",
|
|
844
|
+
url: "git+https://github.com/ryanzen9/nest-observe.git"
|
|
845
|
+
},
|
|
846
|
+
packageManager: "pnpm@10.13.1",
|
|
847
|
+
sideEffects: [
|
|
848
|
+
"./dist/register.js",
|
|
849
|
+
"./dist/register.mjs"
|
|
850
|
+
],
|
|
851
|
+
main: "./dist/index.js",
|
|
852
|
+
module: "./dist/index.mjs",
|
|
853
|
+
types: "./dist/index.d.ts",
|
|
854
|
+
exports: {
|
|
855
|
+
".": {
|
|
856
|
+
import: {
|
|
857
|
+
types: "./dist/index.d.mts",
|
|
858
|
+
default: "./dist/index.mjs"
|
|
859
|
+
},
|
|
860
|
+
require: {
|
|
861
|
+
types: "./dist/index.d.ts",
|
|
862
|
+
default: "./dist/index.js"
|
|
863
|
+
}
|
|
864
|
+
},
|
|
865
|
+
"./register": {
|
|
866
|
+
import: {
|
|
867
|
+
types: "./dist/register.d.mts",
|
|
868
|
+
default: "./dist/register.mjs"
|
|
869
|
+
},
|
|
870
|
+
require: {
|
|
871
|
+
types: "./dist/register.d.ts",
|
|
872
|
+
default: "./dist/register.js"
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
files: [
|
|
877
|
+
"dist",
|
|
878
|
+
"README.md",
|
|
879
|
+
"CHANGELOG.md",
|
|
880
|
+
"LICENSE"
|
|
881
|
+
],
|
|
882
|
+
scripts: {
|
|
883
|
+
build: "tsup",
|
|
884
|
+
test: "vitest run",
|
|
885
|
+
"test:watch": "vitest",
|
|
886
|
+
typecheck: "tsc --noEmit",
|
|
887
|
+
check: "pnpm typecheck && pnpm test && pnpm build"
|
|
888
|
+
},
|
|
889
|
+
engines: {
|
|
890
|
+
node: ">=20"
|
|
891
|
+
},
|
|
892
|
+
peerDependencies: {
|
|
893
|
+
"@nestjs/common": ">=10 <13",
|
|
894
|
+
"@nestjs/core": ">=10 <13",
|
|
895
|
+
"reflect-metadata": ">=0.1.12 <1",
|
|
896
|
+
rxjs: "^7.1.0"
|
|
897
|
+
},
|
|
898
|
+
dependencies: {
|
|
899
|
+
"@opentelemetry/api": "^1.9.0",
|
|
900
|
+
"@opentelemetry/api-logs": "^0.221.0",
|
|
901
|
+
"@opentelemetry/exporter-logs-otlp-proto": "^0.221.0",
|
|
902
|
+
"@opentelemetry/exporter-metrics-otlp-proto": "^0.221.0",
|
|
903
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.221.0",
|
|
904
|
+
"@opentelemetry/instrumentation": "^0.221.0",
|
|
905
|
+
"@opentelemetry/instrumentation-http": "^0.221.0",
|
|
906
|
+
"@opentelemetry/instrumentation-nestjs-core": "^0.67.0",
|
|
907
|
+
"@opentelemetry/resources": "^2.10.0",
|
|
908
|
+
"@opentelemetry/sdk-logs": "^0.221.0",
|
|
909
|
+
"@opentelemetry/sdk-metrics": "^2.10.0",
|
|
910
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
911
|
+
"@opentelemetry/sdk-trace-node": "^2.10.0",
|
|
912
|
+
"@prisma/instrumentation": "^7.10.0"
|
|
913
|
+
},
|
|
914
|
+
devDependencies: {
|
|
915
|
+
"@nestjs/common": "^12.0.1",
|
|
916
|
+
"@nestjs/core": "^12.0.1",
|
|
917
|
+
"@nestjs/testing": "^12.0.1",
|
|
918
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
919
|
+
"@types/node": "^24.0.0",
|
|
920
|
+
"reflect-metadata": "^0.2.2",
|
|
921
|
+
rxjs: "^7.8.2",
|
|
922
|
+
tsup: "^8.5.1",
|
|
923
|
+
typescript: "^5.9.3",
|
|
924
|
+
vitest: "^4.1.11"
|
|
925
|
+
},
|
|
926
|
+
publishConfig: {
|
|
927
|
+
access: "public"
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
// src/resource.ts
|
|
932
|
+
var SDK_NAME = package_default.name;
|
|
933
|
+
var SDK_VERSION = package_default.version;
|
|
699
934
|
function createObserveResource(config) {
|
|
700
935
|
return defaultResource().merge(
|
|
701
936
|
resourceFromAttributes({
|
|
@@ -752,14 +987,23 @@ var SpanRedactionProcessor = class {
|
|
|
752
987
|
|
|
753
988
|
// src/sdk.ts
|
|
754
989
|
var InactiveObserveHandle = class {
|
|
755
|
-
constructor(config) {
|
|
990
|
+
constructor(config, diagnostics) {
|
|
756
991
|
this.config = config;
|
|
992
|
+
this.diagnostics = diagnostics;
|
|
757
993
|
}
|
|
758
994
|
config;
|
|
995
|
+
diagnostics;
|
|
759
996
|
started = false;
|
|
760
997
|
tracerProvider = void 0;
|
|
761
998
|
meterProvider = void 0;
|
|
762
999
|
loggerProvider = void 0;
|
|
1000
|
+
httpRequestMetrics = void 0;
|
|
1001
|
+
get status() {
|
|
1002
|
+
return this.diagnostics.status;
|
|
1003
|
+
}
|
|
1004
|
+
get lastError() {
|
|
1005
|
+
return this.diagnostics.lastError;
|
|
1006
|
+
}
|
|
763
1007
|
forceFlush() {
|
|
764
1008
|
return Promise.resolve();
|
|
765
1009
|
}
|
|
@@ -768,52 +1012,73 @@ var InactiveObserveHandle = class {
|
|
|
768
1012
|
}
|
|
769
1013
|
};
|
|
770
1014
|
var ActiveObserveHandle = class {
|
|
771
|
-
constructor(config, tracerProvider, meterProvider, loggerProvider, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations) {
|
|
1015
|
+
constructor(config, tracerProvider, meterProvider, loggerProvider, httpRequestMetrics, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations, diagnostics) {
|
|
772
1016
|
this.config = config;
|
|
773
1017
|
this.tracerProvider = tracerProvider;
|
|
774
1018
|
this.meterProvider = meterProvider;
|
|
775
1019
|
this.loggerProvider = loggerProvider;
|
|
1020
|
+
this.httpRequestMetrics = httpRequestMetrics;
|
|
776
1021
|
this.runtimeMetrics = runtimeMetrics;
|
|
777
1022
|
this.loggerInstrumentation = loggerInstrumentation;
|
|
778
1023
|
this.exceptionCapture = exceptionCapture;
|
|
779
1024
|
this.instrumentations = instrumentations;
|
|
1025
|
+
this.diagnostics = diagnostics;
|
|
780
1026
|
}
|
|
781
1027
|
config;
|
|
782
1028
|
tracerProvider;
|
|
783
1029
|
meterProvider;
|
|
784
1030
|
loggerProvider;
|
|
1031
|
+
httpRequestMetrics;
|
|
785
1032
|
runtimeMetrics;
|
|
786
1033
|
loggerInstrumentation;
|
|
787
1034
|
exceptionCapture;
|
|
788
1035
|
instrumentations;
|
|
1036
|
+
diagnostics;
|
|
789
1037
|
started = true;
|
|
790
1038
|
stopped = false;
|
|
1039
|
+
get status() {
|
|
1040
|
+
return this.diagnostics.status;
|
|
1041
|
+
}
|
|
1042
|
+
get lastError() {
|
|
1043
|
+
return this.diagnostics.lastError;
|
|
1044
|
+
}
|
|
791
1045
|
async forceFlush() {
|
|
792
|
-
await
|
|
793
|
-
this.tracerProvider
|
|
794
|
-
this.meterProvider
|
|
795
|
-
this.loggerProvider
|
|
796
|
-
]
|
|
1046
|
+
await this.runSafely("forceFlush", [
|
|
1047
|
+
...this.config.traces && this.tracerProvider ? [["traces", () => this.tracerProvider.forceFlush()]] : [],
|
|
1048
|
+
...this.config.metrics && this.meterProvider ? [["metrics", () => this.meterProvider.forceFlush()]] : [],
|
|
1049
|
+
...this.config.logs && this.loggerProvider ? [["logs", () => this.loggerProvider.forceFlush({ timeoutMillis: this.config.exportTimeoutMillis })]] : []
|
|
1050
|
+
]);
|
|
797
1051
|
}
|
|
798
1052
|
async shutdown() {
|
|
799
1053
|
if (this.stopped) return;
|
|
800
1054
|
this.stopped = true;
|
|
801
1055
|
this.loggerInstrumentation?.disable();
|
|
802
|
-
this.runtimeMetrics?.stop();
|
|
803
1056
|
this.exceptionCapture.stop();
|
|
804
1057
|
for (const instrumentation of this.instrumentations) {
|
|
805
1058
|
try {
|
|
806
1059
|
instrumentation.disable();
|
|
807
|
-
} catch {
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
this.diagnostics.failure("sdk", "shutdown", error);
|
|
808
1062
|
}
|
|
809
1063
|
}
|
|
810
1064
|
await this.forceFlush();
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this.
|
|
814
|
-
this.
|
|
815
|
-
|
|
1065
|
+
this.runtimeMetrics?.stop();
|
|
1066
|
+
await this.runSafely("shutdown", [
|
|
1067
|
+
...this.tracerProvider ? [["traces", () => this.tracerProvider.shutdown()]] : [],
|
|
1068
|
+
...this.meterProvider ? [["metrics", () => this.meterProvider.shutdown()]] : [],
|
|
1069
|
+
...this.loggerProvider ? [["logs", () => this.loggerProvider.shutdown()]] : []
|
|
1070
|
+
]);
|
|
816
1071
|
if (activeRuntime === this) activeRuntime = void 0;
|
|
1072
|
+
this.diagnostics.stop();
|
|
1073
|
+
}
|
|
1074
|
+
async runSafely(stage, operations) {
|
|
1075
|
+
await Promise.all(operations.map(async ([signal, operation]) => {
|
|
1076
|
+
try {
|
|
1077
|
+
await operation();
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
this.diagnostics.failure(signal, stage, error);
|
|
1080
|
+
}
|
|
1081
|
+
}));
|
|
817
1082
|
}
|
|
818
1083
|
};
|
|
819
1084
|
var activeRuntime;
|
|
@@ -824,12 +1089,16 @@ function exporterConfig(url, config) {
|
|
|
824
1089
|
timeoutMillis: config.exportTimeoutMillis
|
|
825
1090
|
};
|
|
826
1091
|
}
|
|
827
|
-
function createTraceProvider(config, resource) {
|
|
1092
|
+
function createTraceProvider(config, resource, diagnostics) {
|
|
828
1093
|
if (!config.traces && !config.metrics) return void 0;
|
|
829
1094
|
const spanProcessors = [new SpanRedactionProcessor()];
|
|
830
1095
|
if (config.traces) {
|
|
831
1096
|
const exporter = config.exporters?.span ?? new OTLPTraceExporter(exporterConfig(config.endpoints.traces, config));
|
|
832
|
-
spanProcessors.push(new BatchSpanProcessor(
|
|
1097
|
+
spanProcessors.push(new BatchSpanProcessor(withExporterDiagnostics(
|
|
1098
|
+
exporter,
|
|
1099
|
+
"traces",
|
|
1100
|
+
diagnostics
|
|
1101
|
+
), {
|
|
833
1102
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
834
1103
|
maxQueueSize: 2048,
|
|
835
1104
|
maxExportBatchSize: 512
|
|
@@ -844,14 +1113,18 @@ function createTraceProvider(config, resource) {
|
|
|
844
1113
|
provider.register();
|
|
845
1114
|
return provider;
|
|
846
1115
|
}
|
|
847
|
-
function createMeterProvider(config, resource) {
|
|
1116
|
+
function createMeterProvider(config, resource, diagnostics) {
|
|
848
1117
|
if (!config.metrics) return void 0;
|
|
849
1118
|
let reader;
|
|
850
1119
|
if (config.exporters?.metricReader) {
|
|
851
1120
|
reader = config.exporters.metricReader;
|
|
852
1121
|
} else {
|
|
853
1122
|
reader = new PeriodicExportingMetricReader({
|
|
854
|
-
exporter:
|
|
1123
|
+
exporter: withExporterDiagnostics(
|
|
1124
|
+
new OTLPMetricExporter(exporterConfig(config.endpoints.metrics, config)),
|
|
1125
|
+
"metrics",
|
|
1126
|
+
diagnostics
|
|
1127
|
+
),
|
|
855
1128
|
exportIntervalMillis: config.metricExportIntervalMillis,
|
|
856
1129
|
exportTimeoutMillis: Math.min(config.exportTimeoutMillis, config.metricExportIntervalMillis),
|
|
857
1130
|
cardinalityLimits: { default: 2e3, histogram: 2e3 }
|
|
@@ -869,13 +1142,13 @@ function createMeterProvider(config, resource) {
|
|
|
869
1142
|
metrics.setGlobalMeterProvider(provider);
|
|
870
1143
|
return provider;
|
|
871
1144
|
}
|
|
872
|
-
function createLoggerProvider(config, resource) {
|
|
1145
|
+
function createLoggerProvider(config, resource, diagnostics) {
|
|
873
1146
|
if (!config.logs) return void 0;
|
|
874
1147
|
const exporter = config.exporters?.log ?? new OTLPLogExporter(exporterConfig(config.endpoints.logs, config));
|
|
875
1148
|
const provider = new LoggerProvider({
|
|
876
1149
|
resource,
|
|
877
1150
|
processors: [new BatchLogRecordProcessor({
|
|
878
|
-
exporter,
|
|
1151
|
+
exporter: withExporterDiagnostics(exporter, "logs", diagnostics),
|
|
879
1152
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
880
1153
|
maxQueueSize: 2048,
|
|
881
1154
|
maxExportBatchSize: 512
|
|
@@ -887,7 +1160,11 @@ function createLoggerProvider(config, resource) {
|
|
|
887
1160
|
function observe(options = {}) {
|
|
888
1161
|
if (activeRuntime?.started) return activeRuntime;
|
|
889
1162
|
const config = resolveObserveConfig(options);
|
|
890
|
-
|
|
1163
|
+
const diagnostics = new ObserveDiagnostics(config.diagnosticLogging, options.onError);
|
|
1164
|
+
if (!config.enabled) {
|
|
1165
|
+
diagnostics.inactive();
|
|
1166
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
1167
|
+
}
|
|
891
1168
|
let tracerProvider;
|
|
892
1169
|
let meterProvider;
|
|
893
1170
|
let loggerProvider;
|
|
@@ -897,10 +1174,11 @@ function observe(options = {}) {
|
|
|
897
1174
|
const instrumentations = [];
|
|
898
1175
|
try {
|
|
899
1176
|
const resource = createObserveResource(config);
|
|
900
|
-
meterProvider = createMeterProvider(config, resource);
|
|
1177
|
+
meterProvider = createMeterProvider(config, resource, diagnostics);
|
|
901
1178
|
const meter = meterProvider?.getMeter(SDK_NAME, SDK_VERSION);
|
|
902
|
-
|
|
903
|
-
|
|
1179
|
+
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
1180
|
+
tracerProvider = createTraceProvider(config, resource, diagnostics);
|
|
1181
|
+
loggerProvider = createLoggerProvider(config, resource, diagnostics);
|
|
904
1182
|
runtimeMetrics = meter ? new RuntimeMetrics(meter) : void 0;
|
|
905
1183
|
runtimeMetrics?.start();
|
|
906
1184
|
const otelLogger = loggerProvider?.getLogger(SDK_NAME, SDK_VERSION);
|
|
@@ -915,7 +1193,6 @@ function observe(options = {}) {
|
|
|
915
1193
|
exceptionCapture.start();
|
|
916
1194
|
if (config.traces || config.metrics) {
|
|
917
1195
|
const safeHeaders = config.allowedHeaders.filter((header) => !isSensitiveKey(header));
|
|
918
|
-
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
919
1196
|
instrumentations.push(new HttpInstrumentation({
|
|
920
1197
|
requireParentforOutgoingSpans: false,
|
|
921
1198
|
headersToSpanAttributes: {
|
|
@@ -959,14 +1236,18 @@ function observe(options = {}) {
|
|
|
959
1236
|
tracerProvider,
|
|
960
1237
|
meterProvider,
|
|
961
1238
|
loggerProvider,
|
|
1239
|
+
httpRequestMetrics,
|
|
962
1240
|
runtimeMetrics,
|
|
963
1241
|
loggerInstrumentation,
|
|
964
1242
|
exceptionCapture,
|
|
965
|
-
instrumentations
|
|
1243
|
+
instrumentations,
|
|
1244
|
+
diagnostics
|
|
966
1245
|
);
|
|
1246
|
+
diagnostics.activate();
|
|
967
1247
|
activeRuntime = runtime;
|
|
968
1248
|
return runtime;
|
|
969
|
-
} catch {
|
|
1249
|
+
} catch (error) {
|
|
1250
|
+
diagnostics.failure("sdk", "initialization", error);
|
|
970
1251
|
loggerInstrumentation?.disable();
|
|
971
1252
|
runtimeMetrics?.stop();
|
|
972
1253
|
exceptionCapture?.stop();
|
|
@@ -981,7 +1262,9 @@ function observe(options = {}) {
|
|
|
981
1262
|
meterProvider?.shutdown(),
|
|
982
1263
|
loggerProvider?.shutdown()
|
|
983
1264
|
].filter((item) => Boolean(item)));
|
|
984
|
-
|
|
1265
|
+
diagnostics.inactive();
|
|
1266
|
+
if (config.failFast) throw toError(error);
|
|
1267
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
985
1268
|
}
|
|
986
1269
|
}
|
|
987
1270
|
function getObserveRuntime() {
|
|
@@ -991,6 +1274,37 @@ function getObserveRuntime() {
|
|
|
991
1274
|
// src/nest/observe.module.ts
|
|
992
1275
|
var OBSERVE_OPTIONS = /* @__PURE__ */ Symbol("OBSERVE_OPTIONS");
|
|
993
1276
|
var OBSERVE_HANDLE = /* @__PURE__ */ Symbol("OBSERVE_HANDLE");
|
|
1277
|
+
var NestHttpMetricsInterceptor = class {
|
|
1278
|
+
constructor(handle) {
|
|
1279
|
+
this.handle = handle;
|
|
1280
|
+
}
|
|
1281
|
+
handle;
|
|
1282
|
+
intercept(context3, next) {
|
|
1283
|
+
if (context3.getType() !== "http" || !this.handle.started || !this.handle.httpRequestMetrics) {
|
|
1284
|
+
return next.handle();
|
|
1285
|
+
}
|
|
1286
|
+
const http = context3.switchToHttp();
|
|
1287
|
+
const request = http.getRequest();
|
|
1288
|
+
const response = http.getResponse();
|
|
1289
|
+
const started = this.handle.httpRequestMetrics.start(request);
|
|
1290
|
+
const result = next.handle();
|
|
1291
|
+
if (!started) return result;
|
|
1292
|
+
const responseEventSource = response.raw ?? response;
|
|
1293
|
+
if (typeof responseEventSource.once === "function") {
|
|
1294
|
+
responseEventSource.once("finish", () => {
|
|
1295
|
+
this.handle.httpRequestMetrics?.record(request, response);
|
|
1296
|
+
});
|
|
1297
|
+
return result;
|
|
1298
|
+
}
|
|
1299
|
+
return result.pipe(finalize2(() => {
|
|
1300
|
+
this.handle.httpRequestMetrics?.record(request, response);
|
|
1301
|
+
}));
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
NestHttpMetricsInterceptor = __decorateClass([
|
|
1305
|
+
Injectable(),
|
|
1306
|
+
__decorateParam(0, Inject(OBSERVE_HANDLE))
|
|
1307
|
+
], NestHttpMetricsInterceptor);
|
|
994
1308
|
var NestObserveExplorer = class {
|
|
995
1309
|
constructor(discovery, options, handle) {
|
|
996
1310
|
this.discovery = discovery;
|
|
@@ -1015,7 +1329,7 @@ var NestObserveExplorer = class {
|
|
|
1015
1329
|
}
|
|
1016
1330
|
instrument(wrappers, instrumenter, kind) {
|
|
1017
1331
|
for (const wrapper of wrappers) {
|
|
1018
|
-
if (!wrapper.metatype) continue;
|
|
1332
|
+
if (!wrapper.metatype || wrapper.inject !== void 0) continue;
|
|
1019
1333
|
if (["ObserveModule", "DiscoveryModule", "InternalCoreModule"].includes(wrapper.host?.name ?? "")) continue;
|
|
1020
1334
|
if (wrapper.metatype === NestObserveExplorer) continue;
|
|
1021
1335
|
if (wrapper.instance) {
|
|
@@ -1044,6 +1358,7 @@ var ObserveModule = class {
|
|
|
1044
1358
|
providers: [
|
|
1045
1359
|
{ provide: OBSERVE_OPTIONS, useValue: options },
|
|
1046
1360
|
{ provide: OBSERVE_HANDLE, useFactory: () => observe(options) },
|
|
1361
|
+
{ provide: APP_INTERCEPTOR, useClass: NestHttpMetricsInterceptor },
|
|
1047
1362
|
NestObserveExplorer
|
|
1048
1363
|
],
|
|
1049
1364
|
exports: [OBSERVE_HANDLE]
|
|
@@ -1058,6 +1373,7 @@ export {
|
|
|
1058
1373
|
CompatibleNestInstrumentation,
|
|
1059
1374
|
HttpRequestMetrics,
|
|
1060
1375
|
IgnoreTrace,
|
|
1376
|
+
NestHttpMetricsInterceptor,
|
|
1061
1377
|
NestLoggerInstrumentation,
|
|
1062
1378
|
NestMethodInstrumenter,
|
|
1063
1379
|
OBSERVE_HANDLE,
|