220 lines
6.1 KiB
JavaScript
Executable File
220 lines
6.1 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { spawn, execSync } from 'child_process';
|
|
import { fileURLToPath } from 'url';
|
|
import {
|
|
BIN_DIR,
|
|
OTEL_DIR,
|
|
ensureBinary,
|
|
fileExists,
|
|
manageTelemetrySettings,
|
|
registerCleanup,
|
|
waitForPort,
|
|
} from './telemetry_utils.js';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const OTEL_CONFIG_FILE = path.join(OTEL_DIR, 'collector-local.yaml');
|
|
const OTEL_LOG_FILE = path.join(OTEL_DIR, 'collector.log');
|
|
const JAEGER_LOG_FILE = path.join(OTEL_DIR, 'jaeger.log');
|
|
const JAEGER_PORT = 16686;
|
|
|
|
// This configuration is for the primary otelcol-contrib instance.
|
|
// It receives from the CLI on 4317, exports traces to Jaeger on 14317,
|
|
// and sends metrics/logs to the debug log.
|
|
const OTEL_CONFIG_CONTENT = `
|
|
receivers:
|
|
otlp:
|
|
protocols:
|
|
grpc:
|
|
endpoint: "localhost:4317"
|
|
processors:
|
|
batch:
|
|
timeout: 1s
|
|
exporters:
|
|
otlp:
|
|
endpoint: "localhost:14317"
|
|
tls:
|
|
insecure: true
|
|
debug:
|
|
verbosity: detailed
|
|
service:
|
|
telemetry:
|
|
logs:
|
|
level: "debug"
|
|
metrics:
|
|
level: "none"
|
|
pipelines:
|
|
traces:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [otlp]
|
|
metrics:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [debug]
|
|
logs:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [debug]
|
|
`;
|
|
|
|
async function main() {
|
|
// 1. Ensure binaries are available, downloading if necessary.
|
|
// Binaries are stored in the project's .gemini/otel/bin directory
|
|
// to avoid modifying the user's system.
|
|
if (!fileExists(BIN_DIR)) fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
|
|
const otelcolPath = await ensureBinary(
|
|
'otelcol-contrib',
|
|
'open-telemetry/opentelemetry-collector-releases',
|
|
(version, platform, arch, ext) =>
|
|
`otelcol-contrib_${version}_${platform}_${arch}.${ext}`,
|
|
'otelcol-contrib',
|
|
false, // isJaeger = false
|
|
).catch((e) => {
|
|
console.error(`🛑 Error getting otelcol-contrib: ${e.message}`);
|
|
return null;
|
|
});
|
|
if (!otelcolPath) process.exit(1);
|
|
|
|
const jaegerPath = await ensureBinary(
|
|
'jaeger',
|
|
'jaegertracing/jaeger',
|
|
(version, platform, arch, ext) =>
|
|
`jaeger-${version}-${platform}-${arch}.${ext}`,
|
|
'jaeger',
|
|
true, // isJaeger = true
|
|
).catch((e) => {
|
|
console.error(`🛑 Error getting jaeger: ${e.message}`);
|
|
return null;
|
|
});
|
|
if (!jaegerPath) process.exit(1);
|
|
|
|
// 2. Kill any existing processes to ensure a clean start.
|
|
console.log('🧹 Cleaning up old processes and logs...');
|
|
try {
|
|
execSync('pkill -f "otelcol-contrib"');
|
|
console.log('✅ Stopped existing otelcol-contrib process.');
|
|
} catch (_e) {} // eslint-disable-line no-empty
|
|
try {
|
|
execSync('pkill -f "jaeger"');
|
|
console.log('✅ Stopped existing jaeger process.');
|
|
} catch (_e) {} // eslint-disable-line no-empty
|
|
try {
|
|
if (fileExists(OTEL_LOG_FILE)) fs.unlinkSync(OTEL_LOG_FILE);
|
|
console.log('✅ Deleted old collector log.');
|
|
} catch (e) {
|
|
if (e.code !== 'ENOENT') console.error(e);
|
|
}
|
|
try {
|
|
if (fileExists(JAEGER_LOG_FILE)) fs.unlinkSync(JAEGER_LOG_FILE);
|
|
console.log('✅ Deleted old jaeger log.');
|
|
} catch (e) {
|
|
if (e.code !== 'ENOENT') console.error(e);
|
|
}
|
|
|
|
let jaegerProcess, collectorProcess;
|
|
let jaegerLogFd, collectorLogFd;
|
|
|
|
const originalSandboxSetting = manageTelemetrySettings(
|
|
true,
|
|
'http://localhost:4317',
|
|
'local',
|
|
);
|
|
|
|
registerCleanup(
|
|
() => [jaegerProcess, collectorProcess],
|
|
() => [jaegerLogFd, collectorLogFd],
|
|
originalSandboxSetting,
|
|
);
|
|
|
|
if (!fileExists(OTEL_DIR)) fs.mkdirSync(OTEL_DIR, { recursive: true });
|
|
fs.writeFileSync(OTEL_CONFIG_FILE, OTEL_CONFIG_CONTENT);
|
|
console.log('📄 Wrote OTEL collector config.');
|
|
|
|
// Start Jaeger
|
|
console.log(`🚀 Starting Jaeger service... Logs: ${JAEGER_LOG_FILE}`);
|
|
jaegerLogFd = fs.openSync(JAEGER_LOG_FILE, 'a');
|
|
jaegerProcess = spawn(
|
|
jaegerPath,
|
|
['--set=receivers.otlp.protocols.grpc.endpoint=localhost:14317'],
|
|
{ stdio: ['ignore', jaegerLogFd, jaegerLogFd] },
|
|
);
|
|
console.log(`⏳ Waiting for Jaeger to start (PID: ${jaegerProcess.pid})...`);
|
|
|
|
try {
|
|
await waitForPort(JAEGER_PORT);
|
|
console.log(`✅ Jaeger started successfully.`);
|
|
} catch (_) {
|
|
console.error(`🛑 Error: Jaeger failed to start on port ${JAEGER_PORT}.`);
|
|
if (jaegerProcess && jaegerProcess.pid) {
|
|
process.kill(jaegerProcess.pid, 'SIGKILL');
|
|
}
|
|
if (fileExists(JAEGER_LOG_FILE)) {
|
|
console.error('📄 Jaeger Log Output:');
|
|
console.error(fs.readFileSync(JAEGER_LOG_FILE, 'utf-8'));
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
// Start the primary OTEL collector
|
|
console.log(`🚀 Starting OTEL collector... Logs: ${OTEL_LOG_FILE}`);
|
|
collectorLogFd = fs.openSync(OTEL_LOG_FILE, 'a');
|
|
collectorProcess = spawn(otelcolPath, ['--config', OTEL_CONFIG_FILE], {
|
|
stdio: ['ignore', collectorLogFd, collectorLogFd],
|
|
});
|
|
console.log(
|
|
`⏳ Waiting for OTEL collector to start (PID: ${collectorProcess.pid})...`,
|
|
);
|
|
|
|
try {
|
|
await waitForPort(4317);
|
|
console.log(`✅ OTEL collector started successfully.`);
|
|
} catch (_) {
|
|
console.error(`🛑 Error: OTEL collector failed to start on port 4317.`);
|
|
if (collectorProcess && collectorProcess.pid) {
|
|
process.kill(collectorProcess.pid, 'SIGKILL');
|
|
}
|
|
if (fileExists(OTEL_LOG_FILE)) {
|
|
console.error('📄 OTEL Collector Log Output:');
|
|
console.error(fs.readFileSync(OTEL_LOG_FILE, 'utf-8'));
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
[jaegerProcess, collectorProcess].forEach((proc) => {
|
|
if (proc) {
|
|
proc.on('error', (err) => {
|
|
console.error(`${proc.spawnargs[0]} process error:`, err);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
});
|
|
|
|
console.log(`
|
|
✨ Local telemetry environment is running.`);
|
|
console.log(
|
|
`
|
|
🔎 View traces in the Jaeger UI: http://localhost:${JAEGER_PORT}`,
|
|
);
|
|
console.log(`📊 View metrics in the logs and metrics: ${OTEL_LOG_FILE}`);
|
|
console.log(
|
|
`
|
|
📄 Tail logs and metrics in another terminal: tail -f ${OTEL_LOG_FILE}`,
|
|
);
|
|
console.log(`
|
|
Press Ctrl+C to exit.`);
|
|
}
|
|
|
|
main();
|