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

234 lines (229 loc) • 7.83 kB
#!/usr/bin/env node /** Bounded, deterministic OpenObserve history queries; never accept partial data. */ import { pathToFileURL } from "node:url"; import { resolveProxyTelemetryBackend, validateProxyTelemetryBackend, } from "./proxy-telemetry-backend.mjs"; const KINDS = new Set([ "request_final", "attempt", "lifecycle", "supervisor", "body_capture_index", "stream_error", "telemetry_delivery", "console", ]); /** * Query metadata in small windows; body chunks require a targeted lookup. * @param {{ baseUrl: string, organization?: string, stream?: string, authorization?: string, startTime: number, endTime: number, kind?: string, lifecycleEvents?: string[], maxRows?: number, budget?: import("../../src/lib/types/index.js").ProxyTelemetryQueryBudget, fetchImpl?: typeof fetch }} options */ export async function queryProxyHistory({ baseUrl, organization = "default", stream = "neurolink_proxy", authorization, startTime, endTime, kind = "request_final", lifecycleEvents, maxRows = 10_000, fetchImpl = fetch, budget = { used: 0, limit: 512 }, }) { if ( !/^[a-zA-Z0-9_-]+$/.test(organization) || !/^[a-zA-Z0-9_]+$/.test(stream) || !KINDS.has(kind) || (lifecycleEvents !== undefined && (kind !== "lifecycle" || lifecycleEvents.some( (event) => !["request_accepted", "request_terminal"].includes(event), ))) ) { throw new Error("Invalid organization, stream or metadata record kind"); } if ( !Number.isSafeInteger(startTime) || !Number.isSafeInteger(endTime) || startTime >= endTime || !Number.isSafeInteger(maxRows) || maxRows < 1 || maxRows > 100_000 ) { throw new Error( "Provide an increasing microsecond time range and maxRows between 1 and 100000", ); } validateProxyTelemetryBackend({ baseUrl, organization, stream, authorization, }); const endpoint = new URL(`/api/${organization}/_search?type=logs`, baseUrl); const loopback = ["localhost", "127.0.0.1", "[::1]"].includes( endpoint.hostname, ); if ( authorization && endpoint.protocol !== "https:" && !(endpoint.protocol === "http:" && loopback) ) { throw new Error( "Credentialed OpenObserve queries require HTTPS outside loopback", ); } /** @type {Array<{start: number, endExclusive: number, offset: number, partial: boolean, tookMs?: number}>} */ const queries = []; let rowsRead = 0; /** @param {number} start @param {number} end @returns {Promise<Array<Record<string, unknown>>>} */ async function readWindow(start, end) { const rows = []; for (let offset = 0; ; offset += 200) { if (budget.used >= budget.limit) { throw new Error( "History exceeds the 512-query budget; narrow the interval", ); } budget.used++; const response = await fetchImpl(endpoint, { method: "POST", redirect: "error", signal: globalThis.AbortSignal.timeout(30_000), headers: { "Content-Type": "application/json", ...(authorization ? { Authorization: authorization } : {}), }, body: JSON.stringify({ query: { // The body is small metadata, not arbitrary request/response chunks. // Include a secondary key: timestamp-only paging loses equal-time events. sql: `SELECT _timestamp, proxy_event_id, service_instance_id, request_id, body FROM "${stream}" WHERE proxy_record_kind='${kind}'${lifecycleEvents?.length ? ` AND proxy_lifecycle_event IN (${lifecycleEvents.map((event) => `'${event}'`).join(",")})` : ""} ORDER BY _timestamp ASC, proxy_event_id ASC, service_instance_id ASC, request_id ASC, body ASC`, start_time: start, end_time: end - 1, from: offset, size: 200, }, }), }); if (!response.ok) { throw new Error(`OpenObserve search failed: HTTP ${response.status}`); } const result = await response.json(); const partial = result.is_partial === true || (Array.isArray(result.function_error) ? result.function_error.length > 0 : Boolean(result.function_error)); queries.push({ start, endExclusive: end, offset, partial, tookMs: result.took, }); if (partial) { // Discard this window's pages before splitting, so no page is duplicated. if (end - start <= 10_000_000) { throw new Error( "OpenObserve still returned partial data in a 10-second window; no complete report can be produced", ); } rowsRead -= rows.length; const middle = Math.floor((start + end) / 2); return [ ...(await readWindow(start, middle)), ...(await readWindow(middle, end)), ]; } if (!Array.isArray(result.hits)) { throw new Error("OpenObserve search omitted hits"); } rowsRead += result.hits.length; if (rowsRead > maxRows) { throw new Error( `History exceeds the explicit ${maxRows}-row bound; narrow the interval or increase --max-rows`, ); } rows.push(...result.hits); if (result.hits.length < 200) { return rows; } } } const records = []; const queriedAt = Date.now() * 1000; for (let start = startTime; start < endTime; start += 600_000_000) { records.push( ...(await readWindow(start, Math.min(start + 600_000_000, endTime))), ); } const unique = new Map(); let exactRetryDuplicates = 0; const deduplicated = []; for (const record of records) { const key = typeof record.proxy_event_id === "string" && record.proxy_event_id ? JSON.stringify([record.service_instance_id, record.proxy_event_id]) : undefined; // Ingestion may move _timestamp; event payload is the producer identity. const payload = JSON.stringify([record.request_id, record.body]); if (key && unique.get(key) === payload) { exactRetryDuplicates++; continue; } if (key && !unique.has(key)) {unique.set(key, payload);} deduplicated.push(record); // Keep identity conflicts for the doctor to fail. } return { startTime, endTimeExclusive: endTime, kind, complete: true, recordCount: deduplicated.length, rawRecordCount: records.length, exactRetryDuplicates, queriedAtMicroseconds: queriedAt, lateIngestionBoundary: "Pagination is complete at query time; later ingestion can change this event-time interval", queries, records: deduplicated, }; } async function main() { const args = process.argv.slice(2); /** @param {string} name */ const value = (name) => { const index = args.indexOf(name); return index < 0 ? undefined : args[index + 1]; }; if (args.includes("--help")) { console.log( "Usage: node scripts/observability/query-proxy-history.mjs --since ISO_DATE [--until ISO_DATE] [--kind request_final|attempt|lifecycle|supervisor|body_capture_index|stream_error] [--max-rows 10000]", ); return; } const since = Date.parse(value("--since") ?? ""); const untilValue = value("--until"); const until = untilValue ? Date.parse(untilValue) : Date.now(); const backend = await resolveProxyTelemetryBackend(); const report = await queryProxyHistory({ ...backend, startTime: since * 1000, endTime: until * 1000, kind: value("--kind") ?? "request_final", maxRows: Number(value("--max-rows") ?? 10_000), }); console.log(JSON.stringify(report, null, 2)); } if ( process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href ) { main().catch((error) => { console.error(error.message); process.exitCode = 1; }); }