@omen.foundation/node-microservice-runtime 0.1.44 → 0.1.46

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/logger.cjs CHANGED
@@ -426,7 +426,47 @@ function createLogger(env, options = {}) {
426
426
  var _a, _b, _c;
427
427
  const configuredDestination = (_a = options.destinationPath) !== null && _a !== void 0 ? _a : process.env.LOG_PATH;
428
428
  const usePrettyLogs = shouldUsePrettyLogs();
429
- const otlpProvider = initializeOtlpSync(options.serviceName, options.qualifiedServiceName, env, 60000);
429
+ let otlpProvider = null;
430
+ if (options.otlpEndpoint) {
431
+ const originalEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
432
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;
433
+ const initLogger = (0, pino_1.default)({
434
+ name: 'beamable-otlp-init',
435
+ level: 'info',
436
+ }, process.stdout);
437
+ let provider = null;
438
+ let completed = false;
439
+ initializeOtlpLogging(options.serviceName, options.qualifiedServiceName, env, initLogger).then((result) => {
440
+ provider = result;
441
+ completed = true;
442
+ if (result) {
443
+ initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);
444
+ }
445
+ }).catch((error) => {
446
+ initLogger.error(`[OTLP] Failed to create OTLP provider: ${error instanceof Error ? error.message : String(error)}`);
447
+ completed = true;
448
+ provider = null;
449
+ });
450
+ const deasync = require('deasync');
451
+ const startTime = Date.now();
452
+ const timeout = 2000;
453
+ deasync.loopWhile(() => {
454
+ if (Date.now() - startTime >= timeout) {
455
+ return false;
456
+ }
457
+ return !completed;
458
+ });
459
+ otlpProvider = provider;
460
+ if (originalEndpoint !== undefined) {
461
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = originalEndpoint;
462
+ }
463
+ else {
464
+ delete process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
465
+ }
466
+ }
467
+ else {
468
+ otlpProvider = initializeOtlpSync(options.serviceName, options.qualifiedServiceName, env, 60000);
469
+ }
430
470
  const otlpProviderRef = { provider: otlpProvider };
431
471
  const pinoOptions = {
432
472
  name: (_b = options.name) !== null && _b !== void 0 ? _b : 'beamable-node-runtime',
package/dist/logger.d.ts CHANGED
@@ -5,6 +5,7 @@ interface LoggerFactoryOptions {
5
5
  destinationPath?: string;
6
6
  serviceName?: string;
7
7
  qualifiedServiceName?: string;
8
+ otlpEndpoint?: string;
8
9
  }
9
10
  export declare function createLogger(env: EnvironmentConfig, options?: LoggerFactoryOptions): Logger;
10
11
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAe,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAI1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkCpD,UAAU,oBAAoB;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAklBD,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CA6F/F"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAe,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAI1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkCpD,UAAU,oBAAoB;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAslBD,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAyJ/F"}
package/dist/logger.js CHANGED
@@ -500,6 +500,9 @@ function initializeOtlpSync(serviceName, qualifiedServiceName, env, timeoutMs =
500
500
  name: 'beamable-otlp-init',
501
501
  level: 'info',
502
502
  }, process.stdout);
503
+ // If collector was already set up via setupCollectorBeforeLogging,
504
+ // discoverOrStartCollector will find it and use a shorter timeout.
505
+ // If not, it will start it (with full timeout).
503
506
  // Use deasync to wait synchronously for the async initialization
504
507
  // This allows the event loop to process while we wait, enabling async operations
505
508
  // (like collector download) to complete
@@ -569,11 +572,60 @@ export function createLogger(env, options = {}) {
569
572
  const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;
570
573
  const usePrettyLogs = shouldUsePrettyLogs();
571
574
  // Initialize OTLP synchronously BEFORE creating the logger
572
- // This ensures all logs from this point forward are captured via OTLP
573
- // Similar to C# microservices which configure logging early in startup
574
- // CRITICAL: We wait for collector to be fully initialized and ready before proceeding
575
- const otlpProvider = initializeOtlpSync(options.serviceName, options.qualifiedServiceName, env, 60000 // 60 second timeout to allow collector download, startup, and readiness verification
576
- );
575
+ // If otlpEndpoint is provided (collector already set up), create provider directly
576
+ // Otherwise, try to discover/start collector (with timeout)
577
+ let otlpProvider = null;
578
+ if (options.otlpEndpoint) {
579
+ // Collector is already set up, create OTLP provider directly without discovery/startup
580
+ // Set endpoint in env temporarily so initializeOtlpLogging uses it directly
581
+ const originalEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
582
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;
583
+ // Create OTLP provider directly (collector is already running, so this should be fast)
584
+ const initLogger = pino({
585
+ name: 'beamable-otlp-init',
586
+ level: 'info',
587
+ }, process.stdout);
588
+ // Create provider synchronously - since endpoint is explicitly provided,
589
+ // initializeOtlpLogging will skip discovery and create provider directly
590
+ let provider = null;
591
+ let completed = false;
592
+ initializeOtlpLogging(options.serviceName, options.qualifiedServiceName, env, initLogger).then((result) => {
593
+ provider = result;
594
+ completed = true;
595
+ if (result) {
596
+ initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);
597
+ }
598
+ }).catch((error) => {
599
+ initLogger.error(`[OTLP] Failed to create OTLP provider: ${error instanceof Error ? error.message : String(error)}`);
600
+ completed = true;
601
+ provider = null;
602
+ });
603
+ // Wait briefly for provider creation (should be very fast, < 1 second)
604
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
605
+ const deasync = require('deasync');
606
+ const startTime = Date.now();
607
+ const timeout = 2000; // 2 second timeout (should be fast since no discovery needed)
608
+ deasync.loopWhile(() => {
609
+ if (Date.now() - startTime >= timeout) {
610
+ return false;
611
+ }
612
+ return !completed;
613
+ });
614
+ otlpProvider = provider;
615
+ // Restore original endpoint if it existed
616
+ if (originalEndpoint !== undefined) {
617
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = originalEndpoint;
618
+ }
619
+ else {
620
+ delete process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
621
+ }
622
+ }
623
+ else {
624
+ // No endpoint provided - try to discover/start collector (full initialization)
625
+ // This ensures all logs from this point forward are captured via OTLP
626
+ otlpProvider = initializeOtlpSync(options.serviceName, options.qualifiedServiceName, env, 60000 // 60 second timeout to allow collector download, startup, and readiness verification
627
+ );
628
+ }
577
629
  // Shared reference for OTLP logger provider
578
630
  const otlpProviderRef = { provider: otlpProvider };
579
631
  const pinoOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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","sourcesContent":["import pino, { destination, type Logger, type LoggerOptions } from 'pino';\r\nimport { Transform } from 'node:stream';\r\nimport { createRequire } from 'node:module';\r\nimport { ensureWritableTempDirectory } from './env.js';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { logs } from '@opentelemetry/api-logs';\r\nimport { LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs';\r\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\r\nimport { resourceFromAttributes, defaultResource } from '@opentelemetry/resources';\r\nimport { discoverOrStartCollector } from './collector-manager.js';\r\nimport type { Logger as PinoLogger } from 'pino';\r\nimport deasync from 'deasync';\r\n\r\n// Helper to get require function that works in both CJS and ESM\r\ndeclare const require: any;\r\nfunction getRequire(): any {\r\n // Check if we're in CJS context (require.main exists)\r\n if (typeof require !== 'undefined' && typeof require.main !== 'undefined') {\r\n // CJS context - use require directly\r\n return require;\r\n }\r\n // ESM context - use createRequire with import.meta.url\r\n // TypeScript will complain in CJS builds, but this code only runs in ESM\r\n // @ts-ignore - import.meta is ESM-only, TypeScript error in CJS is expected\r\n return createRequire(import.meta.url);\r\n}\r\n\r\n/**\r\n * Determines if we should use pretty logs (local dev) or raw JSON logs (deployed).\r\n * \r\n * Simple check: If IS_LOCAL=1 is set in environment, use pretty logs.\r\n * Otherwise, use raw Beamable JSON format for log collection.\r\n */\r\nfunction shouldUsePrettyLogs(): boolean {\r\n // Check for explicit IS_LOCAL flag\r\n return process.env.IS_LOCAL === '1' || process.env.IS_LOCAL === 'true';\r\n}\r\n\r\ninterface LoggerFactoryOptions {\r\n name?: string;\r\n destinationPath?: string;\r\n serviceName?: string; // Service name for log filtering (e.g., \"ExampleNodeService\")\r\n qualifiedServiceName?: string; // Full qualified service name (e.g., \"micro_ExampleNodeService\")\r\n}\r\n\r\n/**\r\n * Maps Pino log levels to Beamable log levels\r\n * Pino levels: 10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal\r\n * Beamable levels: Debug, Info, Warning, Error, Fatal\r\n */\r\nfunction mapPinoLevelToBeamableLevel(level: number): string {\r\n switch (level) {\r\n case 10: // trace\r\n return 'Debug';\r\n case 20: // debug\r\n return 'Debug';\r\n case 30: // info\r\n return 'Info';\r\n case 40: // warn\r\n return 'Warning';\r\n case 50: // error\r\n return 'Error';\r\n case 60: // fatal\r\n return 'Fatal';\r\n default:\r\n return 'Info';\r\n }\r\n}\r\n\r\n/**\r\n * Initializes OpenTelemetry OTLP log exporter if configured.\r\n * Similar to C# microservices, checks for BEAM_OTEL_EXPORTER_OTLP_ENDPOINT or uses standard enabled flag.\r\n * \r\n * @param serviceName - Service name for resource attributes\r\n * @param qualifiedServiceName - Qualified service name for resource attributes\r\n * @param env - Environment configuration\r\n * @returns OTLP logger provider if configured, null otherwise\r\n */\r\nasync function initializeOtlpLogging(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n env?: EnvironmentConfig,\r\n logger?: PinoLogger\r\n): Promise<LoggerProvider | null> {\r\n // Check for explicit OTLP endpoint (same as C#: BEAM_OTEL_EXPORTER_OTLP_ENDPOINT)\r\n // Also check standard OTEL environment variables\r\n const otlpEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT \r\n || process.env.OTEL_EXPORTER_OTLP_ENDPOINT\r\n || (process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS : null);\r\n \r\n // Check for explicit OTLP protocol (same as C#: OtelExporterOtlpProtocol)\r\n // C# uses OtlpExportProtocol enum: HttpProtobuf or HttpJson\r\n const otlpProtocol = process.env.BEAM_OTEL_EXPORTER_OTLP_PROTOCOL\r\n || process.env.OTEL_EXPORTER_OTLP_PROTOCOL\r\n || process.env.OTEL_EXPORTER_OTLP_PROTOCOL_LOGS;\r\n \r\n // Check if standard OTLP is enabled (matching C# OtelExporterStandardEnabled)\r\n // C#: (this.InDocker() || UseLocalOtel) && string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"BEAM_DISABLE_STANDARD_OTEL\"))\r\n // UseLocalOtel = BEAM_LOCAL_OTEL is set\r\n // InDocker = IS_LOCAL is not set (for Node.js, we check IS_LOCAL !== '1' && !== 'true')\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 \r\n // If no explicit endpoint and standard OTLP not enabled, skip OTLP\r\n if (!otlpEndpoint && !standardOtelEnabled) {\r\n return Promise.resolve(null);\r\n }\r\n \r\n try {\r\n // Build resource attributes (similar to C# resourceProvider)\r\n const resourceAttributes: Record<string, string> = {};\r\n if (serviceName) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n if (qualifiedServiceName) {\r\n resourceAttributes['service.instance.id'] = qualifiedServiceName;\r\n }\r\n if (env?.cid) {\r\n resourceAttributes['beam.cid'] = String(env.cid);\r\n }\r\n if (env?.pid) {\r\n resourceAttributes['beam.pid'] = String(env.pid);\r\n }\r\n if (env?.routingKey) {\r\n resourceAttributes['beam.routing_key'] = String(env.routingKey);\r\n }\r\n \r\n // Determine endpoint URL\r\n // If explicit endpoint provided, use it (append /v1/logs if needed for HTTP)\r\n // If standard OTLP enabled but no explicit endpoint, try to discover or start collector\r\n let endpointUrl = otlpEndpoint;\r\n \r\n if (!endpointUrl && standardOtelEnabled && logger) {\r\n // Try to discover existing collector or start a new one (like C# does)\r\n try {\r\n const discoveredEndpoint = await discoverOrStartCollector(logger, standardOtelEnabled, env);\r\n if (discoveredEndpoint) {\r\n endpointUrl = discoveredEndpoint;\r\n } else {\r\n console.error('[OTLP] Standard OTLP is enabled but could not discover or start collector.');\r\n return Promise.resolve(null);\r\n }\r\n } catch (error) {\r\n console.error('[OTLP] Failed to discover/start collector:', error instanceof Error ? error.message : String(error));\r\n return Promise.resolve(null);\r\n }\r\n }\r\n \r\n // If still no endpoint, skip OTLP\r\n if (!endpointUrl) {\r\n if (standardOtelEnabled) {\r\n console.error('[OTLP] Standard OTLP is enabled but no endpoint available. Set BEAM_OTEL_EXPORTER_OTLP_ENDPOINT to enable OTLP logging.');\r\n }\r\n return Promise.resolve(null);\r\n }\r\n \r\n // Ensure endpoint format is correct based on protocol\r\n // C# behavior:\r\n // - Http protocol: endpoint should be like \"http://127.0.0.1:4348\" (with /v1/logs appended)\r\n // - Grpc protocol: endpoint should be like \"127.0.0.1:4348\" (no http:// prefix, no /v1/logs)\r\n // For now, we only support HTTP exporter, so we append /v1/logs\r\n // If Grpc is specified, we'd need a different exporter package\r\n let finalEndpointUrl = endpointUrl;\r\n if (otlpProtocol && otlpProtocol.toLowerCase() === 'grpc') {\r\n // Grpc protocol - don't modify endpoint (no http://, no /v1/logs)\r\n // Note: Grpc exporter not yet implemented, this is for future support\r\n console.warn('[OTLP] Grpc protocol specified but not yet supported, using HTTP endpoint format');\r\n finalEndpointUrl = endpointUrl.includes('/v1/logs') \r\n ? endpointUrl \r\n : `${endpointUrl.replace(/\\/$/, '')}/v1/logs`;\r\n } else {\r\n // HTTP protocol - ensure /v1/logs suffix\r\n finalEndpointUrl = endpointUrl.includes('/v1/logs') \r\n ? endpointUrl \r\n : `${endpointUrl.replace(/\\/$/, '')}/v1/logs`;\r\n }\r\n \r\n // Create OTLP HTTP exporter\r\n // Beamable uses HttpProtobuf as the standard protocol\r\n // C# behavior:\r\n // 1. If OtelExporterOtlpEndpoint and OtelExporterOtlpProtocol are provided, use them\r\n // 2. Otherwise, always use HttpProtobuf protocol (Beamable's standard)\r\n // Node.js: @opentelemetry/exporter-logs-otlp-http uses HTTP/JSON by default\r\n // We configure contentType to 'application/x-protobuf' to match Beamable's standard\r\n const exporterOptions: {\r\n url: string;\r\n headers?: Record<string, string>;\r\n contentType?: string;\r\n } = {\r\n url: finalEndpointUrl,\r\n };\r\n \r\n // Configure protocol/contentType (matching C# OtlpExportProtocol)\r\n // Beamable uses HttpProtobuf as the default protocol\r\n // C# supports: HttpProtobuf, HttpJson, Grpc\r\n // If explicit protocol provided, use it; otherwise always default to HttpProtobuf\r\n if (otlpProtocol) {\r\n // Parse protocol string (HttpProtobuf, HttpJson, or Grpc)\r\n const protocol = otlpProtocol.toLowerCase();\r\n if (protocol === 'httpprotobuf' || protocol === 'protobuf') {\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n } else if (protocol === 'httpjson' || protocol === 'json') {\r\n exporterOptions.contentType = 'application/json';\r\n } else if (protocol === 'grpc') {\r\n // Note: Grpc protocol would require a different exporter package\r\n // For now, we'll log a warning and fall back to HttpProtobuf\r\n console.warn('[OTLP] Grpc protocol is not yet supported in Node.js runtime, falling back to HttpProtobuf');\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n } else {\r\n // Invalid protocol - default to HttpProtobuf (Beamable's standard)\r\n console.warn(`[OTLP] Unknown protocol \"${otlpProtocol}\", defaulting to HttpProtobuf`);\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n }\r\n } else {\r\n // No protocol specified - always default to HttpProtobuf (Beamable's standard)\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n }\r\n \r\n // Headers if provided (matching C# OtelExporterOtlpHeaders)\r\n if (process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS) {\r\n exporterOptions.headers = JSON.parse(process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS);\r\n }\r\n \r\n const exporter = new OTLPLogExporter(exporterOptions);\r\n \r\n // Create resource with attributes (merge with default resource)\r\n // Note: BEAM_ALLOW_STARTUP_WITHOUT_ATTRIBUTES_RESOURCE is not applicable here\r\n // as we always create a resource with attributes\r\n const baseResource = defaultResource();\r\n const customResource = resourceFromAttributes(resourceAttributes);\r\n const resource = baseResource.merge(customResource);\r\n \r\n // Create log record processor\r\n // Note: C# supports retry via BEAM_DISABLE_RETRY_OTEL and BEAM_OTEL_RETRY_MAX_SIZE\r\n // SimpleLogRecordProcessor doesn't support retry - would need BatchLogRecordProcessor\r\n // For now, we use SimpleLogRecordProcessor (no retry)\r\n // TODO: Consider implementing retry logic if BEAM_DISABLE_RETRY_OTEL is not set\r\n const processor = new SimpleLogRecordProcessor(exporter);\r\n \r\n // Create logger provider with resource and processor\r\n const loggerProvider = new LoggerProvider({\r\n resource: resource,\r\n processors: [processor],\r\n });\r\n \r\n // Set as global logger provider\r\n logs.setGlobalLoggerProvider(loggerProvider);\r\n \r\n // Log successful initialization (to stdout for debugging)\r\n // This helps diagnose if OTLP is working in deployed environments\r\n console.error(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${finalEndpointUrl}, Service: ${serviceName || 'unknown'}`);\r\n \r\n // CRITICAL: Verify collector is actually ready before returning\r\n // If we started a collector, wait for it to be ready (up to 5 seconds)\r\n if (standardOtelEnabled && logger) {\r\n try {\r\n const { isCollectorRunning } = await import('./collector-manager.js');\r\n // Wait up to 5 seconds for collector to be ready\r\n for (let i = 0; i < 50; i++) {\r\n const status = await isCollectorRunning();\r\n if (status.isRunning && status.isReady) {\r\n if (logger) {\r\n logger.info(`[OTLP] Collector confirmed ready at ${status.otlpEndpoint || finalEndpointUrl}`);\r\n }\r\n break;\r\n }\r\n // Wait 100ms between checks\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n }\r\n } catch (error) {\r\n // If we can't verify, log but continue\r\n if (logger) {\r\n logger.warn(`[OTLP] Could not verify collector readiness: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n }\r\n \r\n return Promise.resolve(loggerProvider);\r\n } catch (error) {\r\n // If OTLP initialization fails, log error but continue without OTLP\r\n // Don't throw - we still want stdout logging to work\r\n // Log to stderr so it's visible in container logs\r\n console.error('[OTLP] Failed to initialize OTLP logging:', error instanceof Error ? error.message : String(error));\r\n if (error instanceof Error && error.stack) {\r\n console.error('[OTLP] Stack trace:', error.stack);\r\n }\r\n return Promise.resolve(null);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a transform stream that converts Pino JSON logs to Beamable's expected format.\r\n * Beamable expects logs with __t (timestamp), __l (level), and __m (message) fields.\r\n * Also includes OpenTelemetry-compatible fields for ClickHouse compatibility.\r\n * Pino writes JSON strings (one per line) to the stream.\r\n * \r\n * Also sends logs via OTLP if OTLP logger provider is configured.\r\n */\r\nfunction createBeamableLogFormatter(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n otlpProviderRef?: { provider: LoggerProvider | null }\r\n): Transform {\r\n return new Transform({\r\n objectMode: false, // Pino writes strings/Buffers, not objects\r\n transform(chunk: Buffer, _encoding, callback) {\r\n // Ensure we have a Buffer - Pino may write strings or Buffers\r\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\r\n try {\r\n const line = buffer.toString('utf8');\r\n // Skip empty lines\r\n if (!line.trim()) {\r\n callback();\r\n return;\r\n }\r\n \r\n // Parse Pino's JSON log line\r\n const pinoLog = JSON.parse(line);\r\n \r\n // Extract timestamp - Pino uses 'time' field (ISO 8601 string or milliseconds)\r\n // Convert to ISO 8601 string for Beamable\r\n let timestamp: string;\r\n if (typeof pinoLog.time === 'string') {\r\n timestamp = pinoLog.time;\r\n } else if (typeof pinoLog.time === 'number') {\r\n timestamp = new Date(pinoLog.time).toISOString();\r\n } else {\r\n timestamp = new Date().toISOString();\r\n }\r\n \r\n // Map Pino level to Beamable level\r\n const level = mapPinoLevelToBeamableLevel(pinoLog.level);\r\n \r\n // Build the message - combine msg with any additional fields\r\n // Pino's 'msg' field contains the log message\r\n const messageParts: string[] = [];\r\n if (pinoLog.msg) {\r\n messageParts.push(pinoLog.msg);\r\n }\r\n \r\n // Include error information if present\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n const errMsg = err.message || err.msg || 'Error';\r\n const errStack = err.stack ? `\\n${err.stack}` : '';\r\n messageParts.push(`${errMsg}${errStack}`);\r\n }\r\n \r\n // Build the Beamable log format (for CloudWatch Logs Insights)\r\n const beamableLog: Record<string, unknown> = {\r\n __t: timestamp,\r\n __l: level,\r\n __m: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n };\r\n \r\n // Include additional context fields that might be useful\r\n // These are included in the message object but not as top-level fields\r\n const contextFields: Record<string, unknown> = {};\r\n if (pinoLog.cid) contextFields.cid = pinoLog.cid;\r\n if (pinoLog.pid) contextFields.pid = pinoLog.pid;\r\n if (pinoLog.routingKey) contextFields.routingKey = pinoLog.routingKey;\r\n if (pinoLog.service) contextFields.service = pinoLog.service;\r\n if (pinoLog.component) contextFields.component = pinoLog.component;\r\n \r\n // Include service name in context for CloudWatch filtering\r\n if (serviceName) {\r\n contextFields.serviceName = serviceName;\r\n }\r\n if (qualifiedServiceName) {\r\n contextFields.qualifiedServiceName = qualifiedServiceName;\r\n }\r\n \r\n // Include any other fields that aren't standard Pino fields\r\n const standardPinoFields = ['level', 'time', 'pid', 'hostname', 'name', 'msg', 'err', 'v', 'cid', 'pid', 'routingKey', 'sdkVersionExecution', 'service', 'component'];\r\n for (const [key, value] of Object.entries(pinoLog)) {\r\n if (!standardPinoFields.includes(key) && value !== undefined && value !== null) {\r\n contextFields[key] = value;\r\n }\r\n }\r\n \r\n // If there are context fields, include them in the log\r\n if (Object.keys(contextFields).length > 0) {\r\n beamableLog.__c = contextFields;\r\n }\r\n \r\n // Add OpenTelemetry-compatible fields for ClickHouse compatibility\r\n // These fields allow an OpenTelemetry collector to parse and forward logs to ClickHouse\r\n // The Portal's realm-level logs page queries ClickHouse's otel_logs table\r\n const otelFields: Record<string, unknown> = {};\r\n \r\n // ResourceAttributes - service identification (for ClickHouse filtering)\r\n const resourceAttributes: Record<string, unknown> = {};\r\n // IMPORTANT: The Portal searches for service:ExampleNodeService (just the service name)\r\n // So we need to set service.namespace to the service name, NOT the qualified name\r\n // The qualified name (micro_ExampleNodeService) is used for CloudWatch log stream filtering\r\n // But ClickHouse uses just the service name for filtering\r\n if (serviceName) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n // Also include qualified name for reference\r\n if (qualifiedServiceName) {\r\n resourceAttributes['service.qualifiedName'] = qualifiedServiceName;\r\n }\r\n if (pinoLog.cid) {\r\n resourceAttributes['beam.cid'] = String(pinoLog.cid);\r\n }\r\n if (pinoLog.pid) {\r\n resourceAttributes['beam.pid'] = String(pinoLog.pid);\r\n }\r\n if (pinoLog.routingKey) {\r\n resourceAttributes['beam.routing_key'] = String(pinoLog.routingKey);\r\n }\r\n \r\n // LogAttributes - log-specific attributes\r\n const logAttributes: Record<string, unknown> = {};\r\n if (pinoLog.component) {\r\n logAttributes['component'] = String(pinoLog.component);\r\n }\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n if (err.message) logAttributes['exception.message'] = String(err.message);\r\n if (err.stack) logAttributes['exception.stacktrace'] = String(err.stack);\r\n if (err.type) logAttributes['exception.type'] = String(err.type);\r\n }\r\n \r\n // Map Beamable log level to OpenTelemetry SeverityText\r\n // Beamable: Debug, Info, Warning, Error, Fatal\r\n // OpenTelemetry: Trace, Debug, Info, Warn, Error, Fatal, Unspecified\r\n const severityTextMap: Record<string, string> = {\r\n 'Debug': 'Debug',\r\n 'Info': 'Information',\r\n 'Warning': 'Warning',\r\n 'Error': 'Error',\r\n 'Fatal': 'Critical',\r\n };\r\n const severityText = severityTextMap[level] || 'Information';\r\n \r\n // CRITICAL: ResourceAttributes and LogAttributes MUST always be present (even if empty)\r\n // ClickHouse schema expects these fields to exist for proper querying\r\n // The Portal queries ResourceAttributes['service.namespace'] - if ResourceAttributes is missing, queries fail\r\n \r\n // Ensure ResourceAttributes always has service.namespace when serviceName is provided\r\n // This is the primary field used by Portal for service filtering\r\n if (serviceName && !resourceAttributes['service.namespace']) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n \r\n // Add OpenTelemetry fields to the log\r\n // These are in addition to the Beamable format, so both systems can parse the logs\r\n // CRITICAL: Always include all required OpenTelemetry fields for ClickHouse compatibility\r\n otelFields['Timestamp'] = timestamp; // OpenTelemetry timestamp format (ISO 8601)\r\n otelFields['SeverityText'] = severityText;\r\n otelFields['Body'] = messageParts.length > 0 ? messageParts.join(' ') : 'No message';\r\n // ALWAYS include ResourceAttributes (even if empty) - required for ClickHouse schema\r\n otelFields['ResourceAttributes'] = resourceAttributes;\r\n // ALWAYS include LogAttributes (even if empty) - required for ClickHouse schema\r\n otelFields['LogAttributes'] = logAttributes;\r\n \r\n // IMPORTANT: For CloudWatch Logs Insights, we need to ensure @message contains valid JSON\r\n // The Portal expects @message to be a JSON string that can be parsed to extract __t, __l, __m\r\n // We output the Beamable format as the primary format, and include OpenTelemetry fields\r\n // CloudWatch will store this as @message, and an OpenTelemetry collector will parse it\r\n // and forward to ClickHouse's otel_logs table\r\n \r\n // Merge OpenTelemetry fields into the log (for ClickHouse compatibility)\r\n // An OpenTelemetry collector can parse these fields and forward to ClickHouse\r\n // Note: These extra fields won't break CloudWatch - it will just store them in @message\r\n Object.assign(beamableLog, otelFields);\r\n \r\n // Send log via OTLP if configured (similar to C# MicroserviceOtelLogRecordExporter)\r\n // Check if provider is available (may be null if still initializing)\r\n if (otlpProviderRef?.provider) {\r\n try {\r\n const otlpLogger = otlpProviderRef.provider.getLogger(\r\n serviceName || 'beamable-node-runtime',\r\n undefined, // version\r\n {\r\n schemaUrl: undefined, // optional schema URL\r\n }\r\n );\r\n \r\n // Map Beamable level to OpenTelemetry SeverityNumber\r\n const severityNumberMap: Record<string, number> = {\r\n 'Debug': 5, // SEVERITY_NUMBER_DEBUG\r\n 'Info': 9, // SEVERITY_NUMBER_INFO\r\n 'Warning': 13, // SEVERITY_NUMBER_WARN\r\n 'Error': 17, // SEVERITY_NUMBER_ERROR\r\n 'Fatal': 21, // SEVERITY_NUMBER_FATAL\r\n };\r\n \r\n // Create log record for OTLP\r\n otlpLogger.emit({\r\n severityNumber: severityNumberMap[level] || 9,\r\n severityText: severityText,\r\n body: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n attributes: {\r\n ...logAttributes,\r\n // Include additional context\r\n ...(pinoLog.component ? { component: String(pinoLog.component) } : {}),\r\n },\r\n timestamp: new Date(timestamp).getTime() * 1_000_000, // nanoseconds\r\n observedTimestamp: Date.now() * 1_000_000, // nanoseconds\r\n });\r\n } catch (otlpError) {\r\n // If OTLP send fails, continue with stdout logging\r\n // Don't block the log output\r\n // Note: C# supports retry via BEAM_DISABLE_RETRY_OTEL and BEAM_OTEL_RETRY_MAX_SIZE\r\n // SimpleLogRecordProcessor doesn't support retry - would need BatchLogRecordProcessor\r\n // For now, we silently continue (retry would be handled at processor level if implemented)\r\n }\r\n }\r\n \r\n // Output as a single-line JSON string (required for CloudWatch)\r\n // CloudWatch Logs Insights will store this entire JSON string in the @message field\r\n const output = JSON.stringify(beamableLog) + '\\n';\r\n callback(null, Buffer.from(output, 'utf8'));\r\n } catch (error) {\r\n // If parsing fails, output a fallback log entry\r\n const fallbackLog = {\r\n __t: new Date().toISOString(),\r\n __l: 'Error',\r\n __m: `Failed to parse log entry: ${chunk.toString().substring(0, 200)}`,\r\n };\r\n callback(null, Buffer.from(JSON.stringify(fallbackLog) + '\\n', 'utf8'));\r\n }\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Synchronously initializes OTLP logging with a timeout.\r\n * This ensures OTLP is ready before any logs are emitted.\r\n * Similar to C# microservices which configure logging early in startup.\r\n * \r\n * Uses a blocking wait mechanism to ensure initialization completes before returning.\r\n */\r\nfunction initializeOtlpSync(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n env?: EnvironmentConfig,\r\n timeoutMs: number = 60000 // 60 seconds to allow collector download, startup, and readiness check\r\n): LoggerProvider | 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\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n \r\n // Use deasync to wait synchronously for the async initialization\r\n // This allows the event loop to process while we wait, enabling async operations\r\n // (like collector download) to complete\r\n let provider: LoggerProvider | null = null;\r\n let completed = false;\r\n let initError: Error | null = null;\r\n \r\n // Start initialization promise (callbacks set flags for deasync.loopWhile to check)\r\n initializeOtlpLogging(\r\n serviceName,\r\n qualifiedServiceName,\r\n env,\r\n initLogger\r\n ).then((result) => {\r\n provider = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info('[OTLP] OpenTelemetry logging initialized successfully');\r\n }\r\n return result;\r\n }).catch((error) => {\r\n initError = error instanceof Error ? error : new Error(String(error));\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to initialize: ${initError.message}`);\r\n return null;\r\n });\r\n \r\n // Set timeout to prevent infinite wait\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Initialization timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n \r\n // Wait synchronously for the promise to resolve using deasync\r\n // deasync.loopWhile() allows event loop to process while we wait\r\n // This enables async operations (like collector download) to run and complete\r\n // CRITICAL: This must complete before the logger is created to capture all startup logs\r\n try {\r\n // Use deasync to wait for completion, with timeout check\r\n // loopWhile returns false to stop waiting, true to continue\r\n deasync.loopWhile(() => {\r\n // Check if we've exceeded timeout\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n initLogger.warn(`[OTLP] Synchronous wait timeout after ${elapsed}ms`);\r\n return false; // Stop waiting\r\n }\r\n // Continue waiting if not completed\r\n // This allows the event loop to process async operations\r\n return !completed;\r\n });\r\n } catch (error) {\r\n // If deasync fails, log and continue\r\n initLogger.error(`[OTLP] Error during synchronous wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n \r\n clearTimeout(timeoutId);\r\n \r\n // Verify we got a provider (collector is ready)\r\n if (completed && provider) {\r\n initLogger.info('[OTLP] Initialization completed successfully, collector is ready');\r\n } else if (!completed) {\r\n initLogger.warn('[OTLP] Initialization did not complete in time, logs may not be sent via OTLP initially');\r\n initLogger.warn('[OTLP] Service will continue without OTLP telemetry - requests will still be serviced');\r\n } else {\r\n initLogger.warn('[OTLP] Initialization completed but no provider returned, OTLP telemetry disabled');\r\n }\r\n \r\n return provider;\r\n}\r\n\r\nexport function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptions = {}): Logger {\r\n const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;\r\n const usePrettyLogs = shouldUsePrettyLogs();\r\n \r\n // Initialize OTLP synchronously BEFORE creating the logger\r\n // This ensures all logs from this point forward are captured via OTLP\r\n // Similar to C# microservices which configure logging early in startup\r\n // CRITICAL: We wait for collector to be fully initialized and ready before proceeding\r\n const otlpProvider = initializeOtlpSync(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n 60000 // 60 second timeout to allow collector download, startup, and readiness verification\r\n );\r\n \r\n // Shared reference for OTLP logger provider\r\n const otlpProviderRef: { provider: LoggerProvider | null } = { provider: otlpProvider };\r\n\r\n const pinoOptions: LoggerOptions = {\r\n name: options.name ?? 'beamable-node-runtime',\r\n level: env.logLevel,\r\n base: {\r\n cid: env.cid,\r\n pid: env.pid,\r\n routingKey: env.routingKey ?? null,\r\n sdkVersionExecution: env.sdkVersionExecution,\r\n // Include service name in base fields for filtering\r\n serviceName: options.serviceName,\r\n qualifiedServiceName: options.qualifiedServiceName,\r\n },\r\n redact: {\r\n paths: ['secret', 'refreshToken'],\r\n censor: '***',\r\n },\r\n // Use timestamp in milliseconds (Pino default) for accurate conversion\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n };\r\n\r\n // For deployed services, always log to stdout so container orchestrator can collect logs\r\n // For local development, log to stdout unless a specific file path is provided\r\n if (!configuredDestination || configuredDestination === '-' || configuredDestination === 'stdout' || configuredDestination === 'console') {\r\n if (!usePrettyLogs) {\r\n // Deployed/remote: Use Beamable JSON format for log collection\r\n // Include OpenTelemetry fields for ClickHouse compatibility\r\n // Also send logs via OTLP if configured\r\n const beamableFormatter = createBeamableLogFormatter(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n otlpProviderRef\r\n );\r\n beamableFormatter.pipe(process.stdout);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n // Local development: Use Pino's pretty printing for human-readable logs\r\n // Try to use pino-pretty if available (optional dependency)\r\n // If not available, fall back to default Pino JSON output\r\n try {\r\n // Check if pino-pretty is available\r\n // Use getRequire() which handles both CJS and ESM contexts\r\n const requireFn = getRequire();\r\n const pinoPretty = requireFn('pino-pretty');\r\n // Create a pretty stream with formatting options\r\n const prettyStream = pinoPretty({\r\n colorize: true,\r\n translateTime: 'HH:MM:ss.l',\r\n ignore: 'pid,hostname',\r\n singleLine: false,\r\n });\r\n // Use pino with the pretty stream\r\n return pino(pinoOptions, prettyStream);\r\n } catch {\r\n // pino-pretty not available, use default Pino output (JSON but readable)\r\n // This is expected if pino-pretty isn't installed, so we silently fall back\r\n return pino(pinoOptions, process.stdout);\r\n }\r\n }\r\n }\r\n\r\n // For file logging: Use Beamable format if not local, default Pino format if local\r\n const resolvedDestination = configuredDestination === 'temp' ? ensureWritableTempDirectory() : configuredDestination;\r\n if (!usePrettyLogs) {\r\n const beamableFormatter = createBeamableLogFormatter(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n otlpProviderRef\r\n );\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n beamableFormatter.pipe(fileStream as unknown as NodeJS.WritableStream);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n return pino(pinoOptions, fileStream);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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","sourcesContent":["import pino, { destination, type Logger, type LoggerOptions } from 'pino';\r\nimport { Transform } from 'node:stream';\r\nimport { createRequire } from 'node:module';\r\nimport { ensureWritableTempDirectory } from './env.js';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { logs } from '@opentelemetry/api-logs';\r\nimport { LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs';\r\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\r\nimport { resourceFromAttributes, defaultResource } from '@opentelemetry/resources';\r\nimport { discoverOrStartCollector } from './collector-manager.js';\r\nimport type { Logger as PinoLogger } from 'pino';\r\nimport deasync from 'deasync';\r\n\r\n// Helper to get require function that works in both CJS and ESM\r\ndeclare const require: any;\r\nfunction getRequire(): any {\r\n // Check if we're in CJS context (require.main exists)\r\n if (typeof require !== 'undefined' && typeof require.main !== 'undefined') {\r\n // CJS context - use require directly\r\n return require;\r\n }\r\n // ESM context - use createRequire with import.meta.url\r\n // TypeScript will complain in CJS builds, but this code only runs in ESM\r\n // @ts-ignore - import.meta is ESM-only, TypeScript error in CJS is expected\r\n return createRequire(import.meta.url);\r\n}\r\n\r\n/**\r\n * Determines if we should use pretty logs (local dev) or raw JSON logs (deployed).\r\n * \r\n * Simple check: If IS_LOCAL=1 is set in environment, use pretty logs.\r\n * Otherwise, use raw Beamable JSON format for log collection.\r\n */\r\nfunction shouldUsePrettyLogs(): boolean {\r\n // Check for explicit IS_LOCAL flag\r\n return process.env.IS_LOCAL === '1' || process.env.IS_LOCAL === 'true';\r\n}\r\n\r\ninterface LoggerFactoryOptions {\r\n name?: string;\r\n destinationPath?: string;\r\n serviceName?: string; // Service name for log filtering (e.g., \"ExampleNodeService\")\r\n qualifiedServiceName?: string; // Full qualified service name (e.g., \"micro_ExampleNodeService\")\r\n otlpEndpoint?: string; // OTLP endpoint if collector is already set up (avoids re-discovery)\r\n}\r\n\r\n/**\r\n * Maps Pino log levels to Beamable log levels\r\n * Pino levels: 10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal\r\n * Beamable levels: Debug, Info, Warning, Error, Fatal\r\n */\r\nfunction mapPinoLevelToBeamableLevel(level: number): string {\r\n switch (level) {\r\n case 10: // trace\r\n return 'Debug';\r\n case 20: // debug\r\n return 'Debug';\r\n case 30: // info\r\n return 'Info';\r\n case 40: // warn\r\n return 'Warning';\r\n case 50: // error\r\n return 'Error';\r\n case 60: // fatal\r\n return 'Fatal';\r\n default:\r\n return 'Info';\r\n }\r\n}\r\n\r\n/**\r\n * Initializes OpenTelemetry OTLP log exporter if configured.\r\n * Similar to C# microservices, checks for BEAM_OTEL_EXPORTER_OTLP_ENDPOINT or uses standard enabled flag.\r\n * \r\n * @param serviceName - Service name for resource attributes\r\n * @param qualifiedServiceName - Qualified service name for resource attributes\r\n * @param env - Environment configuration\r\n * @returns OTLP logger provider if configured, null otherwise\r\n */\r\nasync function initializeOtlpLogging(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n env?: EnvironmentConfig,\r\n logger?: PinoLogger\r\n): Promise<LoggerProvider | null> {\r\n // Check for explicit OTLP endpoint (same as C#: BEAM_OTEL_EXPORTER_OTLP_ENDPOINT)\r\n // Also check standard OTEL environment variables\r\n const otlpEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT \r\n || process.env.OTEL_EXPORTER_OTLP_ENDPOINT\r\n || (process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS : null);\r\n \r\n // Check for explicit OTLP protocol (same as C#: OtelExporterOtlpProtocol)\r\n // C# uses OtlpExportProtocol enum: HttpProtobuf or HttpJson\r\n const otlpProtocol = process.env.BEAM_OTEL_EXPORTER_OTLP_PROTOCOL\r\n || process.env.OTEL_EXPORTER_OTLP_PROTOCOL\r\n || process.env.OTEL_EXPORTER_OTLP_PROTOCOL_LOGS;\r\n \r\n // Check if standard OTLP is enabled (matching C# OtelExporterStandardEnabled)\r\n // C#: (this.InDocker() || UseLocalOtel) && string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"BEAM_DISABLE_STANDARD_OTEL\"))\r\n // UseLocalOtel = BEAM_LOCAL_OTEL is set\r\n // InDocker = IS_LOCAL is not set (for Node.js, we check IS_LOCAL !== '1' && !== 'true')\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 \r\n // If no explicit endpoint and standard OTLP not enabled, skip OTLP\r\n if (!otlpEndpoint && !standardOtelEnabled) {\r\n return Promise.resolve(null);\r\n }\r\n \r\n try {\r\n // Build resource attributes (similar to C# resourceProvider)\r\n const resourceAttributes: Record<string, string> = {};\r\n if (serviceName) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n if (qualifiedServiceName) {\r\n resourceAttributes['service.instance.id'] = qualifiedServiceName;\r\n }\r\n if (env?.cid) {\r\n resourceAttributes['beam.cid'] = String(env.cid);\r\n }\r\n if (env?.pid) {\r\n resourceAttributes['beam.pid'] = String(env.pid);\r\n }\r\n if (env?.routingKey) {\r\n resourceAttributes['beam.routing_key'] = String(env.routingKey);\r\n }\r\n \r\n // Determine endpoint URL\r\n // If explicit endpoint provided, use it (append /v1/logs if needed for HTTP)\r\n // If standard OTLP enabled but no explicit endpoint, try to discover or start collector\r\n let endpointUrl = otlpEndpoint;\r\n \r\n if (!endpointUrl && standardOtelEnabled && logger) {\r\n // Try to discover existing collector or start a new one (like C# does)\r\n try {\r\n const discoveredEndpoint = await discoverOrStartCollector(logger, standardOtelEnabled, env);\r\n if (discoveredEndpoint) {\r\n endpointUrl = discoveredEndpoint;\r\n } else {\r\n console.error('[OTLP] Standard OTLP is enabled but could not discover or start collector.');\r\n return Promise.resolve(null);\r\n }\r\n } catch (error) {\r\n console.error('[OTLP] Failed to discover/start collector:', error instanceof Error ? error.message : String(error));\r\n return Promise.resolve(null);\r\n }\r\n }\r\n \r\n // If still no endpoint, skip OTLP\r\n if (!endpointUrl) {\r\n if (standardOtelEnabled) {\r\n console.error('[OTLP] Standard OTLP is enabled but no endpoint available. Set BEAM_OTEL_EXPORTER_OTLP_ENDPOINT to enable OTLP logging.');\r\n }\r\n return Promise.resolve(null);\r\n }\r\n \r\n // Ensure endpoint format is correct based on protocol\r\n // C# behavior:\r\n // - Http protocol: endpoint should be like \"http://127.0.0.1:4348\" (with /v1/logs appended)\r\n // - Grpc protocol: endpoint should be like \"127.0.0.1:4348\" (no http:// prefix, no /v1/logs)\r\n // For now, we only support HTTP exporter, so we append /v1/logs\r\n // If Grpc is specified, we'd need a different exporter package\r\n let finalEndpointUrl = endpointUrl;\r\n if (otlpProtocol && otlpProtocol.toLowerCase() === 'grpc') {\r\n // Grpc protocol - don't modify endpoint (no http://, no /v1/logs)\r\n // Note: Grpc exporter not yet implemented, this is for future support\r\n console.warn('[OTLP] Grpc protocol specified but not yet supported, using HTTP endpoint format');\r\n finalEndpointUrl = endpointUrl.includes('/v1/logs') \r\n ? endpointUrl \r\n : `${endpointUrl.replace(/\\/$/, '')}/v1/logs`;\r\n } else {\r\n // HTTP protocol - ensure /v1/logs suffix\r\n finalEndpointUrl = endpointUrl.includes('/v1/logs') \r\n ? endpointUrl \r\n : `${endpointUrl.replace(/\\/$/, '')}/v1/logs`;\r\n }\r\n \r\n // Create OTLP HTTP exporter\r\n // Beamable uses HttpProtobuf as the standard protocol\r\n // C# behavior:\r\n // 1. If OtelExporterOtlpEndpoint and OtelExporterOtlpProtocol are provided, use them\r\n // 2. Otherwise, always use HttpProtobuf protocol (Beamable's standard)\r\n // Node.js: @opentelemetry/exporter-logs-otlp-http uses HTTP/JSON by default\r\n // We configure contentType to 'application/x-protobuf' to match Beamable's standard\r\n const exporterOptions: {\r\n url: string;\r\n headers?: Record<string, string>;\r\n contentType?: string;\r\n } = {\r\n url: finalEndpointUrl,\r\n };\r\n \r\n // Configure protocol/contentType (matching C# OtlpExportProtocol)\r\n // Beamable uses HttpProtobuf as the default protocol\r\n // C# supports: HttpProtobuf, HttpJson, Grpc\r\n // If explicit protocol provided, use it; otherwise always default to HttpProtobuf\r\n if (otlpProtocol) {\r\n // Parse protocol string (HttpProtobuf, HttpJson, or Grpc)\r\n const protocol = otlpProtocol.toLowerCase();\r\n if (protocol === 'httpprotobuf' || protocol === 'protobuf') {\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n } else if (protocol === 'httpjson' || protocol === 'json') {\r\n exporterOptions.contentType = 'application/json';\r\n } else if (protocol === 'grpc') {\r\n // Note: Grpc protocol would require a different exporter package\r\n // For now, we'll log a warning and fall back to HttpProtobuf\r\n console.warn('[OTLP] Grpc protocol is not yet supported in Node.js runtime, falling back to HttpProtobuf');\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n } else {\r\n // Invalid protocol - default to HttpProtobuf (Beamable's standard)\r\n console.warn(`[OTLP] Unknown protocol \"${otlpProtocol}\", defaulting to HttpProtobuf`);\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n }\r\n } else {\r\n // No protocol specified - always default to HttpProtobuf (Beamable's standard)\r\n exporterOptions.contentType = 'application/x-protobuf';\r\n }\r\n \r\n // Headers if provided (matching C# OtelExporterOtlpHeaders)\r\n if (process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS) {\r\n exporterOptions.headers = JSON.parse(process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS);\r\n }\r\n \r\n const exporter = new OTLPLogExporter(exporterOptions);\r\n \r\n // Create resource with attributes (merge with default resource)\r\n // Note: BEAM_ALLOW_STARTUP_WITHOUT_ATTRIBUTES_RESOURCE is not applicable here\r\n // as we always create a resource with attributes\r\n const baseResource = defaultResource();\r\n const customResource = resourceFromAttributes(resourceAttributes);\r\n const resource = baseResource.merge(customResource);\r\n \r\n // Create log record processor\r\n // Note: C# supports retry via BEAM_DISABLE_RETRY_OTEL and BEAM_OTEL_RETRY_MAX_SIZE\r\n // SimpleLogRecordProcessor doesn't support retry - would need BatchLogRecordProcessor\r\n // For now, we use SimpleLogRecordProcessor (no retry)\r\n // TODO: Consider implementing retry logic if BEAM_DISABLE_RETRY_OTEL is not set\r\n const processor = new SimpleLogRecordProcessor(exporter);\r\n \r\n // Create logger provider with resource and processor\r\n const loggerProvider = new LoggerProvider({\r\n resource: resource,\r\n processors: [processor],\r\n });\r\n \r\n // Set as global logger provider\r\n logs.setGlobalLoggerProvider(loggerProvider);\r\n \r\n // Log successful initialization (to stdout for debugging)\r\n // This helps diagnose if OTLP is working in deployed environments\r\n console.error(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${finalEndpointUrl}, Service: ${serviceName || 'unknown'}`);\r\n \r\n // CRITICAL: Verify collector is actually ready before returning\r\n // If we started a collector, wait for it to be ready (up to 5 seconds)\r\n if (standardOtelEnabled && logger) {\r\n try {\r\n const { isCollectorRunning } = await import('./collector-manager.js');\r\n // Wait up to 5 seconds for collector to be ready\r\n for (let i = 0; i < 50; i++) {\r\n const status = await isCollectorRunning();\r\n if (status.isRunning && status.isReady) {\r\n if (logger) {\r\n logger.info(`[OTLP] Collector confirmed ready at ${status.otlpEndpoint || finalEndpointUrl}`);\r\n }\r\n break;\r\n }\r\n // Wait 100ms between checks\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n }\r\n } catch (error) {\r\n // If we can't verify, log but continue\r\n if (logger) {\r\n logger.warn(`[OTLP] Could not verify collector readiness: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n }\r\n \r\n return Promise.resolve(loggerProvider);\r\n } catch (error) {\r\n // If OTLP initialization fails, log error but continue without OTLP\r\n // Don't throw - we still want stdout logging to work\r\n // Log to stderr so it's visible in container logs\r\n console.error('[OTLP] Failed to initialize OTLP logging:', error instanceof Error ? error.message : String(error));\r\n if (error instanceof Error && error.stack) {\r\n console.error('[OTLP] Stack trace:', error.stack);\r\n }\r\n return Promise.resolve(null);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a transform stream that converts Pino JSON logs to Beamable's expected format.\r\n * Beamable expects logs with __t (timestamp), __l (level), and __m (message) fields.\r\n * Also includes OpenTelemetry-compatible fields for ClickHouse compatibility.\r\n * Pino writes JSON strings (one per line) to the stream.\r\n * \r\n * Also sends logs via OTLP if OTLP logger provider is configured.\r\n */\r\nfunction createBeamableLogFormatter(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n otlpProviderRef?: { provider: LoggerProvider | null }\r\n): Transform {\r\n return new Transform({\r\n objectMode: false, // Pino writes strings/Buffers, not objects\r\n transform(chunk: Buffer, _encoding, callback) {\r\n // Ensure we have a Buffer - Pino may write strings or Buffers\r\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\r\n try {\r\n const line = buffer.toString('utf8');\r\n // Skip empty lines\r\n if (!line.trim()) {\r\n callback();\r\n return;\r\n }\r\n \r\n // Parse Pino's JSON log line\r\n const pinoLog = JSON.parse(line);\r\n \r\n // Extract timestamp - Pino uses 'time' field (ISO 8601 string or milliseconds)\r\n // Convert to ISO 8601 string for Beamable\r\n let timestamp: string;\r\n if (typeof pinoLog.time === 'string') {\r\n timestamp = pinoLog.time;\r\n } else if (typeof pinoLog.time === 'number') {\r\n timestamp = new Date(pinoLog.time).toISOString();\r\n } else {\r\n timestamp = new Date().toISOString();\r\n }\r\n \r\n // Map Pino level to Beamable level\r\n const level = mapPinoLevelToBeamableLevel(pinoLog.level);\r\n \r\n // Build the message - combine msg with any additional fields\r\n // Pino's 'msg' field contains the log message\r\n const messageParts: string[] = [];\r\n if (pinoLog.msg) {\r\n messageParts.push(pinoLog.msg);\r\n }\r\n \r\n // Include error information if present\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n const errMsg = err.message || err.msg || 'Error';\r\n const errStack = err.stack ? `\\n${err.stack}` : '';\r\n messageParts.push(`${errMsg}${errStack}`);\r\n }\r\n \r\n // Build the Beamable log format (for CloudWatch Logs Insights)\r\n const beamableLog: Record<string, unknown> = {\r\n __t: timestamp,\r\n __l: level,\r\n __m: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n };\r\n \r\n // Include additional context fields that might be useful\r\n // These are included in the message object but not as top-level fields\r\n const contextFields: Record<string, unknown> = {};\r\n if (pinoLog.cid) contextFields.cid = pinoLog.cid;\r\n if (pinoLog.pid) contextFields.pid = pinoLog.pid;\r\n if (pinoLog.routingKey) contextFields.routingKey = pinoLog.routingKey;\r\n if (pinoLog.service) contextFields.service = pinoLog.service;\r\n if (pinoLog.component) contextFields.component = pinoLog.component;\r\n \r\n // Include service name in context for CloudWatch filtering\r\n if (serviceName) {\r\n contextFields.serviceName = serviceName;\r\n }\r\n if (qualifiedServiceName) {\r\n contextFields.qualifiedServiceName = qualifiedServiceName;\r\n }\r\n \r\n // Include any other fields that aren't standard Pino fields\r\n const standardPinoFields = ['level', 'time', 'pid', 'hostname', 'name', 'msg', 'err', 'v', 'cid', 'pid', 'routingKey', 'sdkVersionExecution', 'service', 'component'];\r\n for (const [key, value] of Object.entries(pinoLog)) {\r\n if (!standardPinoFields.includes(key) && value !== undefined && value !== null) {\r\n contextFields[key] = value;\r\n }\r\n }\r\n \r\n // If there are context fields, include them in the log\r\n if (Object.keys(contextFields).length > 0) {\r\n beamableLog.__c = contextFields;\r\n }\r\n \r\n // Add OpenTelemetry-compatible fields for ClickHouse compatibility\r\n // These fields allow an OpenTelemetry collector to parse and forward logs to ClickHouse\r\n // The Portal's realm-level logs page queries ClickHouse's otel_logs table\r\n const otelFields: Record<string, unknown> = {};\r\n \r\n // ResourceAttributes - service identification (for ClickHouse filtering)\r\n const resourceAttributes: Record<string, unknown> = {};\r\n // IMPORTANT: The Portal searches for service:ExampleNodeService (just the service name)\r\n // So we need to set service.namespace to the service name, NOT the qualified name\r\n // The qualified name (micro_ExampleNodeService) is used for CloudWatch log stream filtering\r\n // But ClickHouse uses just the service name for filtering\r\n if (serviceName) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n // Also include qualified name for reference\r\n if (qualifiedServiceName) {\r\n resourceAttributes['service.qualifiedName'] = qualifiedServiceName;\r\n }\r\n if (pinoLog.cid) {\r\n resourceAttributes['beam.cid'] = String(pinoLog.cid);\r\n }\r\n if (pinoLog.pid) {\r\n resourceAttributes['beam.pid'] = String(pinoLog.pid);\r\n }\r\n if (pinoLog.routingKey) {\r\n resourceAttributes['beam.routing_key'] = String(pinoLog.routingKey);\r\n }\r\n \r\n // LogAttributes - log-specific attributes\r\n const logAttributes: Record<string, unknown> = {};\r\n if (pinoLog.component) {\r\n logAttributes['component'] = String(pinoLog.component);\r\n }\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n if (err.message) logAttributes['exception.message'] = String(err.message);\r\n if (err.stack) logAttributes['exception.stacktrace'] = String(err.stack);\r\n if (err.type) logAttributes['exception.type'] = String(err.type);\r\n }\r\n \r\n // Map Beamable log level to OpenTelemetry SeverityText\r\n // Beamable: Debug, Info, Warning, Error, Fatal\r\n // OpenTelemetry: Trace, Debug, Info, Warn, Error, Fatal, Unspecified\r\n const severityTextMap: Record<string, string> = {\r\n 'Debug': 'Debug',\r\n 'Info': 'Information',\r\n 'Warning': 'Warning',\r\n 'Error': 'Error',\r\n 'Fatal': 'Critical',\r\n };\r\n const severityText = severityTextMap[level] || 'Information';\r\n \r\n // CRITICAL: ResourceAttributes and LogAttributes MUST always be present (even if empty)\r\n // ClickHouse schema expects these fields to exist for proper querying\r\n // The Portal queries ResourceAttributes['service.namespace'] - if ResourceAttributes is missing, queries fail\r\n \r\n // Ensure ResourceAttributes always has service.namespace when serviceName is provided\r\n // This is the primary field used by Portal for service filtering\r\n if (serviceName && !resourceAttributes['service.namespace']) {\r\n resourceAttributes['service.namespace'] = serviceName;\r\n resourceAttributes['service.name'] = serviceName;\r\n }\r\n \r\n // Add OpenTelemetry fields to the log\r\n // These are in addition to the Beamable format, so both systems can parse the logs\r\n // CRITICAL: Always include all required OpenTelemetry fields for ClickHouse compatibility\r\n otelFields['Timestamp'] = timestamp; // OpenTelemetry timestamp format (ISO 8601)\r\n otelFields['SeverityText'] = severityText;\r\n otelFields['Body'] = messageParts.length > 0 ? messageParts.join(' ') : 'No message';\r\n // ALWAYS include ResourceAttributes (even if empty) - required for ClickHouse schema\r\n otelFields['ResourceAttributes'] = resourceAttributes;\r\n // ALWAYS include LogAttributes (even if empty) - required for ClickHouse schema\r\n otelFields['LogAttributes'] = logAttributes;\r\n \r\n // IMPORTANT: For CloudWatch Logs Insights, we need to ensure @message contains valid JSON\r\n // The Portal expects @message to be a JSON string that can be parsed to extract __t, __l, __m\r\n // We output the Beamable format as the primary format, and include OpenTelemetry fields\r\n // CloudWatch will store this as @message, and an OpenTelemetry collector will parse it\r\n // and forward to ClickHouse's otel_logs table\r\n \r\n // Merge OpenTelemetry fields into the log (for ClickHouse compatibility)\r\n // An OpenTelemetry collector can parse these fields and forward to ClickHouse\r\n // Note: These extra fields won't break CloudWatch - it will just store them in @message\r\n Object.assign(beamableLog, otelFields);\r\n \r\n // Send log via OTLP if configured (similar to C# MicroserviceOtelLogRecordExporter)\r\n // Check if provider is available (may be null if still initializing)\r\n if (otlpProviderRef?.provider) {\r\n try {\r\n const otlpLogger = otlpProviderRef.provider.getLogger(\r\n serviceName || 'beamable-node-runtime',\r\n undefined, // version\r\n {\r\n schemaUrl: undefined, // optional schema URL\r\n }\r\n );\r\n \r\n // Map Beamable level to OpenTelemetry SeverityNumber\r\n const severityNumberMap: Record<string, number> = {\r\n 'Debug': 5, // SEVERITY_NUMBER_DEBUG\r\n 'Info': 9, // SEVERITY_NUMBER_INFO\r\n 'Warning': 13, // SEVERITY_NUMBER_WARN\r\n 'Error': 17, // SEVERITY_NUMBER_ERROR\r\n 'Fatal': 21, // SEVERITY_NUMBER_FATAL\r\n };\r\n \r\n // Create log record for OTLP\r\n otlpLogger.emit({\r\n severityNumber: severityNumberMap[level] || 9,\r\n severityText: severityText,\r\n body: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n attributes: {\r\n ...logAttributes,\r\n // Include additional context\r\n ...(pinoLog.component ? { component: String(pinoLog.component) } : {}),\r\n },\r\n timestamp: new Date(timestamp).getTime() * 1_000_000, // nanoseconds\r\n observedTimestamp: Date.now() * 1_000_000, // nanoseconds\r\n });\r\n } catch (otlpError) {\r\n // If OTLP send fails, continue with stdout logging\r\n // Don't block the log output\r\n // Note: C# supports retry via BEAM_DISABLE_RETRY_OTEL and BEAM_OTEL_RETRY_MAX_SIZE\r\n // SimpleLogRecordProcessor doesn't support retry - would need BatchLogRecordProcessor\r\n // For now, we silently continue (retry would be handled at processor level if implemented)\r\n }\r\n }\r\n \r\n // Output as a single-line JSON string (required for CloudWatch)\r\n // CloudWatch Logs Insights will store this entire JSON string in the @message field\r\n const output = JSON.stringify(beamableLog) + '\\n';\r\n callback(null, Buffer.from(output, 'utf8'));\r\n } catch (error) {\r\n // If parsing fails, output a fallback log entry\r\n const fallbackLog = {\r\n __t: new Date().toISOString(),\r\n __l: 'Error',\r\n __m: `Failed to parse log entry: ${chunk.toString().substring(0, 200)}`,\r\n };\r\n callback(null, Buffer.from(JSON.stringify(fallbackLog) + '\\n', 'utf8'));\r\n }\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Synchronously initializes OTLP logging with a timeout.\r\n * This ensures OTLP is ready before any logs are emitted.\r\n * Similar to C# microservices which configure logging early in startup.\r\n * \r\n * Uses a blocking wait mechanism to ensure initialization completes before returning.\r\n */\r\nfunction initializeOtlpSync(\r\n serviceName?: string,\r\n qualifiedServiceName?: string,\r\n env?: EnvironmentConfig,\r\n timeoutMs: number = 60000 // 60 seconds to allow collector download, startup, and readiness check\r\n): LoggerProvider | 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\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n // If collector was already set up via setupCollectorBeforeLogging, \r\n // discoverOrStartCollector will find it and use a shorter timeout.\r\n // If not, it will start it (with full timeout).\r\n \r\n // Use deasync to wait synchronously for the async initialization\r\n // This allows the event loop to process while we wait, enabling async operations\r\n // (like collector download) to complete\r\n let provider: LoggerProvider | null = null;\r\n let completed = false;\r\n let initError: Error | null = null;\r\n \r\n // Start initialization promise (callbacks set flags for deasync.loopWhile to check)\r\n initializeOtlpLogging(\r\n serviceName,\r\n qualifiedServiceName,\r\n env,\r\n initLogger\r\n ).then((result) => {\r\n provider = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info('[OTLP] OpenTelemetry logging initialized successfully');\r\n }\r\n return result;\r\n }).catch((error) => {\r\n initError = error instanceof Error ? error : new Error(String(error));\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to initialize: ${initError.message}`);\r\n return null;\r\n });\r\n \r\n // Set timeout to prevent infinite wait\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Initialization timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n \r\n // Wait synchronously for the promise to resolve using deasync\r\n // deasync.loopWhile() allows event loop to process while we wait\r\n // This enables async operations (like collector download) to run and complete\r\n // CRITICAL: This must complete before the logger is created to capture all startup logs\r\n try {\r\n // Use deasync to wait for completion, with timeout check\r\n // loopWhile returns false to stop waiting, true to continue\r\n deasync.loopWhile(() => {\r\n // Check if we've exceeded timeout\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n initLogger.warn(`[OTLP] Synchronous wait timeout after ${elapsed}ms`);\r\n return false; // Stop waiting\r\n }\r\n // Continue waiting if not completed\r\n // This allows the event loop to process async operations\r\n return !completed;\r\n });\r\n } catch (error) {\r\n // If deasync fails, log and continue\r\n initLogger.error(`[OTLP] Error during synchronous wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n \r\n clearTimeout(timeoutId);\r\n \r\n // Verify we got a provider (collector is ready)\r\n if (completed && provider) {\r\n initLogger.info('[OTLP] Initialization completed successfully, collector is ready');\r\n } else if (!completed) {\r\n initLogger.warn('[OTLP] Initialization did not complete in time, logs may not be sent via OTLP initially');\r\n initLogger.warn('[OTLP] Service will continue without OTLP telemetry - requests will still be serviced');\r\n } else {\r\n initLogger.warn('[OTLP] Initialization completed but no provider returned, OTLP telemetry disabled');\r\n }\r\n \r\n return provider;\r\n}\r\n\r\nexport function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptions = {}): Logger {\r\n const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;\r\n const usePrettyLogs = shouldUsePrettyLogs();\r\n \r\n // Initialize OTLP synchronously BEFORE creating the logger\r\n // If otlpEndpoint is provided (collector already set up), create provider directly\r\n // Otherwise, try to discover/start collector (with timeout)\r\n let otlpProvider: LoggerProvider | null = null;\r\n \r\n if (options.otlpEndpoint) {\r\n // Collector is already set up, create OTLP provider directly without discovery/startup\r\n // Set endpoint in env temporarily so initializeOtlpLogging uses it directly\r\n const originalEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;\r\n \r\n // Create OTLP provider directly (collector is already running, so this should be fast)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n \r\n // Create provider synchronously - since endpoint is explicitly provided,\r\n // initializeOtlpLogging will skip discovery and create provider directly\r\n let provider: LoggerProvider | null = null;\r\n let completed = false;\r\n \r\n initializeOtlpLogging(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n initLogger\r\n ).then((result) => {\r\n provider = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);\r\n }\r\n }).catch((error) => {\r\n initLogger.error(`[OTLP] Failed to create OTLP provider: ${error instanceof Error ? error.message : String(error)}`);\r\n completed = true;\r\n provider = null;\r\n });\r\n \r\n // Wait briefly for provider creation (should be very fast, < 1 second)\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n const deasync = require('deasync');\r\n const startTime = Date.now();\r\n const timeout = 2000; // 2 second timeout (should be fast since no discovery needed)\r\n \r\n deasync.loopWhile(() => {\r\n if (Date.now() - startTime >= timeout) {\r\n return false;\r\n }\r\n return !completed;\r\n });\r\n \r\n otlpProvider = provider;\r\n \r\n // Restore original endpoint if it existed\r\n if (originalEndpoint !== undefined) {\r\n process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = originalEndpoint;\r\n } else {\r\n delete process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n }\r\n } else {\r\n // No endpoint provided - try to discover/start collector (full initialization)\r\n // This ensures all logs from this point forward are captured via OTLP\r\n otlpProvider = initializeOtlpSync(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n 60000 // 60 second timeout to allow collector download, startup, and readiness verification\r\n );\r\n }\r\n \r\n // Shared reference for OTLP logger provider\r\n const otlpProviderRef: { provider: LoggerProvider | null } = { provider: otlpProvider };\r\n\r\n const pinoOptions: LoggerOptions = {\r\n name: options.name ?? 'beamable-node-runtime',\r\n level: env.logLevel,\r\n base: {\r\n cid: env.cid,\r\n pid: env.pid,\r\n routingKey: env.routingKey ?? null,\r\n sdkVersionExecution: env.sdkVersionExecution,\r\n // Include service name in base fields for filtering\r\n serviceName: options.serviceName,\r\n qualifiedServiceName: options.qualifiedServiceName,\r\n },\r\n redact: {\r\n paths: ['secret', 'refreshToken'],\r\n censor: '***',\r\n },\r\n // Use timestamp in milliseconds (Pino default) for accurate conversion\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n };\r\n\r\n // For deployed services, always log to stdout so container orchestrator can collect logs\r\n // For local development, log to stdout unless a specific file path is provided\r\n if (!configuredDestination || configuredDestination === '-' || configuredDestination === 'stdout' || configuredDestination === 'console') {\r\n if (!usePrettyLogs) {\r\n // Deployed/remote: Use Beamable JSON format for log collection\r\n // Include OpenTelemetry fields for ClickHouse compatibility\r\n // Also send logs via OTLP if configured\r\n const beamableFormatter = createBeamableLogFormatter(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n otlpProviderRef\r\n );\r\n beamableFormatter.pipe(process.stdout);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n // Local development: Use Pino's pretty printing for human-readable logs\r\n // Try to use pino-pretty if available (optional dependency)\r\n // If not available, fall back to default Pino JSON output\r\n try {\r\n // Check if pino-pretty is available\r\n // Use getRequire() which handles both CJS and ESM contexts\r\n const requireFn = getRequire();\r\n const pinoPretty = requireFn('pino-pretty');\r\n // Create a pretty stream with formatting options\r\n const prettyStream = pinoPretty({\r\n colorize: true,\r\n translateTime: 'HH:MM:ss.l',\r\n ignore: 'pid,hostname',\r\n singleLine: false,\r\n });\r\n // Use pino with the pretty stream\r\n return pino(pinoOptions, prettyStream);\r\n } catch {\r\n // pino-pretty not available, use default Pino output (JSON but readable)\r\n // This is expected if pino-pretty isn't installed, so we silently fall back\r\n return pino(pinoOptions, process.stdout);\r\n }\r\n }\r\n }\r\n\r\n // For file logging: Use Beamable format if not local, default Pino format if local\r\n const resolvedDestination = configuredDestination === 'temp' ? ensureWritableTempDirectory() : configuredDestination;\r\n if (!usePrettyLogs) {\r\n const beamableFormatter = createBeamableLogFormatter(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n otlpProviderRef\r\n );\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n beamableFormatter.pipe(fileStream as unknown as NodeJS.WritableStream);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n return pino(pinoOptions, fileStream);\r\n }\r\n}\r\n"]}
package/dist/runtime.cjs CHANGED
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.MicroserviceRuntime = void 0;
4
7
  exports.runMicroservice = runMicroservice;
@@ -9,6 +12,8 @@ const requester_js_1 = require("./requester.js");
9
12
  const auth_js_1 = require("./auth.js");
10
13
  const logger_js_1 = require("./logger.js");
11
14
  const env_js_1 = require("./env.js");
15
+ const collector_manager_js_1 = require("./collector-manager.js");
16
+ const pino_1 = __importDefault(require("pino"));
12
17
  const decorators_js_1 = require("./decorators.js");
13
18
  const docs_js_1 = require("./docs.js");
14
19
  const index_js_1 = require("./index.js");
@@ -24,16 +29,30 @@ class MicroserviceRuntime {
24
29
  this.microServiceId = (0, node_crypto_1.randomUUID)();
25
30
  this.isReady = false;
26
31
  this.env = env !== null && env !== void 0 ? env : (0, env_js_1.loadEnvironmentConfig)();
32
+ const startupLogger = (0, pino_1.default)({
33
+ name: 'beamable-runtime-startup',
34
+ level: 'info',
35
+ }, process.stdout);
36
+ startupLogger.info('Starting Beamable Node microservice runtime.');
27
37
  const registered = (0, decorators_js_1.listRegisteredServices)();
28
38
  if (registered.length === 0) {
29
39
  throw new Error('No microservices registered. Use the @Microservice decorator to register at least one class.');
30
40
  }
31
41
  const primaryService = registered[0];
32
42
  const qualifiedServiceName = `micro_${primaryService.qualifiedName}`;
43
+ startupLogger.info('Setting up OpenTelemetry collector...');
44
+ const otlpEndpoint = (0, collector_manager_js_1.setupCollectorBeforeLogging)(this.env, 60000);
45
+ if (otlpEndpoint) {
46
+ startupLogger.info(`Collector ready at ${otlpEndpoint}, creating main logger...`);
47
+ }
48
+ else {
49
+ startupLogger.warn('Collector setup did not complete, continuing without OTLP logging');
50
+ }
33
51
  this.logger = (0, logger_js_1.createLogger)(this.env, {
34
52
  name: 'beamable-node-microservice',
35
53
  serviceName: primaryService.name,
36
54
  qualifiedServiceName: qualifiedServiceName,
55
+ otlpEndpoint: otlpEndpoint || undefined,
37
56
  });
38
57
  this.serviceManager = new services_js_1.BeamableServiceManager(this.env, this.logger);
39
58
  this.services = registered.map((definition) => {
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,iBAAiB,EAOlB,MAAM,YAAY,CAAC;AA2BpB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,OAAO,CAAkB;gBAErB,GAAG,CAAC,EAAE,iBAAiB;IA2D7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6DtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YASjB,sBAAsB;YA2CtB,qBAAqB;YAarB,eAAe;YA+Gf,WAAW;IA8BzB,OAAO,CAAC,gBAAgB;IAkFxB,OAAO,CAAC,kBAAkB;YAUZ,QAAQ;IAsDtB,OAAO,CAAC,wBAAwB;YAmBlB,mBAAmB;YAiBnB,sBAAsB;YAStB,wBAAwB;YAoBxB,mBAAmB;IA2GjC,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,gBAAgB;YA+BV,6BAA6B;IA6B3C,OAAO,CAAC,kBAAkB;CAK3B;AA+GD,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoDrD;AAED,UAAU,sBAAsB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,4CAA4C,CAC1D,SAAS,GAAE,OAAO,CAAC,iBAAiB,CAAM,EAC1C,OAAO,GAAE,sBAA2B,GACnC,OAAO,CA6BT"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,iBAAiB,EAOlB,MAAM,YAAY,CAAC;AA2BpB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,OAAO,CAAkB;gBAErB,GAAG,CAAC,EAAE,iBAAiB;IAoF7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6DtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YASjB,sBAAsB;YA2CtB,qBAAqB;YAarB,eAAe;YA+Gf,WAAW;IA8BzB,OAAO,CAAC,gBAAgB;IAkFxB,OAAO,CAAC,kBAAkB;YAUZ,QAAQ;IAsDtB,OAAO,CAAC,wBAAwB;YAmBlB,mBAAmB;YAiBnB,sBAAsB;YAStB,wBAAwB;YAoBxB,mBAAmB;IA2GjC,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,gBAAgB;YA+BV,6BAA6B;IA6B3C,OAAO,CAAC,kBAAkB;CAK3B;AA+GD,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoDrD;AAED,UAAU,sBAAsB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,4CAA4C,CAC1D,SAAS,GAAE,OAAO,CAAC,iBAAiB,CAAM,EAC1C,OAAO,GAAE,sBAA2B,GACnC,OAAO,CA6BT"}
package/dist/runtime.js 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';
@@ -28,7 +30,14 @@ export class MicroserviceRuntime {
28
30
  isReady = false;
29
31
  constructor(env) {
30
32
  this.env = env ?? loadEnvironmentConfig();
31
- // Get registered services first to extract service name for logger
33
+ // STEP 1: Create minimal console logger for startup messages (before collector setup)
34
+ // This ensures we have logging available immediately, even before collector is ready
35
+ const startupLogger = pino({
36
+ name: 'beamable-runtime-startup',
37
+ level: 'info',
38
+ }, process.stdout);
39
+ startupLogger.info('Starting Beamable Node microservice runtime.');
40
+ // STEP 2: Get registered services to extract service name
32
41
  const registered = listRegisteredServices();
33
42
  if (registered.length === 0) {
34
43
  throw new Error('No microservices registered. Use the @Microservice decorator to register at least one class.');
@@ -36,10 +45,24 @@ export class MicroserviceRuntime {
36
45
  // Use the first service's name for the main logger (for CloudWatch filtering and ClickHouse compatibility)
37
46
  const primaryService = registered[0];
38
47
  const qualifiedServiceName = `micro_${primaryService.qualifiedName}`;
48
+ // STEP 3: Setup collector BEFORE creating the main logger
49
+ // This ensures all logs from the main logger are captured via OTLP
50
+ startupLogger.info('Setting up OpenTelemetry collector...');
51
+ const otlpEndpoint = setupCollectorBeforeLogging(this.env, 60000 // 60 second timeout
52
+ );
53
+ if (otlpEndpoint) {
54
+ startupLogger.info(`Collector ready at ${otlpEndpoint}, creating main logger...`);
55
+ }
56
+ else {
57
+ startupLogger.warn('Collector setup did not complete, continuing without OTLP logging');
58
+ }
59
+ // STEP 4: Create main logger (collector is now ready, so all logs will be captured)
60
+ // Pass the OTLP endpoint to skip re-discovery/startup
39
61
  this.logger = createLogger(this.env, {
40
62
  name: 'beamable-node-microservice',
41
63
  serviceName: primaryService.name,
42
64
  qualifiedServiceName: qualifiedServiceName,
65
+ otlpEndpoint: otlpEndpoint || undefined, // Pass endpoint if collector was set up
43
66
  });
44
67
  this.serviceManager = new BeamableServiceManager(this.env, this.logger);
45
68
  this.services = registered.map((definition) => {