Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
3.3 kB ยท 114 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115import { db as defaultDb } from "@openstatus/db";
import { type ServiceContext, defaultTb } from "../context";import { ForbiddenError, ValidationError } from "../errors";import { getMonitorInWorkspace } from "./internal";import { toPipeParams } from "./response-logs-cursor";import { GetResponseLogFacetsInput } from "./schemas";
/** Marker the facet pipes use for the rows that carry the window summary. */const SUMMARY_FIELD = "__summary";
export type ResponseLogFacet = { rows: { value: string; total: number }[]; total: number; min?: number; max?: number;};
export type GetResponseLogFacetsResult = { totalRowCount: number; filterRowCount: number; facets: Record<string, ResponseLogFacet>;};
export async function getResponseLogFacets(args: { ctx: ServiceContext; input: GetResponseLogFacetsInput;}): Promise<GetResponseLogFacetsResult> { const { ctx } = args; const input = GetResponseLogFacetsInput.parse(args.input); if (!ctx.workspace.limits["response-logs"]) { throw new ForbiddenError("Response logs are not enabled on this plan."); } const db = ctx.db ?? defaultDb;
const record = await getMonitorInWorkspace({ tx: db, id: input.monitorId, workspaceId: ctx.workspace.id, }); const jobType = record.jobType; if ( jobType !== "http" && jobType !== "tcp" && jobType !== "dns" && jobType !== "icmp" && jobType !== "grpc" ) { throw new ValidationError( `getResponseLogFacets only supports HTTP, TCP, DNS, ICMP and gRPC monitors (got '${jobType}').`, ); }
const tb = ctx.tb ?? defaultTb; const getter = jobType === "http" ? tb.httpListFacets : jobType === "tcp" ? tb.tcpListFacets : jobType === "icmp" ? tb.icmpListFacets : jobType === "grpc" ? tb.grpcListFacets : tb.dnsListFacets;
const result = await getter({ monitorId: String(record.id), fromDate: input.fromTimestamp, toDate: input.toTimestamp, ...toPipeParams(input), });
const facets: Record<string, ResponseLogFacet> = {}; const summary = new Map<string, number>();
for (const row of result.data) { if (row.field === SUMMARY_FIELD) { summary.set(row.value, row.count); continue; } const facet = (facets[row.field] ??= { rows: [], total: 0 }); facet.rows.push({ value: row.value, total: row.count }); facet.total += row.count; }
for (const facet of Object.values(facets)) { facet.rows.sort((a, b) => b.total - a.total); }
const totalRowCount = summary.get("total") ?? 0; const latencyMin = summary.get("latencyMin"); const latencyMax = summary.get("latencyMax"); // `min()`/`max()` have no GROUP BY, so an empty window still returns a row โ // holding 0. Reporting that as the bounds collapses the slider to [0, 0] and // every range the user then types is clamped to it, so leave the facet out // and let the column's declared bounds stand. if ( totalRowCount > 0 && (latencyMin !== undefined || latencyMax !== undefined) ) { facets.latency = { rows: [], total: 0, min: latencyMin ?? 0, max: latencyMax ?? 0, }; }
return { totalRowCount, filterRowCount: summary.get("filtered") ?? 0, facets, };}