@omen.foundation/node-microservice-runtime 0.1.51 → 0.1.53

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.
@@ -40,6 +40,8 @@ exports.fetchClickHouseCredentials = fetchClickHouseCredentials;
40
40
  exports.getClickHouseCredentialsStatus = getClickHouseCredentialsStatus;
41
41
  exports.isCollectorRunning = isCollectorRunning;
42
42
  exports.addAuthEnvironmentVars = addAuthEnvironmentVars;
43
+ exports.startCollectorAndWaitForReady = startCollectorAndWaitForReady;
44
+ exports.startCollectorAsync = startCollectorAsync;
43
45
  exports.setupCollectorBeforeLogging = setupCollectorBeforeLogging;
44
46
  exports.startCollector = startCollector;
45
47
  exports.getCollectorProcessStatus = getCollectorProcessStatus;
@@ -272,20 +274,24 @@ async function resolveCollector(allowDownload = true, logger) {
272
274
  else if ((0, fs_1.existsSync)(configPath)) {
273
275
  logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Config found at: ${configPath}`);
274
276
  }
275
- for (const item of itemsToDownload) {
276
- try {
277
- logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Downloading ${item.url}...`);
278
- await downloadAndDecompressGzip(item.url, item.path, item.executable);
279
- logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Downloaded to ${item.path}`);
280
- }
281
- catch (error) {
282
- const errorMsg = error instanceof Error ? error.message : String(error);
283
- logger === null || logger === void 0 ? void 0 : logger.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);
284
- if (error instanceof Error && errorMsg.includes(item.url)) {
285
- throw error;
277
+ if (itemsToDownload.length > 0) {
278
+ logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);
279
+ const downloadPromises = itemsToDownload.map(async (item) => {
280
+ try {
281
+ logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Downloading ${item.url}...`);
282
+ await downloadAndDecompressGzip(item.url, item.path, item.executable);
283
+ logger === null || logger === void 0 ? void 0 : logger.info(`[Collector] Downloaded to ${item.path}`);
286
284
  }
287
- throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);
288
- }
285
+ catch (error) {
286
+ const errorMsg = error instanceof Error ? error.message : String(error);
287
+ logger === null || logger === void 0 ? void 0 : logger.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);
288
+ if (error instanceof Error && errorMsg.includes(item.url)) {
289
+ throw error;
290
+ }
291
+ throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);
292
+ }
293
+ });
294
+ await Promise.all(downloadPromises);
289
295
  }
290
296
  return {
291
297
  binaryPath: (0, fs_1.existsSync)(binaryPath) ? binaryPath : null,
@@ -423,6 +429,69 @@ function addAuthEnvironmentVars(endpoint, username, password) {
423
429
  throw new Error(`Failed to set ClickHouse credentials in process.env - this should never happen in Node.js`);
424
430
  }
425
431
  }
432
+ async function startCollectorAndWaitForReady(env, timeoutMs = 180000) {
433
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
434
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
435
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
436
+ const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
437
+ if (!standardOtelEnabled && !hasExplicitEndpoint) {
438
+ return null;
439
+ }
440
+ const initLogger = (0, pino_1.default)({
441
+ name: 'beamable-otlp-init',
442
+ level: 'info',
443
+ }, process.stdout);
444
+ initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');
445
+ const startTime = Date.now();
446
+ let endpoint = null;
447
+ let completed = false;
448
+ const setupPromise = discoverOrStartCollector(initLogger, standardOtelEnabled, env);
449
+ const timeoutPromise = new Promise((resolve) => {
450
+ setTimeout(() => {
451
+ if (!completed) {
452
+ initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without Portal logs`);
453
+ completed = true;
454
+ resolve(null);
455
+ }
456
+ }, timeoutMs);
457
+ });
458
+ const result = await Promise.race([setupPromise, timeoutPromise]);
459
+ if (result && !completed) {
460
+ endpoint = result;
461
+ completed = true;
462
+ const elapsed = Date.now() - startTime;
463
+ initLogger.info(`[OTLP] Collector ready at ${endpoint} (took ${elapsed}ms). Portal logs now enabled.`);
464
+ return endpoint;
465
+ }
466
+ return null;
467
+ }
468
+ function startCollectorAsync(env) {
469
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
470
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
471
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
472
+ const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
473
+ if (!standardOtelEnabled && !hasExplicitEndpoint) {
474
+ return;
475
+ }
476
+ const initLogger = (0, pino_1.default)({
477
+ name: 'beamable-otlp-init',
478
+ level: 'info',
479
+ }, process.stdout);
480
+ initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');
481
+ discoverOrStartCollector(initLogger, standardOtelEnabled, env)
482
+ .then((result) => {
483
+ if (result) {
484
+ initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);
485
+ }
486
+ else {
487
+ initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');
488
+ }
489
+ })
490
+ .catch((error) => {
491
+ const errorMsg = error instanceof Error ? error.message : String(error);
492
+ initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);
493
+ });
494
+ }
426
495
  function setupCollectorBeforeLogging(env, timeoutMs = 60000) {
427
496
  const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
428
497
  const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
@@ -41,10 +41,23 @@ export declare function isCollectorRunning(): Promise<CollectorStatus>;
41
41
  */
42
42
  export declare function addAuthEnvironmentVars(endpoint: string, username: string, password: string): void;
43
43
  /**
44
- * Sets up the collector BEFORE logging is initialized.
45
- * This ensures all startup logs are captured via OTLP.
46
- * Uses a minimal console logger for setup messages.
47
- * Returns the OTLP endpoint if successful, null otherwise.
44
+ * Starts the collector and waits for it to be ready before returning.
45
+ * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.
46
+ * Returns the OTLP endpoint when ready, or null if it times out or fails.
47
+ */
48
+ export declare function startCollectorAndWaitForReady(env: EnvironmentConfig, timeoutMs?: number): Promise<string | null>;
49
+ /**
50
+ * Starts the collector asynchronously in the background (non-blocking).
51
+ * This allows the service to start immediately while collector downloads/starts.
52
+ * Returns immediately - collector setup happens in background.
53
+ * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready
54
+ */
55
+ export declare function startCollectorAsync(env: EnvironmentConfig): void;
56
+ /**
57
+ * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).
58
+ * This function is kept for backwards compatibility but is no longer recommended.
59
+ * Use startCollectorAsync() for non-blocking startup instead.
60
+ * @deprecated Use startCollectorAsync() for non-blocking startup
48
61
  */
49
62
  export declare function setupCollectorBeforeLogging(env: EnvironmentConfig, timeoutMs?: number): string | null;
50
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAwChC;AA0OD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAyEnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmJxB"}
1
+ {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAwChC;AAiPD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAyEnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAe,GACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmDxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAsChE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmJxB"}
@@ -270,22 +270,28 @@ async function resolveCollector(allowDownload = true, logger) {
270
270
  else if (existsSync(configPath)) {
271
271
  logger?.info(`[Collector] Config found at: ${configPath}`);
272
272
  }
273
- for (const item of itemsToDownload) {
274
- try {
275
- logger?.info(`[Collector] Downloading ${item.url}...`);
276
- await downloadAndDecompressGzip(item.url, item.path, item.executable);
277
- logger?.info(`[Collector] Downloaded to ${item.path}`);
278
- }
279
- catch (error) {
280
- // Don't wrap the error again if it already contains the URL and details
281
- const errorMsg = error instanceof Error ? error.message : String(error);
282
- logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);
283
- // Only wrap if the error doesn't already contain the URL
284
- if (error instanceof Error && errorMsg.includes(item.url)) {
285
- throw error; // Error already has URL and context
273
+ // Download items in parallel for faster startup (binary and config simultaneously)
274
+ if (itemsToDownload.length > 0) {
275
+ logger?.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);
276
+ const downloadPromises = itemsToDownload.map(async (item) => {
277
+ try {
278
+ logger?.info(`[Collector] Downloading ${item.url}...`);
279
+ await downloadAndDecompressGzip(item.url, item.path, item.executable);
280
+ logger?.info(`[Collector] Downloaded to ${item.path}`);
286
281
  }
287
- throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);
288
- }
282
+ catch (error) {
283
+ // Don't wrap the error again if it already contains the URL and details
284
+ const errorMsg = error instanceof Error ? error.message : String(error);
285
+ logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);
286
+ // Only wrap if the error doesn't already contain the URL
287
+ if (error instanceof Error && errorMsg.includes(item.url)) {
288
+ throw error; // Error already has URL and context
289
+ }
290
+ throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);
291
+ }
292
+ });
293
+ // Wait for all downloads to complete (or fail)
294
+ await Promise.all(downloadPromises);
289
295
  }
290
296
  return {
291
297
  binaryPath: existsSync(binaryPath) ? binaryPath : null,
@@ -462,10 +468,100 @@ export function addAuthEnvironmentVars(endpoint, username, password) {
462
468
  }
463
469
  }
464
470
  /**
465
- * Sets up the collector BEFORE logging is initialized.
466
- * This ensures all startup logs are captured via OTLP.
467
- * Uses a minimal console logger for setup messages.
468
- * Returns the OTLP endpoint if successful, null otherwise.
471
+ * Starts the collector and waits for it to be ready before returning.
472
+ * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.
473
+ * Returns the OTLP endpoint when ready, or null if it times out or fails.
474
+ */
475
+ export async function startCollectorAndWaitForReady(env, timeoutMs = 180000 // 3 minutes to allow for download + startup
476
+ ) {
477
+ // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL
478
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
479
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
480
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
481
+ const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
482
+ // If OTLP is not needed, return immediately
483
+ if (!standardOtelEnabled && !hasExplicitEndpoint) {
484
+ return null;
485
+ }
486
+ // Create a minimal console logger for initialization messages (no OTLP yet)
487
+ const initLogger = pino({
488
+ name: 'beamable-otlp-init',
489
+ level: 'info',
490
+ }, process.stdout);
491
+ initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');
492
+ // Wait for collector to be ready with timeout
493
+ const startTime = Date.now();
494
+ let endpoint = null;
495
+ let completed = false;
496
+ // Start collector setup
497
+ const setupPromise = discoverOrStartCollector(initLogger, standardOtelEnabled, env);
498
+ // Set timeout
499
+ const timeoutPromise = new Promise((resolve) => {
500
+ setTimeout(() => {
501
+ if (!completed) {
502
+ initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without Portal logs`);
503
+ completed = true;
504
+ resolve(null);
505
+ }
506
+ }, timeoutMs);
507
+ });
508
+ // Race between setup and timeout
509
+ const result = await Promise.race([setupPromise, timeoutPromise]);
510
+ if (result && !completed) {
511
+ endpoint = result;
512
+ completed = true;
513
+ const elapsed = Date.now() - startTime;
514
+ initLogger.info(`[OTLP] Collector ready at ${endpoint} (took ${elapsed}ms). Portal logs now enabled.`);
515
+ return endpoint;
516
+ }
517
+ return null;
518
+ }
519
+ /**
520
+ * Starts the collector asynchronously in the background (non-blocking).
521
+ * This allows the service to start immediately while collector downloads/starts.
522
+ * Returns immediately - collector setup happens in background.
523
+ * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready
524
+ */
525
+ export function startCollectorAsync(env) {
526
+ // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL
527
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
528
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
529
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
530
+ const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
531
+ // If OTLP is not needed, return immediately
532
+ if (!standardOtelEnabled && !hasExplicitEndpoint) {
533
+ return;
534
+ }
535
+ // Create a minimal console logger for initialization messages (no OTLP yet)
536
+ const initLogger = pino({
537
+ name: 'beamable-otlp-init',
538
+ level: 'info',
539
+ }, process.stdout);
540
+ initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');
541
+ // Start collector setup asynchronously - don't wait for it
542
+ // The service can start immediately, collector will connect when ready
543
+ discoverOrStartCollector(initLogger, standardOtelEnabled, env)
544
+ .then((result) => {
545
+ if (result) {
546
+ initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);
547
+ // Update the global logger provider if it exists to enable OTLP
548
+ // The logger will automatically start using OTLP once the provider is set
549
+ }
550
+ else {
551
+ initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');
552
+ }
553
+ })
554
+ .catch((error) => {
555
+ const errorMsg = error instanceof Error ? error.message : String(error);
556
+ initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);
557
+ });
558
+ // Return immediately - service can start serving requests
559
+ }
560
+ /**
561
+ * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).
562
+ * This function is kept for backwards compatibility but is no longer recommended.
563
+ * Use startCollectorAsync() for non-blocking startup instead.
564
+ * @deprecated Use startCollectorAsync() for non-blocking startup
469
565
  */
470
566
  export function setupCollectorBeforeLogging(env, timeoutMs = 60000) {
471
567
  // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL