@omen.foundation/node-microservice-runtime 0.1.43 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collector-manager.cjs +100 -1
- package/dist/collector-manager.d.ts +7 -0
- package/dist/collector-manager.d.ts.map +1 -1
- package/dist/collector-manager.js +125 -2
- package/dist/collector-manager.js.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +41 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +57 -5
- package/dist/logger.js.map +1 -1
- package/dist/runtime.cjs +19 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +24 -1
- package/dist/runtime.js.map +1 -1
- package/package.json +1 -1
- package/src/collector-manager.ts +136 -2
- package/src/index.ts +1 -0
- package/src/logger.ts +74 -9
- package/src/runtime.ts +28 -1
package/src/logger.ts
CHANGED
|
@@ -41,6 +41,7 @@ interface LoggerFactoryOptions {
|
|
|
41
41
|
destinationPath?: string;
|
|
42
42
|
serviceName?: string; // Service name for log filtering (e.g., "ExampleNodeService")
|
|
43
43
|
qualifiedServiceName?: string; // Full qualified service name (e.g., "micro_ExampleNodeService")
|
|
44
|
+
otlpEndpoint?: string; // OTLP endpoint if collector is already set up (avoids re-discovery)
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/**
|
|
@@ -560,6 +561,10 @@ function initializeOtlpSync(
|
|
|
560
561
|
name: 'beamable-otlp-init',
|
|
561
562
|
level: 'info',
|
|
562
563
|
}, process.stdout);
|
|
564
|
+
|
|
565
|
+
// If collector was already set up via setupCollectorBeforeLogging,
|
|
566
|
+
// discoverOrStartCollector will find it and use a shorter timeout.
|
|
567
|
+
// If not, it will start it (with full timeout).
|
|
563
568
|
|
|
564
569
|
// Use deasync to wait synchronously for the async initialization
|
|
565
570
|
// This allows the event loop to process while we wait, enabling async operations
|
|
@@ -640,15 +645,75 @@ export function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptio
|
|
|
640
645
|
const usePrettyLogs = shouldUsePrettyLogs();
|
|
641
646
|
|
|
642
647
|
// Initialize OTLP synchronously BEFORE creating the logger
|
|
643
|
-
//
|
|
644
|
-
//
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
env
|
|
650
|
-
|
|
651
|
-
|
|
648
|
+
// If otlpEndpoint is provided (collector already set up), create provider directly
|
|
649
|
+
// Otherwise, try to discover/start collector (with timeout)
|
|
650
|
+
let otlpProvider: LoggerProvider | null = null;
|
|
651
|
+
|
|
652
|
+
if (options.otlpEndpoint) {
|
|
653
|
+
// Collector is already set up, create OTLP provider directly without discovery/startup
|
|
654
|
+
// Set endpoint in env temporarily so initializeOtlpLogging uses it directly
|
|
655
|
+
const originalEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
656
|
+
process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;
|
|
657
|
+
|
|
658
|
+
// Create OTLP provider directly (collector is already running, so this should be fast)
|
|
659
|
+
const initLogger = pino({
|
|
660
|
+
name: 'beamable-otlp-init',
|
|
661
|
+
level: 'info',
|
|
662
|
+
}, process.stdout);
|
|
663
|
+
|
|
664
|
+
// Create provider synchronously - since endpoint is explicitly provided,
|
|
665
|
+
// initializeOtlpLogging will skip discovery and create provider directly
|
|
666
|
+
let provider: LoggerProvider | null = null;
|
|
667
|
+
let completed = false;
|
|
668
|
+
|
|
669
|
+
initializeOtlpLogging(
|
|
670
|
+
options.serviceName,
|
|
671
|
+
options.qualifiedServiceName,
|
|
672
|
+
env,
|
|
673
|
+
initLogger
|
|
674
|
+
).then((result) => {
|
|
675
|
+
provider = result;
|
|
676
|
+
completed = true;
|
|
677
|
+
if (result) {
|
|
678
|
+
initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);
|
|
679
|
+
}
|
|
680
|
+
}).catch((error) => {
|
|
681
|
+
initLogger.error(`[OTLP] Failed to create OTLP provider: ${error instanceof Error ? error.message : String(error)}`);
|
|
682
|
+
completed = true;
|
|
683
|
+
provider = null;
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// Wait briefly for provider creation (should be very fast, < 1 second)
|
|
687
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
688
|
+
const deasync = require('deasync');
|
|
689
|
+
const startTime = Date.now();
|
|
690
|
+
const timeout = 2000; // 2 second timeout (should be fast since no discovery needed)
|
|
691
|
+
|
|
692
|
+
deasync.loopWhile(() => {
|
|
693
|
+
if (Date.now() - startTime >= timeout) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
return !completed;
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
otlpProvider = provider;
|
|
700
|
+
|
|
701
|
+
// Restore original endpoint if it existed
|
|
702
|
+
if (originalEndpoint !== undefined) {
|
|
703
|
+
process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = originalEndpoint;
|
|
704
|
+
} else {
|
|
705
|
+
delete process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
706
|
+
}
|
|
707
|
+
} else {
|
|
708
|
+
// No endpoint provided - try to discover/start collector (full initialization)
|
|
709
|
+
// This ensures all logs from this point forward are captured via OTLP
|
|
710
|
+
otlpProvider = initializeOtlpSync(
|
|
711
|
+
options.serviceName,
|
|
712
|
+
options.qualifiedServiceName,
|
|
713
|
+
env,
|
|
714
|
+
60000 // 60 second timeout to allow collector download, startup, and readiness verification
|
|
715
|
+
);
|
|
716
|
+
}
|
|
652
717
|
|
|
653
718
|
// Shared reference for OTLP logger provider
|
|
654
719
|
const otlpProviderRef: { provider: LoggerProvider | null } = { provider: otlpProvider };
|
package/src/runtime.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { GatewayRequester } from './requester.js';
|
|
|
4
4
|
import { AuthManager } from './auth.js';
|
|
5
5
|
import { createLogger } from './logger.js';
|
|
6
6
|
import { loadEnvironmentConfig } from './env.js';
|
|
7
|
+
import { setupCollectorBeforeLogging } from './collector-manager.js';
|
|
8
|
+
import pino from 'pino';
|
|
7
9
|
import { listRegisteredServices, getServiceOptions, getConfigureServicesHandlers, getInitializeServicesHandlers } from './decorators.js';
|
|
8
10
|
import { generateOpenApiDocument } from './docs.js';
|
|
9
11
|
import { VERSION } from './index.js';
|
|
@@ -60,7 +62,15 @@ export class MicroserviceRuntime {
|
|
|
60
62
|
constructor(env?: EnvironmentConfig) {
|
|
61
63
|
this.env = env ?? loadEnvironmentConfig();
|
|
62
64
|
|
|
63
|
-
//
|
|
65
|
+
// STEP 1: Create minimal console logger for startup messages (before collector setup)
|
|
66
|
+
// This ensures we have logging available immediately, even before collector is ready
|
|
67
|
+
const startupLogger = pino({
|
|
68
|
+
name: 'beamable-runtime-startup',
|
|
69
|
+
level: 'info',
|
|
70
|
+
}, process.stdout);
|
|
71
|
+
startupLogger.info('Starting Beamable Node microservice runtime.');
|
|
72
|
+
|
|
73
|
+
// STEP 2: Get registered services to extract service name
|
|
64
74
|
const registered = listRegisteredServices();
|
|
65
75
|
if (registered.length === 0) {
|
|
66
76
|
throw new Error('No microservices registered. Use the @Microservice decorator to register at least one class.');
|
|
@@ -70,10 +80,27 @@ export class MicroserviceRuntime {
|
|
|
70
80
|
const primaryService = registered[0];
|
|
71
81
|
const qualifiedServiceName = `micro_${primaryService.qualifiedName}`;
|
|
72
82
|
|
|
83
|
+
// STEP 3: Setup collector BEFORE creating the main logger
|
|
84
|
+
// This ensures all logs from the main logger are captured via OTLP
|
|
85
|
+
startupLogger.info('Setting up OpenTelemetry collector...');
|
|
86
|
+
const otlpEndpoint = setupCollectorBeforeLogging(
|
|
87
|
+
this.env,
|
|
88
|
+
60000 // 60 second timeout
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (otlpEndpoint) {
|
|
92
|
+
startupLogger.info(`Collector ready at ${otlpEndpoint}, creating main logger...`);
|
|
93
|
+
} else {
|
|
94
|
+
startupLogger.warn('Collector setup did not complete, continuing without OTLP logging');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// STEP 4: Create main logger (collector is now ready, so all logs will be captured)
|
|
98
|
+
// Pass the OTLP endpoint to skip re-discovery/startup
|
|
73
99
|
this.logger = createLogger(this.env, {
|
|
74
100
|
name: 'beamable-node-microservice',
|
|
75
101
|
serviceName: primaryService.name,
|
|
76
102
|
qualifiedServiceName: qualifiedServiceName,
|
|
103
|
+
otlpEndpoint: otlpEndpoint || undefined, // Pass endpoint if collector was set up
|
|
77
104
|
});
|
|
78
105
|
this.serviceManager = new BeamableServiceManager(this.env, this.logger);
|
|
79
106
|
|