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