@omen.foundation/node-microservice-runtime 0.1.60 → 0.1.61
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.
|
@@ -146,6 +146,11 @@ async function fetchClickHouseCredentials(env) {
|
|
|
146
146
|
return credentials;
|
|
147
147
|
}
|
|
148
148
|
function getCollectorStoragePath() {
|
|
149
|
+
const productionPath = '/opt/beam/collectors';
|
|
150
|
+
const productionVersionPath = (0, path_1.join)(productionPath, COLLECTOR_VERSION);
|
|
151
|
+
if ((0, fs_1.existsSync)(productionPath)) {
|
|
152
|
+
return productionVersionPath;
|
|
153
|
+
}
|
|
149
154
|
const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
|
|
150
155
|
return (0, path_1.join)(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
|
|
151
156
|
}
|
|
@@ -310,12 +315,42 @@ async function resolveCollector(allowDownload = true, logger) {
|
|
|
310
315
|
configPath: (0, fs_1.existsSync)(configPath) ? configPath : null,
|
|
311
316
|
};
|
|
312
317
|
}
|
|
313
|
-
function discoverCollectorViaUDP(timeoutMs =
|
|
318
|
+
function discoverCollectorViaUDP(timeoutMs = 1000) {
|
|
314
319
|
return new Promise((resolve) => {
|
|
315
320
|
const socket = dgram_1.default.createSocket('udp4');
|
|
316
321
|
const discovered = [];
|
|
317
322
|
let timeout;
|
|
323
|
+
let resolved = false;
|
|
318
324
|
const startTime = Date.now();
|
|
325
|
+
const safetyTimeout = setTimeout(() => {
|
|
326
|
+
if (!resolved) {
|
|
327
|
+
console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
|
|
328
|
+
resolved = true;
|
|
329
|
+
try {
|
|
330
|
+
socket.removeAllListeners();
|
|
331
|
+
socket.close();
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
}
|
|
335
|
+
clearTimeout(timeout);
|
|
336
|
+
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
337
|
+
}
|
|
338
|
+
}, timeoutMs + 100);
|
|
339
|
+
const doResolve = (result) => {
|
|
340
|
+
if (!resolved) {
|
|
341
|
+
resolved = true;
|
|
342
|
+
clearTimeout(timeout);
|
|
343
|
+
clearTimeout(safetyTimeout);
|
|
344
|
+
try {
|
|
345
|
+
socket.removeAllListeners();
|
|
346
|
+
socket.close();
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
}
|
|
350
|
+
console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
|
|
351
|
+
resolve(result);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
319
354
|
socket.on('message', (msg) => {
|
|
320
355
|
try {
|
|
321
356
|
const message = JSON.parse(msg.toString());
|
|
@@ -323,17 +358,16 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
323
358
|
discovered.push(message);
|
|
324
359
|
const elapsed = Date.now() - startTime;
|
|
325
360
|
console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
|
|
361
|
+
doResolve(discovered[0]);
|
|
326
362
|
}
|
|
327
363
|
}
|
|
328
364
|
catch (error) {
|
|
329
365
|
}
|
|
330
366
|
});
|
|
331
367
|
socket.on('error', (err) => {
|
|
332
|
-
clearTimeout(timeout);
|
|
333
|
-
socket.close();
|
|
334
368
|
const elapsed = Date.now() - startTime;
|
|
335
369
|
console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
|
|
336
|
-
|
|
370
|
+
doResolve(null);
|
|
337
371
|
});
|
|
338
372
|
socket.bind(() => {
|
|
339
373
|
socket.setBroadcast(true);
|
|
@@ -346,13 +380,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
346
380
|
else {
|
|
347
381
|
console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
|
|
348
382
|
}
|
|
349
|
-
|
|
350
|
-
socket.close(() => {
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
catch (closeError) {
|
|
354
|
-
}
|
|
355
|
-
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
383
|
+
doResolve(discovered.length > 0 ? discovered[0] : null);
|
|
356
384
|
}, timeoutMs);
|
|
357
385
|
});
|
|
358
386
|
});
|
|
@@ -417,9 +445,10 @@ async function isCollectorRunning() {
|
|
|
417
445
|
try {
|
|
418
446
|
const udpStartTime = Date.now();
|
|
419
447
|
console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
|
|
420
|
-
|
|
448
|
+
console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
|
|
449
|
+
const discovered = await discoverCollectorViaUDP(1000);
|
|
421
450
|
const udpElapsed = Date.now() - udpStartTime;
|
|
422
|
-
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);
|
|
451
|
+
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
|
|
423
452
|
if (discovered) {
|
|
424
453
|
console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
|
|
425
454
|
return {
|
|
@@ -435,7 +464,11 @@ async function isCollectorRunning() {
|
|
|
435
464
|
}
|
|
436
465
|
}
|
|
437
466
|
catch (error) {
|
|
438
|
-
|
|
467
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
468
|
+
console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
|
|
469
|
+
if (error instanceof Error && error.stack) {
|
|
470
|
+
console.log(`[UDP Discovery] Error stack: ${error.stack}`);
|
|
471
|
+
}
|
|
439
472
|
}
|
|
440
473
|
console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
|
|
441
474
|
return {
|
|
@@ -785,13 +818,14 @@ async function discoverOrStartCollector(logger, standardOtelEnabled, env) {
|
|
|
785
818
|
}
|
|
786
819
|
}
|
|
787
820
|
if (!globalCollectorProcess) {
|
|
788
|
-
logger.info('[Collector]
|
|
821
|
+
logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
|
|
789
822
|
const udpStartTime = Date.now();
|
|
823
|
+
logger.info('[Collector] Calling isCollectorRunning()...');
|
|
790
824
|
const status = await isCollectorRunning();
|
|
791
825
|
const udpElapsed = Date.now() - udpStartTime;
|
|
792
|
-
logger.info(`[Collector]
|
|
826
|
+
logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
|
|
793
827
|
if (status.isRunning && status.isReady && status.otlpEndpoint) {
|
|
794
|
-
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
|
|
828
|
+
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
|
|
795
829
|
return `http://${status.otlpEndpoint}`;
|
|
796
830
|
}
|
|
797
831
|
logger.info('[Collector] No existing collector found, will start new one...');
|
|
@@ -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,CAsDhC;
|
|
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,CAsDhC;AAuSD;;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,CAuFnE;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,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwCxB;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,CAuNtD;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,CAyKxB"}
|
|
@@ -124,9 +124,18 @@ export async function fetchClickHouseCredentials(env) {
|
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)
|
|
127
|
+
* Checks production location first (pre-installed in Docker), then falls back to temp directory
|
|
127
128
|
*/
|
|
128
129
|
function getCollectorStoragePath() {
|
|
129
|
-
//
|
|
130
|
+
// Check production location first (pre-installed in Docker image at /opt/beam/collectors)
|
|
131
|
+
// This avoids runtime download delays (~12 seconds)
|
|
132
|
+
const productionPath = '/opt/beam/collectors';
|
|
133
|
+
const productionVersionPath = join(productionPath, COLLECTOR_VERSION);
|
|
134
|
+
// Use production path if it exists (Docker image pre-installed collector)
|
|
135
|
+
if (existsSync(productionPath)) {
|
|
136
|
+
return productionVersionPath;
|
|
137
|
+
}
|
|
138
|
+
// Fallback to temp directory (local development without Docker)
|
|
130
139
|
const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
|
|
131
140
|
return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
|
|
132
141
|
}
|
|
@@ -314,12 +323,45 @@ async function resolveCollector(allowDownload = true, logger) {
|
|
|
314
323
|
/**
|
|
315
324
|
* Discovers collector via UDP broadcast
|
|
316
325
|
*/
|
|
317
|
-
function discoverCollectorViaUDP(timeoutMs =
|
|
326
|
+
function discoverCollectorViaUDP(timeoutMs = 1000) {
|
|
318
327
|
return new Promise((resolve) => {
|
|
319
328
|
const socket = dgram.createSocket('udp4');
|
|
320
329
|
const discovered = [];
|
|
321
330
|
let timeout;
|
|
331
|
+
let resolved = false; // Guard to prevent double resolution
|
|
322
332
|
const startTime = Date.now();
|
|
333
|
+
// Safety timeout - force resolve after timeout + 100ms buffer
|
|
334
|
+
const safetyTimeout = setTimeout(() => {
|
|
335
|
+
if (!resolved) {
|
|
336
|
+
console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
|
|
337
|
+
resolved = true;
|
|
338
|
+
try {
|
|
339
|
+
socket.removeAllListeners();
|
|
340
|
+
socket.close();
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
// Ignore
|
|
344
|
+
}
|
|
345
|
+
clearTimeout(timeout);
|
|
346
|
+
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
347
|
+
}
|
|
348
|
+
}, timeoutMs + 100);
|
|
349
|
+
const doResolve = (result) => {
|
|
350
|
+
if (!resolved) {
|
|
351
|
+
resolved = true;
|
|
352
|
+
clearTimeout(timeout);
|
|
353
|
+
clearTimeout(safetyTimeout);
|
|
354
|
+
try {
|
|
355
|
+
socket.removeAllListeners();
|
|
356
|
+
socket.close();
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
// Ignore
|
|
360
|
+
}
|
|
361
|
+
console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
|
|
362
|
+
resolve(result);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
323
365
|
socket.on('message', (msg) => {
|
|
324
366
|
try {
|
|
325
367
|
const message = JSON.parse(msg.toString());
|
|
@@ -328,6 +370,8 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
328
370
|
discovered.push(message);
|
|
329
371
|
const elapsed = Date.now() - startTime;
|
|
330
372
|
console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
|
|
373
|
+
// Resolve immediately when collector found
|
|
374
|
+
doResolve(discovered[0]);
|
|
331
375
|
}
|
|
332
376
|
}
|
|
333
377
|
catch (error) {
|
|
@@ -335,11 +379,9 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
335
379
|
}
|
|
336
380
|
});
|
|
337
381
|
socket.on('error', (err) => {
|
|
338
|
-
clearTimeout(timeout);
|
|
339
|
-
socket.close();
|
|
340
382
|
const elapsed = Date.now() - startTime;
|
|
341
383
|
console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
|
|
342
|
-
|
|
384
|
+
doResolve(null);
|
|
343
385
|
});
|
|
344
386
|
socket.bind(() => {
|
|
345
387
|
socket.setBroadcast(true);
|
|
@@ -352,17 +394,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
352
394
|
else {
|
|
353
395
|
console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
|
|
354
396
|
}
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
socket.close(() => {
|
|
358
|
-
// Socket closed callback (optional, we don't wait for this)
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
catch (closeError) {
|
|
362
|
-
// Ignore close errors
|
|
363
|
-
}
|
|
364
|
-
// Return the first discovered collector immediately
|
|
365
|
-
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
397
|
+
doResolve(discovered.length > 0 ? discovered[0] : null);
|
|
366
398
|
}, timeoutMs);
|
|
367
399
|
});
|
|
368
400
|
});
|
|
@@ -446,9 +478,10 @@ export async function isCollectorRunning() {
|
|
|
446
478
|
try {
|
|
447
479
|
const udpStartTime = Date.now();
|
|
448
480
|
console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
|
|
449
|
-
|
|
481
|
+
console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
|
|
482
|
+
const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)
|
|
450
483
|
const udpElapsed = Date.now() - udpStartTime;
|
|
451
|
-
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);
|
|
484
|
+
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
|
|
452
485
|
if (discovered) {
|
|
453
486
|
console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
|
|
454
487
|
return {
|
|
@@ -465,7 +498,11 @@ export async function isCollectorRunning() {
|
|
|
465
498
|
}
|
|
466
499
|
catch (error) {
|
|
467
500
|
// Discovery failed, collector probably not running
|
|
468
|
-
|
|
501
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
502
|
+
console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
|
|
503
|
+
if (error instanceof Error && error.stack) {
|
|
504
|
+
console.log(`[UDP Discovery] Error stack: ${error.stack}`);
|
|
505
|
+
}
|
|
469
506
|
}
|
|
470
507
|
console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
|
|
471
508
|
return {
|
|
@@ -929,16 +966,18 @@ export async function discoverOrStartCollector(logger, standardOtelEnabled, env)
|
|
|
929
966
|
globalCollectorStderr = [];
|
|
930
967
|
}
|
|
931
968
|
}
|
|
932
|
-
// First, check if collector is already running (via UDP discovery)
|
|
969
|
+
// First, quick check if collector is already running (via UDP discovery)
|
|
970
|
+
// Match C#: 10 attempts × 100ms = 1 second max (much faster than before)
|
|
933
971
|
// Skip UDP discovery if we already have a process reference (faster)
|
|
934
972
|
if (!globalCollectorProcess) {
|
|
935
|
-
logger.info('[Collector]
|
|
973
|
+
logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
|
|
936
974
|
const udpStartTime = Date.now();
|
|
975
|
+
logger.info('[Collector] Calling isCollectorRunning()...');
|
|
937
976
|
const status = await isCollectorRunning();
|
|
938
977
|
const udpElapsed = Date.now() - udpStartTime;
|
|
939
|
-
logger.info(`[Collector]
|
|
978
|
+
logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
|
|
940
979
|
if (status.isRunning && status.isReady && status.otlpEndpoint) {
|
|
941
|
-
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
|
|
980
|
+
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
|
|
942
981
|
return `http://${status.otlpEndpoint}`;
|
|
943
982
|
}
|
|
944
983
|
logger.info('[Collector] No existing collector found, will start new one...');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-manager.js","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, ChildProcess } from 'child_process';\r\nimport { createWriteStream, existsSync, chmodSync, mkdirSync } from 'fs';\r\nimport { join, dirname } from 'path';\r\nimport { pipeline } from 'stream/promises';\r\nimport { createGunzip } from 'zlib';\r\nimport { createHash } from 'node:crypto';\r\nimport { createServer } from 'net';\r\nimport type { Logger } from 'pino';\r\nimport pino from 'pino';\r\nimport dgram from 'dgram';\r\nimport deasync from 'deasync';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl } from './utils/urls.js';\r\n\r\n// Protocol is httpprotobuf \r\n\r\ninterface CollectorDiscoveryEntry {\r\n version: string;\r\n status: string;\r\n pid: number;\r\n otlpEndpoint: string;\r\n}\r\n\r\nexport interface CollectorStatus {\r\n isRunning: boolean;\r\n isReady: boolean;\r\n pid: number;\r\n otlpEndpoint?: string;\r\n version?: string;\r\n}\r\n\r\nconst COLLECTOR_VERSION = '1.0.1'; // Match C# collector version (from collector-version.json)\r\nconst COLLECTOR_DOWNLOAD_BASE = `https://collectors.beamable.com/version/${COLLECTOR_VERSION}`;\r\nconst DISCOVERY_PORT = parseInt(process.env.BEAM_COLLECTOR_DISCOVERY_PORT || '8688', 10);\r\n\r\n/**\r\n * Finds a free TCP port (matching C# PortUtil.FreeTcpPort())\r\n */\r\nfunction findFreePort(): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const server = createServer();\r\n server.listen(0, () => {\r\n const address = server.address();\r\n const port = typeof address === 'object' && address !== null ? address.port : 0;\r\n server.close(() => {\r\n if (port > 0) {\r\n resolve(port);\r\n } else {\r\n // Fallback to a default port if something went wrong\r\n resolve(9090);\r\n }\r\n });\r\n });\r\n server.on('error', (err) => {\r\n reject(err);\r\n });\r\n });\r\n}\r\n\r\n// Global storage for collector process and errors (to prevent GC and track status)\r\nlet globalCollectorProcess: ChildProcess | null = null;\r\nlet globalCollectorStartError: string | null = null;\r\nlet globalCollectorExitCode: number | null = null;\r\nlet globalCollectorStderr: string[] = [];\r\n// Track if collector startup is in progress to prevent duplicate starts\r\nlet globalCollectorStartupPromise: Promise<string | null> | null = null;\r\nlet globalCollectorInitError: string | null = null; // Tracks errors from discoverOrStartCollector\r\n\r\n/**\r\n * ClickHouse credentials response from Beamable API\r\n */\r\ninterface ClickHouseCredentials {\r\n endpoint: string;\r\n expiresAt?: string;\r\n password: string;\r\n username: string;\r\n}\r\n\r\n/**\r\n * Calculates Beamable signature for signed requests\r\n * Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64\r\n * Matches C# SignedRequesterHelper.CalculateSignature\r\n */\r\nfunction calculateSignature(\r\n pid: string,\r\n secret: string,\r\n uriPathAndQuery: string,\r\n body: string | null = null,\r\n version: string = '1'\r\n): string {\r\n let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;\r\n if (body) {\r\n dataToSign += body;\r\n }\r\n \r\n // MD5 hash to Base64 (matching C# implementation)\r\n const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');\r\n return hash;\r\n}\r\n\r\n/**\r\n * Extracts path and query from a URL\r\n */\r\nfunction getPathAndQuery(url: string): string {\r\n try {\r\n const urlObj = new URL(url);\r\n return urlObj.pathname + urlObj.search;\r\n } catch {\r\n // If URL parsing fails, return as-is\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * Fetches ClickHouse credentials from Beamable API\r\n * GET /api/beamo/otel/auth/writer/config\r\n * Requires signed request authentication (X-BEAM-SIGNATURE header)\r\n */\r\nexport async function fetchClickHouseCredentials(\r\n env: EnvironmentConfig\r\n): Promise<ClickHouseCredentials> {\r\n const apiUrl = hostToHttpUrl(env.host);\r\n const uriPath = '/api/beamo/otel/auth/writer/config';\r\n const configUrl = new URL(uriPath, apiUrl).toString();\r\n \r\n // Create a minimal logger for verbose output\r\n const verboseLogger = pino({ name: 'fetch-credentials', level: 'info' }, process.stdout);\r\n verboseLogger.info(`[Credentials] Starting credential fetch from ${configUrl}...`);\r\n \r\n // Get secret from environment (required for signed requests)\r\n const secret = process.env.SECRET;\r\n if (!secret) {\r\n verboseLogger.error('[Credentials] SECRET environment variable is missing');\r\n throw new Error('SECRET environment variable is required to fetch ClickHouse credentials');\r\n }\r\n verboseLogger.info('[Credentials] SECRET found, calculating signature...');\r\n \r\n // Calculate signature for signed request (matching C# HttpSignedRequester)\r\n const pathAndQuery = getPathAndQuery(uriPath);\r\n const signature = calculateSignature(env.pid, secret, pathAndQuery, null, '1');\r\n verboseLogger.info('[Credentials] Signature calculated, making API request...');\r\n \r\n // Build headers with signed authentication (matching C# HttpSignedRequester)\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,\r\n 'X-BEAM-SIGNATURE': signature,\r\n };\r\n \r\n const fetchStartTime = Date.now();\r\n const response = await fetch(configUrl, {\r\n method: 'GET',\r\n headers,\r\n });\r\n const fetchElapsed = Date.now() - fetchStartTime;\r\n verboseLogger.info(`[Credentials] API request completed in ${fetchElapsed}ms, status: ${response.status}`);\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'Unknown error');\r\n verboseLogger.error(`[Credentials] API request failed: ${response.status} ${response.statusText}`);\r\n throw new Error(`Failed to fetch ClickHouse credentials from ${configUrl}: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);\r\n }\r\n \r\n verboseLogger.info('[Credentials] Parsing response JSON...');\r\n const credentials = await response.json() as ClickHouseCredentials;\r\n \r\n if (!credentials.endpoint || !credentials.username || !credentials.password) {\r\n verboseLogger.error('[Credentials] Invalid response: missing required fields');\r\n throw new Error('Invalid ClickHouse credentials response: missing required fields');\r\n }\r\n \r\n verboseLogger.info(`[Credentials] Successfully fetched credentials (endpoint: ${credentials.endpoint}, username: ${credentials.username})`);\r\n return credentials;\r\n}\r\n\r\n/**\r\n * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)\r\n */\r\nfunction getCollectorStoragePath(): string {\r\n // Use temp directory for now - in containers this should be writable\r\n const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';\r\n return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);\r\n}\r\n\r\n/**\r\n * Gets the collector binary name for the current platform\r\n */\r\nfunction getCollectorBinaryName(): string {\r\n const platform = process.platform;\r\n const arch = process.arch;\r\n \r\n // Match C# naming: collector-{osArchSuffix}\r\n // C# returns \"collector-linux-amd64\", not \"beamable-collector-linux-amd64\"\r\n if (platform === 'linux' && arch === 'x64') {\r\n return 'collector-linux-amd64';\r\n } else if (platform === 'linux' && arch === 'arm64') {\r\n return 'collector-linux-arm64';\r\n } else if (platform === 'darwin' && arch === 'x64') {\r\n return 'collector-darwin-amd64';\r\n } else if (platform === 'darwin' && arch === 'arm64') {\r\n return 'collector-darwin-arm64';\r\n } else if (platform === 'win32' && arch === 'x64') {\r\n return 'collector-windows-amd64.exe';\r\n }\r\n \r\n throw new Error(`Unsupported platform: ${platform} ${arch}`);\r\n}\r\n\r\n/**\r\n * Downloads and decompresses a gzipped file\r\n */\r\nasync function downloadAndDecompressGzip(url: string, outputPath: string, makeExecutable: boolean = false): Promise<void> {\r\n let response: Response;\r\n try {\r\n // Add timeout and better error handling\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout\r\n \r\n try {\r\n response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n 'User-Agent': 'Beamable-Node-Microservice-Runtime/1.0',\r\n },\r\n });\r\n clearTimeout(timeoutId);\r\n } catch (fetchError) {\r\n clearTimeout(timeoutId);\r\n if (fetchError instanceof Error) {\r\n // Extract underlying error details from cause\r\n let underlyingError = '';\r\n if ((fetchError as any).cause) {\r\n const cause = (fetchError as any).cause;\r\n if (cause instanceof Error) {\r\n const causeCode = (cause as any).code;\r\n underlyingError = ` (cause: ${cause.name} - ${cause.message}${causeCode ? ` [code: ${causeCode}]` : ''})`;\r\n } else if (typeof cause === 'object' && cause.code) {\r\n underlyingError = ` (cause code: ${cause.code})`;\r\n }\r\n }\r\n \r\n // Provide more context about the error\r\n if (fetchError.name === 'AbortError') {\r\n throw new Error(`Timeout downloading ${url} (30s limit exceeded)${underlyingError}`);\r\n }\r\n \r\n // Check error code if available (Node.js system errors)\r\n const errorCode = (fetchError as any).code || ((fetchError as any).cause?.code);\r\n if (errorCode) {\r\n if (errorCode === 'ENOTFOUND' || errorCode === 'EAI_AGAIN') {\r\n throw new Error(`DNS resolution failed for ${url} (code: ${errorCode}). Check network connectivity and DNS settings.`);\r\n }\r\n if (errorCode === 'ECONNREFUSED') {\r\n throw new Error(`Connection refused to ${url} (code: ${errorCode}). Server may be down or firewall blocking.`);\r\n }\r\n if (errorCode === 'ETIMEDOUT' || errorCode === 'ECONNRESET') {\r\n throw new Error(`Connection timeout/reset to ${url} (code: ${errorCode}). Network may be slow or unreachable.`);\r\n }\r\n if (errorCode === 'CERT_HAS_EXPIRED' || errorCode === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\r\n throw new Error(`SSL/TLS certificate error connecting to ${url} (code: ${errorCode}): ${fetchError.message}`);\r\n }\r\n }\r\n \r\n // Check for common network errors in message\r\n const errorMsg = fetchError.message.toLowerCase();\r\n if (errorMsg.includes('enotfound') || errorMsg.includes('dns')) {\r\n throw new Error(`DNS resolution failed for ${url}. Check network connectivity and DNS settings.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('econnrefused') || errorMsg.includes('connection refused')) {\r\n throw new Error(`Connection refused to ${url}. Server may be down or firewall blocking.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('etimedout') || errorMsg.includes('timeout')) {\r\n throw new Error(`Connection timeout to ${url}. Network may be slow or unreachable.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('certificate') || errorMsg.includes('ssl') || errorMsg.includes('tls')) {\r\n throw new Error(`SSL/TLS error connecting to ${url}: ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${fetchError.name} - ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(fetchError)}`);\r\n }\r\n } catch (error) {\r\n // Re-throw with more context\r\n if (error instanceof Error) {\r\n if (error.message.includes('Timeout') || error.message.includes('DNS') || error.message.includes('Connection')) {\r\n throw error; // Already has good context\r\n }\r\n throw new Error(`Network error downloading ${url}: ${error.message}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(error)}`);\r\n }\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => '');\r\n throw new Error(`HTTP ${response.status} downloading ${url}: ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`);\r\n }\r\n \r\n const dir = dirname(outputPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n const gunzip = createGunzip();\r\n const writeStream = createWriteStream(outputPath);\r\n \r\n await pipeline(response.body as any, gunzip, writeStream);\r\n \r\n if (makeExecutable && process.platform !== 'win32') {\r\n try {\r\n chmodSync(outputPath, 0o755);\r\n } catch (error) {\r\n console.error(`Failed to make ${outputPath} executable:`, error);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolves the collector binary and config, downloading if needed\r\n */\r\nasync function resolveCollector(allowDownload: boolean = true, logger?: Logger): Promise<{ binaryPath: string | null; configPath: string | null }> {\r\n const basePath = getCollectorStoragePath();\r\n const binaryName = getCollectorBinaryName();\r\n const configName = 'clickhouse-config.yaml';\r\n \r\n const binaryPath = join(basePath, binaryName);\r\n const configPath = join(basePath, configName);\r\n \r\n const itemsToDownload: Array<{ url: string; path: string; executable: boolean }> = [];\r\n \r\n if (!existsSync(binaryPath) && allowDownload) {\r\n const binaryUrl = `${COLLECTOR_DOWNLOAD_BASE}/${binaryName}.gz`;\r\n itemsToDownload.push({ url: binaryUrl, path: binaryPath, executable: true });\r\n logger?.info(`[Collector] Will download binary from: ${binaryUrl}`);\r\n } else if (existsSync(binaryPath)) {\r\n logger?.info(`[Collector] Binary found at: ${binaryPath}`);\r\n }\r\n \r\n if (!existsSync(configPath) && allowDownload) {\r\n const configUrl = `${COLLECTOR_DOWNLOAD_BASE}/${configName}.gz`;\r\n itemsToDownload.push({ url: configUrl, path: configPath, executable: false });\r\n logger?.info(`[Collector] Will download config from: ${configUrl}`);\r\n } else if (existsSync(configPath)) {\r\n logger?.info(`[Collector] Config found at: ${configPath}`);\r\n }\r\n \r\n // Download items in parallel for faster startup (binary and config simultaneously)\r\n if (itemsToDownload.length > 0) {\r\n logger?.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);\r\n const downloadPromises = itemsToDownload.map(async (item) => {\r\n try {\r\n logger?.info(`[Collector] Downloading ${item.url}...`);\r\n await downloadAndDecompressGzip(item.url, item.path, item.executable);\r\n logger?.info(`[Collector] Downloaded to ${item.path}`);\r\n } catch (error) {\r\n // Don't wrap the error again if it already contains the URL and details\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);\r\n // Only wrap if the error doesn't already contain the URL\r\n if (error instanceof Error && errorMsg.includes(item.url)) {\r\n throw error; // Error already has URL and context\r\n }\r\n throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);\r\n }\r\n });\r\n \r\n // Wait for all downloads to complete (or fail)\r\n await Promise.all(downloadPromises);\r\n }\r\n \r\n return {\r\n binaryPath: existsSync(binaryPath) ? binaryPath : null,\r\n configPath: existsSync(configPath) ? configPath : null,\r\n };\r\n}\r\n\r\n/**\r\n * Discovers collector via UDP broadcast\r\n */\r\nfunction discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDiscoveryEntry | null> {\r\n return new Promise((resolve) => {\r\n const socket = dgram.createSocket('udp4');\r\n const discovered: CollectorDiscoveryEntry[] = [];\r\n let timeout: NodeJS.Timeout;\r\n const startTime = Date.now();\r\n \r\n socket.on('message', (msg) => {\r\n try {\r\n const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;\r\n // Check if version matches\r\n if (message.version === COLLECTOR_VERSION && message.status === 'READY') {\r\n discovered.push(message);\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);\r\n }\r\n } catch (error) {\r\n // Ignore parse errors\r\n }\r\n });\r\n \r\n socket.on('error', (err) => {\r\n clearTimeout(timeout);\r\n socket.close();\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);\r\n resolve(null);\r\n });\r\n \r\n socket.bind(() => {\r\n socket.setBroadcast(true);\r\n console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);\r\n \r\n timeout = setTimeout(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (discovered.length > 0) {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);\r\n } else {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);\r\n }\r\n // Close socket and resolve immediately (don't wait for close callback)\r\n try {\r\n socket.close(() => {\r\n // Socket closed callback (optional, we don't wait for this)\r\n });\r\n } catch (closeError) {\r\n // Ignore close errors\r\n }\r\n // Return the first discovered collector immediately\r\n resolve(discovered.length > 0 ? discovered[0] : null);\r\n }, timeoutMs);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Gets the current status of ClickHouse credentials (from env or API)\r\n */\r\nexport function getClickHouseCredentialsStatus(): {\r\n hasEndpoint: boolean;\r\n hasUsername: boolean;\r\n hasPassword: boolean;\r\n source: 'environment' | 'api' | 'missing';\r\n} {\r\n const hasEndpoint = !!process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const hasUsername = !!process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const hasPassword = !!process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (hasEndpoint && hasUsername && hasPassword) {\r\n return {\r\n hasEndpoint: true,\r\n hasUsername: true,\r\n hasPassword: true,\r\n source: 'environment',\r\n };\r\n }\r\n \r\n return {\r\n hasEndpoint,\r\n hasUsername,\r\n hasPassword,\r\n source: 'missing',\r\n };\r\n}\r\n\r\n/**\r\n * Checks if collector is already running via UDP discovery\r\n */\r\nexport async function isCollectorRunning(): Promise<CollectorStatus> {\r\n // First, check if we have a global collector process reference\r\n // If the process is running and we've seen \"Everything is ready\" in stderr, it's ready\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n try {\r\n // Process is alive if we can access it and it hasn't exited\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n // Check if we've seen the \"Everything is ready\" message in stderr\r\n // This is a reliable indicator that the collector is ready\r\n const stderrText = globalCollectorStderr.join('\\n');\r\n const isReady = stderrText.includes('Everything is ready') || \r\n stderrText.includes('Begin running and processing data');\r\n \r\n if (isReady) {\r\n // Try UDP discovery to get the endpoint, but if it fails, use the configured endpoint\r\n try {\r\n const discovered = await discoverCollectorViaUDP(1000); // Shorter timeout since we know it's running\r\n if (discovered && discovered.status === 'READY') {\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: discovered.pid || globalCollectorProcess.pid || 0,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n }\r\n } catch {\r\n // UDP discovery failed, but process is alive and has \"Everything is ready\" message\r\n // Use the configured endpoint as fallback\r\n }\r\n \r\n // Process is alive and we've seen \"Everything is ready\" - treat as ready\r\n // Extract endpoint from environment or use default\r\n const configuredEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT || '0.0.0.0:4318';\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: globalCollectorProcess.pid || 0,\r\n otlpEndpoint: configuredEndpoint,\r\n version: COLLECTOR_VERSION,\r\n };\r\n }\r\n }\r\n } catch {\r\n // Process might have exited or is invalid\r\n }\r\n }\r\n \r\n // Try UDP discovery as fallback\r\n try {\r\n const udpStartTime = Date.now();\r\n console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');\r\n const discovered = await discoverCollectorViaUDP(2000);\r\n const udpElapsed = Date.now() - udpStartTime;\r\n console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);\r\n if (discovered) {\r\n console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);\r\n return {\r\n isRunning: true,\r\n isReady: discovered.status === 'READY',\r\n pid: discovered.pid,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n } else {\r\n console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);\r\n }\r\n } catch (error) {\r\n // Discovery failed, collector probably not running\r\n console.log(`[UDP Discovery] Error in isCollectorRunning(): ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n \r\n console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');\r\n return {\r\n isRunning: false,\r\n isReady: false,\r\n pid: 0,\r\n };\r\n}\r\n\r\n/**\r\n * Sets default collector configuration environment variables in process.env\r\n * Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n */\r\nfunction addCollectorConfigurationToEnvironment(): void {\r\n const defaults: Record<string, string> = {\r\n BEAM_CLICKHOUSE_PROCESSOR_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_PROCESSOR_BATCH_SIZE: '5000',\r\n BEAM_CLICKHOUSE_EXPORTER_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_QUEUE_SIZE: '1000',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_ENABLED: 'true',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_INITIAL_INTERVAL: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_INTERVAL: '30s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_ELAPSED_TIME: '300s',\r\n };\r\n \r\n // Only set if not already set (matching C# behavior)\r\n for (const [key, defaultValue] of Object.entries(defaults)) {\r\n if (!process.env[key]) {\r\n process.env[key] = defaultValue;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Sets ClickHouse credentials in process.env (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n */\r\nexport function addAuthEnvironmentVars(endpoint: string, username: string, password: string): void {\r\n // Always set the values when explicitly provided (matching C# behavior)\r\n // This ensures credentials fetched from API override any existing (potentially empty) values\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n process.env.BEAM_CLICKHOUSE_ENDPOINT = endpoint;\r\n process.env.BEAM_CLICKHOUSE_USERNAME = username;\r\n process.env.BEAM_CLICKHOUSE_PASSWORD = password;\r\n \r\n // Verify they were actually set (for debugging)\r\n if (!process.env.BEAM_CLICKHOUSE_ENDPOINT || !process.env.BEAM_CLICKHOUSE_USERNAME || !process.env.BEAM_CLICKHOUSE_PASSWORD) {\r\n throw new Error(`Failed to set ClickHouse credentials in process.env - this should never happen in Node.js`);\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector and waits for it to be ready before returning.\r\n * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.\r\n * Returns the OTLP endpoint when ready, or null if it times out or fails.\r\n */\r\nexport async function startCollectorAndWaitForReady(\r\n env: EnvironmentConfig,\r\n _timeoutMs?: number // Not used - kept for API compatibility\r\n): Promise<string | null> {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');\r\n const setupStartTime = Date.now();\r\n\r\n // Simple linear async/await - no timeouts, no Promise.race complexity\r\n try {\r\n initLogger.info('[OTLP] Step 1: Discovering or starting collector...');\r\n const endpoint = await discoverOrStartCollector(initLogger, standardOtelEnabled, env);\r\n const elapsed = Date.now() - setupStartTime;\r\n \r\n if (endpoint) {\r\n initLogger.info(`[OTLP] Collector ready at ${endpoint}. Portal logs now enabled. (took ${elapsed}ms)`);\r\n return endpoint;\r\n } else {\r\n initLogger.warn(`[OTLP] Collector setup failed, continuing without Portal logs. (took ${elapsed}ms)`);\r\n return null;\r\n }\r\n } catch (error) {\r\n const elapsed = Date.now() - setupStartTime;\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Collector setup failed after ${elapsed}ms: ${errorMsg}`);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector asynchronously in the background (non-blocking).\r\n * This allows the service to start immediately while collector downloads/starts.\r\n * Returns immediately - collector setup happens in background.\r\n * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready\r\n */\r\nexport function startCollectorAsync(env: EnvironmentConfig): void {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');\r\n\r\n // Start collector setup asynchronously - don't wait for it\r\n // The service can start immediately, collector will connect when ready\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);\r\n // Update the global logger provider if it exists to enable OTLP\r\n // The logger will automatically start using OTLP once the provider is set\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n })\r\n .catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);\r\n });\r\n \r\n // Return immediately - service can start serving requests\r\n}\r\n\r\n/**\r\n * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).\r\n * This function is kept for backwards compatibility but is no longer recommended.\r\n * Use startCollectorAsync() for non-blocking startup instead.\r\n * @deprecated Use startCollectorAsync() for non-blocking startup\r\n */\r\nexport function setupCollectorBeforeLogging(\r\n env: EnvironmentConfig,\r\n timeoutMs: number = 60000\r\n): string | null {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector before logging initialization...');\r\n\r\n // Use deasync to wait synchronously for collector setup\r\n let endpoint: string | null = null;\r\n let completed = false;\r\n let setupError: string | null = null;\r\n\r\n // Start collector setup promise\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n endpoint = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete, endpoint: ${result}`);\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n return result;\r\n })\r\n .catch((error) => {\r\n setupError = error instanceof Error ? error.message : String(error);\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to setup collector: ${setupError}`);\r\n endpoint = null;\r\n });\r\n\r\n // Wait synchronously for collector setup to complete\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n\r\n try {\r\n // Use deasync to wait for completion (allows event loop to process async operations)\r\n deasync.loopWhile(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n return false; // Stop waiting\r\n }\r\n return !completed; // Continue waiting if not completed\r\n });\r\n } catch (error) {\r\n initLogger.error(`[OTLP] Error during collector setup wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (completed && endpoint) {\r\n initLogger.info('[OTLP] Collector is ready, proceeding with logger creation');\r\n return endpoint;\r\n } else if (setupError) {\r\n initLogger.error(`[OTLP] Collector setup failed: ${setupError}, continuing without OTLP`);\r\n return null;\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup did not complete in time, continuing without OTLP');\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the OpenTelemetry collector process\r\n */\r\nexport async function startCollector(\r\n logger: Logger,\r\n otlpEndpoint?: string,\r\n env?: EnvironmentConfig\r\n): Promise<{ process: ChildProcess; endpoint: string }> {\r\n logger.info('[Collector] === startCollector() ENTERED ===');\r\n // Clear any previous errors\r\n globalCollectorStartError = null;\r\n globalCollectorInitError = null;\r\n \r\n // CRITICAL: Fetch credentials FIRST, before resolving collector binary/config\r\n // This ensures credentials are in process.env even if collector download fails\r\n // The credentials will persist in process.env for the lifetime of the process.\r\n // Per Gabriel: \"these OTEL related ones you need to do it yourself at the beginning of the microservice startup\"\r\n let clickhouseEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n let clickhouseUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n let clickhousePassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if ((!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) && env) {\r\n try {\r\n logger.info('[Collector] Fetching ClickHouse credentials from Beamable API...');\r\n const credStartTime = Date.now();\r\n const credentials = await fetchClickHouseCredentials(env);\r\n const credElapsed = Date.now() - credStartTime;\r\n logger.info(`[Collector] ClickHouse credentials fetch completed in ${credElapsed}ms`);\r\n clickhouseEndpoint = credentials.endpoint;\r\n clickhouseUsername = credentials.username;\r\n clickhousePassword = credentials.password;\r\n \r\n // CRITICAL: Set them in process.env IMMEDIATELY after fetching (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n // This ensures they're available to both the Node.js process and inherited by the collector child process\r\n addAuthEnvironmentVars(clickhouseEndpoint, clickhouseUsername, clickhousePassword);\r\n \r\n // Verify they were set (defensive check - should never fail in Node.js)\r\n const verifyEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const verifyUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const verifyPassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (!verifyEndpoint || !verifyUsername || !verifyPassword) {\r\n logger.error(`[Collector] CRITICAL: Credentials were set but are missing from process.env! This should never happen.`);\r\n throw new Error('Failed to persist ClickHouse credentials in process.env');\r\n }\r\n \r\n logger.info('[Collector] ClickHouse credentials fetched from API and verified in process.env');\r\n } catch (error) {\r\n const errorMsg = `[Collector] Failed to fetch ClickHouse credentials from API: ${error instanceof Error ? error.message : String(error)}`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n }\r\n \r\n // Validate required environment variables (matching C# behavior)\r\n // These must be set before starting the collector, otherwise it will fail\r\n if (!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) {\r\n const errorMsg = `[Collector] Required ClickHouse credentials are missing. Set BEAM_CLICKHOUSE_ENDPOINT, BEAM_CLICKHOUSE_USERNAME, and BEAM_CLICKHOUSE_PASSWORD, or ensure the API endpoint is accessible.`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n \r\n // Now resolve collector binary and config (after credentials are fetched and set)\r\n logger.info('[Collector] Step 2: Resolving collector binary and config...');\r\n const resolveStartTime = Date.now();\r\n const collectorInfo = await resolveCollector(true, logger);\r\n const resolveElapsed = Date.now() - resolveStartTime;\r\n logger.info(`[Collector] Collector binary/config resolution completed in ${resolveElapsed}ms`);\r\n \r\n if (!collectorInfo.binaryPath) {\r\n logger.error('[Collector] Binary not found and download failed');\r\n throw new Error('Collector binary not found and download failed');\r\n }\r\n \r\n if (!collectorInfo.configPath) {\r\n logger.error('[Collector] Config not found and download failed');\r\n throw new Error('Collector config not found and download failed');\r\n }\r\n \r\n logger.info(`[Collector] Using binary: ${collectorInfo.binaryPath}`);\r\n logger.info(`[Collector] Using config: ${collectorInfo.configPath}`);\r\n \r\n // Verify binary exists\r\n if (!collectorInfo.binaryPath || !existsSync(collectorInfo.binaryPath)) {\r\n throw new Error(`Collector binary not found at ${collectorInfo.binaryPath}`);\r\n }\r\n \r\n // Check if binary is executable (Unix only - Windows doesn't have execute permission)\r\n if (process.platform !== 'win32') {\r\n try {\r\n const fsPromises = await import('fs/promises');\r\n const stats = await fsPromises.stat(collectorInfo.binaryPath);\r\n const mode = Number(stats.mode);\r\n const isExecutable = !!(mode & parseInt('111', 8)); // Check execute bit\r\n if (!isExecutable) {\r\n logger.warn(`[Collector] Binary may not be executable. Mode: ${mode.toString(8)}`);\r\n // Try to make it executable again\r\n try {\r\n chmodSync(collectorInfo.binaryPath, 0o755);\r\n logger.info(`[Collector] Made binary executable`);\r\n } catch (chmodError) {\r\n logger.error(`[Collector] Failed to make binary executable: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}`);\r\n }\r\n }\r\n } catch (statError) {\r\n logger.warn(`[Collector] Could not check binary permissions: ${statError instanceof Error ? statError.message : String(statError)}`);\r\n }\r\n }\r\n\r\n // Set default collector configuration environment variables in process.env\r\n // This ensures they're available to both the Node.js process and the collector child process\r\n // Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n addCollectorConfigurationToEnvironment();\r\n \r\n // CRITICAL: Set BEAM_COLLECTOR_DISCOVERY_PORT if not already set (matching C# AddDefaultCollectorHostAndPortFallback)\r\n // This MUST be set before starting the collector\r\n if (!process.env.BEAM_COLLECTOR_DISCOVERY_PORT) {\r\n process.env.BEAM_COLLECTOR_DISCOVERY_PORT = String(DISCOVERY_PORT);\r\n logger.info(`[Collector] Set BEAM_COLLECTOR_DISCOVERY_PORT=${DISCOVERY_PORT} (default)`);\r\n }\r\n \r\n // Determine OTLP endpoint\r\n // Use a free port if not specified (like C# does with PortUtil.FreeEndpoint())\r\n let localEndpoint = otlpEndpoint;\r\n if (!localEndpoint) {\r\n // For now, use default OTLP HTTP port\r\n // In production, this would be discovered or set by Beamable\r\n localEndpoint = '0.0.0.0:4318';\r\n }\r\n localEndpoint = localEndpoint.replace(/^http:\\/\\//, '').replace(/^https:\\/\\//, '');\r\n \r\n // Find a free port for Prometheus (matching C# PortUtil.FreeTcpPort())\r\n // We'll use a simple approach: bind to port 0 and let the OS assign a port\r\n // For now, use a default port (9090 is common for Prometheus) or find a free one\r\n // C# uses PortUtil.FreeTcpPort() which finds an available TCP port\r\n // We'll use a simple helper to find a free port\r\n const prometheusPort = await findFreePort();\r\n \r\n // Set environment variables for collector\r\n // Note: BEAM_CLICKHOUSE_ENDPOINT is for collector → ClickHouse communication\r\n // This is different from the OTLP endpoint (microservice → collector)\r\n // The collector process will inherit all environment variables from process.env automatically\r\n // We only need to set the OTLP endpoint, discovery port, and Prometheus port explicitly here\r\n const collectorEnv: NodeJS.ProcessEnv = {\r\n ...process.env, // Inherit all process.env (including credentials and config we just set)\r\n BEAM_OTLP_HTTP_ENDPOINT: localEndpoint,\r\n BEAM_COLLECTOR_DISCOVERY_PORT: String(DISCOVERY_PORT),\r\n BEAM_COLLECTOR_PROMETHEUS_PORT: String(prometheusPort),\r\n };\r\n \r\n // Start collector process\r\n const collectorProcess = spawn(collectorInfo.binaryPath, ['--config', collectorInfo.configPath], {\r\n env: collectorEnv,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n detached: false,\r\n });\r\n \r\n // Store globally to prevent GC and track status\r\n globalCollectorProcess = collectorProcess;\r\n globalCollectorStartError = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n \r\n // Set up handlers BEFORE we check if process started, so we capture all output\r\n collectorProcess.stdout?.on('data', (data) => {\r\n const outputLine = data.toString().trim();\r\n // Log stdout at info level to see collector output\r\n logger.info(`[Collector OUT] ${outputLine}`);\r\n });\r\n \r\n collectorProcess.stderr?.on('data', (data) => {\r\n const errorLine = data.toString().trim();\r\n globalCollectorStderr.push(errorLine);\r\n // Keep only last 50 lines to prevent memory issues\r\n if (globalCollectorStderr.length > 50) {\r\n globalCollectorStderr.shift();\r\n }\r\n // Log stderr at info level so we can see why collector crashes\r\n logger.info(`[Collector ERR] ${errorLine}`);\r\n });\r\n \r\n collectorProcess.on('error', (err) => {\r\n globalCollectorStartError = err.message;\r\n logger.error(`[Collector] Failed to start: ${err.message}`);\r\n });\r\n \r\n collectorProcess.on('exit', (code, signal) => {\r\n globalCollectorExitCode = code;\r\n logger.warn(`[Collector] Process exited with code ${code}${signal ? `, signal ${signal}` : ''}`);\r\n \r\n // If process exited with an error code, log accumulated stderr\r\n if (code !== 0 && globalCollectorStderr.length > 0) {\r\n logger.error(`[Collector] Exit error - Last ${Math.min(10, globalCollectorStderr.length)} stderr lines:`);\r\n globalCollectorStderr.slice(-10).forEach((line) => {\r\n logger.error(`[Collector ERR] ${line}`);\r\n });\r\n }\r\n \r\n // Don't clear reference immediately - keep it for status checks\r\n // globalCollectorProcess = null; // Keep reference for getCollectorProcessStatus()\r\n });\r\n \r\n logger.info(`[Collector] Started with PID ${collectorProcess.pid}, endpoint: ${localEndpoint}`);\r\n \r\n // Give the process a moment to start and potentially write to stderr\r\n // This helps capture immediate startup errors\r\n // Wait a bit longer to ensure we catch immediate crashes\r\n await new Promise(resolve => setTimeout(resolve, 500));\r\n \r\n // Check if process already exited (immediate crash)\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const stderrMsg = globalCollectorStderr.length > 0 \r\n ? ` Stderr: ${globalCollectorStderr.join('; ')}` \r\n : ' No stderr output captured.';\r\n throw new Error(`Collector process exited immediately after startup with code ${globalCollectorExitCode}.${stderrMsg}`);\r\n }\r\n \r\n return {\r\n process: collectorProcess,\r\n endpoint: `http://${localEndpoint}`,\r\n };\r\n}\r\n\r\n/**\r\n * Gets detailed collector status including process info and errors\r\n */\r\nexport function getCollectorProcessStatus(): {\r\n hasProcess: boolean;\r\n pid: number | null;\r\n exitCode: number | null;\r\n startError: string | null;\r\n initError: string | null;\r\n stderr: string[];\r\n} {\r\n return {\r\n hasProcess: globalCollectorProcess !== null,\r\n pid: globalCollectorProcess?.pid ?? null,\r\n exitCode: globalCollectorExitCode,\r\n startError: globalCollectorStartError,\r\n initError: globalCollectorInitError,\r\n stderr: [...globalCollectorStderr], // Return a copy\r\n };\r\n}\r\n\r\n/**\r\n * Discovers or starts the collector and returns the OTLP endpoint\r\n */\r\nexport async function discoverOrStartCollector(\r\n logger: Logger,\r\n standardOtelEnabled: boolean,\r\n env?: EnvironmentConfig\r\n): Promise<string | null> {\r\n if (!standardOtelEnabled) {\r\n return null;\r\n }\r\n \r\n // CRITICAL: Check if collector startup is already in progress\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n // (e.g., if setupCollectorBeforeLogging times out but the promise is still running)\r\n if (globalCollectorStartupPromise) {\r\n logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');\r\n try {\r\n const result = await globalCollectorStartupPromise;\r\n // Clear the promise after it completes (success or failure)\r\n globalCollectorStartupPromise = null;\r\n return result;\r\n } catch (error) {\r\n logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);\r\n // Clear the promise so we can retry\r\n globalCollectorStartupPromise = null;\r\n // Fall through to start a new one\r\n }\r\n }\r\n \r\n // CRITICAL: Check if we already have a collector process starting/running\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n let existingEndpoint: string | undefined;\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n logger.info(`[Collector] Collector process already exists (PID ${globalCollectorProcess.pid}), waiting for it to be ready...`);\r\n // Use the configured endpoint from environment (we started it earlier)\r\n existingEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT ? \r\n `http://${process.env.BEAM_OTLP_HTTP_ENDPOINT}` : \r\n 'http://0.0.0.0:4318';\r\n // Fall through to the wait logic below (don't start a new collector)\r\n } else {\r\n // Process is dead, clear it and start fresh\r\n logger.warn(`[Collector] Previous collector process (PID ${globalCollectorProcess.pid}) is dead, starting new one...`);\r\n globalCollectorProcess = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n }\r\n }\r\n \r\n // First, check if collector is already running (via UDP discovery)\r\n // Skip UDP discovery if we already have a process reference (faster)\r\n if (!globalCollectorProcess) {\r\n logger.info('[Collector] Checking for existing collector via UDP discovery (timeout: 2s)...');\r\n const udpStartTime = Date.now();\r\n const status = await isCollectorRunning();\r\n const udpElapsed = Date.now() - udpStartTime;\r\n logger.info(`[Collector] UDP discovery completed in ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);\r\n if (status.isRunning && status.isReady && status.otlpEndpoint) {\r\n logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);\r\n return `http://${status.otlpEndpoint}`;\r\n }\r\n logger.info('[Collector] No existing collector found, will start new one...');\r\n } else {\r\n logger.info('[Collector] Collector process already exists, skipping UDP discovery...');\r\n }\r\n \r\n // Collector not running - start it (or wait for existing one to be ready)\r\n // Wrap the entire startup logic in a promise that we track globally\r\n // This prevents duplicate starts if this function is called multiple times\r\n logger.info('[Collector] Creating startup promise...');\r\n const startupPromise = (async (): Promise<string | null> => {\r\n logger.info('[Collector] Startup promise executing...');\r\n try {\r\n // Clear any previous init error\r\n globalCollectorInitError = null;\r\n logger.info(`[Collector] Checking existingEndpoint: ${existingEndpoint || 'none'}`);\r\n \r\n let endpoint: string;\r\n if (existingEndpoint) {\r\n // Collector already starting, just wait for it to be ready\r\n endpoint = existingEndpoint;\r\n logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);\r\n } else {\r\n // Start a new collector\r\n logger.info('[Collector] Starting new OpenTelemetry collector...');\r\n const startCollectorTime = Date.now();\r\n const startResult = await startCollector(logger, undefined, env);\r\n const startCollectorElapsed = Date.now() - startCollectorTime;\r\n logger.info(`[Collector] Collector process started in ${startCollectorElapsed}ms, endpoint: ${startResult.endpoint}`);\r\n endpoint = startResult.endpoint;\r\n \r\n // Check if collector process exited immediately (crashed)\r\n logger.info('[Collector] Checking if collector process is still running...');\r\n await new Promise(resolve => setTimeout(resolve, 200));\r\n \r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n logger.info('[Collector] Collector process is still running, proceeding to readiness check...');\r\n }\r\n \r\n // CRITICAL: Wait for collector to be fully ready before returning\r\n // We'll wait up to 60 seconds, checking every 500ms\r\n // This ensures the collector is actually ready to receive logs before we continue\r\n const maxWaitTime = 60000; // 60 seconds\r\n const checkInterval = 500; // Check every 500ms\r\n const maxChecks = Math.floor(maxWaitTime / checkInterval);\r\n \r\n logger.info(`[Collector] Waiting for collector to become ready (checking every ${checkInterval}ms, max ${maxWaitTime / 1000}s)...`);\r\n const readinessStartTime = Date.now();\r\n \r\n for (let i = 0; i < maxChecks; i++) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n const elapsed = Date.now() - readinessStartTime;\r\n \r\n // Check if process exited during wait\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg} (after ${elapsed}ms)`);\r\n return null;\r\n }\r\n \r\n logger.info(`[Collector] Checking collector readiness... (${(elapsed / 1000).toFixed(1)}s elapsed, attempt ${i + 1}/${maxChecks})`);\r\n const newStatus = await isCollectorRunning();\r\n logger.info(`[Collector] Collector status: isRunning=${newStatus.isRunning}, isReady=${newStatus.isReady}, pid=${newStatus.pid}, endpoint=${newStatus.otlpEndpoint || 'none'}`);\r\n \r\n if (newStatus.isRunning && newStatus.isReady) {\r\n logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint} (ready after ${elapsed}ms)`);\r\n return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;\r\n }\r\n \r\n // Log progress every second (every 2 checks)\r\n if (i > 0 && i % 2 === 0) {\r\n logger.info(`[Collector] Still waiting for collector to become ready... (${(elapsed / 1000).toFixed(1)}s elapsed)`);\r\n }\r\n }\r\n \r\n // Check one more time if process exited\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n \r\n // Collector did not become ready within timeout\r\n logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);\r\n return null;\r\n } catch (err) {\r\n const errorMsg = err instanceof Error ? err.message : String(err);\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] Failed to start collector: ${errorMsg}`);\r\n return null;\r\n }\r\n })();\r\n \r\n // Store the promise globally so other calls to this function can wait for it\r\n globalCollectorStartupPromise = startupPromise;\r\n \r\n // Clear the promise when it completes (so we don't keep waiting on old promises)\r\n startupPromise.finally(() => {\r\n globalCollectorStartupPromise = null;\r\n });\r\n \r\n return await startupPromise;\r\n}\r\n\r\n"]}
|
|
1
|
+
{"version":3,"file":"collector-manager.js","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, ChildProcess } from 'child_process';\r\nimport { createWriteStream, existsSync, chmodSync, mkdirSync } from 'fs';\r\nimport { join, dirname } from 'path';\r\nimport { pipeline } from 'stream/promises';\r\nimport { createGunzip } from 'zlib';\r\nimport { createHash } from 'node:crypto';\r\nimport { createServer } from 'net';\r\nimport type { Logger } from 'pino';\r\nimport pino from 'pino';\r\nimport dgram from 'dgram';\r\nimport deasync from 'deasync';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl } from './utils/urls.js';\r\n\r\n// Protocol is httpprotobuf \r\n\r\ninterface CollectorDiscoveryEntry {\r\n version: string;\r\n status: string;\r\n pid: number;\r\n otlpEndpoint: string;\r\n}\r\n\r\nexport interface CollectorStatus {\r\n isRunning: boolean;\r\n isReady: boolean;\r\n pid: number;\r\n otlpEndpoint?: string;\r\n version?: string;\r\n}\r\n\r\nconst COLLECTOR_VERSION = '1.0.1'; // Match C# collector version (from collector-version.json)\r\nconst COLLECTOR_DOWNLOAD_BASE = `https://collectors.beamable.com/version/${COLLECTOR_VERSION}`;\r\nconst DISCOVERY_PORT = parseInt(process.env.BEAM_COLLECTOR_DISCOVERY_PORT || '8688', 10);\r\n\r\n/**\r\n * Finds a free TCP port (matching C# PortUtil.FreeTcpPort())\r\n */\r\nfunction findFreePort(): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const server = createServer();\r\n server.listen(0, () => {\r\n const address = server.address();\r\n const port = typeof address === 'object' && address !== null ? address.port : 0;\r\n server.close(() => {\r\n if (port > 0) {\r\n resolve(port);\r\n } else {\r\n // Fallback to a default port if something went wrong\r\n resolve(9090);\r\n }\r\n });\r\n });\r\n server.on('error', (err) => {\r\n reject(err);\r\n });\r\n });\r\n}\r\n\r\n// Global storage for collector process and errors (to prevent GC and track status)\r\nlet globalCollectorProcess: ChildProcess | null = null;\r\nlet globalCollectorStartError: string | null = null;\r\nlet globalCollectorExitCode: number | null = null;\r\nlet globalCollectorStderr: string[] = [];\r\n// Track if collector startup is in progress to prevent duplicate starts\r\nlet globalCollectorStartupPromise: Promise<string | null> | null = null;\r\nlet globalCollectorInitError: string | null = null; // Tracks errors from discoverOrStartCollector\r\n\r\n/**\r\n * ClickHouse credentials response from Beamable API\r\n */\r\ninterface ClickHouseCredentials {\r\n endpoint: string;\r\n expiresAt?: string;\r\n password: string;\r\n username: string;\r\n}\r\n\r\n/**\r\n * Calculates Beamable signature for signed requests\r\n * Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64\r\n * Matches C# SignedRequesterHelper.CalculateSignature\r\n */\r\nfunction calculateSignature(\r\n pid: string,\r\n secret: string,\r\n uriPathAndQuery: string,\r\n body: string | null = null,\r\n version: string = '1'\r\n): string {\r\n let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;\r\n if (body) {\r\n dataToSign += body;\r\n }\r\n \r\n // MD5 hash to Base64 (matching C# implementation)\r\n const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');\r\n return hash;\r\n}\r\n\r\n/**\r\n * Extracts path and query from a URL\r\n */\r\nfunction getPathAndQuery(url: string): string {\r\n try {\r\n const urlObj = new URL(url);\r\n return urlObj.pathname + urlObj.search;\r\n } catch {\r\n // If URL parsing fails, return as-is\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * Fetches ClickHouse credentials from Beamable API\r\n * GET /api/beamo/otel/auth/writer/config\r\n * Requires signed request authentication (X-BEAM-SIGNATURE header)\r\n */\r\nexport async function fetchClickHouseCredentials(\r\n env: EnvironmentConfig\r\n): Promise<ClickHouseCredentials> {\r\n const apiUrl = hostToHttpUrl(env.host);\r\n const uriPath = '/api/beamo/otel/auth/writer/config';\r\n const configUrl = new URL(uriPath, apiUrl).toString();\r\n \r\n // Create a minimal logger for verbose output\r\n const verboseLogger = pino({ name: 'fetch-credentials', level: 'info' }, process.stdout);\r\n verboseLogger.info(`[Credentials] Starting credential fetch from ${configUrl}...`);\r\n \r\n // Get secret from environment (required for signed requests)\r\n const secret = process.env.SECRET;\r\n if (!secret) {\r\n verboseLogger.error('[Credentials] SECRET environment variable is missing');\r\n throw new Error('SECRET environment variable is required to fetch ClickHouse credentials');\r\n }\r\n verboseLogger.info('[Credentials] SECRET found, calculating signature...');\r\n \r\n // Calculate signature for signed request (matching C# HttpSignedRequester)\r\n const pathAndQuery = getPathAndQuery(uriPath);\r\n const signature = calculateSignature(env.pid, secret, pathAndQuery, null, '1');\r\n verboseLogger.info('[Credentials] Signature calculated, making API request...');\r\n \r\n // Build headers with signed authentication (matching C# HttpSignedRequester)\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,\r\n 'X-BEAM-SIGNATURE': signature,\r\n };\r\n \r\n const fetchStartTime = Date.now();\r\n const response = await fetch(configUrl, {\r\n method: 'GET',\r\n headers,\r\n });\r\n const fetchElapsed = Date.now() - fetchStartTime;\r\n verboseLogger.info(`[Credentials] API request completed in ${fetchElapsed}ms, status: ${response.status}`);\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'Unknown error');\r\n verboseLogger.error(`[Credentials] API request failed: ${response.status} ${response.statusText}`);\r\n throw new Error(`Failed to fetch ClickHouse credentials from ${configUrl}: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);\r\n }\r\n \r\n verboseLogger.info('[Credentials] Parsing response JSON...');\r\n const credentials = await response.json() as ClickHouseCredentials;\r\n \r\n if (!credentials.endpoint || !credentials.username || !credentials.password) {\r\n verboseLogger.error('[Credentials] Invalid response: missing required fields');\r\n throw new Error('Invalid ClickHouse credentials response: missing required fields');\r\n }\r\n \r\n verboseLogger.info(`[Credentials] Successfully fetched credentials (endpoint: ${credentials.endpoint}, username: ${credentials.username})`);\r\n return credentials;\r\n}\r\n\r\n/**\r\n * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)\r\n * Checks production location first (pre-installed in Docker), then falls back to temp directory\r\n */\r\nfunction getCollectorStoragePath(): string {\r\n // Check production location first (pre-installed in Docker image at /opt/beam/collectors)\r\n // This avoids runtime download delays (~12 seconds)\r\n const productionPath = '/opt/beam/collectors';\r\n const productionVersionPath = join(productionPath, COLLECTOR_VERSION);\r\n \r\n // Use production path if it exists (Docker image pre-installed collector)\r\n if (existsSync(productionPath)) {\r\n return productionVersionPath;\r\n }\r\n \r\n // Fallback to temp directory (local development without Docker)\r\n const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';\r\n return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);\r\n}\r\n\r\n/**\r\n * Gets the collector binary name for the current platform\r\n */\r\nfunction getCollectorBinaryName(): string {\r\n const platform = process.platform;\r\n const arch = process.arch;\r\n \r\n // Match C# naming: collector-{osArchSuffix}\r\n // C# returns \"collector-linux-amd64\", not \"beamable-collector-linux-amd64\"\r\n if (platform === 'linux' && arch === 'x64') {\r\n return 'collector-linux-amd64';\r\n } else if (platform === 'linux' && arch === 'arm64') {\r\n return 'collector-linux-arm64';\r\n } else if (platform === 'darwin' && arch === 'x64') {\r\n return 'collector-darwin-amd64';\r\n } else if (platform === 'darwin' && arch === 'arm64') {\r\n return 'collector-darwin-arm64';\r\n } else if (platform === 'win32' && arch === 'x64') {\r\n return 'collector-windows-amd64.exe';\r\n }\r\n \r\n throw new Error(`Unsupported platform: ${platform} ${arch}`);\r\n}\r\n\r\n/**\r\n * Downloads and decompresses a gzipped file\r\n */\r\nasync function downloadAndDecompressGzip(url: string, outputPath: string, makeExecutable: boolean = false): Promise<void> {\r\n let response: Response;\r\n try {\r\n // Add timeout and better error handling\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout\r\n \r\n try {\r\n response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n 'User-Agent': 'Beamable-Node-Microservice-Runtime/1.0',\r\n },\r\n });\r\n clearTimeout(timeoutId);\r\n } catch (fetchError) {\r\n clearTimeout(timeoutId);\r\n if (fetchError instanceof Error) {\r\n // Extract underlying error details from cause\r\n let underlyingError = '';\r\n if ((fetchError as any).cause) {\r\n const cause = (fetchError as any).cause;\r\n if (cause instanceof Error) {\r\n const causeCode = (cause as any).code;\r\n underlyingError = ` (cause: ${cause.name} - ${cause.message}${causeCode ? ` [code: ${causeCode}]` : ''})`;\r\n } else if (typeof cause === 'object' && cause.code) {\r\n underlyingError = ` (cause code: ${cause.code})`;\r\n }\r\n }\r\n \r\n // Provide more context about the error\r\n if (fetchError.name === 'AbortError') {\r\n throw new Error(`Timeout downloading ${url} (30s limit exceeded)${underlyingError}`);\r\n }\r\n \r\n // Check error code if available (Node.js system errors)\r\n const errorCode = (fetchError as any).code || ((fetchError as any).cause?.code);\r\n if (errorCode) {\r\n if (errorCode === 'ENOTFOUND' || errorCode === 'EAI_AGAIN') {\r\n throw new Error(`DNS resolution failed for ${url} (code: ${errorCode}). Check network connectivity and DNS settings.`);\r\n }\r\n if (errorCode === 'ECONNREFUSED') {\r\n throw new Error(`Connection refused to ${url} (code: ${errorCode}). Server may be down or firewall blocking.`);\r\n }\r\n if (errorCode === 'ETIMEDOUT' || errorCode === 'ECONNRESET') {\r\n throw new Error(`Connection timeout/reset to ${url} (code: ${errorCode}). Network may be slow or unreachable.`);\r\n }\r\n if (errorCode === 'CERT_HAS_EXPIRED' || errorCode === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\r\n throw new Error(`SSL/TLS certificate error connecting to ${url} (code: ${errorCode}): ${fetchError.message}`);\r\n }\r\n }\r\n \r\n // Check for common network errors in message\r\n const errorMsg = fetchError.message.toLowerCase();\r\n if (errorMsg.includes('enotfound') || errorMsg.includes('dns')) {\r\n throw new Error(`DNS resolution failed for ${url}. Check network connectivity and DNS settings.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('econnrefused') || errorMsg.includes('connection refused')) {\r\n throw new Error(`Connection refused to ${url}. Server may be down or firewall blocking.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('etimedout') || errorMsg.includes('timeout')) {\r\n throw new Error(`Connection timeout to ${url}. Network may be slow or unreachable.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('certificate') || errorMsg.includes('ssl') || errorMsg.includes('tls')) {\r\n throw new Error(`SSL/TLS error connecting to ${url}: ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${fetchError.name} - ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(fetchError)}`);\r\n }\r\n } catch (error) {\r\n // Re-throw with more context\r\n if (error instanceof Error) {\r\n if (error.message.includes('Timeout') || error.message.includes('DNS') || error.message.includes('Connection')) {\r\n throw error; // Already has good context\r\n }\r\n throw new Error(`Network error downloading ${url}: ${error.message}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(error)}`);\r\n }\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => '');\r\n throw new Error(`HTTP ${response.status} downloading ${url}: ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`);\r\n }\r\n \r\n const dir = dirname(outputPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n const gunzip = createGunzip();\r\n const writeStream = createWriteStream(outputPath);\r\n \r\n await pipeline(response.body as any, gunzip, writeStream);\r\n \r\n if (makeExecutable && process.platform !== 'win32') {\r\n try {\r\n chmodSync(outputPath, 0o755);\r\n } catch (error) {\r\n console.error(`Failed to make ${outputPath} executable:`, error);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolves the collector binary and config, downloading if needed\r\n */\r\nasync function resolveCollector(allowDownload: boolean = true, logger?: Logger): Promise<{ binaryPath: string | null; configPath: string | null }> {\r\n const basePath = getCollectorStoragePath();\r\n const binaryName = getCollectorBinaryName();\r\n const configName = 'clickhouse-config.yaml';\r\n \r\n const binaryPath = join(basePath, binaryName);\r\n const configPath = join(basePath, configName);\r\n \r\n const itemsToDownload: Array<{ url: string; path: string; executable: boolean }> = [];\r\n \r\n if (!existsSync(binaryPath) && allowDownload) {\r\n const binaryUrl = `${COLLECTOR_DOWNLOAD_BASE}/${binaryName}.gz`;\r\n itemsToDownload.push({ url: binaryUrl, path: binaryPath, executable: true });\r\n logger?.info(`[Collector] Will download binary from: ${binaryUrl}`);\r\n } else if (existsSync(binaryPath)) {\r\n logger?.info(`[Collector] Binary found at: ${binaryPath}`);\r\n }\r\n \r\n if (!existsSync(configPath) && allowDownload) {\r\n const configUrl = `${COLLECTOR_DOWNLOAD_BASE}/${configName}.gz`;\r\n itemsToDownload.push({ url: configUrl, path: configPath, executable: false });\r\n logger?.info(`[Collector] Will download config from: ${configUrl}`);\r\n } else if (existsSync(configPath)) {\r\n logger?.info(`[Collector] Config found at: ${configPath}`);\r\n }\r\n \r\n // Download items in parallel for faster startup (binary and config simultaneously)\r\n if (itemsToDownload.length > 0) {\r\n logger?.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);\r\n const downloadPromises = itemsToDownload.map(async (item) => {\r\n try {\r\n logger?.info(`[Collector] Downloading ${item.url}...`);\r\n await downloadAndDecompressGzip(item.url, item.path, item.executable);\r\n logger?.info(`[Collector] Downloaded to ${item.path}`);\r\n } catch (error) {\r\n // Don't wrap the error again if it already contains the URL and details\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);\r\n // Only wrap if the error doesn't already contain the URL\r\n if (error instanceof Error && errorMsg.includes(item.url)) {\r\n throw error; // Error already has URL and context\r\n }\r\n throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);\r\n }\r\n });\r\n \r\n // Wait for all downloads to complete (or fail)\r\n await Promise.all(downloadPromises);\r\n }\r\n \r\n return {\r\n binaryPath: existsSync(binaryPath) ? binaryPath : null,\r\n configPath: existsSync(configPath) ? configPath : null,\r\n };\r\n}\r\n\r\n/**\r\n * Discovers collector via UDP broadcast\r\n */\r\nfunction discoverCollectorViaUDP(timeoutMs: number = 1000): Promise<CollectorDiscoveryEntry | null> {\r\n return new Promise((resolve) => {\r\n const socket = dgram.createSocket('udp4');\r\n const discovered: CollectorDiscoveryEntry[] = [];\r\n let timeout: NodeJS.Timeout;\r\n let resolved = false; // Guard to prevent double resolution\r\n const startTime = Date.now();\r\n \r\n // Safety timeout - force resolve after timeout + 100ms buffer\r\n const safetyTimeout = setTimeout(() => {\r\n if (!resolved) {\r\n console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);\r\n resolved = true;\r\n try {\r\n socket.removeAllListeners();\r\n socket.close();\r\n } catch (e) {\r\n // Ignore\r\n }\r\n clearTimeout(timeout);\r\n resolve(discovered.length > 0 ? discovered[0] : null);\r\n }\r\n }, timeoutMs + 100);\r\n \r\n const doResolve = (result: CollectorDiscoveryEntry | null) => {\r\n if (!resolved) {\r\n resolved = true;\r\n clearTimeout(timeout);\r\n clearTimeout(safetyTimeout);\r\n try {\r\n socket.removeAllListeners();\r\n socket.close();\r\n } catch (e) {\r\n // Ignore\r\n }\r\n console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);\r\n resolve(result);\r\n }\r\n };\r\n \r\n socket.on('message', (msg) => {\r\n try {\r\n const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;\r\n // Check if version matches\r\n if (message.version === COLLECTOR_VERSION && message.status === 'READY') {\r\n discovered.push(message);\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);\r\n // Resolve immediately when collector found\r\n doResolve(discovered[0]);\r\n }\r\n } catch (error) {\r\n // Ignore parse errors\r\n }\r\n });\r\n \r\n socket.on('error', (err) => {\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);\r\n doResolve(null);\r\n });\r\n \r\n socket.bind(() => {\r\n socket.setBroadcast(true);\r\n console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);\r\n \r\n timeout = setTimeout(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (discovered.length > 0) {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);\r\n } else {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);\r\n }\r\n doResolve(discovered.length > 0 ? discovered[0] : null);\r\n }, timeoutMs);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Gets the current status of ClickHouse credentials (from env or API)\r\n */\r\nexport function getClickHouseCredentialsStatus(): {\r\n hasEndpoint: boolean;\r\n hasUsername: boolean;\r\n hasPassword: boolean;\r\n source: 'environment' | 'api' | 'missing';\r\n} {\r\n const hasEndpoint = !!process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const hasUsername = !!process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const hasPassword = !!process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (hasEndpoint && hasUsername && hasPassword) {\r\n return {\r\n hasEndpoint: true,\r\n hasUsername: true,\r\n hasPassword: true,\r\n source: 'environment',\r\n };\r\n }\r\n \r\n return {\r\n hasEndpoint,\r\n hasUsername,\r\n hasPassword,\r\n source: 'missing',\r\n };\r\n}\r\n\r\n/**\r\n * Checks if collector is already running via UDP discovery\r\n */\r\nexport async function isCollectorRunning(): Promise<CollectorStatus> {\r\n // First, check if we have a global collector process reference\r\n // If the process is running and we've seen \"Everything is ready\" in stderr, it's ready\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n try {\r\n // Process is alive if we can access it and it hasn't exited\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n // Check if we've seen the \"Everything is ready\" message in stderr\r\n // This is a reliable indicator that the collector is ready\r\n const stderrText = globalCollectorStderr.join('\\n');\r\n const isReady = stderrText.includes('Everything is ready') || \r\n stderrText.includes('Begin running and processing data');\r\n \r\n if (isReady) {\r\n // Try UDP discovery to get the endpoint, but if it fails, use the configured endpoint\r\n try {\r\n const discovered = await discoverCollectorViaUDP(1000); // Shorter timeout since we know it's running\r\n if (discovered && discovered.status === 'READY') {\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: discovered.pid || globalCollectorProcess.pid || 0,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n }\r\n } catch {\r\n // UDP discovery failed, but process is alive and has \"Everything is ready\" message\r\n // Use the configured endpoint as fallback\r\n }\r\n \r\n // Process is alive and we've seen \"Everything is ready\" - treat as ready\r\n // Extract endpoint from environment or use default\r\n const configuredEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT || '0.0.0.0:4318';\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: globalCollectorProcess.pid || 0,\r\n otlpEndpoint: configuredEndpoint,\r\n version: COLLECTOR_VERSION,\r\n };\r\n }\r\n }\r\n } catch {\r\n // Process might have exited or is invalid\r\n }\r\n }\r\n \r\n // Try UDP discovery as fallback\r\n try {\r\n const udpStartTime = Date.now();\r\n console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');\r\n console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');\r\n const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)\r\n const udpElapsed = Date.now() - udpStartTime;\r\n console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);\r\n if (discovered) {\r\n console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);\r\n return {\r\n isRunning: true,\r\n isReady: discovered.status === 'READY',\r\n pid: discovered.pid,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n } else {\r\n console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);\r\n }\r\n } catch (error) {\r\n // Discovery failed, collector probably not running\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);\r\n if (error instanceof Error && error.stack) {\r\n console.log(`[UDP Discovery] Error stack: ${error.stack}`);\r\n }\r\n }\r\n \r\n console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');\r\n return {\r\n isRunning: false,\r\n isReady: false,\r\n pid: 0,\r\n };\r\n}\r\n\r\n/**\r\n * Sets default collector configuration environment variables in process.env\r\n * Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n */\r\nfunction addCollectorConfigurationToEnvironment(): void {\r\n const defaults: Record<string, string> = {\r\n BEAM_CLICKHOUSE_PROCESSOR_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_PROCESSOR_BATCH_SIZE: '5000',\r\n BEAM_CLICKHOUSE_EXPORTER_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_QUEUE_SIZE: '1000',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_ENABLED: 'true',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_INITIAL_INTERVAL: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_INTERVAL: '30s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_ELAPSED_TIME: '300s',\r\n };\r\n \r\n // Only set if not already set (matching C# behavior)\r\n for (const [key, defaultValue] of Object.entries(defaults)) {\r\n if (!process.env[key]) {\r\n process.env[key] = defaultValue;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Sets ClickHouse credentials in process.env (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n */\r\nexport function addAuthEnvironmentVars(endpoint: string, username: string, password: string): void {\r\n // Always set the values when explicitly provided (matching C# behavior)\r\n // This ensures credentials fetched from API override any existing (potentially empty) values\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n process.env.BEAM_CLICKHOUSE_ENDPOINT = endpoint;\r\n process.env.BEAM_CLICKHOUSE_USERNAME = username;\r\n process.env.BEAM_CLICKHOUSE_PASSWORD = password;\r\n \r\n // Verify they were actually set (for debugging)\r\n if (!process.env.BEAM_CLICKHOUSE_ENDPOINT || !process.env.BEAM_CLICKHOUSE_USERNAME || !process.env.BEAM_CLICKHOUSE_PASSWORD) {\r\n throw new Error(`Failed to set ClickHouse credentials in process.env - this should never happen in Node.js`);\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector and waits for it to be ready before returning.\r\n * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.\r\n * Returns the OTLP endpoint when ready, or null if it times out or fails.\r\n */\r\nexport async function startCollectorAndWaitForReady(\r\n env: EnvironmentConfig,\r\n _timeoutMs?: number // Not used - kept for API compatibility\r\n): Promise<string | null> {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');\r\n const setupStartTime = Date.now();\r\n\r\n // Simple linear async/await - no timeouts, no Promise.race complexity\r\n try {\r\n initLogger.info('[OTLP] Step 1: Discovering or starting collector...');\r\n const endpoint = await discoverOrStartCollector(initLogger, standardOtelEnabled, env);\r\n const elapsed = Date.now() - setupStartTime;\r\n \r\n if (endpoint) {\r\n initLogger.info(`[OTLP] Collector ready at ${endpoint}. Portal logs now enabled. (took ${elapsed}ms)`);\r\n return endpoint;\r\n } else {\r\n initLogger.warn(`[OTLP] Collector setup failed, continuing without Portal logs. (took ${elapsed}ms)`);\r\n return null;\r\n }\r\n } catch (error) {\r\n const elapsed = Date.now() - setupStartTime;\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Collector setup failed after ${elapsed}ms: ${errorMsg}`);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector asynchronously in the background (non-blocking).\r\n * This allows the service to start immediately while collector downloads/starts.\r\n * Returns immediately - collector setup happens in background.\r\n * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready\r\n */\r\nexport function startCollectorAsync(env: EnvironmentConfig): void {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');\r\n\r\n // Start collector setup asynchronously - don't wait for it\r\n // The service can start immediately, collector will connect when ready\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);\r\n // Update the global logger provider if it exists to enable OTLP\r\n // The logger will automatically start using OTLP once the provider is set\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n })\r\n .catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);\r\n });\r\n \r\n // Return immediately - service can start serving requests\r\n}\r\n\r\n/**\r\n * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).\r\n * This function is kept for backwards compatibility but is no longer recommended.\r\n * Use startCollectorAsync() for non-blocking startup instead.\r\n * @deprecated Use startCollectorAsync() for non-blocking startup\r\n */\r\nexport function setupCollectorBeforeLogging(\r\n env: EnvironmentConfig,\r\n timeoutMs: number = 60000\r\n): string | null {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector before logging initialization...');\r\n\r\n // Use deasync to wait synchronously for collector setup\r\n let endpoint: string | null = null;\r\n let completed = false;\r\n let setupError: string | null = null;\r\n\r\n // Start collector setup promise\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n endpoint = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete, endpoint: ${result}`);\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n return result;\r\n })\r\n .catch((error) => {\r\n setupError = error instanceof Error ? error.message : String(error);\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to setup collector: ${setupError}`);\r\n endpoint = null;\r\n });\r\n\r\n // Wait synchronously for collector setup to complete\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n\r\n try {\r\n // Use deasync to wait for completion (allows event loop to process async operations)\r\n deasync.loopWhile(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n return false; // Stop waiting\r\n }\r\n return !completed; // Continue waiting if not completed\r\n });\r\n } catch (error) {\r\n initLogger.error(`[OTLP] Error during collector setup wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (completed && endpoint) {\r\n initLogger.info('[OTLP] Collector is ready, proceeding with logger creation');\r\n return endpoint;\r\n } else if (setupError) {\r\n initLogger.error(`[OTLP] Collector setup failed: ${setupError}, continuing without OTLP`);\r\n return null;\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup did not complete in time, continuing without OTLP');\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the OpenTelemetry collector process\r\n */\r\nexport async function startCollector(\r\n logger: Logger,\r\n otlpEndpoint?: string,\r\n env?: EnvironmentConfig\r\n): Promise<{ process: ChildProcess; endpoint: string }> {\r\n logger.info('[Collector] === startCollector() ENTERED ===');\r\n // Clear any previous errors\r\n globalCollectorStartError = null;\r\n globalCollectorInitError = null;\r\n \r\n // CRITICAL: Fetch credentials FIRST, before resolving collector binary/config\r\n // This ensures credentials are in process.env even if collector download fails\r\n // The credentials will persist in process.env for the lifetime of the process.\r\n // Per Gabriel: \"these OTEL related ones you need to do it yourself at the beginning of the microservice startup\"\r\n let clickhouseEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n let clickhouseUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n let clickhousePassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if ((!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) && env) {\r\n try {\r\n logger.info('[Collector] Fetching ClickHouse credentials from Beamable API...');\r\n const credStartTime = Date.now();\r\n const credentials = await fetchClickHouseCredentials(env);\r\n const credElapsed = Date.now() - credStartTime;\r\n logger.info(`[Collector] ClickHouse credentials fetch completed in ${credElapsed}ms`);\r\n clickhouseEndpoint = credentials.endpoint;\r\n clickhouseUsername = credentials.username;\r\n clickhousePassword = credentials.password;\r\n \r\n // CRITICAL: Set them in process.env IMMEDIATELY after fetching (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n // This ensures they're available to both the Node.js process and inherited by the collector child process\r\n addAuthEnvironmentVars(clickhouseEndpoint, clickhouseUsername, clickhousePassword);\r\n \r\n // Verify they were set (defensive check - should never fail in Node.js)\r\n const verifyEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const verifyUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const verifyPassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (!verifyEndpoint || !verifyUsername || !verifyPassword) {\r\n logger.error(`[Collector] CRITICAL: Credentials were set but are missing from process.env! This should never happen.`);\r\n throw new Error('Failed to persist ClickHouse credentials in process.env');\r\n }\r\n \r\n logger.info('[Collector] ClickHouse credentials fetched from API and verified in process.env');\r\n } catch (error) {\r\n const errorMsg = `[Collector] Failed to fetch ClickHouse credentials from API: ${error instanceof Error ? error.message : String(error)}`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n }\r\n \r\n // Validate required environment variables (matching C# behavior)\r\n // These must be set before starting the collector, otherwise it will fail\r\n if (!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) {\r\n const errorMsg = `[Collector] Required ClickHouse credentials are missing. Set BEAM_CLICKHOUSE_ENDPOINT, BEAM_CLICKHOUSE_USERNAME, and BEAM_CLICKHOUSE_PASSWORD, or ensure the API endpoint is accessible.`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n \r\n // Now resolve collector binary and config (after credentials are fetched and set)\r\n logger.info('[Collector] Step 2: Resolving collector binary and config...');\r\n const resolveStartTime = Date.now();\r\n const collectorInfo = await resolveCollector(true, logger);\r\n const resolveElapsed = Date.now() - resolveStartTime;\r\n logger.info(`[Collector] Collector binary/config resolution completed in ${resolveElapsed}ms`);\r\n \r\n if (!collectorInfo.binaryPath) {\r\n logger.error('[Collector] Binary not found and download failed');\r\n throw new Error('Collector binary not found and download failed');\r\n }\r\n \r\n if (!collectorInfo.configPath) {\r\n logger.error('[Collector] Config not found and download failed');\r\n throw new Error('Collector config not found and download failed');\r\n }\r\n \r\n logger.info(`[Collector] Using binary: ${collectorInfo.binaryPath}`);\r\n logger.info(`[Collector] Using config: ${collectorInfo.configPath}`);\r\n \r\n // Verify binary exists\r\n if (!collectorInfo.binaryPath || !existsSync(collectorInfo.binaryPath)) {\r\n throw new Error(`Collector binary not found at ${collectorInfo.binaryPath}`);\r\n }\r\n \r\n // Check if binary is executable (Unix only - Windows doesn't have execute permission)\r\n if (process.platform !== 'win32') {\r\n try {\r\n const fsPromises = await import('fs/promises');\r\n const stats = await fsPromises.stat(collectorInfo.binaryPath);\r\n const mode = Number(stats.mode);\r\n const isExecutable = !!(mode & parseInt('111', 8)); // Check execute bit\r\n if (!isExecutable) {\r\n logger.warn(`[Collector] Binary may not be executable. Mode: ${mode.toString(8)}`);\r\n // Try to make it executable again\r\n try {\r\n chmodSync(collectorInfo.binaryPath, 0o755);\r\n logger.info(`[Collector] Made binary executable`);\r\n } catch (chmodError) {\r\n logger.error(`[Collector] Failed to make binary executable: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}`);\r\n }\r\n }\r\n } catch (statError) {\r\n logger.warn(`[Collector] Could not check binary permissions: ${statError instanceof Error ? statError.message : String(statError)}`);\r\n }\r\n }\r\n\r\n // Set default collector configuration environment variables in process.env\r\n // This ensures they're available to both the Node.js process and the collector child process\r\n // Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n addCollectorConfigurationToEnvironment();\r\n \r\n // CRITICAL: Set BEAM_COLLECTOR_DISCOVERY_PORT if not already set (matching C# AddDefaultCollectorHostAndPortFallback)\r\n // This MUST be set before starting the collector\r\n if (!process.env.BEAM_COLLECTOR_DISCOVERY_PORT) {\r\n process.env.BEAM_COLLECTOR_DISCOVERY_PORT = String(DISCOVERY_PORT);\r\n logger.info(`[Collector] Set BEAM_COLLECTOR_DISCOVERY_PORT=${DISCOVERY_PORT} (default)`);\r\n }\r\n \r\n // Determine OTLP endpoint\r\n // Use a free port if not specified (like C# does with PortUtil.FreeEndpoint())\r\n let localEndpoint = otlpEndpoint;\r\n if (!localEndpoint) {\r\n // For now, use default OTLP HTTP port\r\n // In production, this would be discovered or set by Beamable\r\n localEndpoint = '0.0.0.0:4318';\r\n }\r\n localEndpoint = localEndpoint.replace(/^http:\\/\\//, '').replace(/^https:\\/\\//, '');\r\n \r\n // Find a free port for Prometheus (matching C# PortUtil.FreeTcpPort())\r\n // We'll use a simple approach: bind to port 0 and let the OS assign a port\r\n // For now, use a default port (9090 is common for Prometheus) or find a free one\r\n // C# uses PortUtil.FreeTcpPort() which finds an available TCP port\r\n // We'll use a simple helper to find a free port\r\n const prometheusPort = await findFreePort();\r\n \r\n // Set environment variables for collector\r\n // Note: BEAM_CLICKHOUSE_ENDPOINT is for collector → ClickHouse communication\r\n // This is different from the OTLP endpoint (microservice → collector)\r\n // The collector process will inherit all environment variables from process.env automatically\r\n // We only need to set the OTLP endpoint, discovery port, and Prometheus port explicitly here\r\n const collectorEnv: NodeJS.ProcessEnv = {\r\n ...process.env, // Inherit all process.env (including credentials and config we just set)\r\n BEAM_OTLP_HTTP_ENDPOINT: localEndpoint,\r\n BEAM_COLLECTOR_DISCOVERY_PORT: String(DISCOVERY_PORT),\r\n BEAM_COLLECTOR_PROMETHEUS_PORT: String(prometheusPort),\r\n };\r\n \r\n // Start collector process\r\n const collectorProcess = spawn(collectorInfo.binaryPath, ['--config', collectorInfo.configPath], {\r\n env: collectorEnv,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n detached: false,\r\n });\r\n \r\n // Store globally to prevent GC and track status\r\n globalCollectorProcess = collectorProcess;\r\n globalCollectorStartError = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n \r\n // Set up handlers BEFORE we check if process started, so we capture all output\r\n collectorProcess.stdout?.on('data', (data) => {\r\n const outputLine = data.toString().trim();\r\n // Log stdout at info level to see collector output\r\n logger.info(`[Collector OUT] ${outputLine}`);\r\n });\r\n \r\n collectorProcess.stderr?.on('data', (data) => {\r\n const errorLine = data.toString().trim();\r\n globalCollectorStderr.push(errorLine);\r\n // Keep only last 50 lines to prevent memory issues\r\n if (globalCollectorStderr.length > 50) {\r\n globalCollectorStderr.shift();\r\n }\r\n // Log stderr at info level so we can see why collector crashes\r\n logger.info(`[Collector ERR] ${errorLine}`);\r\n });\r\n \r\n collectorProcess.on('error', (err) => {\r\n globalCollectorStartError = err.message;\r\n logger.error(`[Collector] Failed to start: ${err.message}`);\r\n });\r\n \r\n collectorProcess.on('exit', (code, signal) => {\r\n globalCollectorExitCode = code;\r\n logger.warn(`[Collector] Process exited with code ${code}${signal ? `, signal ${signal}` : ''}`);\r\n \r\n // If process exited with an error code, log accumulated stderr\r\n if (code !== 0 && globalCollectorStderr.length > 0) {\r\n logger.error(`[Collector] Exit error - Last ${Math.min(10, globalCollectorStderr.length)} stderr lines:`);\r\n globalCollectorStderr.slice(-10).forEach((line) => {\r\n logger.error(`[Collector ERR] ${line}`);\r\n });\r\n }\r\n \r\n // Don't clear reference immediately - keep it for status checks\r\n // globalCollectorProcess = null; // Keep reference for getCollectorProcessStatus()\r\n });\r\n \r\n logger.info(`[Collector] Started with PID ${collectorProcess.pid}, endpoint: ${localEndpoint}`);\r\n \r\n // Give the process a moment to start and potentially write to stderr\r\n // This helps capture immediate startup errors\r\n // Wait a bit longer to ensure we catch immediate crashes\r\n await new Promise(resolve => setTimeout(resolve, 500));\r\n \r\n // Check if process already exited (immediate crash)\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const stderrMsg = globalCollectorStderr.length > 0 \r\n ? ` Stderr: ${globalCollectorStderr.join('; ')}` \r\n : ' No stderr output captured.';\r\n throw new Error(`Collector process exited immediately after startup with code ${globalCollectorExitCode}.${stderrMsg}`);\r\n }\r\n \r\n return {\r\n process: collectorProcess,\r\n endpoint: `http://${localEndpoint}`,\r\n };\r\n}\r\n\r\n/**\r\n * Gets detailed collector status including process info and errors\r\n */\r\nexport function getCollectorProcessStatus(): {\r\n hasProcess: boolean;\r\n pid: number | null;\r\n exitCode: number | null;\r\n startError: string | null;\r\n initError: string | null;\r\n stderr: string[];\r\n} {\r\n return {\r\n hasProcess: globalCollectorProcess !== null,\r\n pid: globalCollectorProcess?.pid ?? null,\r\n exitCode: globalCollectorExitCode,\r\n startError: globalCollectorStartError,\r\n initError: globalCollectorInitError,\r\n stderr: [...globalCollectorStderr], // Return a copy\r\n };\r\n}\r\n\r\n/**\r\n * Discovers or starts the collector and returns the OTLP endpoint\r\n */\r\nexport async function discoverOrStartCollector(\r\n logger: Logger,\r\n standardOtelEnabled: boolean,\r\n env?: EnvironmentConfig\r\n): Promise<string | null> {\r\n if (!standardOtelEnabled) {\r\n return null;\r\n }\r\n \r\n // CRITICAL: Check if collector startup is already in progress\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n // (e.g., if setupCollectorBeforeLogging times out but the promise is still running)\r\n if (globalCollectorStartupPromise) {\r\n logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');\r\n try {\r\n const result = await globalCollectorStartupPromise;\r\n // Clear the promise after it completes (success or failure)\r\n globalCollectorStartupPromise = null;\r\n return result;\r\n } catch (error) {\r\n logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);\r\n // Clear the promise so we can retry\r\n globalCollectorStartupPromise = null;\r\n // Fall through to start a new one\r\n }\r\n }\r\n \r\n // CRITICAL: Check if we already have a collector process starting/running\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n let existingEndpoint: string | undefined;\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n logger.info(`[Collector] Collector process already exists (PID ${globalCollectorProcess.pid}), waiting for it to be ready...`);\r\n // Use the configured endpoint from environment (we started it earlier)\r\n existingEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT ? \r\n `http://${process.env.BEAM_OTLP_HTTP_ENDPOINT}` : \r\n 'http://0.0.0.0:4318';\r\n // Fall through to the wait logic below (don't start a new collector)\r\n } else {\r\n // Process is dead, clear it and start fresh\r\n logger.warn(`[Collector] Previous collector process (PID ${globalCollectorProcess.pid}) is dead, starting new one...`);\r\n globalCollectorProcess = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n }\r\n }\r\n \r\n // First, quick check if collector is already running (via UDP discovery)\r\n // Match C#: 10 attempts × 100ms = 1 second max (much faster than before)\r\n // Skip UDP discovery if we already have a process reference (faster)\r\n if (!globalCollectorProcess) {\r\n logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');\r\n const udpStartTime = Date.now();\r\n logger.info('[Collector] Calling isCollectorRunning()...');\r\n const status = await isCollectorRunning();\r\n const udpElapsed = Date.now() - udpStartTime;\r\n logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);\r\n if (status.isRunning && status.isReady && status.otlpEndpoint) {\r\n logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);\r\n return `http://${status.otlpEndpoint}`;\r\n }\r\n logger.info('[Collector] No existing collector found, will start new one...');\r\n } else {\r\n logger.info('[Collector] Collector process already exists, skipping UDP discovery...');\r\n }\r\n \r\n // Collector not running - start it (or wait for existing one to be ready)\r\n // Wrap the entire startup logic in a promise that we track globally\r\n // This prevents duplicate starts if this function is called multiple times\r\n logger.info('[Collector] Creating startup promise...');\r\n const startupPromise = (async (): Promise<string | null> => {\r\n logger.info('[Collector] Startup promise executing...');\r\n try {\r\n // Clear any previous init error\r\n globalCollectorInitError = null;\r\n logger.info(`[Collector] Checking existingEndpoint: ${existingEndpoint || 'none'}`);\r\n \r\n let endpoint: string;\r\n if (existingEndpoint) {\r\n // Collector already starting, just wait for it to be ready\r\n endpoint = existingEndpoint;\r\n logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);\r\n } else {\r\n // Start a new collector\r\n logger.info('[Collector] Starting new OpenTelemetry collector...');\r\n const startCollectorTime = Date.now();\r\n const startResult = await startCollector(logger, undefined, env);\r\n const startCollectorElapsed = Date.now() - startCollectorTime;\r\n logger.info(`[Collector] Collector process started in ${startCollectorElapsed}ms, endpoint: ${startResult.endpoint}`);\r\n endpoint = startResult.endpoint;\r\n \r\n // Check if collector process exited immediately (crashed)\r\n logger.info('[Collector] Checking if collector process is still running...');\r\n await new Promise(resolve => setTimeout(resolve, 200));\r\n \r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n logger.info('[Collector] Collector process is still running, proceeding to readiness check...');\r\n }\r\n \r\n // CRITICAL: Wait for collector to be fully ready before returning\r\n // We'll wait up to 60 seconds, checking every 500ms\r\n // This ensures the collector is actually ready to receive logs before we continue\r\n const maxWaitTime = 60000; // 60 seconds\r\n const checkInterval = 500; // Check every 500ms\r\n const maxChecks = Math.floor(maxWaitTime / checkInterval);\r\n \r\n logger.info(`[Collector] Waiting for collector to become ready (checking every ${checkInterval}ms, max ${maxWaitTime / 1000}s)...`);\r\n const readinessStartTime = Date.now();\r\n \r\n for (let i = 0; i < maxChecks; i++) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n const elapsed = Date.now() - readinessStartTime;\r\n \r\n // Check if process exited during wait\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg} (after ${elapsed}ms)`);\r\n return null;\r\n }\r\n \r\n logger.info(`[Collector] Checking collector readiness... (${(elapsed / 1000).toFixed(1)}s elapsed, attempt ${i + 1}/${maxChecks})`);\r\n const newStatus = await isCollectorRunning();\r\n logger.info(`[Collector] Collector status: isRunning=${newStatus.isRunning}, isReady=${newStatus.isReady}, pid=${newStatus.pid}, endpoint=${newStatus.otlpEndpoint || 'none'}`);\r\n \r\n if (newStatus.isRunning && newStatus.isReady) {\r\n logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint} (ready after ${elapsed}ms)`);\r\n return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;\r\n }\r\n \r\n // Log progress every second (every 2 checks)\r\n if (i > 0 && i % 2 === 0) {\r\n logger.info(`[Collector] Still waiting for collector to become ready... (${(elapsed / 1000).toFixed(1)}s elapsed)`);\r\n }\r\n }\r\n \r\n // Check one more time if process exited\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n \r\n // Collector did not become ready within timeout\r\n logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);\r\n return null;\r\n } catch (err) {\r\n const errorMsg = err instanceof Error ? err.message : String(err);\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] Failed to start collector: ${errorMsg}`);\r\n return null;\r\n }\r\n })();\r\n \r\n // Store the promise globally so other calls to this function can wait for it\r\n globalCollectorStartupPromise = startupPromise;\r\n \r\n // Clear the promise when it completes (so we don't keep waiting on old promises)\r\n startupPromise.finally(() => {\r\n globalCollectorStartupPromise = null;\r\n });\r\n \r\n return await startupPromise;\r\n}\r\n\r\n"]}
|
package/package.json
CHANGED
package/src/collector-manager.ts
CHANGED
|
@@ -176,9 +176,20 @@ export async function fetchClickHouseCredentials(
|
|
|
176
176
|
|
|
177
177
|
/**
|
|
178
178
|
* Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)
|
|
179
|
+
* Checks production location first (pre-installed in Docker), then falls back to temp directory
|
|
179
180
|
*/
|
|
180
181
|
function getCollectorStoragePath(): string {
|
|
181
|
-
//
|
|
182
|
+
// Check production location first (pre-installed in Docker image at /opt/beam/collectors)
|
|
183
|
+
// This avoids runtime download delays (~12 seconds)
|
|
184
|
+
const productionPath = '/opt/beam/collectors';
|
|
185
|
+
const productionVersionPath = join(productionPath, COLLECTOR_VERSION);
|
|
186
|
+
|
|
187
|
+
// Use production path if it exists (Docker image pre-installed collector)
|
|
188
|
+
if (existsSync(productionPath)) {
|
|
189
|
+
return productionVersionPath;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Fallback to temp directory (local development without Docker)
|
|
182
193
|
const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
|
|
183
194
|
return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
|
|
184
195
|
}
|
|
@@ -377,13 +388,46 @@ async function resolveCollector(allowDownload: boolean = true, logger?: Logger):
|
|
|
377
388
|
/**
|
|
378
389
|
* Discovers collector via UDP broadcast
|
|
379
390
|
*/
|
|
380
|
-
function discoverCollectorViaUDP(timeoutMs: number =
|
|
391
|
+
function discoverCollectorViaUDP(timeoutMs: number = 1000): Promise<CollectorDiscoveryEntry | null> {
|
|
381
392
|
return new Promise((resolve) => {
|
|
382
393
|
const socket = dgram.createSocket('udp4');
|
|
383
394
|
const discovered: CollectorDiscoveryEntry[] = [];
|
|
384
395
|
let timeout: NodeJS.Timeout;
|
|
396
|
+
let resolved = false; // Guard to prevent double resolution
|
|
385
397
|
const startTime = Date.now();
|
|
386
398
|
|
|
399
|
+
// Safety timeout - force resolve after timeout + 100ms buffer
|
|
400
|
+
const safetyTimeout = setTimeout(() => {
|
|
401
|
+
if (!resolved) {
|
|
402
|
+
console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
|
|
403
|
+
resolved = true;
|
|
404
|
+
try {
|
|
405
|
+
socket.removeAllListeners();
|
|
406
|
+
socket.close();
|
|
407
|
+
} catch (e) {
|
|
408
|
+
// Ignore
|
|
409
|
+
}
|
|
410
|
+
clearTimeout(timeout);
|
|
411
|
+
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
412
|
+
}
|
|
413
|
+
}, timeoutMs + 100);
|
|
414
|
+
|
|
415
|
+
const doResolve = (result: CollectorDiscoveryEntry | null) => {
|
|
416
|
+
if (!resolved) {
|
|
417
|
+
resolved = true;
|
|
418
|
+
clearTimeout(timeout);
|
|
419
|
+
clearTimeout(safetyTimeout);
|
|
420
|
+
try {
|
|
421
|
+
socket.removeAllListeners();
|
|
422
|
+
socket.close();
|
|
423
|
+
} catch (e) {
|
|
424
|
+
// Ignore
|
|
425
|
+
}
|
|
426
|
+
console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
|
|
427
|
+
resolve(result);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
387
431
|
socket.on('message', (msg) => {
|
|
388
432
|
try {
|
|
389
433
|
const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;
|
|
@@ -392,6 +436,8 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
|
|
|
392
436
|
discovered.push(message);
|
|
393
437
|
const elapsed = Date.now() - startTime;
|
|
394
438
|
console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
|
|
439
|
+
// Resolve immediately when collector found
|
|
440
|
+
doResolve(discovered[0]);
|
|
395
441
|
}
|
|
396
442
|
} catch (error) {
|
|
397
443
|
// Ignore parse errors
|
|
@@ -399,11 +445,9 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
|
|
|
399
445
|
});
|
|
400
446
|
|
|
401
447
|
socket.on('error', (err) => {
|
|
402
|
-
clearTimeout(timeout);
|
|
403
|
-
socket.close();
|
|
404
448
|
const elapsed = Date.now() - startTime;
|
|
405
449
|
console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
|
|
406
|
-
|
|
450
|
+
doResolve(null);
|
|
407
451
|
});
|
|
408
452
|
|
|
409
453
|
socket.bind(() => {
|
|
@@ -417,16 +461,7 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
|
|
|
417
461
|
} else {
|
|
418
462
|
console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
|
|
419
463
|
}
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
socket.close(() => {
|
|
423
|
-
// Socket closed callback (optional, we don't wait for this)
|
|
424
|
-
});
|
|
425
|
-
} catch (closeError) {
|
|
426
|
-
// Ignore close errors
|
|
427
|
-
}
|
|
428
|
-
// Return the first discovered collector immediately
|
|
429
|
-
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
464
|
+
doResolve(discovered.length > 0 ? discovered[0] : null);
|
|
430
465
|
}, timeoutMs);
|
|
431
466
|
});
|
|
432
467
|
});
|
|
@@ -521,9 +556,10 @@ export async function isCollectorRunning(): Promise<CollectorStatus> {
|
|
|
521
556
|
try {
|
|
522
557
|
const udpStartTime = Date.now();
|
|
523
558
|
console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
|
|
524
|
-
|
|
559
|
+
console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
|
|
560
|
+
const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)
|
|
525
561
|
const udpElapsed = Date.now() - udpStartTime;
|
|
526
|
-
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);
|
|
562
|
+
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
|
|
527
563
|
if (discovered) {
|
|
528
564
|
console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
|
|
529
565
|
return {
|
|
@@ -538,7 +574,11 @@ export async function isCollectorRunning(): Promise<CollectorStatus> {
|
|
|
538
574
|
}
|
|
539
575
|
} catch (error) {
|
|
540
576
|
// Discovery failed, collector probably not running
|
|
541
|
-
|
|
577
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
578
|
+
console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
|
|
579
|
+
if (error instanceof Error && error.stack) {
|
|
580
|
+
console.log(`[UDP Discovery] Error stack: ${error.stack}`);
|
|
581
|
+
}
|
|
542
582
|
}
|
|
543
583
|
|
|
544
584
|
console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
|
|
@@ -1074,16 +1114,18 @@ export async function discoverOrStartCollector(
|
|
|
1074
1114
|
}
|
|
1075
1115
|
}
|
|
1076
1116
|
|
|
1077
|
-
// First, check if collector is already running (via UDP discovery)
|
|
1117
|
+
// First, quick check if collector is already running (via UDP discovery)
|
|
1118
|
+
// Match C#: 10 attempts × 100ms = 1 second max (much faster than before)
|
|
1078
1119
|
// Skip UDP discovery if we already have a process reference (faster)
|
|
1079
1120
|
if (!globalCollectorProcess) {
|
|
1080
|
-
logger.info('[Collector]
|
|
1121
|
+
logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
|
|
1081
1122
|
const udpStartTime = Date.now();
|
|
1123
|
+
logger.info('[Collector] Calling isCollectorRunning()...');
|
|
1082
1124
|
const status = await isCollectorRunning();
|
|
1083
1125
|
const udpElapsed = Date.now() - udpStartTime;
|
|
1084
|
-
logger.info(`[Collector]
|
|
1126
|
+
logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
|
|
1085
1127
|
if (status.isRunning && status.isReady && status.otlpEndpoint) {
|
|
1086
|
-
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
|
|
1128
|
+
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
|
|
1087
1129
|
return `http://${status.otlpEndpoint}`;
|
|
1088
1130
|
}
|
|
1089
1131
|
logger.info('[Collector] No existing collector found, will start new one...');
|