From dab3188f21074f142b6e71dac48a0d519bf33d8f Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:22:09 +1200 Subject: [PATCH] feat: getting all logs without authentication --- src/utils/query-string.ts | 19 +++++++++++++++++ src/v2/logging/index.ts | 33 ++++++++++++++++++++++++++++ src/v2/logging/schemas.ts | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/utils/query-string.ts create mode 100644 src/v2/logging/schemas.ts diff --git a/src/utils/query-string.ts b/src/utils/query-string.ts new file mode 100644 index 0000000..787ae2e --- /dev/null +++ b/src/utils/query-string.ts @@ -0,0 +1,19 @@ +/** + * Takes a URL and returns an object with the query string parameters, multiple of the same key will be an array + */ +export function getQueryParams(url: string): Record { + const search = new URL(url).searchParams; + const params: Record = {}; + search.forEach((value, key) => { + if (params[key]) { + if (Array.isArray(params[key])) { + params[key] = [...params[key], value]; + } else { + params[key] = [params[key] as string, value]; + } + } else { + params[key] = value; + } + }); + return params; +} diff --git a/src/v2/logging/index.ts b/src/v2/logging/index.ts index 2326abd..7645855 100644 --- a/src/v2/logging/index.ts +++ b/src/v2/logging/index.ts @@ -1,7 +1,40 @@ import { Hono } from "hono"; import type { ServerContext } from "@/types/hono"; +import { getQueryParams } from "@/utils/query-string"; +import { getLogsFiltersSchema } from "./schemas"; +import { db } from "@/config/db"; const app = new Hono(); +/** + * Get all log entries + */ +app.get("/", async (c) => { + const searchQuery = getQueryParams(c.req.url); + const search = getLogsFiltersSchema.parse(searchQuery); + + const logLevels = search.level.filter((val) => val !== "all"); + + const logs = await db.query.logs.findMany({ + limit: search.page_size, + offset: search.page_size * (search.page - 1), + orderBy: (fields, { asc, desc }) => (search.sort === "ASC" ? asc(fields.createdAt) : desc(fields.createdAt)), + where: (fields, { and, eq, inArray }) => + and( + // ...[eq(fields.serviceId, data.serviceId)], + ...(search.environment ? [eq(fields.environment, search.environment)] : []), + ...(search.lookup ? [eq(fields.lookupFilterValue, search.lookup)] : []), + ...(logLevels.length > 0 ? [inArray(fields.level, logLevels)] : []), + ), + }); + + return c.json(logs); +}); + +/** + * Create a log entry + */ +app.post("/", async (c) => {}); + export default app; diff --git a/src/v2/logging/schemas.ts b/src/v2/logging/schemas.ts new file mode 100644 index 0000000..c947d36 --- /dev/null +++ b/src/v2/logging/schemas.ts @@ -0,0 +1,45 @@ +import { z } from "zod"; + +const f = { + action: z.string(), + environment: z.string(), + ip: z.string().nullable().optional(), + lookupFilterValue: z.string().nullable().optional(), + data: z.record(z.string(), z.any()).nullable(), + level: z + .preprocess( + (val) => { + if (val) return val; + return val; + }, + z.enum(["info", "warn", "error", "fatal"]), + ) + .default("info"), + levelWithAll: z + .preprocess( + (val) => { + if (val) return val; + return ["all"]; + }, + z.array(z.enum(["all", "info", "warn", "error", "fatal"])), + ) + .default(["all"]), +}; + +export const createLogSchema = z.object({ + action: f.action, + environment: f.environment.default("production"), + ip: f.ip, + lookupFilterValue: f.lookupFilterValue, + data: f.data, + level: f.level, +}); + +export const getLogsFiltersSchema = z.object({ + lookup: f.lookupFilterValue.optional(), + environment: f.environment.optional(), + sort: z.enum(["ASC", "DESC"]).default("DESC"), + page: z.number().min(1).default(1), + page_size: z.number().min(1).default(50), + level: f.levelWithAll, +});