import {spawn} from 'node:child_process'; import {mkdirSync, writeFileSync} from 'node:fs'; import path from 'node:path'; const [, , rawMode = 'debug', ...args] = process.argv; const mode = rawMode.trim(); const printConfigOnly = args.includes('--print-config'); const supportedModes = new Set(['debug', 'rider']); if (!supportedModes.has(mode)) { console.error('[otelcol] mode must be one of: debug, rider'); process.exit(1); } const otlpHttpEndpoint = readEnv('OTELCOL_OTLP_HTTP_ENDPOINT', '127.0.0.1:4318'); const otlpGrpcEndpoint = readEnv('OTELCOL_OTLP_GRPC_ENDPOINT', '127.0.0.1:4317'); const riderEndpoint = readEnv('RIDER_OTLP_GRPC_ENDPOINT', '127.0.0.1:17011'); const debugVerbosity = readEnv('OTELCOL_DEBUG_VERBOSITY', 'detailed'); const otelcolBin = readEnv('OTELCOL_BIN', 'otelcol-contrib'); const configText = buildConfig(mode); const configDir = path.resolve('.codex-temp', 'otelcol'); const configPath = path.join(configDir, `genarrative-${mode}.yaml`); mkdirSync(configDir, {recursive: true}); writeFileSync(configPath, configText, 'utf8'); console.log(`[otelcol] wrote ${configPath}`); console.log(`[otelcol] receiving OTLP HTTP at http://${otlpHttpEndpoint}`); console.log(`[otelcol] receiving OTLP gRPC at ${otlpGrpcEndpoint}`); if (mode === 'rider') { console.log(`[otelcol] forwarding traces/metrics/logs to Rider OTLP gRPC at ${riderEndpoint}`); } console.log( '[otelcol] api-server env: GENARRATIVE_OTEL_ENABLED=true OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318' ); if (printConfigOnly) { console.log(configText); process.exit(0); } const child = spawn(otelcolBin, ['--config', configPath], { cwd: process.cwd(), env: process.env, stdio: 'inherit', }); const stopChild = () => { if (!child.killed) { child.kill(); } }; for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) { process.on(signal, () => { stopChild(); process.exit(130); }); } process.on('exit', stopChild); child.on('error', (error) => { console.error(`[otelcol] failed to start ${otelcolBin}: ${error.message}`); console.error('[otelcol] install otelcol-contrib and make sure it is on PATH, or set OTELCOL_BIN.'); process.exit(1); }); child.on('exit', (code, signal) => { if (signal) { console.error(`[otelcol] exited by signal: ${signal}`); process.exit(1); } process.exit(code ?? 0); }); function readEnv(key, fallback) { const value = process.env[key]?.trim(); return value ? value : fallback; } function buildConfig(selectedMode) { const exporters = selectedMode === 'rider' ? ` otlp/rider: endpoint: ${riderEndpoint} tls: insecure: true debug: verbosity: ${debugVerbosity}` : ` debug: verbosity: ${debugVerbosity}`; const pipelineExporters = selectedMode === 'rider' ? '[otlp/rider, debug]' : '[debug]'; return `receivers: otlp: protocols: grpc: endpoint: ${otlpGrpcEndpoint} http: endpoint: ${otlpHttpEndpoint} exporters: ${exporters} service: pipelines: traces: receivers: [otlp] exporters: ${pipelineExporters} metrics: receivers: [otlp] exporters: ${pipelineExporters} logs: receivers: [otlp] exporters: ${pipelineExporters} `; }