@ryanzeng/nest-observe 0.1.0 → 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 +31 -1
- package/dist/index.d.mts +42 -15
- package/dist/index.d.ts +42 -15
- package/dist/index.js +379 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -60
- package/dist/index.mjs.map +1 -1
- package/dist/register.js +327 -52
- package/dist/register.js.map +1 -1
- package/dist/register.mjs +330 -52
- 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;
|
|
@@ -182,19 +184,28 @@ function invokeWithSpan(tracer, spanName, attributes, invoke, onFinish) {
|
|
|
182
184
|
// src/decorators/trace.decorator.ts
|
|
183
185
|
function decorateMethod(target, propertyKey, descriptor, options) {
|
|
184
186
|
const original = descriptor.value;
|
|
185
|
-
if (typeof original !== "function" || isTraceIgnored(original, target.constructor))
|
|
187
|
+
if (typeof original !== "function" || isTraceIgnored(original, target.constructor))
|
|
188
|
+
return;
|
|
186
189
|
const className = target.constructor?.name || "Anonymous";
|
|
187
190
|
const methodName = String(propertyKey);
|
|
188
191
|
const wrapped = function(...args) {
|
|
189
|
-
const tracer = trace.getTracer("@
|
|
190
|
-
return invokeWithSpan(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
const tracer = trace.getTracer("@ryanzeng/nest-observe");
|
|
193
|
+
return invokeWithSpan(
|
|
194
|
+
tracer,
|
|
195
|
+
options.name ?? `${className}.${methodName}`,
|
|
196
|
+
{
|
|
197
|
+
"code.function.name": methodName,
|
|
198
|
+
"nestjs.class": className,
|
|
199
|
+
"nestjs.method": methodName,
|
|
200
|
+
...options.attributes
|
|
201
|
+
},
|
|
202
|
+
() => original.apply(this, args)
|
|
203
|
+
);
|
|
196
204
|
};
|
|
197
|
-
Object.defineProperty(wrapped, "name", {
|
|
205
|
+
Object.defineProperty(wrapped, "name", {
|
|
206
|
+
value: original.name,
|
|
207
|
+
configurable: true
|
|
208
|
+
});
|
|
198
209
|
markTraceDecorated(wrapped);
|
|
199
210
|
descriptor.value = wrapped;
|
|
200
211
|
}
|
|
@@ -276,7 +287,13 @@ var SEVERITY = {
|
|
|
276
287
|
};
|
|
277
288
|
function bodyValue(message) {
|
|
278
289
|
if (message instanceof Error) return redactText(message.stack ?? `${message.name}: ${message.message}`);
|
|
279
|
-
|
|
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
|
+
}
|
|
280
297
|
}
|
|
281
298
|
var NestLoggerInstrumentation = class {
|
|
282
299
|
constructor(emitter, resourceAttributes = {}) {
|
|
@@ -339,7 +356,7 @@ var SEVERITY_NUMBER = {
|
|
|
339
356
|
};
|
|
340
357
|
var OpenTelemetryLogEmitter = class {
|
|
341
358
|
logger;
|
|
342
|
-
constructor(name = "@
|
|
359
|
+
constructor(name = "@ryanzeng/nest-observe", version, logger) {
|
|
343
360
|
this.logger = logger ?? logs.getLogger(name, version);
|
|
344
361
|
}
|
|
345
362
|
emit(record) {
|
|
@@ -513,9 +530,14 @@ var HttpRequestMetrics = class {
|
|
|
513
530
|
errorCount;
|
|
514
531
|
startedAt = /* @__PURE__ */ new WeakMap();
|
|
515
532
|
start(request) {
|
|
533
|
+
if (this.startedAt.has(request)) return false;
|
|
516
534
|
this.startedAt.set(request, process.hrtime.bigint());
|
|
535
|
+
return true;
|
|
517
536
|
}
|
|
518
537
|
record(request, response) {
|
|
538
|
+
const started = this.startedAt.get(request);
|
|
539
|
+
if (started === void 0) return false;
|
|
540
|
+
this.startedAt.delete(request);
|
|
519
541
|
const statusCode = Number.isFinite(response.statusCode) ? response.statusCode : 0;
|
|
520
542
|
const attributes = {
|
|
521
543
|
"service.name": this.serviceName,
|
|
@@ -524,12 +546,9 @@ var HttpRequestMetrics = class {
|
|
|
524
546
|
"http.response.status_code": statusCode
|
|
525
547
|
};
|
|
526
548
|
this.requestCount.add(1, attributes);
|
|
527
|
-
|
|
528
|
-
if (started !== void 0) {
|
|
529
|
-
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
530
|
-
this.startedAt.delete(request);
|
|
531
|
-
}
|
|
549
|
+
this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
|
|
532
550
|
if (statusCode >= 500) this.errorCount.add(1, attributes);
|
|
551
|
+
return true;
|
|
533
552
|
}
|
|
534
553
|
};
|
|
535
554
|
|
|
@@ -615,9 +634,15 @@ var RuntimeMetrics = class {
|
|
|
615
634
|
};
|
|
616
635
|
|
|
617
636
|
// src/nest/observe.module.ts
|
|
618
|
-
import {
|
|
619
|
-
|
|
637
|
+
import {
|
|
638
|
+
Global,
|
|
639
|
+
Inject,
|
|
640
|
+
Injectable,
|
|
641
|
+
Module
|
|
642
|
+
} from "@nestjs/common";
|
|
643
|
+
import { APP_INTERCEPTOR, DiscoveryModule, DiscoveryService } from "@nestjs/core";
|
|
620
644
|
import { metrics as metrics2, trace as trace5 } from "@opentelemetry/api";
|
|
645
|
+
import { finalize as finalize2 } from "rxjs";
|
|
621
646
|
|
|
622
647
|
// src/sdk.ts
|
|
623
648
|
import { logs as logs2 } from "@opentelemetry/api-logs";
|
|
@@ -633,6 +658,113 @@ import { AggregationType, MeterProvider, PeriodicExportingMetricReader } from "@
|
|
|
633
658
|
import { AlwaysOffSampler, BatchSpanProcessor, ParentBasedSampler, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
|
|
634
659
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
635
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
|
+
|
|
636
768
|
// src/exceptions/process-exception-capture.ts
|
|
637
769
|
import { trace as trace3, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
|
|
638
770
|
function asError(value) {
|
|
@@ -680,21 +812,136 @@ var ProcessExceptionCapture = class {
|
|
|
680
812
|
};
|
|
681
813
|
|
|
682
814
|
// src/resource.ts
|
|
815
|
+
import {
|
|
816
|
+
defaultResource,
|
|
817
|
+
resourceFromAttributes
|
|
818
|
+
} from "@opentelemetry/resources";
|
|
683
819
|
import { hostname } from "os";
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
var
|
|
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;
|
|
687
932
|
function createObserveResource(config) {
|
|
688
|
-
return defaultResource().merge(
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
933
|
+
return defaultResource().merge(
|
|
934
|
+
resourceFromAttributes({
|
|
935
|
+
...config.resourceAttributes,
|
|
936
|
+
"service.name": config.serviceName,
|
|
937
|
+
"service.version": config.serviceVersion,
|
|
938
|
+
"deployment.environment.name": config.environment,
|
|
939
|
+
"service.instance.id": config.instanceId,
|
|
940
|
+
"telemetry.sdk.name": SDK_NAME,
|
|
941
|
+
"telemetry.sdk.version": SDK_VERSION,
|
|
942
|
+
"host.name": config.resourceAttributes["host.name"] ?? hostname()
|
|
943
|
+
})
|
|
944
|
+
);
|
|
698
945
|
}
|
|
699
946
|
|
|
700
947
|
// src/security/span-redaction-processor.ts
|
|
@@ -738,14 +985,23 @@ var SpanRedactionProcessor = class {
|
|
|
738
985
|
|
|
739
986
|
// src/sdk.ts
|
|
740
987
|
var InactiveObserveHandle = class {
|
|
741
|
-
constructor(config) {
|
|
988
|
+
constructor(config, diagnostics) {
|
|
742
989
|
this.config = config;
|
|
990
|
+
this.diagnostics = diagnostics;
|
|
743
991
|
}
|
|
744
992
|
config;
|
|
993
|
+
diagnostics;
|
|
745
994
|
started = false;
|
|
746
995
|
tracerProvider = void 0;
|
|
747
996
|
meterProvider = void 0;
|
|
748
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
|
+
}
|
|
749
1005
|
forceFlush() {
|
|
750
1006
|
return Promise.resolve();
|
|
751
1007
|
}
|
|
@@ -754,52 +1010,73 @@ var InactiveObserveHandle = class {
|
|
|
754
1010
|
}
|
|
755
1011
|
};
|
|
756
1012
|
var ActiveObserveHandle = class {
|
|
757
|
-
constructor(config, tracerProvider, meterProvider, loggerProvider, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations) {
|
|
1013
|
+
constructor(config, tracerProvider, meterProvider, loggerProvider, httpRequestMetrics, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations, diagnostics) {
|
|
758
1014
|
this.config = config;
|
|
759
1015
|
this.tracerProvider = tracerProvider;
|
|
760
1016
|
this.meterProvider = meterProvider;
|
|
761
1017
|
this.loggerProvider = loggerProvider;
|
|
1018
|
+
this.httpRequestMetrics = httpRequestMetrics;
|
|
762
1019
|
this.runtimeMetrics = runtimeMetrics;
|
|
763
1020
|
this.loggerInstrumentation = loggerInstrumentation;
|
|
764
1021
|
this.exceptionCapture = exceptionCapture;
|
|
765
1022
|
this.instrumentations = instrumentations;
|
|
1023
|
+
this.diagnostics = diagnostics;
|
|
766
1024
|
}
|
|
767
1025
|
config;
|
|
768
1026
|
tracerProvider;
|
|
769
1027
|
meterProvider;
|
|
770
1028
|
loggerProvider;
|
|
1029
|
+
httpRequestMetrics;
|
|
771
1030
|
runtimeMetrics;
|
|
772
1031
|
loggerInstrumentation;
|
|
773
1032
|
exceptionCapture;
|
|
774
1033
|
instrumentations;
|
|
1034
|
+
diagnostics;
|
|
775
1035
|
started = true;
|
|
776
1036
|
stopped = false;
|
|
1037
|
+
get status() {
|
|
1038
|
+
return this.diagnostics.status;
|
|
1039
|
+
}
|
|
1040
|
+
get lastError() {
|
|
1041
|
+
return this.diagnostics.lastError;
|
|
1042
|
+
}
|
|
777
1043
|
async forceFlush() {
|
|
778
|
-
await
|
|
779
|
-
this.tracerProvider
|
|
780
|
-
this.meterProvider
|
|
781
|
-
this.loggerProvider
|
|
782
|
-
]
|
|
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
|
+
]);
|
|
783
1049
|
}
|
|
784
1050
|
async shutdown() {
|
|
785
1051
|
if (this.stopped) return;
|
|
786
1052
|
this.stopped = true;
|
|
787
1053
|
this.loggerInstrumentation?.disable();
|
|
788
|
-
this.runtimeMetrics?.stop();
|
|
789
1054
|
this.exceptionCapture.stop();
|
|
790
1055
|
for (const instrumentation of this.instrumentations) {
|
|
791
1056
|
try {
|
|
792
1057
|
instrumentation.disable();
|
|
793
|
-
} catch {
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
this.diagnostics.failure("sdk", "shutdown", error);
|
|
794
1060
|
}
|
|
795
1061
|
}
|
|
796
1062
|
await this.forceFlush();
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
this.
|
|
800
|
-
this.
|
|
801
|
-
|
|
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
|
+
]);
|
|
802
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
|
+
}));
|
|
803
1080
|
}
|
|
804
1081
|
};
|
|
805
1082
|
var activeRuntime;
|
|
@@ -810,12 +1087,16 @@ function exporterConfig(url, config) {
|
|
|
810
1087
|
timeoutMillis: config.exportTimeoutMillis
|
|
811
1088
|
};
|
|
812
1089
|
}
|
|
813
|
-
function createTraceProvider(config, resource) {
|
|
1090
|
+
function createTraceProvider(config, resource, diagnostics) {
|
|
814
1091
|
if (!config.traces && !config.metrics) return void 0;
|
|
815
1092
|
const spanProcessors = [new SpanRedactionProcessor()];
|
|
816
1093
|
if (config.traces) {
|
|
817
1094
|
const exporter = config.exporters?.span ?? new OTLPTraceExporter(exporterConfig(config.endpoints.traces, config));
|
|
818
|
-
spanProcessors.push(new BatchSpanProcessor(
|
|
1095
|
+
spanProcessors.push(new BatchSpanProcessor(withExporterDiagnostics(
|
|
1096
|
+
exporter,
|
|
1097
|
+
"traces",
|
|
1098
|
+
diagnostics
|
|
1099
|
+
), {
|
|
819
1100
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
820
1101
|
maxQueueSize: 2048,
|
|
821
1102
|
maxExportBatchSize: 512
|
|
@@ -830,14 +1111,18 @@ function createTraceProvider(config, resource) {
|
|
|
830
1111
|
provider.register();
|
|
831
1112
|
return provider;
|
|
832
1113
|
}
|
|
833
|
-
function createMeterProvider(config, resource) {
|
|
1114
|
+
function createMeterProvider(config, resource, diagnostics) {
|
|
834
1115
|
if (!config.metrics) return void 0;
|
|
835
1116
|
let reader;
|
|
836
1117
|
if (config.exporters?.metricReader) {
|
|
837
1118
|
reader = config.exporters.metricReader;
|
|
838
1119
|
} else {
|
|
839
1120
|
reader = new PeriodicExportingMetricReader({
|
|
840
|
-
exporter:
|
|
1121
|
+
exporter: withExporterDiagnostics(
|
|
1122
|
+
new OTLPMetricExporter(exporterConfig(config.endpoints.metrics, config)),
|
|
1123
|
+
"metrics",
|
|
1124
|
+
diagnostics
|
|
1125
|
+
),
|
|
841
1126
|
exportIntervalMillis: config.metricExportIntervalMillis,
|
|
842
1127
|
exportTimeoutMillis: Math.min(config.exportTimeoutMillis, config.metricExportIntervalMillis),
|
|
843
1128
|
cardinalityLimits: { default: 2e3, histogram: 2e3 }
|
|
@@ -855,13 +1140,13 @@ function createMeterProvider(config, resource) {
|
|
|
855
1140
|
metrics.setGlobalMeterProvider(provider);
|
|
856
1141
|
return provider;
|
|
857
1142
|
}
|
|
858
|
-
function createLoggerProvider(config, resource) {
|
|
1143
|
+
function createLoggerProvider(config, resource, diagnostics) {
|
|
859
1144
|
if (!config.logs) return void 0;
|
|
860
1145
|
const exporter = config.exporters?.log ?? new OTLPLogExporter(exporterConfig(config.endpoints.logs, config));
|
|
861
1146
|
const provider = new LoggerProvider({
|
|
862
1147
|
resource,
|
|
863
1148
|
processors: [new BatchLogRecordProcessor({
|
|
864
|
-
exporter,
|
|
1149
|
+
exporter: withExporterDiagnostics(exporter, "logs", diagnostics),
|
|
865
1150
|
exportTimeoutMillis: config.exportTimeoutMillis,
|
|
866
1151
|
maxQueueSize: 2048,
|
|
867
1152
|
maxExportBatchSize: 512
|
|
@@ -873,7 +1158,11 @@ function createLoggerProvider(config, resource) {
|
|
|
873
1158
|
function observe(options = {}) {
|
|
874
1159
|
if (activeRuntime?.started) return activeRuntime;
|
|
875
1160
|
const config = resolveObserveConfig(options);
|
|
876
|
-
|
|
1161
|
+
const diagnostics = new ObserveDiagnostics(config.diagnosticLogging, options.onError);
|
|
1162
|
+
if (!config.enabled) {
|
|
1163
|
+
diagnostics.inactive();
|
|
1164
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
1165
|
+
}
|
|
877
1166
|
let tracerProvider;
|
|
878
1167
|
let meterProvider;
|
|
879
1168
|
let loggerProvider;
|
|
@@ -883,10 +1172,11 @@ function observe(options = {}) {
|
|
|
883
1172
|
const instrumentations = [];
|
|
884
1173
|
try {
|
|
885
1174
|
const resource = createObserveResource(config);
|
|
886
|
-
meterProvider = createMeterProvider(config, resource);
|
|
1175
|
+
meterProvider = createMeterProvider(config, resource, diagnostics);
|
|
887
1176
|
const meter = meterProvider?.getMeter(SDK_NAME, SDK_VERSION);
|
|
888
|
-
|
|
889
|
-
|
|
1177
|
+
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
1178
|
+
tracerProvider = createTraceProvider(config, resource, diagnostics);
|
|
1179
|
+
loggerProvider = createLoggerProvider(config, resource, diagnostics);
|
|
890
1180
|
runtimeMetrics = meter ? new RuntimeMetrics(meter) : void 0;
|
|
891
1181
|
runtimeMetrics?.start();
|
|
892
1182
|
const otelLogger = loggerProvider?.getLogger(SDK_NAME, SDK_VERSION);
|
|
@@ -901,7 +1191,6 @@ function observe(options = {}) {
|
|
|
901
1191
|
exceptionCapture.start();
|
|
902
1192
|
if (config.traces || config.metrics) {
|
|
903
1193
|
const safeHeaders = config.allowedHeaders.filter((header) => !isSensitiveKey(header));
|
|
904
|
-
const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
|
|
905
1194
|
instrumentations.push(new HttpInstrumentation({
|
|
906
1195
|
requireParentforOutgoingSpans: false,
|
|
907
1196
|
headersToSpanAttributes: {
|
|
@@ -945,14 +1234,18 @@ function observe(options = {}) {
|
|
|
945
1234
|
tracerProvider,
|
|
946
1235
|
meterProvider,
|
|
947
1236
|
loggerProvider,
|
|
1237
|
+
httpRequestMetrics,
|
|
948
1238
|
runtimeMetrics,
|
|
949
1239
|
loggerInstrumentation,
|
|
950
1240
|
exceptionCapture,
|
|
951
|
-
instrumentations
|
|
1241
|
+
instrumentations,
|
|
1242
|
+
diagnostics
|
|
952
1243
|
);
|
|
1244
|
+
diagnostics.activate();
|
|
953
1245
|
activeRuntime = runtime;
|
|
954
1246
|
return runtime;
|
|
955
|
-
} catch {
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
diagnostics.failure("sdk", "initialization", error);
|
|
956
1249
|
loggerInstrumentation?.disable();
|
|
957
1250
|
runtimeMetrics?.stop();
|
|
958
1251
|
exceptionCapture?.stop();
|
|
@@ -967,7 +1260,9 @@ function observe(options = {}) {
|
|
|
967
1260
|
meterProvider?.shutdown(),
|
|
968
1261
|
loggerProvider?.shutdown()
|
|
969
1262
|
].filter((item) => Boolean(item)));
|
|
970
|
-
|
|
1263
|
+
diagnostics.inactive();
|
|
1264
|
+
if (config.failFast) throw toError(error);
|
|
1265
|
+
return new InactiveObserveHandle(config, diagnostics);
|
|
971
1266
|
}
|
|
972
1267
|
}
|
|
973
1268
|
function getObserveRuntime() {
|
|
@@ -977,6 +1272,37 @@ function getObserveRuntime() {
|
|
|
977
1272
|
// src/nest/observe.module.ts
|
|
978
1273
|
var OBSERVE_OPTIONS = /* @__PURE__ */ Symbol("OBSERVE_OPTIONS");
|
|
979
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);
|
|
980
1306
|
var NestObserveExplorer = class {
|
|
981
1307
|
constructor(discovery, options, handle) {
|
|
982
1308
|
this.discovery = discovery;
|
|
@@ -1030,6 +1356,7 @@ var ObserveModule = class {
|
|
|
1030
1356
|
providers: [
|
|
1031
1357
|
{ provide: OBSERVE_OPTIONS, useValue: options },
|
|
1032
1358
|
{ provide: OBSERVE_HANDLE, useFactory: () => observe(options) },
|
|
1359
|
+
{ provide: APP_INTERCEPTOR, useClass: NestHttpMetricsInterceptor },
|
|
1033
1360
|
NestObserveExplorer
|
|
1034
1361
|
],
|
|
1035
1362
|
exports: [OBSERVE_HANDLE]
|
|
@@ -1044,6 +1371,7 @@ export {
|
|
|
1044
1371
|
CompatibleNestInstrumentation,
|
|
1045
1372
|
HttpRequestMetrics,
|
|
1046
1373
|
IgnoreTrace,
|
|
1374
|
+
NestHttpMetricsInterceptor,
|
|
1047
1375
|
NestLoggerInstrumentation,
|
|
1048
1376
|
NestMethodInstrumenter,
|
|
1049
1377
|
OBSERVE_HANDLE,
|