scripts/telemetry_gcp.js (162 lines of code) (raw):

import path from 'path'; import fs from 'fs'; import { spawn, execSync } from 'child_process'; import { OTEL_DIR, BIN_DIR, fileExists, waitForPort, ensureBinary, manageTelemetrySettings, registerCleanup, } from './telemetry_utils.js'; const OTEL_CONFIG_FILE = path.join(OTEL_DIR, 'collector-gcp.yaml'); const OTEL_LOG_FILE = path.join(OTEL_DIR, 'collector-gcp.log'); const getOtelConfigContent = (projectId) => ` receivers: otlp: protocols: grpc: endpoint: "localhost:4317" processors: batch: timeout: 1s exporters: googlecloud: project: "${projectId}" metric: prefix: "custom.googleapis.com/gemini_cli" log: default_log_name: "gemini_cli" debug: verbosity: detailed service: telemetry: logs: level: "debug" metrics: level: "none" pipelines: traces: receivers: [otlp] processors: [batch] exporters: [googlecloud] metrics: receivers: [otlp] processors: [batch] exporters: [googlecloud, debug] logs: receivers: [otlp] processors: [batch] exporters: [googlecloud, debug] `; async function main() { console.log('โœจ Starting Local Telemetry Exporter for Google Cloud โœจ'); let collectorProcess; let collectorLogFd; const originalSandboxSetting = manageTelemetrySettings( true, 'http://localhost:4317', 'gcp', ); registerCleanup( () => [collectorProcess].filter((p) => p), // Function to get processes () => [collectorLogFd].filter((fd) => fd), // Function to get FDs originalSandboxSetting, ); const projectId = process.env.OTLP_GOOGLE_CLOUD_PROJECT; if (!projectId) { console.error( '๐Ÿ›‘ Error: OTLP_GOOGLE_CLOUD_PROJECT environment variable is not exported.', ); console.log( ' Please set it to your Google Cloud Project ID and try again.', ); console.log(' `export OTLP_GOOGLE_CLOUD_PROJECT=your-project-id`'); process.exit(1); } console.log(`โœ… Using OTLP Google Cloud Project ID: ${projectId}`); console.log('\n๐Ÿ”‘ Please ensure you are authenticated with Google Cloud:'); console.log( ' - Run `gcloud auth application-default login` OR ensure `GOOGLE_APPLICATION_CREDENTIALS` environment variable points to a valid service account key.', ); console.log( ' - The account needs "Cloud Trace Agent", "Monitoring Metric Writer", and "Logs Writer" roles.', ); 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); console.log('๐Ÿงน Cleaning up old processes and logs...'); try { execSync('pkill -f "otelcol-contrib"'); console.log('โœ… Stopped existing otelcol-contrib process.'); } catch (_e) { /* no-op */ } try { fs.unlinkSync(OTEL_LOG_FILE); console.log('โœ… Deleted old GCP collector log.'); } catch (e) { if (e.code !== 'ENOENT') console.error(e); } if (!fileExists(OTEL_DIR)) fs.mkdirSync(OTEL_DIR, { recursive: true }); fs.writeFileSync(OTEL_CONFIG_FILE, getOtelConfigContent(projectId)); console.log(`๐Ÿ“„ Wrote OTEL collector config to ${OTEL_CONFIG_FILE}`); console.log(`๐Ÿš€ Starting OTEL collector for GCP... Logs: ${OTEL_LOG_FILE}`); collectorLogFd = fs.openSync(OTEL_LOG_FILE, 'a'); collectorProcess = spawn(otelcolPath, ['--config', OTEL_CONFIG_FILE], { stdio: ['ignore', collectorLogFd, collectorLogFd], env: { ...process.env }, }); console.log( `โณ Waiting for OTEL collector to start (PID: ${collectorProcess.pid})...`, ); try { await waitForPort(4317); console.log(`โœ… OTEL collector started successfully on port 4317.`); } catch (err) { console.error(`๐Ÿ›‘ Error: OTEL collector failed to start on port 4317.`); console.error(err.message); 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); } collectorProcess.on('error', (err) => { console.error(`${collectorProcess.spawnargs[0]} process error:`, err); process.exit(1); }); console.log(`\nโœจ Local OTEL collector for GCP is running.`); console.log( '\n๐Ÿš€ To send telemetry, run the Gemini CLI in a separate terminal window.', ); console.log(`\n๐Ÿ“„ Collector logs are being written to: ${OTEL_LOG_FILE}`); console.log( `๐Ÿ“„ Tail collector logs in another terminal: tail -f ${OTEL_LOG_FILE}`, ); console.log(`\n๐Ÿ“Š View your telemetry data in Google Cloud Console:`); console.log( ` - Logs: https://console.cloud.google.com/logs/query;query=logName%3D%22projects%2F${projectId}%2Flogs%2Fgemini_cli%22?project=${projectId}`, ); console.log( ` - Metrics: https://console.cloud.google.com/monitoring/metrics-explorer?project=${projectId}`, ); console.log( ` - Traces: https://console.cloud.google.com/traces/list?project=${projectId}`, ); console.log(`\nPress Ctrl+C to exit.`); } main();