@ryanzeng/nest-observe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
28
+
29
+ // src/index.ts
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ CompatibleNestInstrumentation: () => CompatibleNestInstrumentation,
33
+ HttpRequestMetrics: () => HttpRequestMetrics,
34
+ IgnoreTrace: () => IgnoreTrace,
35
+ NestLoggerInstrumentation: () => NestLoggerInstrumentation,
36
+ NestMethodInstrumenter: () => NestMethodInstrumenter,
37
+ OBSERVE_HANDLE: () => OBSERVE_HANDLE,
38
+ OBSERVE_OPTIONS: () => OBSERVE_OPTIONS,
39
+ ObserveModule: () => ObserveModule,
40
+ OpenTelemetryLogEmitter: () => OpenTelemetryLogEmitter,
41
+ REDACTED: () => REDACTED,
42
+ RuntimeMetrics: () => RuntimeMetrics,
43
+ SDK_NAME: () => SDK_NAME,
44
+ SDK_VERSION: () => SDK_VERSION,
45
+ SpanRedactionProcessor: () => SpanRedactionProcessor,
46
+ Trace: () => Trace,
47
+ createObserveResource: () => createObserveResource,
48
+ getObserveRuntime: () => getObserveRuntime,
49
+ isSensitiveKey: () => isSensitiveKey,
50
+ isTraceDecorated: () => isTraceDecorated,
51
+ isTraceIgnored: () => isTraceIgnored,
52
+ markTraceDecorated: () => markTraceDecorated,
53
+ markTraceIgnored: () => markTraceIgnored,
54
+ observe: () => observe,
55
+ parseKeyValueList: () => parseKeyValueList,
56
+ redact: () => redact,
57
+ redactText: () => redactText,
58
+ resolveObserveConfig: () => resolveObserveConfig,
59
+ sanitizeHeaders: () => sanitizeHeaders
60
+ });
61
+ module.exports = __toCommonJS(index_exports);
62
+
63
+ // src/config.ts
64
+ var import_node_crypto = require("crypto");
65
+ var DEFAULT_ALLOWED_HEADERS = ["accept", "content-type", "user-agent", "x-request-id", "traceparent"];
66
+ function booleanValue(value, fallback) {
67
+ if (typeof value === "boolean") return value;
68
+ if (value?.toLowerCase() === "true") return true;
69
+ if (value?.toLowerCase() === "false") return false;
70
+ return fallback;
71
+ }
72
+ function positiveInteger(value, fallback) {
73
+ const number = Number(value);
74
+ return Number.isFinite(number) && number > 0 ? Math.floor(number) : fallback;
75
+ }
76
+ function samplingValue(value) {
77
+ const number = Number(value);
78
+ if (!Number.isFinite(number)) return 1;
79
+ return Math.min(1, Math.max(0, number));
80
+ }
81
+ function environmentSampling(env) {
82
+ const sampler = env.OTEL_TRACES_SAMPLER?.toLowerCase();
83
+ if (sampler === "always_off" || sampler === "parentbased_always_off") return 0;
84
+ if (sampler === "always_on" || sampler === "parentbased_always_on") return 1;
85
+ return samplingValue(env.OTEL_TRACES_SAMPLER_ARG);
86
+ }
87
+ function decode(value) {
88
+ try {
89
+ return decodeURIComponent(value.trim());
90
+ } catch {
91
+ return value.trim();
92
+ }
93
+ }
94
+ function parseKeyValueList(value) {
95
+ if (!value) return {};
96
+ return Object.fromEntries(value.split(",").flatMap((entry) => {
97
+ const separator = entry.indexOf("=");
98
+ if (separator <= 0) return [];
99
+ const key = decode(entry.slice(0, separator));
100
+ const itemValue = decode(entry.slice(separator + 1));
101
+ return key ? [[key, itemValue]] : [];
102
+ }));
103
+ }
104
+ function appendSignalPath(endpoint, signal) {
105
+ if (!endpoint) return void 0;
106
+ return `${endpoint.replace(/\/+$/, "")}/v1/${signal}`;
107
+ }
108
+ function optionalString(value) {
109
+ const result = value?.trim();
110
+ return result ? result : void 0;
111
+ }
112
+ function resolveObserveConfig(options = {}, env = process.env) {
113
+ const otelResources = parseKeyValueList(env.OTEL_RESOURCE_ATTRIBUTES);
114
+ const resourceAttributes = { ...otelResources, ...options.resourceAttributes };
115
+ const genericEndpoint = optionalString(options.endpoint ?? env.OTEL_EXPORTER_OTLP_ENDPOINT);
116
+ const sampling = options.sampling === void 0 ? environmentSampling(env) : samplingValue(options.sampling);
117
+ const allowedHeaders = Array.from(new Set([
118
+ ...DEFAULT_ALLOWED_HEADERS,
119
+ ...options.allowedHeaders ?? []
120
+ ].map((header) => header.toLowerCase().trim()).filter(Boolean)));
121
+ const result = {
122
+ enabled: booleanValue(options.enabled ?? env.OBSERVE_ENABLED, true),
123
+ serviceName: options.serviceName ?? env.OTEL_SERVICE_NAME ?? otelResources["service.name"] ?? "nest-application",
124
+ serviceVersion: options.serviceVersion ?? env.OTEL_SERVICE_VERSION ?? otelResources["service.version"] ?? "unknown",
125
+ environment: options.environment ?? env.OBSERVE_ENVIRONMENT ?? otelResources["deployment.environment.name"] ?? env.NODE_ENV ?? "development",
126
+ instanceId: options.instanceId ?? otelResources["service.instance.id"] ?? env.OTEL_SERVICE_INSTANCE_ID ?? env.HOSTNAME ?? (0, import_node_crypto.randomUUID)(),
127
+ endpoints: {
128
+ traces: optionalString(env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) ?? appendSignalPath(genericEndpoint, "traces"),
129
+ metrics: optionalString(env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) ?? appendSignalPath(genericEndpoint, "metrics"),
130
+ logs: optionalString(env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT) ?? appendSignalPath(genericEndpoint, "logs")
131
+ },
132
+ headers: { ...parseKeyValueList(env.OTEL_EXPORTER_OTLP_HEADERS), ...options.headers },
133
+ traces: booleanValue(options.traces, true),
134
+ logs: booleanValue(options.logs, true),
135
+ metrics: booleanValue(options.metrics, true),
136
+ providerTracing: booleanValue(options.providerTracing, true),
137
+ controllerTracing: booleanValue(options.controllerTracing, true),
138
+ sampling,
139
+ allowedHeaders,
140
+ exportTimeoutMillis: positiveInteger(options.exportTimeoutMillis ?? env.OTEL_EXPORTER_OTLP_TIMEOUT, 1e4),
141
+ metricExportIntervalMillis: positiveInteger(options.metricExportIntervalMillis ?? env.OTEL_METRIC_EXPORT_INTERVAL, 6e4),
142
+ resourceAttributes
143
+ };
144
+ if (options.exporters) result.exporters = options.exporters;
145
+ return result;
146
+ }
147
+
148
+ // src/decorators/metadata.ts
149
+ var ignoredTargets = /* @__PURE__ */ new WeakSet();
150
+ var tracedTargets = /* @__PURE__ */ new WeakSet();
151
+ function markTraceIgnored(target) {
152
+ ignoredTargets.add(target);
153
+ }
154
+ function markTraceDecorated(target) {
155
+ tracedTargets.add(target);
156
+ }
157
+ function isTraceIgnored(method, type) {
158
+ return Boolean(method && ignoredTargets.has(method) || type && ignoredTargets.has(type));
159
+ }
160
+ function isTraceDecorated(method) {
161
+ return Boolean(method && tracedTargets.has(method));
162
+ }
163
+
164
+ // src/decorators/ignore-trace.decorator.ts
165
+ function IgnoreTrace() {
166
+ return ((target, propertyKey, descriptor) => {
167
+ if (propertyKey !== void 0 && descriptor?.value && typeof descriptor.value === "function") {
168
+ markTraceIgnored(descriptor.value);
169
+ return descriptor;
170
+ }
171
+ markTraceIgnored(target);
172
+ return target;
173
+ });
174
+ }
175
+
176
+ // src/decorators/trace.decorator.ts
177
+ var import_api2 = require("@opentelemetry/api");
178
+
179
+ // src/decorators/invoke.ts
180
+ var import_api = require("@opentelemetry/api");
181
+ var import_rxjs = require("rxjs");
182
+ var import_operators = require("rxjs/operators");
183
+ function fail(span, error) {
184
+ span.recordException(error instanceof Error ? error : new Error(String(error)));
185
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) });
186
+ }
187
+ function invokeWithSpan(tracer, spanName, attributes, invoke, onFinish) {
188
+ return tracer.startActiveSpan(spanName, { attributes }, (span) => {
189
+ const started = process.hrtime.bigint();
190
+ const finish = (error) => {
191
+ if (error !== void 0) fail(span, error);
192
+ else span.setStatus({ code: import_api.SpanStatusCode.OK });
193
+ onFinish?.(Number(process.hrtime.bigint() - started) / 1e9, error);
194
+ span.end();
195
+ };
196
+ try {
197
+ const result = invoke();
198
+ if (result instanceof Promise) {
199
+ return result.then(
200
+ (value) => {
201
+ finish();
202
+ return value;
203
+ },
204
+ (error) => {
205
+ finish(error);
206
+ throw error;
207
+ }
208
+ );
209
+ }
210
+ if ((0, import_rxjs.isObservable)(result)) {
211
+ const spanContext = import_api.context.active();
212
+ const source = result;
213
+ return new import_rxjs.Observable((subscriber) => import_api.context.with(spanContext, () => {
214
+ let streamError;
215
+ return source.pipe(
216
+ (0, import_operators.tap)({ error: (error) => {
217
+ streamError = error;
218
+ } }),
219
+ (0, import_operators.finalize)(() => finish(streamError))
220
+ ).subscribe(subscriber);
221
+ }));
222
+ }
223
+ finish();
224
+ return result;
225
+ } catch (error) {
226
+ finish(error);
227
+ throw error;
228
+ }
229
+ });
230
+ }
231
+
232
+ // src/decorators/trace.decorator.ts
233
+ function decorateMethod(target, propertyKey, descriptor, options) {
234
+ const original = descriptor.value;
235
+ if (typeof original !== "function" || isTraceIgnored(original, target.constructor)) return;
236
+ const className = target.constructor?.name || "Anonymous";
237
+ const methodName = String(propertyKey);
238
+ const wrapped = function(...args) {
239
+ const tracer = import_api2.trace.getTracer("@ryanzen9/nest-observe");
240
+ return invokeWithSpan(tracer, options.name ?? `${className}.${methodName}`, {
241
+ "code.function.name": methodName,
242
+ "nestjs.class": className,
243
+ "nestjs.method": methodName,
244
+ ...options.attributes
245
+ }, () => original.apply(this, args));
246
+ };
247
+ Object.defineProperty(wrapped, "name", { value: original.name, configurable: true });
248
+ markTraceDecorated(wrapped);
249
+ descriptor.value = wrapped;
250
+ }
251
+ function Trace(nameOrOptions = {}) {
252
+ const options = typeof nameOrOptions === "string" ? { name: nameOrOptions } : nameOrOptions;
253
+ return ((target, propertyKey, descriptor) => {
254
+ if (propertyKey !== void 0 && descriptor) {
255
+ decorateMethod(target, propertyKey, descriptor, options);
256
+ return descriptor;
257
+ }
258
+ const prototype = target.prototype;
259
+ if (!prototype) return target;
260
+ for (const key of Object.getOwnPropertyNames(prototype)) {
261
+ if (key === "constructor") continue;
262
+ const item = Object.getOwnPropertyDescriptor(prototype, key);
263
+ if (!item || typeof item.value !== "function") continue;
264
+ decorateMethod(prototype, key, item, options);
265
+ Object.defineProperty(prototype, key, item);
266
+ }
267
+ return target;
268
+ });
269
+ }
270
+
271
+ // src/logs/nest-logger-instrumentation.ts
272
+ var import_common = require("@nestjs/common");
273
+ var import_api3 = require("@opentelemetry/api");
274
+
275
+ // src/security/redaction.ts
276
+ var REDACTED = "[REDACTED]";
277
+ var SENSITIVE_KEY = /(?:authorization|proxy-authorization|cookie|set-cookie|pass(?:word|wd)?|secret|token|api[-_]?key|phone|mobile)/i;
278
+ function isSensitiveKey(name) {
279
+ return SENSITIVE_KEY.test(name);
280
+ }
281
+ function redactText(value) {
282
+ return value.replace(/(?<!\d)1[3-9]\d{9}(?!\d)/g, REDACTED).replace(/\b(authorization|proxy-authorization)\s*[:=]\s*(?:bearer\s+|basic\s+)?[^\s,;]+/gi, `$1=${REDACTED}`).replace(/\b(password|passwd|secret|token|access_token|api[-_]?key|cookie)\s*[:=]\s*[^\s,;]+/gi, `$1=${REDACTED}`).replace(/\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, `Bearer ${REDACTED}`);
283
+ }
284
+ function errorValue(error) {
285
+ return {
286
+ name: error.name,
287
+ message: redactText(error.message),
288
+ ...error.stack ? { stack: redactText(error.stack) } : {}
289
+ };
290
+ }
291
+ function visit(value, seen) {
292
+ if (typeof value === "string") return redactText(value);
293
+ if (value === null || typeof value !== "object") return value;
294
+ if (value instanceof Error) return errorValue(value);
295
+ if (seen.has(value)) return "[Circular]";
296
+ seen.add(value);
297
+ if (Array.isArray(value)) return value.map((item) => visit(item, seen));
298
+ const output = {};
299
+ for (const [key, item] of Object.entries(value)) {
300
+ output[key] = SENSITIVE_KEY.test(key) ? REDACTED : visit(item, seen);
301
+ }
302
+ return output;
303
+ }
304
+ function redact(value) {
305
+ return visit(value, /* @__PURE__ */ new WeakSet());
306
+ }
307
+ function sanitizeHeaders(headers, allowedHeaders) {
308
+ const allowed = new Set(allowedHeaders.map((header) => header.toLowerCase()));
309
+ const output = {};
310
+ for (const [originalName, value] of Object.entries(headers)) {
311
+ const name = originalName.toLowerCase();
312
+ if (!allowed.has(name) || value === void 0) continue;
313
+ output[name] = SENSITIVE_KEY.test(name) ? REDACTED : Array.isArray(value) ? value.join(", ") : value;
314
+ }
315
+ return output;
316
+ }
317
+
318
+ // src/logs/nest-logger-instrumentation.ts
319
+ var SEVERITY = {
320
+ verbose: "TRACE",
321
+ debug: "DEBUG",
322
+ log: "INFO",
323
+ warn: "WARN",
324
+ error: "ERROR",
325
+ fatal: "FATAL"
326
+ };
327
+ function bodyValue(message) {
328
+ if (message instanceof Error) return redactText(message.stack ?? `${message.name}: ${message.message}`);
329
+ return redact(message);
330
+ }
331
+ var NestLoggerInstrumentation = class {
332
+ constructor(emitter, resourceAttributes = {}) {
333
+ this.emitter = emitter;
334
+ this.resourceAttributes = resourceAttributes;
335
+ }
336
+ emitter;
337
+ resourceAttributes;
338
+ originals = /* @__PURE__ */ new Map();
339
+ enabled = false;
340
+ enable() {
341
+ if (this.enabled) return;
342
+ this.enabled = true;
343
+ const prototype = import_common.ConsoleLogger.prototype;
344
+ for (const method of Object.keys(SEVERITY)) {
345
+ const original = prototype[method];
346
+ if (typeof original !== "function") continue;
347
+ this.originals.set(method, original);
348
+ const emitter = this.emitter;
349
+ const resourceAttributes = this.resourceAttributes;
350
+ prototype[method] = function(message, ...args) {
351
+ try {
352
+ const spanContext = import_api3.trace.getActiveSpan()?.spanContext();
353
+ const contextName = this.context ?? (typeof args.at(-1) === "string" ? String(args.at(-1)) : void 0);
354
+ const attributes = { ...resourceAttributes };
355
+ if (contextName) attributes["nestjs.context"] = contextName;
356
+ if (spanContext?.traceId) attributes.trace_id = spanContext.traceId;
357
+ if (spanContext?.spanId) attributes.span_id = spanContext.spanId;
358
+ emitter.emit({
359
+ body: bodyValue(message),
360
+ severityText: SEVERITY[method],
361
+ attributes,
362
+ timestamp: Date.now()
363
+ });
364
+ } catch {
365
+ }
366
+ return original.call(this, message, ...args);
367
+ };
368
+ }
369
+ }
370
+ disable() {
371
+ if (!this.enabled) return;
372
+ const prototype = import_common.ConsoleLogger.prototype;
373
+ for (const [method, original] of this.originals) prototype[method] = original;
374
+ this.originals.clear();
375
+ this.enabled = false;
376
+ }
377
+ };
378
+
379
+ // src/logs/otel-log-emitter.ts
380
+ var import_api4 = require("@opentelemetry/api");
381
+ var import_api_logs = require("@opentelemetry/api-logs");
382
+ var SEVERITY_NUMBER = {
383
+ TRACE: import_api_logs.SeverityNumber.TRACE,
384
+ DEBUG: import_api_logs.SeverityNumber.DEBUG,
385
+ INFO: import_api_logs.SeverityNumber.INFO,
386
+ WARN: import_api_logs.SeverityNumber.WARN,
387
+ ERROR: import_api_logs.SeverityNumber.ERROR,
388
+ FATAL: import_api_logs.SeverityNumber.FATAL
389
+ };
390
+ var OpenTelemetryLogEmitter = class {
391
+ logger;
392
+ constructor(name = "@ryanzen9/nest-observe", version, logger) {
393
+ this.logger = logger ?? import_api_logs.logs.getLogger(name, version);
394
+ }
395
+ emit(record) {
396
+ this.logger.emit({
397
+ body: record.body,
398
+ severityText: record.severityText,
399
+ severityNumber: SEVERITY_NUMBER[record.severityText],
400
+ attributes: record.attributes,
401
+ ...record.timestamp === void 0 ? {} : { timestamp: record.timestamp },
402
+ context: import_api4.context.active()
403
+ });
404
+ }
405
+ };
406
+
407
+ // src/instrumentation/nest-compatible-instrumentation.ts
408
+ var import_instrumentation = require("@opentelemetry/instrumentation");
409
+ var import_instrumentation_nestjs_core = require("@opentelemetry/instrumentation-nestjs-core");
410
+
411
+ // src/nest/method-instrumenter.ts
412
+ var NestMethodInstrumenter = class {
413
+ constructor(tracer, meter) {
414
+ this.tracer = tracer;
415
+ this.calls = meter.createCounter("nestjs.method.calls", { unit: "{call}" });
416
+ this.duration = meter.createHistogram("nestjs.method.duration", {
417
+ unit: "s",
418
+ advice: { explicitBucketBoundaries: [1e-3, 5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5] }
419
+ });
420
+ this.errors = meter.createCounter("nestjs.method.errors", { unit: "{error}" });
421
+ }
422
+ tracer;
423
+ calls;
424
+ duration;
425
+ errors;
426
+ instrumented = /* @__PURE__ */ new WeakMap();
427
+ instrumentInstance(instance, kind, componentName) {
428
+ const type = instance.constructor;
429
+ const prototype = Object.getPrototypeOf(instance);
430
+ if (!prototype) return;
431
+ this.instrumentTarget(instance, prototype, type, kind, componentName);
432
+ }
433
+ instrumentPrototype(type, kind, componentName) {
434
+ const prototype = type.prototype;
435
+ if (!prototype) return;
436
+ this.instrumentTarget(prototype, prototype, type, kind, componentName);
437
+ }
438
+ instrumentTarget(target, prototype, type, kind, componentName) {
439
+ if (isTraceIgnored(type)) return;
440
+ const completed = this.instrumented.get(target) ?? /* @__PURE__ */ new Set();
441
+ this.instrumented.set(target, completed);
442
+ for (const methodName of Object.getOwnPropertyNames(prototype)) {
443
+ if (methodName === "constructor" || completed.has(methodName) || methodName.startsWith("onModule")) continue;
444
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName);
445
+ const original = descriptor?.value;
446
+ if (!descriptor || typeof original !== "function" || isTraceIgnored(original, type) || isTraceDecorated(original)) continue;
447
+ const existing = Reflect.get(target, methodName);
448
+ if (typeof existing === "function" && existing !== original && isTraceDecorated(existing)) continue;
449
+ const name = componentName || type.name || "Anonymous";
450
+ const attributes = {
451
+ [`nestjs.${kind}`]: name,
452
+ "nestjs.method": methodName
453
+ };
454
+ const instrumenter = this;
455
+ const wrapped = function(...args) {
456
+ instrumenter.calls.add(1, attributes);
457
+ return invokeWithSpan(
458
+ instrumenter.tracer,
459
+ `${name}.${methodName}`,
460
+ attributes,
461
+ () => original.apply(this, args),
462
+ (seconds, error) => {
463
+ instrumenter.duration.record(seconds, attributes);
464
+ if (error !== void 0) instrumenter.errors.add(1, attributes);
465
+ }
466
+ );
467
+ };
468
+ markTraceDecorated(wrapped);
469
+ try {
470
+ Object.defineProperty(target, methodName, { ...descriptor, value: wrapped });
471
+ completed.add(methodName);
472
+ } catch {
473
+ }
474
+ }
475
+ }
476
+ };
477
+
478
+ // src/instrumentation/nest-compatible-instrumentation.ts
479
+ var SUPPORTED_NEST_VERSIONS = [">=4.0.0 <13"];
480
+ var CompatibleNestInstrumentation = class extends import_instrumentation_nestjs_core.NestInstrumentation {
481
+ constructor(observeConfig = {}) {
482
+ super(observeConfig);
483
+ this.observeConfig = observeConfig;
484
+ }
485
+ observeConfig;
486
+ methodInstrumenter;
487
+ init() {
488
+ const definition = new import_instrumentation.InstrumentationNodeModuleDefinition("@nestjs/core", SUPPORTED_NEST_VERSIONS);
489
+ definition.files.push(
490
+ this.getNestFactoryFileInstrumentation(SUPPORTED_NEST_VERSIONS),
491
+ this.getRouterExecutionContextFileInstrumentation(SUPPORTED_NEST_VERSIONS),
492
+ new import_instrumentation.InstrumentationNodeModuleFile(
493
+ "@nestjs/core/injector/injector.js",
494
+ SUPPORTED_NEST_VERSIONS,
495
+ (moduleExports) => {
496
+ const instrumentation = this;
497
+ this._wrap(moduleExports.Injector.prototype, "instantiateClass", (original) => {
498
+ return async function(...args) {
499
+ const instance = await original.apply(this, args);
500
+ try {
501
+ const wrapper = args[1];
502
+ if (!instance || typeof instance !== "object" || !wrapper?.metatype) return instance;
503
+ if (["InternalCoreModule", "ObserveModule", "DiscoveryModule"].includes(wrapper.host?.name ?? "")) {
504
+ return instance;
505
+ }
506
+ const isController = wrapper.host?.controllers?.get(wrapper.token) === wrapper;
507
+ if (isController && instrumentation.observeConfig.controllerTracing === false || !isController && instrumentation.observeConfig.providerTracing === false) {
508
+ return instance;
509
+ }
510
+ instrumentation.getMethodInstrumenter().instrumentInstance(
511
+ instance,
512
+ isController ? "controller" : "provider",
513
+ wrapper.name ?? wrapper.metatype.name
514
+ );
515
+ } catch {
516
+ }
517
+ return instance;
518
+ };
519
+ });
520
+ return moduleExports;
521
+ },
522
+ (moduleExports) => {
523
+ this._unwrap(moduleExports.Injector.prototype, "instantiateClass");
524
+ }
525
+ )
526
+ );
527
+ return definition;
528
+ }
529
+ getMethodInstrumenter() {
530
+ return this.methodInstrumenter ??= new NestMethodInstrumenter(this.tracer, this.meter);
531
+ }
532
+ };
533
+
534
+ // src/metrics/http-request-metrics.ts
535
+ function routeFor(request) {
536
+ const route = request.route?.path ?? request.routerPath ?? request.routeOptions?.url;
537
+ if (!route) return "<unmatched>";
538
+ return `${request.baseUrl ?? ""}${route}` || "<unmatched>";
539
+ }
540
+ var HttpRequestMetrics = class {
541
+ constructor(meter, serviceName) {
542
+ this.serviceName = serviceName;
543
+ this.requestCount = meter.createCounter("http.server.request.count", {
544
+ description: "Number of completed inbound HTTP requests",
545
+ unit: "{request}"
546
+ });
547
+ this.requestDuration = meter.createHistogram("http.server.request.duration", {
548
+ description: "Inbound HTTP request duration",
549
+ unit: "s",
550
+ advice: { explicitBucketBoundaries: [5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] }
551
+ });
552
+ this.errorCount = meter.createCounter("http.server.error.count", {
553
+ description: "Number of failed inbound HTTP requests",
554
+ unit: "{error}"
555
+ });
556
+ }
557
+ serviceName;
558
+ requestCount;
559
+ requestDuration;
560
+ errorCount;
561
+ startedAt = /* @__PURE__ */ new WeakMap();
562
+ start(request) {
563
+ this.startedAt.set(request, process.hrtime.bigint());
564
+ }
565
+ record(request, response) {
566
+ const statusCode = Number.isFinite(response.statusCode) ? response.statusCode : 0;
567
+ const attributes = {
568
+ "service.name": this.serviceName,
569
+ "http.route": routeFor(request),
570
+ "http.request.method": request.method ?? "UNKNOWN",
571
+ "http.response.status_code": statusCode
572
+ };
573
+ this.requestCount.add(1, attributes);
574
+ const started = this.startedAt.get(request);
575
+ if (started !== void 0) {
576
+ this.requestDuration.record(Number(process.hrtime.bigint() - started) / 1e9, attributes);
577
+ this.startedAt.delete(request);
578
+ }
579
+ if (statusCode >= 500) this.errorCount.add(1, attributes);
580
+ }
581
+ };
582
+
583
+ // src/metrics/runtime-metrics.ts
584
+ var import_node_os = require("os");
585
+ var import_node_perf_hooks = require("perf_hooks");
586
+ var RuntimeMetrics = class {
587
+ constructor(meter) {
588
+ this.meter = meter;
589
+ }
590
+ meter;
591
+ callbacks = [];
592
+ eventLoopDelay;
593
+ gcObserver;
594
+ started = false;
595
+ previousElu = import_node_perf_hooks.performance.eventLoopUtilization();
596
+ observe(instrument, callback) {
597
+ instrument.addCallback(callback);
598
+ this.callbacks.push({ instrument, callback });
599
+ }
600
+ start() {
601
+ if (this.started) return;
602
+ this.started = true;
603
+ const systemCpu = this.meter.createObservableGauge("system.cpu.utilization", { unit: "1" });
604
+ this.observe(systemCpu, (result) => {
605
+ const cores = (0, import_node_os.cpus)();
606
+ let idle = 0;
607
+ let total = 0;
608
+ for (const core of cores) {
609
+ idle += core.times.idle;
610
+ total += Object.values(core.times).reduce((sum, value) => sum + value, 0);
611
+ }
612
+ result.observe(total ? (total - idle) / total : 0);
613
+ });
614
+ const processCpu = this.meter.createObservableCounter("process.cpu.time", { unit: "s" });
615
+ this.observe(processCpu, (result) => {
616
+ const cpu = process.cpuUsage();
617
+ result.observe((cpu.user + cpu.system) / 1e6);
618
+ });
619
+ const rss = this.meter.createObservableGauge("process.memory.rss", { unit: "By" });
620
+ const heapUsed = this.meter.createObservableGauge("nodejs.memory.heap.used", { unit: "By" });
621
+ const heapTotal = this.meter.createObservableGauge("nodejs.memory.heap.total", { unit: "By" });
622
+ this.observe(rss, (result) => result.observe(process.memoryUsage().rss));
623
+ this.observe(heapUsed, (result) => result.observe(process.memoryUsage().heapUsed));
624
+ this.observe(heapTotal, (result) => result.observe(process.memoryUsage().heapTotal));
625
+ this.eventLoopDelay = (0, import_node_perf_hooks.monitorEventLoopDelay)({ resolution: 20 });
626
+ this.eventLoopDelay.enable();
627
+ const delay = this.meter.createObservableGauge("nodejs.eventloop.delay", { unit: "s" });
628
+ this.observe(delay, (result) => {
629
+ const mean = this.eventLoopDelay?.mean ?? 0;
630
+ result.observe(Number.isFinite(mean) ? mean / 1e9 : 0);
631
+ this.eventLoopDelay?.reset();
632
+ });
633
+ const utilization = this.meter.createObservableGauge("nodejs.eventloop.utilization", { unit: "1" });
634
+ this.observe(utilization, (result) => {
635
+ const current = import_node_perf_hooks.performance.eventLoopUtilization(this.previousElu);
636
+ this.previousElu = import_node_perf_hooks.performance.eventLoopUtilization();
637
+ result.observe(current.utilization);
638
+ });
639
+ const gc = this.meter.createHistogram("nodejs.gc.duration", { unit: "s" });
640
+ this.gcObserver = new import_node_perf_hooks.PerformanceObserver((list) => {
641
+ for (const entry of list.getEntries()) {
642
+ const detail = entry.detail;
643
+ gc.record(entry.duration / 1e3, { "nodejs.gc.type": String(detail?.kind ?? "unknown") });
644
+ }
645
+ });
646
+ try {
647
+ this.gcObserver.observe({ entryTypes: ["gc"] });
648
+ } catch {
649
+ }
650
+ const uptime = this.meter.createObservableGauge("process.uptime", { unit: "s" });
651
+ this.observe(uptime, (result) => result.observe(process.uptime()));
652
+ }
653
+ stop() {
654
+ for (const { instrument, callback } of this.callbacks) instrument.removeCallback(callback);
655
+ this.callbacks.length = 0;
656
+ this.eventLoopDelay?.disable();
657
+ this.eventLoopDelay = void 0;
658
+ this.gcObserver?.disconnect();
659
+ this.gcObserver = void 0;
660
+ this.started = false;
661
+ }
662
+ };
663
+
664
+ // src/nest/observe.module.ts
665
+ var import_common2 = require("@nestjs/common");
666
+ var import_core = require("@nestjs/core");
667
+ var import_api7 = require("@opentelemetry/api");
668
+
669
+ // src/sdk.ts
670
+ var import_api_logs2 = require("@opentelemetry/api-logs");
671
+ var import_api6 = require("@opentelemetry/api");
672
+ var import_exporter_logs_otlp_proto = require("@opentelemetry/exporter-logs-otlp-proto");
673
+ var import_exporter_metrics_otlp_proto = require("@opentelemetry/exporter-metrics-otlp-proto");
674
+ var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
675
+ var import_instrumentation2 = require("@opentelemetry/instrumentation");
676
+ var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
677
+ var import_instrumentation3 = require("@prisma/instrumentation");
678
+ var import_sdk_logs = require("@opentelemetry/sdk-logs");
679
+ var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
680
+ var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
681
+ var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
682
+
683
+ // src/exceptions/process-exception-capture.ts
684
+ var import_api5 = require("@opentelemetry/api");
685
+ function asError(value) {
686
+ return value instanceof Error ? value : new Error(String(value));
687
+ }
688
+ var ProcessExceptionCapture = class {
689
+ constructor(emitter) {
690
+ this.emitter = emitter;
691
+ }
692
+ emitter;
693
+ listening = false;
694
+ onUncaughtException = (value) => this.capture(value, "uncaughtException");
695
+ start() {
696
+ if (this.listening) return;
697
+ this.listening = true;
698
+ process.on("uncaughtExceptionMonitor", this.onUncaughtException);
699
+ }
700
+ stop() {
701
+ if (!this.listening) return;
702
+ process.off("uncaughtExceptionMonitor", this.onUncaughtException);
703
+ this.listening = false;
704
+ }
705
+ capture(value, source = "nestjs") {
706
+ try {
707
+ const error = asError(value);
708
+ const span = import_api5.trace.getActiveSpan();
709
+ span?.recordException(error);
710
+ span?.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: error.message });
711
+ const spanContext = span?.spanContext();
712
+ this.emitter?.emit({
713
+ body: redactText(error.stack ?? error.message),
714
+ severityText: "ERROR",
715
+ attributes: {
716
+ "exception.type": error.name,
717
+ "exception.message": redactText(error.message),
718
+ "exception.stacktrace": redactText(error.stack ?? ""),
719
+ "exception.source": source,
720
+ ...spanContext ? { trace_id: spanContext.traceId, span_id: spanContext.spanId } : {}
721
+ },
722
+ timestamp: Date.now()
723
+ });
724
+ } catch {
725
+ }
726
+ }
727
+ };
728
+
729
+ // src/resource.ts
730
+ var import_node_os2 = require("os");
731
+ var import_resources = require("@opentelemetry/resources");
732
+ var SDK_NAME = "@ryanzen9/nest-observe";
733
+ var SDK_VERSION = "0.1.0";
734
+ function createObserveResource(config) {
735
+ return (0, import_resources.defaultResource)().merge((0, import_resources.resourceFromAttributes)({
736
+ ...config.resourceAttributes,
737
+ "service.name": config.serviceName,
738
+ "service.version": config.serviceVersion,
739
+ "deployment.environment.name": config.environment,
740
+ "service.instance.id": config.instanceId,
741
+ "telemetry.sdk.name": SDK_NAME,
742
+ "telemetry.sdk.version": SDK_VERSION,
743
+ "host.name": config.resourceAttributes["host.name"] ?? (0, import_node_os2.hostname)()
744
+ }));
745
+ }
746
+
747
+ // src/security/span-redaction-processor.ts
748
+ var DROP_VALUE = /(?:request\.body|db\.(?:query\.)?parameters?|db\.statement\.parameters?|redis\.(?:args|value))/i;
749
+ function cleanValue(value) {
750
+ if (typeof value === "string") return redactText(value);
751
+ if (Array.isArray(value)) {
752
+ return value.map((item) => typeof item === "string" ? redactText(item) : item);
753
+ }
754
+ return value;
755
+ }
756
+ function cleanAttributes(attributes) {
757
+ if (!attributes) return;
758
+ const mutable = attributes;
759
+ for (const [key, value] of Object.entries(mutable)) {
760
+ if (value === void 0) continue;
761
+ if (DROP_VALUE.test(key) || isSensitiveKey(key)) mutable[key] = REDACTED;
762
+ else mutable[key] = cleanValue(value);
763
+ }
764
+ }
765
+ var SpanRedactionProcessor = class {
766
+ onStart(_span, _parentContext) {
767
+ }
768
+ onEnd(span) {
769
+ const mutable = span;
770
+ try {
771
+ mutable.name = redactText(mutable.name);
772
+ cleanAttributes(mutable.attributes);
773
+ if (mutable.status.message) mutable.status.message = redactText(mutable.status.message);
774
+ for (const event of mutable.events) cleanAttributes(event.attributes);
775
+ } catch {
776
+ }
777
+ }
778
+ forceFlush() {
779
+ return Promise.resolve();
780
+ }
781
+ shutdown() {
782
+ return Promise.resolve();
783
+ }
784
+ };
785
+
786
+ // src/sdk.ts
787
+ var InactiveObserveHandle = class {
788
+ constructor(config) {
789
+ this.config = config;
790
+ }
791
+ config;
792
+ started = false;
793
+ tracerProvider = void 0;
794
+ meterProvider = void 0;
795
+ loggerProvider = void 0;
796
+ forceFlush() {
797
+ return Promise.resolve();
798
+ }
799
+ shutdown() {
800
+ return Promise.resolve();
801
+ }
802
+ };
803
+ var ActiveObserveHandle = class {
804
+ constructor(config, tracerProvider, meterProvider, loggerProvider, runtimeMetrics, loggerInstrumentation, exceptionCapture, instrumentations) {
805
+ this.config = config;
806
+ this.tracerProvider = tracerProvider;
807
+ this.meterProvider = meterProvider;
808
+ this.loggerProvider = loggerProvider;
809
+ this.runtimeMetrics = runtimeMetrics;
810
+ this.loggerInstrumentation = loggerInstrumentation;
811
+ this.exceptionCapture = exceptionCapture;
812
+ this.instrumentations = instrumentations;
813
+ }
814
+ config;
815
+ tracerProvider;
816
+ meterProvider;
817
+ loggerProvider;
818
+ runtimeMetrics;
819
+ loggerInstrumentation;
820
+ exceptionCapture;
821
+ instrumentations;
822
+ started = true;
823
+ stopped = false;
824
+ async forceFlush() {
825
+ await Promise.allSettled([
826
+ this.tracerProvider?.forceFlush(),
827
+ this.meterProvider?.forceFlush(),
828
+ this.loggerProvider?.forceFlush({ timeoutMillis: this.config.exportTimeoutMillis })
829
+ ].filter((item) => Boolean(item)));
830
+ }
831
+ async shutdown() {
832
+ if (this.stopped) return;
833
+ this.stopped = true;
834
+ this.loggerInstrumentation?.disable();
835
+ this.runtimeMetrics?.stop();
836
+ this.exceptionCapture.stop();
837
+ for (const instrumentation of this.instrumentations) {
838
+ try {
839
+ instrumentation.disable();
840
+ } catch {
841
+ }
842
+ }
843
+ await this.forceFlush();
844
+ await Promise.allSettled([
845
+ this.tracerProvider?.shutdown(),
846
+ this.meterProvider?.shutdown(),
847
+ this.loggerProvider?.shutdown()
848
+ ].filter((item) => Boolean(item)));
849
+ if (activeRuntime === this) activeRuntime = void 0;
850
+ }
851
+ };
852
+ var activeRuntime;
853
+ function exporterConfig(url, config) {
854
+ return {
855
+ ...url ? { url } : {},
856
+ headers: config.headers,
857
+ timeoutMillis: config.exportTimeoutMillis
858
+ };
859
+ }
860
+ function createTraceProvider(config, resource) {
861
+ if (!config.traces && !config.metrics) return void 0;
862
+ const spanProcessors = [new SpanRedactionProcessor()];
863
+ if (config.traces) {
864
+ const exporter = config.exporters?.span ?? new import_exporter_trace_otlp_proto.OTLPTraceExporter(exporterConfig(config.endpoints.traces, config));
865
+ spanProcessors.push(new import_sdk_trace_base.BatchSpanProcessor(exporter, {
866
+ exportTimeoutMillis: config.exportTimeoutMillis,
867
+ maxQueueSize: 2048,
868
+ maxExportBatchSize: 512
869
+ }));
870
+ }
871
+ const provider = new import_sdk_trace_node.NodeTracerProvider({
872
+ resource,
873
+ sampler: config.traces ? new import_sdk_trace_base.ParentBasedSampler({ root: new import_sdk_trace_base.TraceIdRatioBasedSampler(config.sampling) }) : new import_sdk_trace_base.AlwaysOffSampler(),
874
+ spanProcessors,
875
+ spanLimits: { attributeCountLimit: 64, eventCountLimit: 64, linkCountLimit: 16 }
876
+ });
877
+ provider.register();
878
+ return provider;
879
+ }
880
+ function createMeterProvider(config, resource) {
881
+ if (!config.metrics) return void 0;
882
+ let reader;
883
+ if (config.exporters?.metricReader) {
884
+ reader = config.exporters.metricReader;
885
+ } else {
886
+ reader = new import_sdk_metrics.PeriodicExportingMetricReader({
887
+ exporter: new import_exporter_metrics_otlp_proto.OTLPMetricExporter(exporterConfig(config.endpoints.metrics, config)),
888
+ exportIntervalMillis: config.metricExportIntervalMillis,
889
+ exportTimeoutMillis: Math.min(config.exportTimeoutMillis, config.metricExportIntervalMillis),
890
+ cardinalityLimits: { default: 2e3, histogram: 2e3 }
891
+ });
892
+ }
893
+ const provider = new import_sdk_metrics.MeterProvider({
894
+ resource,
895
+ readers: [reader],
896
+ views: [{
897
+ instrumentName: "http.server.request.duration",
898
+ meterName: "@opentelemetry/instrumentation-http",
899
+ aggregation: { type: import_sdk_metrics.AggregationType.DROP }
900
+ }]
901
+ });
902
+ import_api6.metrics.setGlobalMeterProvider(provider);
903
+ return provider;
904
+ }
905
+ function createLoggerProvider(config, resource) {
906
+ if (!config.logs) return void 0;
907
+ const exporter = config.exporters?.log ?? new import_exporter_logs_otlp_proto.OTLPLogExporter(exporterConfig(config.endpoints.logs, config));
908
+ const provider = new import_sdk_logs.LoggerProvider({
909
+ resource,
910
+ processors: [new import_sdk_logs.BatchLogRecordProcessor({
911
+ exporter,
912
+ exportTimeoutMillis: config.exportTimeoutMillis,
913
+ maxQueueSize: 2048,
914
+ maxExportBatchSize: 512
915
+ })]
916
+ });
917
+ import_api_logs2.logs.setGlobalLoggerProvider(provider);
918
+ return provider;
919
+ }
920
+ function observe(options = {}) {
921
+ if (activeRuntime?.started) return activeRuntime;
922
+ const config = resolveObserveConfig(options);
923
+ if (!config.enabled) return new InactiveObserveHandle(config);
924
+ let tracerProvider;
925
+ let meterProvider;
926
+ let loggerProvider;
927
+ let runtimeMetrics;
928
+ let loggerInstrumentation;
929
+ let exceptionCapture;
930
+ const instrumentations = [];
931
+ try {
932
+ const resource = createObserveResource(config);
933
+ meterProvider = createMeterProvider(config, resource);
934
+ const meter = meterProvider?.getMeter(SDK_NAME, SDK_VERSION);
935
+ tracerProvider = createTraceProvider(config, resource);
936
+ loggerProvider = createLoggerProvider(config, resource);
937
+ runtimeMetrics = meter ? new RuntimeMetrics(meter) : void 0;
938
+ runtimeMetrics?.start();
939
+ const otelLogger = loggerProvider?.getLogger(SDK_NAME, SDK_VERSION);
940
+ const logEmitter = config.logs ? new OpenTelemetryLogEmitter(SDK_NAME, SDK_VERSION, otelLogger) : void 0;
941
+ loggerInstrumentation = logEmitter ? new NestLoggerInstrumentation(logEmitter, {
942
+ "service.name": config.serviceName,
943
+ "service.version": config.serviceVersion,
944
+ "deployment.environment.name": config.environment
945
+ }) : void 0;
946
+ loggerInstrumentation?.enable();
947
+ exceptionCapture = new ProcessExceptionCapture(logEmitter);
948
+ exceptionCapture.start();
949
+ if (config.traces || config.metrics) {
950
+ const safeHeaders = config.allowedHeaders.filter((header) => !isSensitiveKey(header));
951
+ const httpRequestMetrics = meter ? new HttpRequestMetrics(meter, config.serviceName) : void 0;
952
+ instrumentations.push(new import_instrumentation_http.HttpInstrumentation({
953
+ requireParentforOutgoingSpans: false,
954
+ headersToSpanAttributes: {
955
+ client: { requestHeaders: safeHeaders, responseHeaders: safeHeaders },
956
+ server: { requestHeaders: safeHeaders, responseHeaders: safeHeaders }
957
+ },
958
+ redactedQueryParams: [
959
+ "sig",
960
+ "Signature",
961
+ "AWSAccessKeyId",
962
+ "X-Goog-Signature",
963
+ "password",
964
+ "passwd",
965
+ "token",
966
+ "access_token",
967
+ "api_key",
968
+ "secret"
969
+ ],
970
+ ...httpRequestMetrics ? {
971
+ requestHook: (_span, request) => {
972
+ if (!("getHeader" in request)) httpRequestMetrics.start(request);
973
+ },
974
+ applyCustomAttributesOnSpan: (_span, request, response) => {
975
+ if ("setHeader" in response) httpRequestMetrics.record(request, response);
976
+ }
977
+ } : {}
978
+ }));
979
+ instrumentations.push(new CompatibleNestInstrumentation({
980
+ providerTracing: config.providerTracing,
981
+ controllerTracing: config.controllerTracing
982
+ }));
983
+ if (config.traces) instrumentations.push(new import_instrumentation3.PrismaInstrumentation());
984
+ (0, import_instrumentation2.registerInstrumentations)({
985
+ instrumentations,
986
+ ...tracerProvider ? { tracerProvider } : {},
987
+ ...meterProvider ? { meterProvider } : {}
988
+ });
989
+ }
990
+ const runtime = new ActiveObserveHandle(
991
+ config,
992
+ tracerProvider,
993
+ meterProvider,
994
+ loggerProvider,
995
+ runtimeMetrics,
996
+ loggerInstrumentation,
997
+ exceptionCapture,
998
+ instrumentations
999
+ );
1000
+ activeRuntime = runtime;
1001
+ return runtime;
1002
+ } catch {
1003
+ loggerInstrumentation?.disable();
1004
+ runtimeMetrics?.stop();
1005
+ exceptionCapture?.stop();
1006
+ for (const instrumentation of instrumentations) {
1007
+ try {
1008
+ instrumentation.disable();
1009
+ } catch {
1010
+ }
1011
+ }
1012
+ void Promise.allSettled([
1013
+ tracerProvider?.shutdown(),
1014
+ meterProvider?.shutdown(),
1015
+ loggerProvider?.shutdown()
1016
+ ].filter((item) => Boolean(item)));
1017
+ return new InactiveObserveHandle(config);
1018
+ }
1019
+ }
1020
+ function getObserveRuntime() {
1021
+ return activeRuntime;
1022
+ }
1023
+
1024
+ // src/nest/observe.module.ts
1025
+ var OBSERVE_OPTIONS = /* @__PURE__ */ Symbol("OBSERVE_OPTIONS");
1026
+ var OBSERVE_HANDLE = /* @__PURE__ */ Symbol("OBSERVE_HANDLE");
1027
+ var NestObserveExplorer = class {
1028
+ constructor(discovery, options, handle) {
1029
+ this.discovery = discovery;
1030
+ this.options = options;
1031
+ this.handle = handle;
1032
+ }
1033
+ discovery;
1034
+ options;
1035
+ handle;
1036
+ onModuleInit() {
1037
+ if (!this.handle.started) return;
1038
+ const runtime = getObserveRuntime();
1039
+ const tracer = runtime?.tracerProvider?.getTracer(SDK_NAME, SDK_VERSION) ?? import_api7.trace.getTracer(SDK_NAME, SDK_VERSION);
1040
+ const meter = runtime?.meterProvider?.getMeter(SDK_NAME, SDK_VERSION) ?? import_api7.metrics.getMeter(SDK_NAME, SDK_VERSION);
1041
+ const instrumenter = new NestMethodInstrumenter(tracer, meter);
1042
+ if (this.options.providerTracing !== false) {
1043
+ this.instrument(this.discovery.getProviders(), instrumenter, "provider");
1044
+ }
1045
+ if (this.options.controllerTracing !== false) {
1046
+ this.instrument(this.discovery.getControllers(), instrumenter, "controller");
1047
+ }
1048
+ }
1049
+ instrument(wrappers, instrumenter, kind) {
1050
+ for (const wrapper of wrappers) {
1051
+ if (!wrapper.metatype) continue;
1052
+ if (["ObserveModule", "DiscoveryModule", "InternalCoreModule"].includes(wrapper.host?.name ?? "")) continue;
1053
+ if (wrapper.metatype === NestObserveExplorer) continue;
1054
+ if (wrapper.instance) {
1055
+ instrumenter.instrumentInstance(wrapper.instance, kind, wrapper.name ?? wrapper.metatype.name);
1056
+ } else {
1057
+ instrumenter.instrumentPrototype(wrapper.metatype, kind, wrapper.name ?? wrapper.metatype.name);
1058
+ }
1059
+ }
1060
+ }
1061
+ async onApplicationShutdown() {
1062
+ await this.handle.shutdown();
1063
+ }
1064
+ };
1065
+ NestObserveExplorer = __decorateClass([
1066
+ (0, import_common2.Injectable)(),
1067
+ __decorateParam(0, (0, import_common2.Inject)(import_core.DiscoveryService)),
1068
+ __decorateParam(1, (0, import_common2.Inject)(OBSERVE_OPTIONS)),
1069
+ __decorateParam(2, (0, import_common2.Inject)(OBSERVE_HANDLE))
1070
+ ], NestObserveExplorer);
1071
+ var ObserveModule = class {
1072
+ static forRoot(options = {}) {
1073
+ return {
1074
+ module: ObserveModule,
1075
+ global: true,
1076
+ imports: [import_core.DiscoveryModule],
1077
+ providers: [
1078
+ { provide: OBSERVE_OPTIONS, useValue: options },
1079
+ { provide: OBSERVE_HANDLE, useFactory: () => observe(options) },
1080
+ NestObserveExplorer
1081
+ ],
1082
+ exports: [OBSERVE_HANDLE]
1083
+ };
1084
+ }
1085
+ };
1086
+ ObserveModule = __decorateClass([
1087
+ (0, import_common2.Global)(),
1088
+ (0, import_common2.Module)({})
1089
+ ], ObserveModule);
1090
+ // Annotate the CommonJS export names for ESM import in node:
1091
+ 0 && (module.exports = {
1092
+ CompatibleNestInstrumentation,
1093
+ HttpRequestMetrics,
1094
+ IgnoreTrace,
1095
+ NestLoggerInstrumentation,
1096
+ NestMethodInstrumenter,
1097
+ OBSERVE_HANDLE,
1098
+ OBSERVE_OPTIONS,
1099
+ ObserveModule,
1100
+ OpenTelemetryLogEmitter,
1101
+ REDACTED,
1102
+ RuntimeMetrics,
1103
+ SDK_NAME,
1104
+ SDK_VERSION,
1105
+ SpanRedactionProcessor,
1106
+ Trace,
1107
+ createObserveResource,
1108
+ getObserveRuntime,
1109
+ isSensitiveKey,
1110
+ isTraceDecorated,
1111
+ isTraceIgnored,
1112
+ markTraceDecorated,
1113
+ markTraceIgnored,
1114
+ observe,
1115
+ parseKeyValueList,
1116
+ redact,
1117
+ redactText,
1118
+ resolveObserveConfig,
1119
+ sanitizeHeaders
1120
+ });
1121
+ //# sourceMappingURL=index.js.map