@atrim/instrument-node 0.4.1 → 0.5.0-c05e3a1-20251119131235

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.
@@ -1,4 +1,4 @@
1
- import { Data, Context, Effect, Layer } from 'effect';
1
+ import { Data, Context, Effect, Layer, Deferred } from 'effect';
2
2
  import { NodeSDK } from '@opentelemetry/sdk-node';
3
3
  import { SimpleSpanProcessor, BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
4
4
  import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
@@ -59,7 +59,20 @@ var HttpFilteringConfigSchema = z.object({
59
59
  // Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
60
60
  ignore_incoming_paths: z.array(z.string()).optional(),
61
61
  // Require parent span for outgoing requests (prevents root spans for HTTP calls)
62
- require_parent_for_outgoing_spans: z.boolean().optional()
62
+ require_parent_for_outgoing_spans: z.boolean().optional(),
63
+ // Trace context propagation configuration
64
+ // Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
65
+ propagate_trace_context: z.object({
66
+ // Strategy for trace propagation
67
+ // - "all": Propagate to all cross-origin requests (may cause CORS errors)
68
+ // - "none": Never propagate trace headers
69
+ // - "same-origin": Only propagate to same-origin requests (default, safe)
70
+ // - "patterns": Propagate based on include_urls patterns
71
+ strategy: z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
72
+ // URL patterns to include when strategy is "patterns"
73
+ // Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
74
+ include_urls: z.array(z.string()).optional()
75
+ }).optional()
63
76
  });
64
77
  var InstrumentationConfigSchema = z.object({
65
78
  version: z.string(),
@@ -670,15 +683,6 @@ var getServiceInfoWithFallback = detectServiceInfo.pipe(
670
683
  })
671
684
  )
672
685
  );
673
- async function detectServiceInfoAsync() {
674
- return Effect.runPromise(getServiceInfoWithFallback);
675
- }
676
- async function getServiceNameAsync() {
677
- return Effect.runPromise(getServiceName);
678
- }
679
- async function getServiceVersionAsync() {
680
- return Effect.runPromise(getServiceVersion);
681
- }
682
686
  var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
683
687
  Layer.provide(Layer.mergeAll(NodeContext.layer, FetchHttpClient.layer))
684
688
  );
@@ -760,7 +764,7 @@ async function loadConfigWithOptions(options = {}) {
760
764
 
761
765
  // src/core/sdk-initializer.ts
762
766
  var sdkInstance = null;
763
- var initializationPromise = null;
767
+ var initializationDeferred = null;
764
768
  function buildHttpInstrumentationConfig(options, config, _otlpEndpoint) {
765
769
  const httpConfig = { enabled: true };
766
770
  const programmaticPatterns = options.http?.ignoreOutgoingUrls || [];
@@ -876,27 +880,38 @@ function isTracingAlreadyInitialized() {
876
880
  return false;
877
881
  }
878
882
  }
879
- async function initializeSdk(options = {}) {
883
+ var initializeSdkEffect = (options = {}) => Effect.gen(function* () {
880
884
  if (sdkInstance) {
881
885
  logger.warn("@atrim/instrumentation: SDK already initialized. Returning existing instance.");
882
886
  return sdkInstance;
883
887
  }
884
- if (initializationPromise) {
888
+ if (initializationDeferred) {
885
889
  logger.log(
886
- "@atrim/instrumentation: SDK already initialized, waiting for initialization to complete..."
890
+ "@atrim/instrumentation: SDK initialization in progress, waiting for completion..."
887
891
  );
888
- return initializationPromise;
889
- }
890
- initializationPromise = performInitialization(options);
891
- try {
892
- const result = await initializationPromise;
893
- return result;
894
- } finally {
895
- initializationPromise = null;
896
- }
897
- }
898
- async function performInitialization(options) {
899
- const config = await loadConfigWithOptions(options);
892
+ return yield* Deferred.await(initializationDeferred);
893
+ }
894
+ const deferred = yield* Deferred.make();
895
+ initializationDeferred = deferred;
896
+ const result = yield* performInitializationEffect(options).pipe(
897
+ Effect.tap((sdk) => Deferred.succeed(deferred, sdk)),
898
+ Effect.tapError((error) => Deferred.fail(deferred, error)),
899
+ Effect.ensuring(
900
+ Effect.sync(() => {
901
+ initializationDeferred = null;
902
+ })
903
+ )
904
+ );
905
+ return result;
906
+ });
907
+ var performInitializationEffect = (options) => Effect.gen(function* () {
908
+ const config = yield* Effect.tryPromise({
909
+ try: () => loadConfigWithOptions(options),
910
+ catch: (error) => new InitializationError2({
911
+ reason: "Failed to load configuration",
912
+ cause: error
913
+ })
914
+ });
900
915
  const loggingLevel = config.instrumentation.logging || "on";
901
916
  logger.setLevel(loggingLevel);
902
917
  const alreadyInitialized = isTracingAlreadyInitialized();
@@ -912,14 +927,25 @@ async function performInitialization(options) {
912
927
  logger.log("");
913
928
  return null;
914
929
  }
915
- const serviceInfo = await detectServiceInfoAsync();
930
+ const serviceInfo = yield* detectServiceInfo.pipe(
931
+ Effect.catchAll(
932
+ () => Effect.succeed({
933
+ name: "unknown-service",
934
+ version: void 0
935
+ })
936
+ )
937
+ );
916
938
  const serviceName = options.serviceName || serviceInfo.name;
917
939
  const serviceVersion = options.serviceVersion || serviceInfo.version;
918
- const rawExporter = createOtlpExporter(options.otlp);
919
- const exporter = new SafeSpanExporter(rawExporter);
940
+ const rawExporter = yield* Effect.sync(() => createOtlpExporter(options.otlp));
941
+ const exporter = yield* Effect.sync(() => new SafeSpanExporter(rawExporter));
920
942
  const useSimpleProcessor = process.env.NODE_ENV === "test" || process.env.OTEL_USE_SIMPLE_PROCESSOR === "true";
921
- const baseProcessor = useSimpleProcessor ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter);
922
- const patternProcessor = new PatternSpanProcessor(config, baseProcessor);
943
+ const baseProcessor = yield* Effect.sync(
944
+ () => useSimpleProcessor ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter)
945
+ );
946
+ const patternProcessor = yield* Effect.sync(
947
+ () => new PatternSpanProcessor(config, baseProcessor)
948
+ );
923
949
  const instrumentations = [];
924
950
  const hasWebFramework = hasWebFrameworkInstalled();
925
951
  const enableAutoInstrumentation = shouldEnableAutoInstrumentation(
@@ -932,15 +958,11 @@ async function performInitialization(options) {
932
958
  const undiciConfig = buildUndiciInstrumentationConfig(options, config);
933
959
  instrumentations.push(
934
960
  ...getNodeAutoInstrumentations({
935
- // Enable HTTP instrumentation with filtering (for http/https modules)
936
961
  "@opentelemetry/instrumentation-http": httpConfig,
937
- // Enable undici instrumentation with filtering (for fetch API)
938
962
  "@opentelemetry/instrumentation-undici": undiciConfig,
939
- // Enable web framework instrumentations
940
963
  "@opentelemetry/instrumentation-express": { enabled: true },
941
964
  "@opentelemetry/instrumentation-fastify": { enabled: true },
942
965
  "@opentelemetry/instrumentation-koa": { enabled: true },
943
- // Disable noisy instrumentations by default
944
966
  "@opentelemetry/instrumentation-fs": { enabled: false },
945
967
  "@opentelemetry/instrumentation-dns": { enabled: false }
946
968
  })
@@ -968,18 +990,20 @@ async function performInitialization(options) {
968
990
  serviceName,
969
991
  ...serviceVersion && { serviceVersion },
970
992
  instrumentations,
971
- // Allow advanced overrides
972
993
  ...options.sdk
973
994
  };
974
- const sdk = new NodeSDK(sdkConfig);
975
- sdk.start();
995
+ const sdk = yield* Effect.sync(() => {
996
+ const s = new NodeSDK(sdkConfig);
997
+ s.start();
998
+ return s;
999
+ });
976
1000
  sdkInstance = sdk;
977
1001
  if (!options.disableAutoShutdown) {
978
- registerShutdownHandlers(sdk);
1002
+ yield* Effect.sync(() => registerShutdownHandlers(sdk));
979
1003
  }
980
1004
  logInitialization(config, serviceName, serviceVersion, options, enableAutoInstrumentation);
981
1005
  return sdk;
982
- }
1006
+ });
983
1007
  function getSdkInstance() {
984
1008
  return sdkInstance;
985
1009
  }
@@ -992,7 +1016,7 @@ async function shutdownSdk() {
992
1016
  }
993
1017
  function resetSdk() {
994
1018
  sdkInstance = null;
995
- initializationPromise = null;
1019
+ initializationDeferred = null;
996
1020
  }
997
1021
  function registerShutdownHandlers(sdk) {
998
1022
  const shutdown = async (signal) => {
@@ -1049,30 +1073,8 @@ function logInitialization(config, serviceName, serviceVersion, options, autoIns
1049
1073
  }
1050
1074
 
1051
1075
  // src/api.ts
1052
- async function initializeInstrumentation(options = {}) {
1053
- const sdk = await initializeSdk(options);
1054
- if (sdk) {
1055
- const config = await loadConfigWithOptions(options);
1056
- initializePatternMatcher(config);
1057
- }
1058
- return sdk;
1059
- }
1060
- async function initializePatternMatchingOnly(options = {}) {
1061
- const config = await loadConfigWithOptions(options);
1062
- initializePatternMatcher(config);
1063
- logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1064
- logger.log(
1065
- " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1066
- );
1067
- }
1068
- var initializeInstrumentationEffect = (options = {}) => Effect.gen(function* () {
1069
- const sdk = yield* Effect.tryPromise({
1070
- try: () => initializeSdk(options),
1071
- catch: (error) => new InitializationError2({
1072
- reason: "SDK initialization failed",
1073
- cause: error
1074
- })
1075
- });
1076
+ var initializeInstrumentation = (options = {}) => Effect.gen(function* () {
1077
+ const sdk = yield* initializeSdkEffect(options);
1076
1078
  if (sdk) {
1077
1079
  yield* Effect.tryPromise({
1078
1080
  try: () => loadConfigWithOptions(options),
@@ -1090,7 +1092,7 @@ var initializeInstrumentationEffect = (options = {}) => Effect.gen(function* ()
1090
1092
  }
1091
1093
  return sdk;
1092
1094
  });
1093
- var initializePatternMatchingOnlyEffect = (options = {}) => Effect.gen(function* () {
1095
+ var initializePatternMatchingOnly = (options = {}) => Effect.gen(function* () {
1094
1096
  const config = yield* Effect.tryPromise({
1095
1097
  try: () => loadConfigWithOptions(options),
1096
1098
  catch: (error) => new ConfigError2({
@@ -1100,7 +1102,7 @@ var initializePatternMatchingOnlyEffect = (options = {}) => Effect.gen(function*
1100
1102
  });
1101
1103
  yield* Effect.sync(() => {
1102
1104
  initializePatternMatcher(config);
1103
- logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1105
+ logger.log("@atrim/instrumentation: Pattern matching initialized (pattern-only mode)");
1104
1106
  logger.log(
1105
1107
  " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1106
1108
  );
@@ -1201,6 +1203,6 @@ function suppressShutdownErrors() {
1201
1203
  });
1202
1204
  }
1203
1205
 
1204
- export { ConfigError2 as ConfigError, ConfigFileError2 as ConfigFileError, ConfigUrlError2 as ConfigUrlError, ConfigValidationError2 as ConfigValidationError, ExportError2 as ExportError, InitializationError2 as InitializationError, PatternMatcher, PatternSpanProcessor, ServiceDetectionError2 as ServiceDetectionError, ShutdownError2 as ShutdownError, annotateCacheOperation, annotateDbQuery, annotateHttpRequest, _resetConfigLoaderCache as clearConfigCache, createOtlpExporter, detectServiceInfoAsync as detectServiceInfo, detectServiceInfo as detectServiceInfoEffect, getOtlpEndpoint, getPatternMatcher, getSdkInstance, getServiceInfoWithFallback, getServiceNameAsync as getServiceName, getServiceName as getServiceNameEffect, getServiceVersionAsync as getServiceVersion, getServiceVersion as getServiceVersionEffect, initializeInstrumentation, initializeInstrumentationEffect, initializePatternMatchingOnly, initializePatternMatchingOnlyEffect, loadConfig, loadConfigFromInline, loadConfigWithOptions, markSpanError, markSpanSuccess, recordException, resetSdk, setSpanAttributes, shouldInstrumentSpan, shutdownSdk, suppressShutdownErrors };
1206
+ export { ConfigError2 as ConfigError, ConfigFileError2 as ConfigFileError, ConfigUrlError2 as ConfigUrlError, ConfigValidationError2 as ConfigValidationError, ExportError2 as ExportError, InitializationError2 as InitializationError, PatternMatcher, PatternSpanProcessor, ServiceDetectionError2 as ServiceDetectionError, ShutdownError2 as ShutdownError, annotateCacheOperation, annotateDbQuery, annotateHttpRequest, _resetConfigLoaderCache as clearConfigCache, createOtlpExporter, detectServiceInfo, getOtlpEndpoint, getPatternMatcher, getSdkInstance, getServiceInfoWithFallback, getServiceName, getServiceVersion, initializeInstrumentation, initializePatternMatchingOnly, loadConfig, loadConfigFromInline, loadConfigWithOptions, markSpanError, markSpanSuccess, recordException, resetSdk, setSpanAttributes, shouldInstrumentSpan, shutdownSdk, suppressShutdownErrors };
1205
1207
  //# sourceMappingURL=index.js.map
1206
1208
  //# sourceMappingURL=index.js.map