@ciq-dev/neoiq-foundation-node 1.1.2-beta.1 → 1.1.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { AutoInstrumentationConfigSchema, FeaturesConfigSchema, FoundationConfigSchema, LoggingConfigSchema, OtelConfigSchema, RedactionConfigSchema, RequestLoggingConfigSchema, ShutdownConfigSchema, SpanStatusCode, VaultConfigSchema, context, getActiveSpan, getDefaultOtelEndpoint, getTraceContext, getTracer, isTracingEnabled, parseConfig, propagation, setupTracing, shutdownTracing, trace } from "./tracing-Mxxp4y94.mjs";
1
+ import { AutoInstrumentationConfigSchema, FeaturesConfigSchema, FoundationConfigSchema, LoggingConfigSchema, OtelConfigSchema, RedactionConfigSchema, RequestLoggingConfigSchema, ShutdownConfigSchema, SpanStatusCode, VaultConfigSchema, context, getActiveSpan, getDefaultOtelEndpoint, getTraceContext, getTracer, isTracingEnabled, parseConfig, propagation, setupTracing, shutdownTracing, trace } from "./tracing-BdAbHWu1.mjs";
2
2
  import { resourceFromAttributes } from "@opentelemetry/resources";
3
3
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
4
- import { DiagLogLevel, SpanStatusCode as SpanStatusCode$1, context as context$1, diag, metrics, propagation as propagation$1, trace as trace$1 } from "@opentelemetry/api";
4
+ import { SpanStatusCode as SpanStatusCode$1, context as context$1, metrics, propagation as propagation$1, trace as trace$1 } from "@opentelemetry/api";
5
5
  import { AsyncLocalStorage } from "async_hooks";
6
6
  import pino from "pino";
7
7
  import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc";
@@ -341,7 +341,34 @@ function getGlobalLogger() {
341
341
  //#region src/features/metrics.ts
342
342
  let meterProvider = null;
343
343
  let isInitialized = false;
344
- /** Initialize OpenTelemetry metrics */
344
+ /**
345
+ * Build a gRPC OTLP metric reader for the tracing NodeSDK to own.
346
+ *
347
+ * Preferred path: hand this reader to `setupTracing({ metricReader })` so a single
348
+ * NodeSDK owns both traces and metrics — one global MeterProvider, exporting to the
349
+ * same gRPC collector. This avoids the duplicate global-MeterProvider registration
350
+ * that occurs when NodeSDK and a standalone `setupMetrics` both try to register.
351
+ *
352
+ * The MeterProvider, resource, and global registration are owned by NodeSDK; this
353
+ * function only constructs the reader/exporter.
354
+ */
355
+ function createMetricReader(options = {}) {
356
+ const { endpoint = getDefaultOtelEndpoint(), intervalMs = 5e3 } = options;
357
+ const exporter = new OTLPMetricExporter({ url: endpoint });
358
+ const reader = new PeriodicExportingMetricReader({
359
+ exporter,
360
+ exportIntervalMillis: intervalMs
361
+ });
362
+ isInitialized = true;
363
+ return reader;
364
+ }
365
+ /**
366
+ * Initialize a standalone metrics pipeline with its own MeterProvider.
367
+ *
368
+ * Fallback for when tracing (and thus the NodeSDK) is disabled but metrics are
369
+ * enabled. When tracing is on, prefer {@link createMetricReader} + NodeSDK so a
370
+ * single SDK owns both signals.
371
+ */
345
372
  function setupMetrics(options) {
346
373
  if (isInitialized) {
347
374
  console.warn("[neoiq-foundation] Metrics already initialized");
@@ -944,38 +971,16 @@ function createFoundation(input) {
944
971
  };
945
972
  console.error("[neoiq-foundation] Logger setup failed, using console:", loggingError);
946
973
  }
947
- const diagLevelName = (process.env.OTEL_DIAG_LOG_LEVEL || otel.diagLogLevel).toLowerCase();
948
- if (diagLevelName !== "none") {
949
- const diagLevels = {
950
- error: DiagLogLevel.ERROR,
951
- warn: DiagLogLevel.WARN,
952
- info: DiagLogLevel.INFO,
953
- debug: DiagLogLevel.DEBUG,
954
- verbose: DiagLogLevel.VERBOSE
955
- };
956
- const diagLogger = {
957
- error: (message, ...args) => logger.error({
958
- source: "otel",
959
- args
960
- }, message),
961
- warn: (message, ...args) => logger.warn({
962
- source: "otel",
963
- args
964
- }, message),
965
- info: (message, ...args) => logger.info({
966
- source: "otel",
967
- args
968
- }, message),
969
- debug: (message, ...args) => logger.debug({
970
- source: "otel",
971
- args
972
- }, message),
973
- verbose: (message, ...args) => logger.debug({
974
- source: "otel",
975
- args
976
- }, message)
977
- };
978
- diag.setLogger(diagLogger, diagLevels[diagLevelName] ?? DiagLogLevel.WARN);
974
+ let metricReader;
975
+ let metricsError;
976
+ if (features.metrics && features.tracing) try {
977
+ metricReader = createMetricReader({
978
+ endpoint: otel.endpoint,
979
+ intervalMs: otel.metricsIntervalMs
980
+ });
981
+ } catch (err) {
982
+ metricsError = err.message;
983
+ logger.error({ error: metricsError }, "Metrics setup failed - continuing without metrics");
979
984
  }
980
985
  let tracerInstance = null;
981
986
  let tracingError;
@@ -985,7 +990,8 @@ function createFoundation(input) {
985
990
  serviceVersion,
986
991
  environment,
987
992
  endpoint: otel.endpoint,
988
- autoInstrumentation: featuresConfig.autoInstrumentation
993
+ autoInstrumentation: featuresConfig.autoInstrumentation,
994
+ metricReader
989
995
  });
990
996
  tracerInstance = getTracer(serviceName);
991
997
  logger.info({
@@ -996,9 +1002,7 @@ function createFoundation(input) {
996
1002
  tracingError = err.message;
997
1003
  logger.error({ error: tracingError }, "Tracing setup failed - continuing without tracing");
998
1004
  }
999
- let meterInstance = null;
1000
- let metricsError;
1001
- if (features.metrics) try {
1005
+ if (features.metrics && !features.tracing && !metricsError) try {
1002
1006
  setupMetrics({
1003
1007
  serviceName,
1004
1008
  serviceVersion,
@@ -1006,14 +1010,18 @@ function createFoundation(input) {
1006
1010
  endpoint: otel.endpoint,
1007
1011
  intervalMs: otel.metricsIntervalMs
1008
1012
  });
1013
+ } catch (err) {
1014
+ metricsError = err.message;
1015
+ logger.error({ error: metricsError }, "Metrics setup failed - continuing without metrics");
1016
+ }
1017
+ else if (metricReader && tracingError && !metricsError) metricsError = `metrics SDK (tracing) failed to start: ${tracingError}`;
1018
+ let meterInstance = null;
1019
+ if (features.metrics && !metricsError) {
1009
1020
  meterInstance = getMeter(serviceName);
1010
1021
  logger.info({
1011
1022
  feature: "metrics",
1012
1023
  interval: `${otel.metricsIntervalMs}ms`
1013
1024
  }, "Metrics enabled");
1014
- } catch (err) {
1015
- metricsError = err.message;
1016
- logger.error({ error: metricsError }, "Metrics setup failed - continuing without metrics");
1017
1025
  }
1018
1026
  logger.info({
1019
1027
  serviceName,