UNPKG

@dudousxd/nestjs-telescope

Version:

Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.

100 lines 4.4 kB
import { type RecordInput } from '../entry/entry.js'; import { type CpuProfilerResult } from './cpu-profiler.js'; import type { ResolvedProfilingConfig } from './profiling-config.js'; import type { CpuProfileContent } from './types.js'; /** The `type` of the entries this service records. */ export declare const CPU_PROFILE_ENTRY_TYPE: "cpu_profile"; /** Opaque handle for an in-flight capture, returned by {@link ProfilerService.begin}. */ export interface ProfileHandle { readonly profiler: ProfilerLike; readonly startedAt: number; readonly reason: 'manual' | 'sampled'; /** * The (fire-and-forget) start promise. {@link ProfilerService.end} awaits it * before calling `stop()` so a capture that ends before `start()` settled (a * very fast request, or a synchronous test) is still stopped correctly rather * than seeing `isRunning === false` and silently dropping the profile. */ readonly started: Promise<void>; } /** Minimal profiler contract so the service can be tested with a fake. */ export interface ProfilerLike { readonly isRunning: boolean; start(): Promise<void>; stop(): Promise<CpuProfilerResult | null>; } /** A pending manual capture budget: profile up to `count` more requests. */ interface ManualArm { count: number; /** When set, only requests whose label === this consume the budget. */ label?: string; } export interface ProfilerServiceDeps { /** Records the finished profile as a `cpu_profile` entry (via the Recorder). */ record: (input: RecordInput<CpuProfileContent>) => void; /** RNG for sampling — injectable for deterministic tests. */ random?: () => number; /** Builds a profiler; injectable so tests avoid the real inspector. */ profilerFactory?: () => ProfilerLike; } export interface ProfilerStatus { enabled: boolean; sampleRate: number; /** Currently in-flight captures. */ active: number; maxConcurrent: number; /** Remaining manual budget across all arms. */ pendingManual: number; } /** * Decides whether to profile a request and drives the capture lifecycle around * it. The integration calls {@link shouldProfile} (cheap gate), then * {@link begin}/{@link end} around the request body. * * OVERHEAD: while disabled, {@link shouldProfile} returns false and {@link begin} * returns null after a single boolean check — no profiler is ever constructed * and `node:inspector` is never required. While enabled but a request isn't * selected, the only added cost is the gate and (if sampling) one RNG call. */ export declare class ProfilerService { private readonly config; private readonly deps; private active; private readonly manual; private readonly random; private readonly profilerFactory; constructor(config: ResolvedProfilingConfig, deps: ProfilerServiceDeps); /** * Arm a manual capture for the next `count` requests (optionally only those * matching `label`). Returns the pending budget. No-op when disabled. */ arm(arm: ManualArm): { pendingManual: number; }; /** * Whether this request should be profiled. Consults the manual arm budget * first (targeted captures win), then sampling. Cheap and side-effect-free * EXCEPT it does not yet consume the manual budget — that happens in * {@link begin} so a request rejected by the concurrency cap doesn't waste it. */ shouldProfile(label: string | null): boolean; /** * Begin a capture for a request that {@link shouldProfile} accepted. Returns a * handle to pass to {@link end}, or `null` if the request should not be * profiled (disabled, concurrency cap reached, or not selected). The caller * MUST treat a null handle as "no profiling" and proceed untouched. */ begin(label: string | null): ProfileHandle | null; /** * Stop a capture and record it as a `cpu_profile` entry. Safe to call with a * null handle (no-op). Never throws into the host request path. Captures below * the `minDurationMs` floor are discarded. */ end(handle: ProfileHandle | null, label: string | null): Promise<void>; status(): ProfilerStatus; private pendingManual; /** First arm matching this label (labelled arms require an exact match). */ private matchingArm; } export {}; //# sourceMappingURL=profiler.service.d.ts.map