/** * The hot-tier run: one run of an Elasticsearch hot tier held under a size S. * * Each run, read-only against the cluster: * 1. the hot nodes' index store and disk (`_nodes`, `_nodes//stats`), * and the store of the Receiver's own indices still on hot, split into * kept lines (the pass alias) and tier_down lines (the tier_down alias); * a tier_down index counts as on hot when a shard of it sits on a hot * node (`_cat/shards`), so one placed on warm is outside S; * 2. how long a kept line stays on hot, from the ILM policy on the pass * alias, and how long a tier_down index stays on hot, from its policy * and the mount times of the indices already moved; * 3. every statement's bytes an hour by ingest time, from the Receiver's * indices still on hot: the Receiver stamps `utf8Size` on each returned * record, the same size its byte limits count; * 4. the store each counted byte takes on hot, measured on the indices * still there; * then the allowance: A = (S - lines outside the Receiver - tier_down in * flight on hot, zero when the tier_down write index is off hot) / (store * per byte x hours on hot) counted bytes an hour for the * kept lines, spread over statements with the water level the Datadog run * uses (the noisiest held first), as per-node per-window byte limits. * * A failed read changes nothing: the caller keeps the last files. */ import { type BudgetAction } from './budget-tick.js'; import type { HotTierBudget } from './policy-loader.js'; export interface EsCreds { url: string; apiKey?: string; user?: string; password?: string; } /** `LOG10X_ES_URL` with `LOG10X_ES_API_KEY` (an encoded API key) or `LOG10X_ES_USER` and `LOG10X_ES_PASSWORD`. */ export declare function esCredsFromEnv(env?: NodeJS.ProcessEnv): EsCreds | undefined; export type EsRequest = (method: 'GET' | 'POST', path: string, body?: unknown) => Promise; export declare function esRequester(creds: EsCreds, timeoutMs?: number): EsRequest; /** An Elasticsearch time value (`1h`, `30d`, `0ms`, `90s`) in hours, or undefined. */ export declare function esDurationHours(v: unknown): number | undefined; /** * Hours an index governed by an ILM policy stays on hot: the hot phase's * rollover `max_age` plus the `min_age` of the first phase after hot (a * phase's `min_age` counts from rollover). Undefined when the policy has no * age-based rollover or no phase after hot. */ export declare function ilmHotHours(policy: any): { hours: number; detail: string; } | undefined; export interface StatementBytes { container: string; pattern: string; name: string; severity: string; route: string; bytesPerHour: number; linesPerHour: number; } export interface HotTierReads { hotNodes: number; /** Index store on the hot nodes, every index, bytes. */ hotStoreBytes: number; /** Disk on the hot nodes, bytes. */ hotDiskBytes: number; pass: { storeBytes: number; countedBytes: number; indices: number; }; /** The tier_down indices not yet mounted with a shard on a hot node. */ tierDown: { storeBytes: number; countedBytes: number; indices: number; }; /** The tier_down indices not yet mounted with no shard on a hot node, outside S. */ tierDownOffHot: { storeBytes: number; indices: number; }; /** True when the tier_down write index sits on hot, so moved lines wait there for their mount. */ tierDownOnHot: boolean; retentionHours: number; retentionSource: string; tierDownHotHours: number; tierDownSource: string; statements: StatementBytes[]; /** Documents on hot with no `utf8Size`. */ unsized: number; spanHours: number; } export declare function readHotTierInputs(nowSec: number, hot: HotTierBudget, req: EsRequest): Promise; export interface HotTierRow { container: string; action: BudgetAction; instances: number; /** Fleet counted bytes an hour the service sends now. */ bytesPerHour: number; /** Fleet counted bytes an hour kept on hot under this run. */ keptPerHour: number; /** Per-statement limit, bytes per window per node; 0 exempts the service. */ cap: number; /** Service total, bytes per window per node. */ total: number; } export interface HotTierPlan { targetBytes: number; targetSource: string; hotStoreBytes: number; hotDiskBytes: number; outsideBytes: number; storePerByte: number; storePerByteTierDown: number; retentionHours: number; tierDownHotHours: number; /** Fleet counted bytes an hour the kept lines may add. */ allowancePerHour: number; /** Fleet counted bytes an hour each statement keeps when the size binds; undefined under it. */ levelPerHour?: number; /** Counted bytes an hour the always-pass sample and error keep counts keep whatever the limits. */ floorPerHour: number; /** True when the floor alone exceeds what fits: hot settles above S. */ floorExceedsSize: boolean; movedPerHour: number; tierDownInFlightBytes: number; /** Hot store the limits settle at once the current lines on hot have aged out. */ projectedBytes: number; overSize: boolean; rows: HotTierRow[]; star: { action: BudgetAction; instances: number; cap: number; total: number; keptPerHour: number; }; heldLine: string; lines: string[]; warnings: string[]; } export interface HotTierPlanInput { hot: HotTierBudget; reads: HotTierReads; instances: Record; nodesTotal: number; exceptions: string[]; targetServices: string[]; } /** Where a held line goes on Elasticsearch. */ export declare function elasticDestination(action: BudgetAction): string; export declare function fmtGB(bytes: number): string; export declare function planHotTier(input: HotTierPlanInput): HotTierPlan; export declare function renderHotTierReport(plan: HotTierPlan, hot: HotTierBudget, nowSec: number): string;