UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

475 lines • 21.8 kB
#!/usr/bin/env node /** * NeuroLink CLI Telemetry Commands * * Commands for managing telemetry: * - status: Show telemetry status * - flush: Flush pending spans * - stats: Show token/cost stats */ import chalk from "chalk"; import ora from "ora"; import { logger } from "../../utils/logger.js"; import { NeuroLink } from "../../neurolink.js"; import { flushOpenTelemetry } from "../../services/server/ai/observability/instrumentation.js"; import { formatRow, formatCost } from "../utils/formatters.js"; import { redactUrlCredentials } from "../../utils/logSanitize.js"; import { prepareNativeTelemetry, validateNativeTelemetry, } from "../utils/nativeTelemetry.js"; /** * Telemetry Command Factory */ export class TelemetryCommandFactory { /** * Create the telemetry command group */ static createTelemetryCommands() { return { command: "telemetry <subcommand>", aliases: ["tel"], describe: "Telemetry management", builder: (yargs) => { return yargs .command(TelemetryCommandFactory.createStatusCommand()) .command(TelemetryCommandFactory.createFlushCommand()) .command(TelemetryCommandFactory.createStatsCommand()) .command(TelemetryCommandFactory.createNativePrepareCommand()) .command(TelemetryCommandFactory.createNativeValidateCommand()) .demandCommand(1, "Please specify a subcommand") .strict(); }, handler: () => { // This handler is not called directly due to demandCommand }, }; } /** Stage a native migration without modifying an installed service. */ static createNativePrepareCommand() { return { command: "native-prepare", describe: "Stage private durable/split collector files; never activate a service", builder: (yargs) => yargs .option("collectorConfig", { alias: "collector-config", type: "string", demandOption: true, describe: "Existing native collector YAML (read only)", }) .option("output", { type: "string", demandOption: true, describe: "New absolute staging directory; existing paths are refused", }) .option("queueDirectory", { alias: "queue-directory", type: "string", demandOption: true, describe: "Planned private durable queue directory (not created)", }) .option("compactionDirectory", { alias: "compaction-directory", type: "string", demandOption: true, describe: "Planned separate private compaction directory (not created)", }) .option("bodyPort", { alias: "body-port", type: "number", default: 14319, }) .option("bodyStream", { alias: "body-stream", type: "string", describe: "Separate body stream; defaults to <existing metadata stream>_bodies", }) .option("metadataQueueMib", { alias: "metadata-queue-mib", type: "number", default: 32, describe: "Payload limit per metadata signal (three queues)", }) .option("bodyQueueMib", { alias: "body-queue-mib", type: "number", default: 256, }) .option("diskQuotaMib", { alias: "disk-quota-mib", type: "number", default: 1024, describe: "Operator-managed volume quota to review; not applied by this command", }) .option("metadataRetentionDays", { alias: "metadata-retention-days", type: "number", default: 14, describe: "Planned backend retention; not applied", }) .option("bodyRetentionDays", { alias: "body-retention-days", type: "number", default: 3, describe: "Planned backend body retention; not applied", }), handler: async (args) => { try { logger.always(JSON.stringify(await prepareNativeTelemetry(args), null, 2)); } catch (error) { logger.error(error instanceof Error ? error.message : "Native telemetry preparation failed"); process.exitCode = 1; } }, }; } static createNativeValidateCommand() { return { command: "native-validate", describe: "Validate staged profile using collector >= 0.160; never start or restart a service", builder: (yargs) => yargs .option("directory", { type: "string", demandOption: true, describe: "Private directory produced by native-prepare", }) .option("collectorBin", { alias: "collector-bin", type: "string", demandOption: true, describe: "Absolute path to trusted otelcol-contrib executable", }), handler: async (args) => { try { logger.always(JSON.stringify(await validateNativeTelemetry(args), null, 2)); } catch (error) { logger.error(error instanceof Error ? error.message : "Native telemetry validation failed"); process.exitCode = 1; } }, }; } /** * Create the status subcommand */ static createStatusCommand() { return { command: "status", describe: "Show telemetry status", builder: (yargs) => { return yargs .option("format", { alias: "f", type: "string", choices: ["text", "json", "table"], default: "text", describe: "Output format", }) .option("quiet", { alias: "q", type: "boolean", default: false, describe: "Minimal output", }); }, handler: async (args) => { const spinner = args.quiet ? null : ora("Checking telemetry status...").start(); try { const neurolink = new NeuroLink(); const status = neurolink.getTelemetryStatus(); if (spinner) { spinner.succeed("Status retrieved"); } if (args.format === "json") { logger.always(JSON.stringify(status, (_key, value) => typeof value === "string" && (_key === "baseUrl" || _key === "endpoint") ? redactUrlCredentials(value) : value, 2)); } else { logger.always(""); logger.always(chalk.bold.cyan("=== Telemetry Status ===")); logger.always(""); // Telemetry enabled status const enabledIcon = status.enabled ? chalk.green("ENABLED") : chalk.red("DISABLED"); logger.always(formatRow("Telemetry:", enabledIcon)); // OpenTelemetry status if (status.openTelemetry) { logger.always(""); logger.always(chalk.bold("OpenTelemetry:")); const otelStatus = status.openTelemetry.enabled ? chalk.green("Active") : chalk.gray("Inactive"); logger.always(formatRow(" Status:", otelStatus)); if (status.openTelemetry.endpoint) { logger.always(formatRow(" Endpoint:", redactUrlCredentials(status.openTelemetry.endpoint))); } if (status.openTelemetry.serviceName) { logger.always(formatRow(" Service:", status.openTelemetry.serviceName)); } } // Langfuse status if (status.langfuse) { logger.always(""); logger.always(chalk.bold("Langfuse:")); const lfStatus = status.langfuse.enabled ? chalk.green("Active") : chalk.gray("Inactive"); logger.always(formatRow(" Status:", lfStatus)); if (status.langfuse.baseUrl) { logger.always(formatRow(" URL:", redactUrlCredentials(status.langfuse.baseUrl))); } if (status.langfuse.environment) { logger.always(formatRow(" Environment:", status.langfuse.environment)); } } logger.always(""); } } catch (error) { if (spinner) { spinner.fail("Failed to get status"); } logger.error("Error:", error instanceof Error ? error.message : String(error)); process.exit(1); } }, }; } /** * Create the flush subcommand */ static createFlushCommand() { return { command: "flush", describe: "Flush all pending spans", builder: (yargs) => { return yargs .option("timeout", { alias: "t", type: "number", default: 30000, describe: "Timeout in milliseconds", }) .option("format", { alias: "f", type: "string", choices: ["text", "json", "table"], default: "text", describe: "Output format", }) .option("quiet", { alias: "q", type: "boolean", default: false, describe: "Minimal output", }); }, handler: async (args) => { const spinner = args.quiet ? null : ora("Flushing pending spans...").start(); try { // Create a timeout promise let flushTimer; const timeoutPromise = new Promise((_, reject) => { flushTimer = setTimeout(() => reject(new Error("Flush operation timed out")), args.timeout ?? 30000); }); // Flush OpenTelemetry spans const flushPromise = flushOpenTelemetry(); // Race between flush and timeout await Promise.race([flushPromise, timeoutPromise]); // Cancel the timeout timer to avoid unhandled rejection if (flushTimer !== undefined) { clearTimeout(flushTimer); } if (spinner) { spinner.succeed("Flush completed"); } if (args.format === "json") { logger.always(JSON.stringify({ success: true }, null, 2)); } else { logger.always(""); logger.always(chalk.bold.cyan("=== Flush Complete ===")); logger.always(""); logger.always(""); } } catch (error) { if (spinner) { spinner.fail("Failed to flush spans"); } logger.error("Error:", error instanceof Error ? error.message : String(error)); process.exit(1); } }, }; } /** * Create the stats subcommand */ static createStatsCommand() { return { command: "stats", describe: "Show token usage and cost statistics", builder: (yargs) => { return yargs .option("format", { alias: "f", type: "string", choices: ["text", "json", "table"], default: "text", describe: "Output format", }) .option("detailed", { alias: "d", type: "boolean", default: false, describe: "Show detailed statistics", }) .option("by-model", { alias: "m", type: "boolean", default: true, describe: "Show breakdown by model", }) .option("by-provider", { alias: "p", type: "boolean", default: true, describe: "Show breakdown by provider", }) .option("quiet", { alias: "q", type: "boolean", default: false, describe: "Minimal output", }); }, handler: async (args) => { const spinner = args.quiet ? null : ora("Gathering statistics...").start(); try { const neurolink = new NeuroLink(); const metrics = neurolink.getMetrics(); if (spinner) { spinner.succeed("Statistics retrieved"); } if (args.format === "json") { logger.always(JSON.stringify({ tokens: { input: metrics.tokens.totalInputTokens, output: metrics.tokens.totalOutputTokens, total: metrics.tokens.totalTokens, cacheRead: metrics.tokens.cacheReadTokens, reasoning: metrics.tokens.reasoningTokens, }, cost: { total: metrics.totalCost, byProvider: metrics.costByProvider, byModel: metrics.costByModel, }, requests: { total: metrics.totalSpans, successful: metrics.successfulSpans, failed: metrics.failedSpans, successRate: metrics.successRate, }, latency: metrics.latency, }, null, 2)); } else { logger.always(""); logger.always(chalk.bold.cyan("=== Token & Cost Statistics ===")); logger.always(""); // Token usage logger.always(chalk.bold("Token Usage:")); logger.always(formatRow(" Input tokens:", metrics.tokens.totalInputTokens.toLocaleString())); logger.always(formatRow(" Output tokens:", metrics.tokens.totalOutputTokens.toLocaleString())); logger.always(formatRow(" Total tokens:", metrics.tokens.totalTokens.toLocaleString())); if (args.detailed) { if (metrics.tokens.cacheReadTokens > 0) { logger.always(formatRow(" Cache read:", metrics.tokens.cacheReadTokens.toLocaleString())); } if (metrics.tokens.reasoningTokens > 0) { logger.always(formatRow(" Reasoning:", metrics.tokens.reasoningTokens.toLocaleString())); } } // Cost summary logger.always(""); logger.always(chalk.bold("Cost Summary:")); logger.always(formatRow(" Total cost:", formatCost(metrics.totalCost ?? 0))); // Cost by provider if (args.byProvider !== false && metrics.costByProvider && metrics.costByProvider.length > 0) { logger.always(""); logger.always(chalk.bold("Cost by Provider:")); const sortedProviders = [...metrics.costByProvider].sort((a, b) => b.totalCost - a.totalCost); for (const provider of sortedProviders) { logger.always(` ${chalk.cyan(provider.provider.padEnd(15))} ${formatCost(provider.totalCost)}`); logger.always(chalk.gray(` ${provider.requestCount} requests, avg ${formatCost(provider.avgCostPerRequest)}/req`)); } } // Cost by model if (args.byModel !== false && metrics.costByModel && metrics.costByModel.length > 0) { logger.always(""); logger.always(chalk.bold("Cost by Model:")); const sortedModels = [...metrics.costByModel].sort((a, b) => b.totalCost - a.totalCost); for (const model of sortedModels) { logger.always(` ${chalk.cyan(model.model)}`); logger.always(` Cost: ${formatCost(model.totalCost)}`); logger.always(chalk.gray(` ${model.requestCount} requests, avg ${formatCost(model.avgCostPerRequest)}/req`)); if (args.detailed) { logger.always(chalk.gray(` ${model.inputTokens.toLocaleString()} input, ${model.outputTokens.toLocaleString()} output tokens`)); } } } // Request statistics logger.always(""); logger.always(chalk.bold("Request Statistics:")); logger.always(formatRow(" Total requests:", metrics.totalSpans.toLocaleString())); logger.always(formatRow(" Successful:", metrics.successfulSpans.toLocaleString())); logger.always(formatRow(" Failed:", metrics.failedSpans.toLocaleString())); logger.always(formatRow(" Success rate:", `${(metrics.successRate * 100).toFixed(2)}%`)); // Latency (if detailed) if (args.detailed && metrics.latency.count > 0) { logger.always(""); logger.always(chalk.bold("Latency (ms):")); logger.always(formatRow(" P50:", metrics.latency.p50.toFixed(2))); logger.always(formatRow(" P95:", metrics.latency.p95.toFixed(2))); logger.always(formatRow(" P99:", metrics.latency.p99.toFixed(2))); } // Tracking duration if (metrics.trackingDurationMs) { const durationSec = metrics.trackingDurationMs / 1000; const throughput = metrics.totalSpans > 0 ? metrics.totalSpans / durationSec : 0; logger.always(""); logger.always(chalk.gray(`Tracking: ${durationSec.toFixed(1)}s (${throughput.toFixed(2)} req/s)`)); } logger.always(""); } } catch (error) { if (spinner) { spinner.fail("Failed to get statistics"); } logger.error("Error:", error instanceof Error ? error.message : String(error)); process.exit(1); } }, }; } } //# sourceMappingURL=telemetry.js.map