From 6555be012abde0047ea9eac998a63cbb175281f8 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 10 Mar 2026 10:25:47 -0700 Subject: [PATCH] Add richer metadata to logs and expandable detail panel Enriches webhook logs with sender and ref for better visibility into who triggered events and what they affected (e.g. which branch). PR logs now include the title, comment logs include the first 200 characters of the comment body. Adds an expandable detail row in the log viewer UI that shows all metadata as key-value pairs when clicked, keeping the summary line clean. Co-Authored-By: Claude Haiku 4.5 --- packages/spike/src/bridge/webhook-handler.ts | 4 +- packages/spike/src/log.ts | 9 ++- packages/spike/src/server/index.tsx | 4 +- packages/spike/src/server/logs.tsx | 59 ++++++++++++++++---- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/packages/spike/src/bridge/webhook-handler.ts b/packages/spike/src/bridge/webhook-handler.ts index c58601b..5ea4666 100644 --- a/packages/spike/src/bridge/webhook-handler.ts +++ b/packages/spike/src/bridge/webhook-handler.ts @@ -60,7 +60,7 @@ class PRHandler { await this.handleStateChange(pullRequest, repository) } - log({ type: "pr", action, pr: payload.number, repo: repository.full_name, user: pullRequest.user.login }) + log({ type: "pr", action, pr: payload.number, repo: repository.full_name, user: pullRequest.user.login, title: pullRequest.title }) } static async handleOpened(pullRequest: Gitea.PullRequest, repository: Gitea.Repository) { @@ -153,7 +153,7 @@ class CommentHandler { await this.handleDeleted(comment) } - log({ type: "comment", action, pr: issue.number, repo: repository.full_name, user: comment.user.login }) + log({ type: "comment", action, pr: issue.number, repo: repository.full_name, user: comment.user.login, body: comment.body.slice(0, 200) }) } static async handleCreated(issue: Gitea.Issue, comment: Gitea.Comment, repo: string) { diff --git a/packages/spike/src/log.ts b/packages/spike/src/log.ts index 8310a8c..e6b1669 100644 --- a/packages/spike/src/log.ts +++ b/packages/spike/src/log.ts @@ -3,10 +3,10 @@ import { basename } from "node:path" import { getConfig } from "./config" export type LogEvent = - | { type: "webhook"; eventType: string; repo: string } + | { type: "webhook"; eventType: string; repo: string; sender?: string; ref?: string } | { type: "webhook-ignored"; eventType: string; repo: string } - | { type: "pr"; action: string; pr: number; repo: string; user: string } - | { type: "comment"; action: string; pr: number; repo: string; user: string } + | { type: "pr"; action: string; pr: number; repo: string; user: string; title?: string } + | { type: "comment"; action: string; pr: number; repo: string; user: string; body?: string } | { type: "comment-skipped"; pr: number; repo: string; commentId: number } | { type: "review"; action: string; pr: number; repo: string; user: string } | { type: "thread-auto-created"; pr: number; repo: string } @@ -96,6 +96,9 @@ onLog((event) => { if ("repo" in event) parts.push(dim(event.repo)) if ("pr" in event) parts.push(cyan(`#${event.pr}`)) if ("user" in event) parts.push(dim(event.user)) + if ("sender" in event && event.sender) parts.push(dim(event.sender)) + if ("ref" in event && event.ref) parts.push(dim(event.ref)) + if ("title" in event && event.title) parts.push(event.title) if ("detail" in event) parts.push(event.detail) if ("command" in event) parts.push(event.command) if ("eventType" in event) parts.push(event.eventType) diff --git a/packages/spike/src/server/index.tsx b/packages/spike/src/server/index.tsx index 7ad741e..ff596be 100644 --- a/packages/spike/src/server/index.tsx +++ b/packages/spike/src/server/index.tsx @@ -18,7 +18,9 @@ const server = serve({ const payload = await req.json() const eventType = req.headers.get("X-Gitea-Event") || "unknown" const repo = (payload as any)?.repository?.full_name || "unknown" - log({ type: "webhook", eventType, repo }) + const sender = (payload as any)?.sender?.login as string | undefined + const ref = (payload as any)?.ref as string | undefined + log({ type: "webhook", eventType, repo, sender, ref }) try { await handleGiteaWebhook(payload, eventType as any) diff --git a/packages/spike/src/server/logs.tsx b/packages/spike/src/server/logs.tsx index 0a2975f..c464524 100644 --- a/packages/spike/src/server/logs.tsx +++ b/packages/spike/src/server/logs.tsx @@ -17,7 +17,19 @@ const typeColors: Record = { error: "#f87171", } -function EventRow({ event }: { event: StoredLogEvent }) { +const summaryFields = ["type", "ts"] as const + +function getEventMeta(event: StoredLogEvent): Record { + const meta: Record = {} + for (const [key, value] of Object.entries(event)) { + if (summaryFields.includes(key as any)) continue + if (value === undefined) continue + meta[key] = typeof value === "string" ? value : String(value) + } + return meta +} + +function EventRow({ event, index }: { event: StoredLogEvent; index: number }) { const color = typeColors[event.type] || "#9ca3af" const time = event.ts.slice(11, 19) @@ -35,14 +47,41 @@ function EventRow({ event }: { event: StoredLogEvent }) { details.push(msg) } + const meta = getEventMeta(event) + const hasExtra = Object.keys(meta).length > 0 + return ( - - {time} - - {event.type} - - {details.join(" ")} - + <> + + + {hasExtra && +} + + {time} + + {event.type} + + {details.join(" ")} + + {hasExtra && ( + + + +
+ {Object.entries(meta).map(([key, value]) => ( +
+ {key} + {value} +
+ ))} +
+ + + )} + ) } @@ -154,8 +193,8 @@ export function LogsPage(req: Request) { {/* Events table */} - {events.map((event) => ( - + {events.map((event, i) => ( + ))}