@omen.foundation/node-microservice-runtime 0.1.69 → 0.1.71
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.d.ts.map +1 -1
- package/dist/logger.js +7 -11
- package/dist/logger.js.map +1 -1
- package/dist/services.d.ts +2 -1
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +9 -0
- package/dist/services.js.map +1 -1
- package/package.json +1 -1
package/dist/logger.d.ts.map
CHANGED
|
@@ -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;AAiCpD,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;
|
|
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;AAiCpD,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;AA0eD,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CA6L/F"}
|
package/dist/logger.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Transform } from 'node:stream';
|
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { ensureWritableTempDirectory } from './env.js';
|
|
5
5
|
import { logs } from '@opentelemetry/api-logs';
|
|
6
|
-
import { LoggerProvider,
|
|
6
|
+
import { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
7
7
|
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
|
|
8
8
|
import { resourceFromAttributes, defaultResource } from '@opentelemetry/resources';
|
|
9
9
|
import { discoverOrStartCollector } from './collector-manager.js';
|
|
@@ -204,11 +204,9 @@ async function initializeOtlpLogging(serviceName, qualifiedServiceName, env, log
|
|
|
204
204
|
const customResource = resourceFromAttributes(resourceAttributes);
|
|
205
205
|
const resource = baseResource.merge(customResource);
|
|
206
206
|
// Create log record processor
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
// TODO: Consider implementing retry logic if BEAM_DISABLE_RETRY_OTEL is not set
|
|
211
|
-
const processor = new SimpleLogRecordProcessor(exporter);
|
|
207
|
+
// C# uses BatchLogRecordExportProcessor which batches logs for better performance
|
|
208
|
+
// and includes retry logic. We should match this behavior.
|
|
209
|
+
const processor = new BatchLogRecordProcessor(exporter);
|
|
212
210
|
// Create logger provider with resource and processor
|
|
213
211
|
const loggerProvider = new LoggerProvider({
|
|
214
212
|
resource: resource,
|
|
@@ -455,11 +453,9 @@ function createBeamableLogFormatter(serviceName, qualifiedServiceName, otlpProvi
|
|
|
455
453
|
});
|
|
456
454
|
}
|
|
457
455
|
catch (otlpError) {
|
|
458
|
-
// If OTLP send fails, continue with stdout logging
|
|
459
|
-
// Don't block the log output
|
|
460
|
-
|
|
461
|
-
// SimpleLogRecordProcessor doesn't support retry - would need BatchLogRecordProcessor
|
|
462
|
-
// For now, we silently continue (retry would be handled at processor level if implemented)
|
|
456
|
+
// If OTLP send fails, log the error but continue with stdout logging
|
|
457
|
+
// Don't block the log output - BatchLogRecordProcessor handles retries
|
|
458
|
+
console.error(`[OTLP] Failed to emit log record via OTLP: ${otlpError instanceof Error ? otlpError.message : String(otlpError)}`);
|
|
463
459
|
}
|
|
464
460
|
}
|
|
465
461
|
// Output as a single-line JSON string (required for CloudWatch)
|
package/dist/logger.js.map
CHANGED
|
@@ -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\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 directly (skip discovery/startup)\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 // CRITICAL: Only discover/start collector if no explicit endpoint was provided\r\n // If an endpoint is provided, it means the collector was already set up elsewhere\r\n // (e.g., by setupCollectorBeforeLogging in the runtime constructor)\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\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 // Check if standard OTLP is enabled (needed for the else branch)\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 // Shared reference for OTLP logger provider (create before async operations)\r\n const otlpProviderRef: { provider: LoggerProvider | null } = { provider: 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 OTLP provider asynchronously (non-blocking)\r\n // Since endpoint is explicitly provided and collector is already ready,\r\n // this should complete quickly, but we don't block for it\r\n initializeOtlpLogging(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n initLogger\r\n ).then((provider) => {\r\n if (provider) {\r\n otlpProviderRef.provider = provider;\r\n initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);\r\n initLogger.info(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${options.otlpEndpoint}/v1/logs, Service: ${options.serviceName || 'unknown'}`);\r\n } else {\r\n initLogger.warn('[OTLP] OTLP provider creation returned null, structured logs will not be sent via OTLP');\r\n otlpProviderRef.provider = null;\r\n }\r\n }).catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to create OTLP provider: ${errorMsg}`);\r\n otlpProviderRef.provider = null;\r\n });\r\n \r\n // Don't wait - logger will work immediately with console output,\r\n // and OTLP will be added when the provider is ready (very quickly since collector is already running)\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 - collector is starting asynchronously in background via startCollectorAsync()\r\n // Don't block here - logger works immediately via stdout, OTLP will connect when collector is ready\r\n otlpProviderRef.provider = null; // Start without OTLP - will connect when collector is ready\r\n \r\n // Start async discovery in background (non-blocking)\r\n // This allows the service to start immediately while collector is downloading/starting\r\n // CRITICAL: Only DISCOVER the collector, don't try to START it (startCollectorAsync handles startup)\r\n if (standardOtelEnabled) {\r\n // Poll for collector to become ready (won't block service startup)\r\n // startCollectorAsync() is already starting it, we just need to wait and connect when ready\r\n (async () => {\r\n const bgLogger = pino({ name: 'beamable-otlp-bg', level: 'info' }, process.stdout);\r\n const maxAttempts = 30; // Check for up to 30 seconds (30 * 1000ms)\r\n const checkInterval = 1000; // Check every 1 second\r\n \r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n // Import isCollectorRunning dynamically to avoid circular dependencies\r\n const { isCollectorRunning } = await import('./collector-manager.js');\r\n const collectorStatus = await isCollectorRunning();\r\n \r\n if (collectorStatus.isRunning && collectorStatus.isReady && collectorStatus.otlpEndpoint) {\r\n // Collector is ready - initialize OTLP logging now\r\n const endpoint = collectorStatus.otlpEndpoint.startsWith('http') \r\n ? collectorStatus.otlpEndpoint \r\n : `http://${collectorStatus.otlpEndpoint}`;\r\n \r\n const newProvider = await initializeOtlpLogging(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n bgLogger\r\n );\r\n \r\n if (newProvider) {\r\n // Update the provider reference so future logs use OTLP\r\n otlpProviderRef.provider = newProvider;\r\n console.error(`[OTLP] Connected to collector at ${endpoint} (background connection)`);\r\n break; // Success, stop polling\r\n }\r\n }\r\n } catch (error) {\r\n // Silently fail and continue polling\r\n }\r\n \r\n // Wait before next check (unless we're on the last attempt)\r\n if (attempt < maxAttempts - 1) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n }\r\n }\r\n })(); // Fire and forget - don't await\r\n }\r\n }\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, BatchLogRecordProcessor } 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\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 directly (skip discovery/startup)\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 // CRITICAL: Only discover/start collector if no explicit endpoint was provided\r\n // If an endpoint is provided, it means the collector was already set up elsewhere\r\n // (e.g., by setupCollectorBeforeLogging in the runtime constructor)\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 // C# uses BatchLogRecordExportProcessor which batches logs for better performance\r\n // and includes retry logic. We should match this behavior.\r\n const processor = new BatchLogRecordProcessor(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, log the error but continue with stdout logging\r\n // Don't block the log output - BatchLogRecordProcessor handles retries\r\n console.error(`[OTLP] Failed to emit log record via OTLP: ${otlpError instanceof Error ? otlpError.message : String(otlpError)}`);\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\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 // Check if standard OTLP is enabled (needed for the else branch)\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 // Shared reference for OTLP logger provider (create before async operations)\r\n const otlpProviderRef: { provider: LoggerProvider | null } = { provider: 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 OTLP provider asynchronously (non-blocking)\r\n // Since endpoint is explicitly provided and collector is already ready,\r\n // this should complete quickly, but we don't block for it\r\n initializeOtlpLogging(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n initLogger\r\n ).then((provider) => {\r\n if (provider) {\r\n otlpProviderRef.provider = provider;\r\n initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);\r\n initLogger.info(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${options.otlpEndpoint}/v1/logs, Service: ${options.serviceName || 'unknown'}`);\r\n } else {\r\n initLogger.warn('[OTLP] OTLP provider creation returned null, structured logs will not be sent via OTLP');\r\n otlpProviderRef.provider = null;\r\n }\r\n }).catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to create OTLP provider: ${errorMsg}`);\r\n otlpProviderRef.provider = null;\r\n });\r\n \r\n // Don't wait - logger will work immediately with console output,\r\n // and OTLP will be added when the provider is ready (very quickly since collector is already running)\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 - collector is starting asynchronously in background via startCollectorAsync()\r\n // Don't block here - logger works immediately via stdout, OTLP will connect when collector is ready\r\n otlpProviderRef.provider = null; // Start without OTLP - will connect when collector is ready\r\n \r\n // Start async discovery in background (non-blocking)\r\n // This allows the service to start immediately while collector is downloading/starting\r\n // CRITICAL: Only DISCOVER the collector, don't try to START it (startCollectorAsync handles startup)\r\n if (standardOtelEnabled) {\r\n // Poll for collector to become ready (won't block service startup)\r\n // startCollectorAsync() is already starting it, we just need to wait and connect when ready\r\n (async () => {\r\n const bgLogger = pino({ name: 'beamable-otlp-bg', level: 'info' }, process.stdout);\r\n const maxAttempts = 30; // Check for up to 30 seconds (30 * 1000ms)\r\n const checkInterval = 1000; // Check every 1 second\r\n \r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n // Import isCollectorRunning dynamically to avoid circular dependencies\r\n const { isCollectorRunning } = await import('./collector-manager.js');\r\n const collectorStatus = await isCollectorRunning();\r\n \r\n if (collectorStatus.isRunning && collectorStatus.isReady && collectorStatus.otlpEndpoint) {\r\n // Collector is ready - initialize OTLP logging now\r\n const endpoint = collectorStatus.otlpEndpoint.startsWith('http') \r\n ? collectorStatus.otlpEndpoint \r\n : `http://${collectorStatus.otlpEndpoint}`;\r\n \r\n const newProvider = await initializeOtlpLogging(\r\n options.serviceName,\r\n options.qualifiedServiceName,\r\n env,\r\n bgLogger\r\n );\r\n \r\n if (newProvider) {\r\n // Update the provider reference so future logs use OTLP\r\n otlpProviderRef.provider = newProvider;\r\n console.error(`[OTLP] Connected to collector at ${endpoint} (background connection)`);\r\n break; // Success, stop polling\r\n }\r\n }\r\n } catch (error) {\r\n // Silently fail and continue polling\r\n }\r\n \r\n // Wait before next check (unless we're on the last attempt)\r\n if (attempt < maxAttempts - 1) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n }\r\n }\r\n })(); // Fire and forget - don't await\r\n }\r\n }\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/services.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Logger } from 'pino';
|
|
2
2
|
import { type HttpRequester, AccountService, AnnouncementsService, AuthService, ContentService, LeaderboardsService, StatsService } from 'beamable-sdk';
|
|
3
3
|
import type { EnvironmentConfig } from './types.js';
|
|
4
4
|
import { type InventoryService } from './inventory.js';
|
|
@@ -20,6 +20,7 @@ export interface BeamableMicroserviceServices {
|
|
|
20
20
|
hasScopes(...scopes: string[]): boolean;
|
|
21
21
|
requireScopes(...scopes: string[]): void;
|
|
22
22
|
assumeUser(userId: string | number): BeamableMicroserviceServices;
|
|
23
|
+
getLogger(): Logger;
|
|
23
24
|
}
|
|
24
25
|
export declare class BeamableServiceManager {
|
|
25
26
|
private readonly logger;
|
package/dist/services.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAIL,KAAK,aAAa,EAClB,cAAc,EACd,oBAAoB,EACpB,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,YAAY,EACb,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAK1D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC;AAsQ3E,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,SAAS,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACxC,aAAa,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,4BAA4B,CAAC;IAClE,SAAS,IAAI,MAAM,CAAC;CACrB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAyC;gBAElE,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM;IAM5C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoDjC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,4BAA4B;IAyB9G,YAAY,IAAI,aAAa;IAO7B,WAAW,IAAI,YAAY;IAO3B,iBAAiB,IAAI,cAAc;IAOnC,SAAS,IAAI,MAAM;IAInB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAInF,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1E,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,CAAC,0BAA0B;IAYlC,OAAO,CAAC,uBAAuB;CAWhC"}
|
package/dist/services.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
1
2
|
import { BeamServer, BeamEnvironment, defaultTokenStorage, AccountService, AnnouncementsService, AuthService, ContentService, LeaderboardsService, StatsService, } from 'beamable-sdk';
|
|
2
3
|
import { hostToHttpUrl, hostToPortalUrl, hostToStorageUrl, hostToMicroserviceRegistryUrl } from './utils/urls.js';
|
|
3
4
|
import { createInventoryService } from './inventory.js';
|
|
@@ -102,6 +103,11 @@ class UnavailableBeamableServices {
|
|
|
102
103
|
assumeUser() {
|
|
103
104
|
return this;
|
|
104
105
|
}
|
|
106
|
+
getLogger() {
|
|
107
|
+
// For unavailable services, return a basic logger that logs to stdout
|
|
108
|
+
// This allows logging even when services are unavailable
|
|
109
|
+
return pino({ name: 'beamable-unavailable', level: 'info' }, process.stdout);
|
|
110
|
+
}
|
|
105
111
|
}
|
|
106
112
|
class BeamableServicesFacade {
|
|
107
113
|
manager;
|
|
@@ -187,6 +193,9 @@ class BeamableServicesFacade {
|
|
|
187
193
|
assumeUser(userId) {
|
|
188
194
|
return this.manager.createFacade(String(userId), new Set(this.scopes), this.serviceName);
|
|
189
195
|
}
|
|
196
|
+
getLogger() {
|
|
197
|
+
return this.logger;
|
|
198
|
+
}
|
|
190
199
|
scopeSetHas(scope) {
|
|
191
200
|
const normalized = scope.trim().toLowerCase();
|
|
192
201
|
if (!normalized) {
|
package/dist/services.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Logger } from 'pino';\r\nimport {\r\n BeamServer,\r\n BeamEnvironment,\r\n defaultTokenStorage,\r\n type HttpRequester,\r\n AccountService,\r\n AnnouncementsService,\r\n AuthService,\r\n ContentService,\r\n LeaderboardsService,\r\n StatsService,\r\n} from 'beamable-sdk';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl, hostToPortalUrl, hostToStorageUrl, hostToMicroserviceRegistryUrl } from './utils/urls.js';\r\nimport { createInventoryService, type InventoryService } from './inventory.js';\r\nimport { StorageService } from './storage.js';\r\nimport type { FederationRegistry } from './federation.js';\r\nimport { MissingScopesError } from './errors.js';\r\n\r\nconst RUNTIME_ENVIRONMENT_NAME = 'node-runtime';\r\n\r\nexport type BoundBeamApi = Record<string, (...args: unknown[]) => unknown>;\r\n\r\nlet cachedBeamApiModule: Record<string, unknown> | null = null;\r\n\r\nasync function resolveBeamApiModule(): Promise<Record<string, unknown>> {\r\n if (!cachedBeamApiModule) {\r\n const imported = await import('beamable-sdk/api');\r\n cachedBeamApiModule =\r\n imported && typeof imported === 'object' && 'default' in imported\r\n ? (imported.default as Record<string, unknown>)\r\n : (imported as Record<string, unknown>);\r\n }\r\n return cachedBeamApiModule;\r\n}\r\n\r\nasync function bindBeamApi(requester: HttpRequester): Promise<BoundBeamApi> {\r\n const module = await resolveBeamApiModule();\r\n const bound: Record<string, (...args: unknown[]) => unknown> = {};\r\n for (const key of Object.keys(module)) {\r\n const value = module[key];\r\n if (typeof value === 'function') {\r\n bound[key] = (...args: unknown[]) => (value as (r: HttpRequester, ...params: unknown[]) => unknown)(requester, ...args);\r\n }\r\n }\r\n return bound;\r\n}\r\n\r\nfunction createFailingApi(error: Error): BoundBeamApi {\r\n return new Proxy(\r\n {},\r\n {\r\n get() {\r\n throw error;\r\n },\r\n },\r\n ) as BoundBeamApi;\r\n}\r\n\r\ntype ServiceMap = {\r\n account: AccountService;\r\n announcements: AnnouncementsService;\r\n auth: AuthService;\r\n content: ContentService;\r\n leaderboards: LeaderboardsService;\r\n stats: StatsService;\r\n};\r\n\r\ntype ServiceKey = keyof ServiceMap;\r\n\r\nclass UnavailableRequester implements HttpRequester {\r\n constructor(private readonly error: Error) {}\r\n\r\n async request(): Promise<never> {\r\n throw this.error;\r\n }\r\n\r\n set baseUrl(_: string) {\r\n // no-op\r\n }\r\n\r\n set defaultHeaders(_: Record<string, string>) {\r\n // no-op\r\n }\r\n}\r\n\r\nclass UnavailableBeamableServices implements BeamableMicroserviceServices {\r\n private readonly requesterImpl: HttpRequester;\r\n private readonly apiBindings: BoundBeamApi;\r\n\r\n constructor(private readonly error: Error) {\r\n this.requesterImpl = new UnavailableRequester(this.error);\r\n this.apiBindings = createFailingApi(this.error);\r\n }\r\n\r\n private fail(): never {\r\n throw this.error;\r\n }\r\n\r\n get account(): AccountService {\r\n return this.fail();\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.fail();\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.fail();\r\n }\r\n\r\n get content(): ContentService {\r\n return this.fail();\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.fail();\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.fail();\r\n }\r\n\r\n get inventory(): InventoryService {\r\n return this.fail();\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.fail();\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n return this.fail();\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.requesterImpl;\r\n }\r\n\r\n hasScopes(..._scopes: string[]): boolean {\r\n return false;\r\n }\r\n\r\n requireScopes(...scopes: string[]): void {\r\n throw new MissingScopesError(scopes);\r\n }\r\n\r\n assumeUser(): BeamableMicroserviceServices {\r\n return this;\r\n }\r\n}\r\n\r\nclass BeamableServicesFacade implements BeamableMicroserviceServices {\r\n private readonly cache: Partial<Record<ServiceKey, ServiceMap[ServiceKey]>> = {};\r\n private readonly apiBindings: BoundBeamApi;\r\n private readonly storageService: StorageService;\r\n private readonly scopes: Set<string>;\r\n private readonly logger: Logger;\r\n private readonly serviceName?: string;\r\n private readonly federationRegistry?: FederationRegistry;\r\n private inventoryClient?: InventoryService;\r\n\r\n constructor(\r\n private readonly manager: BeamableServiceManager,\r\n private readonly beamServer: BeamServer,\r\n private readonly userId: string,\r\n scopes: Set<string>,\r\n serviceName?: string,\r\n ) {\r\n this.apiBindings = this.manager.getBoundApi();\r\n this.storageService = this.manager.getStorageService();\r\n this.scopes = scopes;\r\n this.serviceName = serviceName;\r\n this.federationRegistry = serviceName ? this.manager.getFederationRegistry(serviceName) : undefined;\r\n this.logger = this.manager.getLogger().child({ component: 'BeamableServicesFacade', service: serviceName });\r\n }\r\n\r\n private getOrCreate<K extends ServiceKey>(key: K, factory: () => ServiceMap[K]): ServiceMap[K] {\r\n if (!this.cache[key]) {\r\n this.cache[key] = factory();\r\n }\r\n return this.cache[key] as ServiceMap[K];\r\n }\r\n\r\n get account(): AccountService {\r\n return this.getOrCreate('account', () => this.beamServer.account(this.userId));\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.getOrCreate('announcements', () => this.beamServer.announcements(this.userId));\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.getOrCreate('auth', () => this.beamServer.auth(this.userId));\r\n }\r\n\r\n get content(): ContentService {\r\n return this.getOrCreate('content', () => this.beamServer.content(this.userId));\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.getOrCreate('leaderboards', () => this.beamServer.leaderboards(this.userId));\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.getOrCreate('stats', () => this.beamServer.stats(this.userId));\r\n }\r\n\r\n get inventory(): InventoryService {\r\n if (!this.inventoryClient) {\r\n this.inventoryClient = createInventoryService(\r\n this.apiBindings,\r\n this.logger.child({ component: 'InventoryClient' }),\r\n this.userId,\r\n (requiredScopes) => this.hasScopes(...requiredScopes),\r\n );\r\n }\r\n return this.inventoryClient;\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.storageService;\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n if (!this.federationRegistry) {\r\n throw new Error(\r\n this.serviceName\r\n ? `Federation registry is not configured for service \"${this.serviceName}\".`\r\n : 'Federation registry is not configured.',\r\n );\r\n }\r\n return this.federationRegistry;\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.manager.getRequester();\r\n }\r\n\r\n hasScopes(...requiredScopes: string[]): boolean {\r\n if (requiredScopes.length === 0) {\r\n return true;\r\n }\r\n return requiredScopes.every((scope) => this.scopeSetHas(scope));\r\n }\r\n\r\n requireScopes(...requiredScopes: string[]): void {\r\n if (!this.hasScopes(...requiredScopes)) {\r\n throw new MissingScopesError(requiredScopes);\r\n }\r\n }\r\n\r\n assumeUser(userId: string | number): BeamableMicroserviceServices {\r\n return this.manager.createFacade(String(userId), new Set(this.scopes), this.serviceName);\r\n }\r\n\r\n private scopeSetHas(scope: string): boolean {\r\n const normalized = scope.trim().toLowerCase();\r\n if (!normalized) {\r\n return false;\r\n }\r\n return this.scopes.has('*') || this.scopes.has(normalized);\r\n }\r\n}\r\n\r\nexport interface BeamableMicroserviceServices {\r\n readonly account: AccountService;\r\n readonly announcements: AnnouncementsService;\r\n readonly auth: AuthService;\r\n readonly content: ContentService;\r\n readonly leaderboards: LeaderboardsService;\r\n readonly stats: StatsService;\r\n readonly inventory: InventoryService;\r\n readonly storage: StorageService;\r\n readonly federation: FederationRegistry;\r\n readonly api: BoundBeamApi;\r\n readonly requester: HttpRequester;\r\n hasScopes(...scopes: string[]): boolean;\r\n requireScopes(...scopes: string[]): void;\r\n assumeUser(userId: string | number): BeamableMicroserviceServices;\r\n}\r\n\r\nexport class BeamableServiceManager {\r\n private readonly logger: Logger;\r\n private readonly tokenStorage: ReturnType<typeof defaultTokenStorage>;\r\n private readonly env: EnvironmentConfig;\r\n private beamServer?: BeamServer;\r\n private boundApi?: BoundBeamApi;\r\n private storageService?: StorageService;\r\n private initialized = false;\r\n private readonly federationRegistries = new Map<string, FederationRegistry>();\r\n\r\n constructor(env: EnvironmentConfig, logger: Logger) {\r\n this.env = env;\r\n this.logger = logger.child({ component: 'BeamableServiceManager' });\r\n this.tokenStorage = defaultTokenStorage({ pid: env.pid, tag: env.routingKey ?? RUNTIME_ENVIRONMENT_NAME });\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n if (this.initialized) {\r\n return;\r\n }\r\n\r\n this.registerEnvironment();\r\n this.configureSharedEnvironment();\r\n\r\n if (this.env.refreshToken) {\r\n await this.tokenStorage.setTokenData({ refreshToken: this.env.refreshToken });\r\n }\r\n\r\n const useSignedRequest = Boolean(this.env.secret);\r\n if (!useSignedRequest && !this.env.refreshToken) {\r\n this.logger.warn(\r\n 'Beamable realm secret and refresh token are both missing; Beamable SDK requests may fail due to missing credentials.',\r\n );\r\n }\r\n\r\n try {\r\n this.beamServer = await BeamServer.init({\r\n cid: this.env.cid,\r\n pid: this.env.pid,\r\n environment: RUNTIME_ENVIRONMENT_NAME,\r\n useSignedRequest,\r\n tokenStorage: this.tokenStorage,\r\n serverEvents: { enabled: false },\r\n });\r\n } catch (error) {\r\n this.logger.error({ err: error }, 'Failed to initialize Beamable SDK. Services layer will be unavailable.');\r\n this.beamServer = undefined;\r\n this.initialized = false;\r\n return;\r\n }\r\n\r\n this.boundApi = await bindBeamApi(this.beamServer.requester);\r\n \r\n // Configure the requester's default headers to include the routing key in the correct format\r\n // The routing key format is: serviceName:routingKey\r\n // We'll set this per-request in createFacade since we need the service name\r\n this.storageService = new StorageService({\r\n requester: this.beamServer.requester,\r\n api: this.boundApi,\r\n env: this.env,\r\n logger: this.logger.child({ component: 'StorageService' }),\r\n });\r\n\r\n this.registerDefaultServices();\r\n this.initialized = true;\r\n this.logger.debug('Beamable SDK services initialized.');\r\n }\r\n\r\n createFacade(userId: string | number, scopes: Set<string>, serviceName?: string): BeamableMicroserviceServices {\r\n if (!this.initialized || !this.beamServer || !this.boundApi || !this.storageService) {\r\n return new UnavailableBeamableServices(new Error('Beamable services are not initialized.'));\r\n }\r\n \r\n // Set the routing key in the format serviceName:routingKey for the SDK\r\n // The SDK uses BEAM_ROUTING_KEY environment variable to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We need to set it to the full format: serviceName:routingKey\r\n if (serviceName && this.beamServer.requester) {\r\n const fullRoutingKey = `micro_${serviceName}:${this.env.routingKey}`;\r\n BeamServer.env.BEAM_ROUTING_KEY = fullRoutingKey;\r\n \r\n // Set default headers on the requester for all SDK requests\r\n // These headers are required for signature validation and routing\r\n const scopeHeader = `${this.env.cid}.${this.env.pid}`;\r\n this.beamServer.requester.defaultHeaders = {\r\n ...this.beamServer.requester.defaultHeaders,\r\n 'X-BEAM-SCOPE': scopeHeader,\r\n 'X-BEAM-SERVICE-ROUTING-KEY': fullRoutingKey,\r\n };\r\n }\r\n \r\n return new BeamableServicesFacade(this, this.beamServer, String(userId), new Set(scopes), serviceName);\r\n }\r\n\r\n getRequester(): HttpRequester {\r\n if (!this.initialized || !this.beamServer) {\r\n return new UnavailableRequester(new Error('Beamable services are not initialized.'));\r\n }\r\n return this.beamServer.requester;\r\n }\r\n\r\n getBoundApi(): BoundBeamApi {\r\n if (!this.boundApi) {\r\n throw new Error('Beamable bound API is not available.');\r\n }\r\n return this.boundApi;\r\n }\r\n\r\n getStorageService(): StorageService {\r\n if (!this.storageService) {\r\n throw new Error('Storage service is not initialized.');\r\n }\r\n return this.storageService;\r\n }\r\n\r\n getLogger(): Logger {\r\n return this.logger;\r\n }\r\n\r\n registerFederationRegistry(serviceName: string, registry: FederationRegistry): void {\r\n this.federationRegistries.set(serviceName, registry);\r\n }\r\n\r\n getFederationRegistry(serviceName: string): FederationRegistry | undefined {\r\n return this.federationRegistries.get(serviceName);\r\n }\r\n\r\n private registerEnvironment(): void {\r\n const apiUrl = hostToHttpUrl(this.env.host);\r\n const portalUrl = hostToPortalUrl(apiUrl);\r\n const storageUrl = hostToStorageUrl(apiUrl);\r\n const registryUrl = hostToMicroserviceRegistryUrl(apiUrl);\r\n\r\n try {\r\n BeamEnvironment.register(RUNTIME_ENVIRONMENT_NAME, {\r\n apiUrl,\r\n portalUrl,\r\n beamMongoExpressUrl: storageUrl,\r\n dockerRegistryUrl: `${registryUrl}/v2/`,\r\n });\r\n } catch (error) {\r\n this.logger.debug({ err: error }, 'Beamable environment was already registered. Reusing existing configuration.');\r\n }\r\n }\r\n\r\n private configureSharedEnvironment(): void {\r\n if (this.env.secret) {\r\n BeamServer.env.BEAM_REALM_SECRET = this.env.secret;\r\n }\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We set it to just the routing key value here, and will set the full format in createFacade\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // For deployed services, routingKey is undefined, so we set it to empty string\r\n // The SDK will handle this appropriately\r\n BeamServer.env.BEAM_ROUTING_KEY = this.env.routingKey ?? '';\r\n }\r\n\r\n private registerDefaultServices(): void {\r\n if (!this.beamServer) {\r\n return;\r\n }\r\n this.beamServer.use(AccountService);\r\n this.beamServer.use(AnnouncementsService);\r\n this.beamServer.use(AuthService);\r\n this.beamServer.use(ContentService);\r\n this.beamServer.use(LeaderboardsService);\r\n this.beamServer.use(StatsService);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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","sourcesContent":["import pino, { type Logger } from 'pino';\r\nimport {\r\n BeamServer,\r\n BeamEnvironment,\r\n defaultTokenStorage,\r\n type HttpRequester,\r\n AccountService,\r\n AnnouncementsService,\r\n AuthService,\r\n ContentService,\r\n LeaderboardsService,\r\n StatsService,\r\n} from 'beamable-sdk';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl, hostToPortalUrl, hostToStorageUrl, hostToMicroserviceRegistryUrl } from './utils/urls.js';\r\nimport { createInventoryService, type InventoryService } from './inventory.js';\r\nimport { StorageService } from './storage.js';\r\nimport type { FederationRegistry } from './federation.js';\r\nimport { MissingScopesError } from './errors.js';\r\n\r\nconst RUNTIME_ENVIRONMENT_NAME = 'node-runtime';\r\n\r\nexport type BoundBeamApi = Record<string, (...args: unknown[]) => unknown>;\r\n\r\nlet cachedBeamApiModule: Record<string, unknown> | null = null;\r\n\r\nasync function resolveBeamApiModule(): Promise<Record<string, unknown>> {\r\n if (!cachedBeamApiModule) {\r\n const imported = await import('beamable-sdk/api');\r\n cachedBeamApiModule =\r\n imported && typeof imported === 'object' && 'default' in imported\r\n ? (imported.default as Record<string, unknown>)\r\n : (imported as Record<string, unknown>);\r\n }\r\n return cachedBeamApiModule;\r\n}\r\n\r\nasync function bindBeamApi(requester: HttpRequester): Promise<BoundBeamApi> {\r\n const module = await resolveBeamApiModule();\r\n const bound: Record<string, (...args: unknown[]) => unknown> = {};\r\n for (const key of Object.keys(module)) {\r\n const value = module[key];\r\n if (typeof value === 'function') {\r\n bound[key] = (...args: unknown[]) => (value as (r: HttpRequester, ...params: unknown[]) => unknown)(requester, ...args);\r\n }\r\n }\r\n return bound;\r\n}\r\n\r\nfunction createFailingApi(error: Error): BoundBeamApi {\r\n return new Proxy(\r\n {},\r\n {\r\n get() {\r\n throw error;\r\n },\r\n },\r\n ) as BoundBeamApi;\r\n}\r\n\r\ntype ServiceMap = {\r\n account: AccountService;\r\n announcements: AnnouncementsService;\r\n auth: AuthService;\r\n content: ContentService;\r\n leaderboards: LeaderboardsService;\r\n stats: StatsService;\r\n};\r\n\r\ntype ServiceKey = keyof ServiceMap;\r\n\r\nclass UnavailableRequester implements HttpRequester {\r\n constructor(private readonly error: Error) {}\r\n\r\n async request(): Promise<never> {\r\n throw this.error;\r\n }\r\n\r\n set baseUrl(_: string) {\r\n // no-op\r\n }\r\n\r\n set defaultHeaders(_: Record<string, string>) {\r\n // no-op\r\n }\r\n}\r\n\r\nclass UnavailableBeamableServices implements BeamableMicroserviceServices {\r\n private readonly requesterImpl: HttpRequester;\r\n private readonly apiBindings: BoundBeamApi;\r\n\r\n constructor(private readonly error: Error) {\r\n this.requesterImpl = new UnavailableRequester(this.error);\r\n this.apiBindings = createFailingApi(this.error);\r\n }\r\n\r\n private fail(): never {\r\n throw this.error;\r\n }\r\n\r\n get account(): AccountService {\r\n return this.fail();\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.fail();\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.fail();\r\n }\r\n\r\n get content(): ContentService {\r\n return this.fail();\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.fail();\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.fail();\r\n }\r\n\r\n get inventory(): InventoryService {\r\n return this.fail();\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.fail();\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n return this.fail();\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.requesterImpl;\r\n }\r\n\r\n hasScopes(..._scopes: string[]): boolean {\r\n return false;\r\n }\r\n\r\n requireScopes(...scopes: string[]): void {\r\n throw new MissingScopesError(scopes);\r\n }\r\n\r\n assumeUser(): BeamableMicroserviceServices {\r\n return this;\r\n }\r\n\r\n getLogger(): Logger {\r\n // For unavailable services, return a basic logger that logs to stdout\r\n // This allows logging even when services are unavailable\r\n return pino({ name: 'beamable-unavailable', level: 'info' }, process.stdout);\r\n }\r\n}\r\n\r\nclass BeamableServicesFacade implements BeamableMicroserviceServices {\r\n private readonly cache: Partial<Record<ServiceKey, ServiceMap[ServiceKey]>> = {};\r\n private readonly apiBindings: BoundBeamApi;\r\n private readonly storageService: StorageService;\r\n private readonly scopes: Set<string>;\r\n private readonly logger: Logger;\r\n private readonly serviceName?: string;\r\n private readonly federationRegistry?: FederationRegistry;\r\n private inventoryClient?: InventoryService;\r\n\r\n constructor(\r\n private readonly manager: BeamableServiceManager,\r\n private readonly beamServer: BeamServer,\r\n private readonly userId: string,\r\n scopes: Set<string>,\r\n serviceName?: string,\r\n ) {\r\n this.apiBindings = this.manager.getBoundApi();\r\n this.storageService = this.manager.getStorageService();\r\n this.scopes = scopes;\r\n this.serviceName = serviceName;\r\n this.federationRegistry = serviceName ? this.manager.getFederationRegistry(serviceName) : undefined;\r\n this.logger = this.manager.getLogger().child({ component: 'BeamableServicesFacade', service: serviceName });\r\n }\r\n\r\n private getOrCreate<K extends ServiceKey>(key: K, factory: () => ServiceMap[K]): ServiceMap[K] {\r\n if (!this.cache[key]) {\r\n this.cache[key] = factory();\r\n }\r\n return this.cache[key] as ServiceMap[K];\r\n }\r\n\r\n get account(): AccountService {\r\n return this.getOrCreate('account', () => this.beamServer.account(this.userId));\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.getOrCreate('announcements', () => this.beamServer.announcements(this.userId));\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.getOrCreate('auth', () => this.beamServer.auth(this.userId));\r\n }\r\n\r\n get content(): ContentService {\r\n return this.getOrCreate('content', () => this.beamServer.content(this.userId));\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.getOrCreate('leaderboards', () => this.beamServer.leaderboards(this.userId));\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.getOrCreate('stats', () => this.beamServer.stats(this.userId));\r\n }\r\n\r\n get inventory(): InventoryService {\r\n if (!this.inventoryClient) {\r\n this.inventoryClient = createInventoryService(\r\n this.apiBindings,\r\n this.logger.child({ component: 'InventoryClient' }),\r\n this.userId,\r\n (requiredScopes) => this.hasScopes(...requiredScopes),\r\n );\r\n }\r\n return this.inventoryClient;\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.storageService;\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n if (!this.federationRegistry) {\r\n throw new Error(\r\n this.serviceName\r\n ? `Federation registry is not configured for service \"${this.serviceName}\".`\r\n : 'Federation registry is not configured.',\r\n );\r\n }\r\n return this.federationRegistry;\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.manager.getRequester();\r\n }\r\n\r\n hasScopes(...requiredScopes: string[]): boolean {\r\n if (requiredScopes.length === 0) {\r\n return true;\r\n }\r\n return requiredScopes.every((scope) => this.scopeSetHas(scope));\r\n }\r\n\r\n requireScopes(...requiredScopes: string[]): void {\r\n if (!this.hasScopes(...requiredScopes)) {\r\n throw new MissingScopesError(requiredScopes);\r\n }\r\n }\r\n\r\n assumeUser(userId: string | number): BeamableMicroserviceServices {\r\n return this.manager.createFacade(String(userId), new Set(this.scopes), this.serviceName);\r\n }\r\n\r\n getLogger(): Logger {\r\n return this.logger;\r\n }\r\n\r\n private scopeSetHas(scope: string): boolean {\r\n const normalized = scope.trim().toLowerCase();\r\n if (!normalized) {\r\n return false;\r\n }\r\n return this.scopes.has('*') || this.scopes.has(normalized);\r\n }\r\n}\r\n\r\nexport interface BeamableMicroserviceServices {\r\n readonly account: AccountService;\r\n readonly announcements: AnnouncementsService;\r\n readonly auth: AuthService;\r\n readonly content: ContentService;\r\n readonly leaderboards: LeaderboardsService;\r\n readonly stats: StatsService;\r\n readonly inventory: InventoryService;\r\n readonly storage: StorageService;\r\n readonly federation: FederationRegistry;\r\n readonly api: BoundBeamApi;\r\n readonly requester: HttpRequester;\r\n hasScopes(...scopes: string[]): boolean;\r\n requireScopes(...scopes: string[]): void;\r\n assumeUser(userId: string | number): BeamableMicroserviceServices;\r\n getLogger(): Logger;\r\n}\r\n\r\nexport class BeamableServiceManager {\r\n private readonly logger: Logger;\r\n private readonly tokenStorage: ReturnType<typeof defaultTokenStorage>;\r\n private readonly env: EnvironmentConfig;\r\n private beamServer?: BeamServer;\r\n private boundApi?: BoundBeamApi;\r\n private storageService?: StorageService;\r\n private initialized = false;\r\n private readonly federationRegistries = new Map<string, FederationRegistry>();\r\n\r\n constructor(env: EnvironmentConfig, logger: Logger) {\r\n this.env = env;\r\n this.logger = logger.child({ component: 'BeamableServiceManager' });\r\n this.tokenStorage = defaultTokenStorage({ pid: env.pid, tag: env.routingKey ?? RUNTIME_ENVIRONMENT_NAME });\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n if (this.initialized) {\r\n return;\r\n }\r\n\r\n this.registerEnvironment();\r\n this.configureSharedEnvironment();\r\n\r\n if (this.env.refreshToken) {\r\n await this.tokenStorage.setTokenData({ refreshToken: this.env.refreshToken });\r\n }\r\n\r\n const useSignedRequest = Boolean(this.env.secret);\r\n if (!useSignedRequest && !this.env.refreshToken) {\r\n this.logger.warn(\r\n 'Beamable realm secret and refresh token are both missing; Beamable SDK requests may fail due to missing credentials.',\r\n );\r\n }\r\n\r\n try {\r\n this.beamServer = await BeamServer.init({\r\n cid: this.env.cid,\r\n pid: this.env.pid,\r\n environment: RUNTIME_ENVIRONMENT_NAME,\r\n useSignedRequest,\r\n tokenStorage: this.tokenStorage,\r\n serverEvents: { enabled: false },\r\n });\r\n } catch (error) {\r\n this.logger.error({ err: error }, 'Failed to initialize Beamable SDK. Services layer will be unavailable.');\r\n this.beamServer = undefined;\r\n this.initialized = false;\r\n return;\r\n }\r\n\r\n this.boundApi = await bindBeamApi(this.beamServer.requester);\r\n \r\n // Configure the requester's default headers to include the routing key in the correct format\r\n // The routing key format is: serviceName:routingKey\r\n // We'll set this per-request in createFacade since we need the service name\r\n this.storageService = new StorageService({\r\n requester: this.beamServer.requester,\r\n api: this.boundApi,\r\n env: this.env,\r\n logger: this.logger.child({ component: 'StorageService' }),\r\n });\r\n\r\n this.registerDefaultServices();\r\n this.initialized = true;\r\n this.logger.debug('Beamable SDK services initialized.');\r\n }\r\n\r\n createFacade(userId: string | number, scopes: Set<string>, serviceName?: string): BeamableMicroserviceServices {\r\n if (!this.initialized || !this.beamServer || !this.boundApi || !this.storageService) {\r\n return new UnavailableBeamableServices(new Error('Beamable services are not initialized.'));\r\n }\r\n \r\n // Set the routing key in the format serviceName:routingKey for the SDK\r\n // The SDK uses BEAM_ROUTING_KEY environment variable to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We need to set it to the full format: serviceName:routingKey\r\n if (serviceName && this.beamServer.requester) {\r\n const fullRoutingKey = `micro_${serviceName}:${this.env.routingKey}`;\r\n BeamServer.env.BEAM_ROUTING_KEY = fullRoutingKey;\r\n \r\n // Set default headers on the requester for all SDK requests\r\n // These headers are required for signature validation and routing\r\n const scopeHeader = `${this.env.cid}.${this.env.pid}`;\r\n this.beamServer.requester.defaultHeaders = {\r\n ...this.beamServer.requester.defaultHeaders,\r\n 'X-BEAM-SCOPE': scopeHeader,\r\n 'X-BEAM-SERVICE-ROUTING-KEY': fullRoutingKey,\r\n };\r\n }\r\n \r\n return new BeamableServicesFacade(this, this.beamServer, String(userId), new Set(scopes), serviceName);\r\n }\r\n\r\n getRequester(): HttpRequester {\r\n if (!this.initialized || !this.beamServer) {\r\n return new UnavailableRequester(new Error('Beamable services are not initialized.'));\r\n }\r\n return this.beamServer.requester;\r\n }\r\n\r\n getBoundApi(): BoundBeamApi {\r\n if (!this.boundApi) {\r\n throw new Error('Beamable bound API is not available.');\r\n }\r\n return this.boundApi;\r\n }\r\n\r\n getStorageService(): StorageService {\r\n if (!this.storageService) {\r\n throw new Error('Storage service is not initialized.');\r\n }\r\n return this.storageService;\r\n }\r\n\r\n getLogger(): Logger {\r\n return this.logger;\r\n }\r\n\r\n registerFederationRegistry(serviceName: string, registry: FederationRegistry): void {\r\n this.federationRegistries.set(serviceName, registry);\r\n }\r\n\r\n getFederationRegistry(serviceName: string): FederationRegistry | undefined {\r\n return this.federationRegistries.get(serviceName);\r\n }\r\n\r\n private registerEnvironment(): void {\r\n const apiUrl = hostToHttpUrl(this.env.host);\r\n const portalUrl = hostToPortalUrl(apiUrl);\r\n const storageUrl = hostToStorageUrl(apiUrl);\r\n const registryUrl = hostToMicroserviceRegistryUrl(apiUrl);\r\n\r\n try {\r\n BeamEnvironment.register(RUNTIME_ENVIRONMENT_NAME, {\r\n apiUrl,\r\n portalUrl,\r\n beamMongoExpressUrl: storageUrl,\r\n dockerRegistryUrl: `${registryUrl}/v2/`,\r\n });\r\n } catch (error) {\r\n this.logger.debug({ err: error }, 'Beamable environment was already registered. Reusing existing configuration.');\r\n }\r\n }\r\n\r\n private configureSharedEnvironment(): void {\r\n if (this.env.secret) {\r\n BeamServer.env.BEAM_REALM_SECRET = this.env.secret;\r\n }\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We set it to just the routing key value here, and will set the full format in createFacade\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // For deployed services, routingKey is undefined, so we set it to empty string\r\n // The SDK will handle this appropriately\r\n BeamServer.env.BEAM_ROUTING_KEY = this.env.routingKey ?? '';\r\n }\r\n\r\n private registerDefaultServices(): void {\r\n if (!this.beamServer) {\r\n return;\r\n }\r\n this.beamServer.use(AccountService);\r\n this.beamServer.use(AnnouncementsService);\r\n this.beamServer.use(AuthService);\r\n this.beamServer.use(ContentService);\r\n this.beamServer.use(LeaderboardsService);\r\n this.beamServer.use(StatsService);\r\n }\r\n}\r\n"]}
|