@atrim/instrument-node 0.5.0-c05e3a1-20251119131235 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atrim/instrument-node",
3
- "version": "0.5.0-c05e3a1-20251119131235",
3
+ "version": "0.5.0",
4
4
  "description": "OpenTelemetry instrumentation for Node.js with centralized YAML configuration",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -122,10 +122,10 @@
122
122
  "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
123
123
  "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
124
124
  "clean": "rm -rf target",
125
- "publish:dev:version": "pnpm version $(node -p \"require('./package.json').version\")-$(git rev-parse --short HEAD)-$(date -u +%Y%m%d%H%M%S) --no-git-tag-version",
125
+ "publish:dev:version": "npm version $(git describe --tags --abbrev=0 | sed 's/^.*@//' | sed 's/^v//')-$(git rev-parse --short HEAD)-$(date -u +%Y%m%d%H%M%S) --no-git-tag-version",
126
126
  "publish:dev:save": "node -p \"require('./package.json').version\" > .version",
127
127
  "publish:dev:publish": "pnpm build && pnpm publish --tag dev --access public --no-git-checks",
128
- "publish:dev:reset": "pnpm version 0.5.0 --no-git-tag-version",
128
+ "publish:dev:reset": "npm version 1.0.0 --no-git-tag-version",
129
129
  "publish:dev": "pnpm publish:dev:version && pnpm publish:dev:save && pnpm publish:dev:publish && pnpm publish:dev:reset"
130
130
  }
131
131
  }
@@ -82,20 +82,7 @@ var HttpFilteringConfigSchema = zod.z.object({
82
82
  // Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
83
83
  ignore_incoming_paths: zod.z.array(zod.z.string()).optional(),
84
84
  // Require parent span for outgoing requests (prevents root spans for HTTP calls)
85
- require_parent_for_outgoing_spans: zod.z.boolean().optional(),
86
- // Trace context propagation configuration
87
- // Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
88
- propagate_trace_context: zod.z.object({
89
- // Strategy for trace propagation
90
- // - "all": Propagate to all cross-origin requests (may cause CORS errors)
91
- // - "none": Never propagate trace headers
92
- // - "same-origin": Only propagate to same-origin requests (default, safe)
93
- // - "patterns": Propagate based on include_urls patterns
94
- strategy: zod.z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
95
- // URL patterns to include when strategy is "patterns"
96
- // Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
97
- include_urls: zod.z.array(zod.z.string()).optional()
98
- }).optional()
85
+ require_parent_for_outgoing_spans: zod.z.boolean().optional()
99
86
  });
100
87
  var InstrumentationConfigSchema = zod.z.object({
101
88
  version: zod.z.string(),
@@ -706,6 +693,15 @@ var getServiceInfoWithFallback = detectServiceInfo.pipe(
706
693
  })
707
694
  )
708
695
  );
696
+ async function detectServiceInfoAsync() {
697
+ return effect.Effect.runPromise(getServiceInfoWithFallback);
698
+ }
699
+ async function getServiceNameAsync() {
700
+ return effect.Effect.runPromise(getServiceName);
701
+ }
702
+ async function getServiceVersionAsync() {
703
+ return effect.Effect.runPromise(getServiceVersion);
704
+ }
709
705
  var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
710
706
  effect.Layer.provide(effect.Layer.mergeAll(platformNode.NodeContext.layer, platform.FetchHttpClient.layer))
711
707
  );
@@ -787,7 +783,7 @@ async function loadConfigWithOptions(options = {}) {
787
783
 
788
784
  // src/core/sdk-initializer.ts
789
785
  var sdkInstance = null;
790
- var initializationDeferred = null;
786
+ var initializationPromise = null;
791
787
  function buildHttpInstrumentationConfig(options, config, _otlpEndpoint) {
792
788
  const httpConfig = { enabled: true };
793
789
  const programmaticPatterns = options.http?.ignoreOutgoingUrls || [];
@@ -903,38 +899,27 @@ function isTracingAlreadyInitialized() {
903
899
  return false;
904
900
  }
905
901
  }
906
- var initializeSdkEffect = (options = {}) => effect.Effect.gen(function* () {
902
+ async function initializeSdk(options = {}) {
907
903
  if (sdkInstance) {
908
904
  logger.warn("@atrim/instrumentation: SDK already initialized. Returning existing instance.");
909
905
  return sdkInstance;
910
906
  }
911
- if (initializationDeferred) {
907
+ if (initializationPromise) {
912
908
  logger.log(
913
- "@atrim/instrumentation: SDK initialization in progress, waiting for completion..."
909
+ "@atrim/instrumentation: SDK already initialized, waiting for initialization to complete..."
914
910
  );
915
- return yield* effect.Deferred.await(initializationDeferred);
916
- }
917
- const deferred = yield* effect.Deferred.make();
918
- initializationDeferred = deferred;
919
- const result = yield* performInitializationEffect(options).pipe(
920
- effect.Effect.tap((sdk) => effect.Deferred.succeed(deferred, sdk)),
921
- effect.Effect.tapError((error) => effect.Deferred.fail(deferred, error)),
922
- effect.Effect.ensuring(
923
- effect.Effect.sync(() => {
924
- initializationDeferred = null;
925
- })
926
- )
927
- );
928
- return result;
929
- });
930
- var performInitializationEffect = (options) => effect.Effect.gen(function* () {
931
- const config = yield* effect.Effect.tryPromise({
932
- try: () => loadConfigWithOptions(options),
933
- catch: (error) => new InitializationError2({
934
- reason: "Failed to load configuration",
935
- cause: error
936
- })
937
- });
911
+ return initializationPromise;
912
+ }
913
+ initializationPromise = performInitialization(options);
914
+ try {
915
+ const result = await initializationPromise;
916
+ return result;
917
+ } finally {
918
+ initializationPromise = null;
919
+ }
920
+ }
921
+ async function performInitialization(options) {
922
+ const config = await loadConfigWithOptions(options);
938
923
  const loggingLevel = config.instrumentation.logging || "on";
939
924
  logger.setLevel(loggingLevel);
940
925
  const alreadyInitialized = isTracingAlreadyInitialized();
@@ -950,25 +935,14 @@ var performInitializationEffect = (options) => effect.Effect.gen(function* () {
950
935
  logger.log("");
951
936
  return null;
952
937
  }
953
- const serviceInfo = yield* detectServiceInfo.pipe(
954
- effect.Effect.catchAll(
955
- () => effect.Effect.succeed({
956
- name: "unknown-service",
957
- version: void 0
958
- })
959
- )
960
- );
938
+ const serviceInfo = await detectServiceInfoAsync();
961
939
  const serviceName = options.serviceName || serviceInfo.name;
962
940
  const serviceVersion = options.serviceVersion || serviceInfo.version;
963
- const rawExporter = yield* effect.Effect.sync(() => createOtlpExporter(options.otlp));
964
- const exporter = yield* effect.Effect.sync(() => new SafeSpanExporter(rawExporter));
941
+ const rawExporter = createOtlpExporter(options.otlp);
942
+ const exporter = new SafeSpanExporter(rawExporter);
965
943
  const useSimpleProcessor = process.env.NODE_ENV === "test" || process.env.OTEL_USE_SIMPLE_PROCESSOR === "true";
966
- const baseProcessor = yield* effect.Effect.sync(
967
- () => useSimpleProcessor ? new sdkTraceBase.SimpleSpanProcessor(exporter) : new sdkTraceBase.BatchSpanProcessor(exporter)
968
- );
969
- const patternProcessor = yield* effect.Effect.sync(
970
- () => new PatternSpanProcessor(config, baseProcessor)
971
- );
944
+ const baseProcessor = useSimpleProcessor ? new sdkTraceBase.SimpleSpanProcessor(exporter) : new sdkTraceBase.BatchSpanProcessor(exporter);
945
+ const patternProcessor = new PatternSpanProcessor(config, baseProcessor);
972
946
  const instrumentations = [];
973
947
  const hasWebFramework = hasWebFrameworkInstalled();
974
948
  const enableAutoInstrumentation = shouldEnableAutoInstrumentation(
@@ -981,11 +955,15 @@ var performInitializationEffect = (options) => effect.Effect.gen(function* () {
981
955
  const undiciConfig = buildUndiciInstrumentationConfig(options, config);
982
956
  instrumentations.push(
983
957
  ...autoInstrumentationsNode.getNodeAutoInstrumentations({
958
+ // Enable HTTP instrumentation with filtering (for http/https modules)
984
959
  "@opentelemetry/instrumentation-http": httpConfig,
960
+ // Enable undici instrumentation with filtering (for fetch API)
985
961
  "@opentelemetry/instrumentation-undici": undiciConfig,
962
+ // Enable web framework instrumentations
986
963
  "@opentelemetry/instrumentation-express": { enabled: true },
987
964
  "@opentelemetry/instrumentation-fastify": { enabled: true },
988
965
  "@opentelemetry/instrumentation-koa": { enabled: true },
966
+ // Disable noisy instrumentations by default
989
967
  "@opentelemetry/instrumentation-fs": { enabled: false },
990
968
  "@opentelemetry/instrumentation-dns": { enabled: false }
991
969
  })
@@ -1013,20 +991,18 @@ var performInitializationEffect = (options) => effect.Effect.gen(function* () {
1013
991
  serviceName,
1014
992
  ...serviceVersion && { serviceVersion },
1015
993
  instrumentations,
994
+ // Allow advanced overrides
1016
995
  ...options.sdk
1017
996
  };
1018
- const sdk = yield* effect.Effect.sync(() => {
1019
- const s = new sdkNode.NodeSDK(sdkConfig);
1020
- s.start();
1021
- return s;
1022
- });
997
+ const sdk = new sdkNode.NodeSDK(sdkConfig);
998
+ sdk.start();
1023
999
  sdkInstance = sdk;
1024
1000
  if (!options.disableAutoShutdown) {
1025
- yield* effect.Effect.sync(() => registerShutdownHandlers(sdk));
1001
+ registerShutdownHandlers(sdk);
1026
1002
  }
1027
1003
  logInitialization(config, serviceName, serviceVersion, options, enableAutoInstrumentation);
1028
1004
  return sdk;
1029
- });
1005
+ }
1030
1006
  function getSdkInstance() {
1031
1007
  return sdkInstance;
1032
1008
  }
@@ -1039,7 +1015,7 @@ async function shutdownSdk() {
1039
1015
  }
1040
1016
  function resetSdk() {
1041
1017
  sdkInstance = null;
1042
- initializationDeferred = null;
1018
+ initializationPromise = null;
1043
1019
  }
1044
1020
  function registerShutdownHandlers(sdk) {
1045
1021
  const shutdown = async (signal) => {
@@ -1096,8 +1072,30 @@ function logInitialization(config, serviceName, serviceVersion, options, autoIns
1096
1072
  }
1097
1073
 
1098
1074
  // src/api.ts
1099
- var initializeInstrumentation = (options = {}) => effect.Effect.gen(function* () {
1100
- const sdk = yield* initializeSdkEffect(options);
1075
+ async function initializeInstrumentation(options = {}) {
1076
+ const sdk = await initializeSdk(options);
1077
+ if (sdk) {
1078
+ const config = await loadConfigWithOptions(options);
1079
+ initializePatternMatcher(config);
1080
+ }
1081
+ return sdk;
1082
+ }
1083
+ async function initializePatternMatchingOnly(options = {}) {
1084
+ const config = await loadConfigWithOptions(options);
1085
+ initializePatternMatcher(config);
1086
+ logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1087
+ logger.log(
1088
+ " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1089
+ );
1090
+ }
1091
+ var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(function* () {
1092
+ const sdk = yield* effect.Effect.tryPromise({
1093
+ try: () => initializeSdk(options),
1094
+ catch: (error) => new InitializationError2({
1095
+ reason: "SDK initialization failed",
1096
+ cause: error
1097
+ })
1098
+ });
1101
1099
  if (sdk) {
1102
1100
  yield* effect.Effect.tryPromise({
1103
1101
  try: () => loadConfigWithOptions(options),
@@ -1115,7 +1113,7 @@ var initializeInstrumentation = (options = {}) => effect.Effect.gen(function* ()
1115
1113
  }
1116
1114
  return sdk;
1117
1115
  });
1118
- var initializePatternMatchingOnly = (options = {}) => effect.Effect.gen(function* () {
1116
+ var initializePatternMatchingOnlyEffect = (options = {}) => effect.Effect.gen(function* () {
1119
1117
  const config = yield* effect.Effect.tryPromise({
1120
1118
  try: () => loadConfigWithOptions(options),
1121
1119
  catch: (error) => new ConfigError2({
@@ -1125,7 +1123,7 @@ var initializePatternMatchingOnly = (options = {}) => effect.Effect.gen(function
1125
1123
  });
1126
1124
  yield* effect.Effect.sync(() => {
1127
1125
  initializePatternMatcher(config);
1128
- logger.log("@atrim/instrumentation: Pattern matching initialized (pattern-only mode)");
1126
+ logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1129
1127
  logger.log(
1130
1128
  " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1131
1129
  );
@@ -1241,15 +1239,20 @@ exports.annotateDbQuery = annotateDbQuery;
1241
1239
  exports.annotateHttpRequest = annotateHttpRequest;
1242
1240
  exports.clearConfigCache = _resetConfigLoaderCache;
1243
1241
  exports.createOtlpExporter = createOtlpExporter;
1244
- exports.detectServiceInfo = detectServiceInfo;
1242
+ exports.detectServiceInfo = detectServiceInfoAsync;
1243
+ exports.detectServiceInfoEffect = detectServiceInfo;
1245
1244
  exports.getOtlpEndpoint = getOtlpEndpoint;
1246
1245
  exports.getPatternMatcher = getPatternMatcher;
1247
1246
  exports.getSdkInstance = getSdkInstance;
1248
1247
  exports.getServiceInfoWithFallback = getServiceInfoWithFallback;
1249
- exports.getServiceName = getServiceName;
1250
- exports.getServiceVersion = getServiceVersion;
1248
+ exports.getServiceName = getServiceNameAsync;
1249
+ exports.getServiceNameEffect = getServiceName;
1250
+ exports.getServiceVersion = getServiceVersionAsync;
1251
+ exports.getServiceVersionEffect = getServiceVersion;
1251
1252
  exports.initializeInstrumentation = initializeInstrumentation;
1253
+ exports.initializeInstrumentationEffect = initializeInstrumentationEffect;
1252
1254
  exports.initializePatternMatchingOnly = initializePatternMatchingOnly;
1255
+ exports.initializePatternMatchingOnlyEffect = initializePatternMatchingOnlyEffect;
1253
1256
  exports.loadConfig = loadConfig;
1254
1257
  exports.loadConfigFromInline = loadConfigFromInline;
1255
1258
  exports.loadConfigWithOptions = loadConfigWithOptions;