From 3773fdc780df86f0db14a8f1faac9bbba5c7ae90 Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Thu, 23 Apr 2026 09:55:35 +0800 Subject: [PATCH] feat(admin): add structured error logger for all API routes Replace bare console.error() calls with logError() utility across all 47 API route handlers. logError() prints timestamp + context + message + stack trace + extra request data to stderr, and redacts sensitive fields (password, token, secret, key, etc.) from logged objects. --- admin/src/app/api/admin/ai/models/route.ts | 7 +- .../app/api/admin/ai/pricing/[id]/route.ts | 3 +- admin/src/app/api/admin/ai/providers/route.ts | 7 +- admin/src/app/api/admin/ai/versions/route.ts | 7 +- .../api/admin/daily-report/ai-config/route.ts | 5 +- .../api/admin/daily-report/generate/route.ts | 5 +- .../daily-report/recipients/[id]/route.ts | 5 +- .../admin/daily-report/recipients/route.ts | 5 +- admin/src/app/api/admin/daily-report/route.ts | 5 +- .../api/admin/projects/[id]/billing/route.ts | 5 +- .../projects/[id]/members/[memberId]/route.ts | 5 +- .../api/admin/projects/[id]/members/route.ts | 5 +- .../src/app/api/admin/projects/[id]/route.ts | 3 +- admin/src/app/api/admin/projects/route.ts | 3 +- admin/src/app/api/admin/repos/[id]/route.ts | 3 +- admin/src/app/api/api-tokens/[id]/route.ts | 3 +- admin/src/app/api/api-tokens/route.ts | 5 +- admin/src/app/api/auth/login/route.ts | 3 +- admin/src/app/api/auth/logout/route.ts | 3 +- admin/src/app/api/auth/me/route.ts | 3 +- admin/src/app/api/health/route.ts | 3 +- admin/src/app/api/logs/route.ts | 3 +- admin/src/app/api/permissions/route.ts | 9 +-- .../app/api/platform/activity-stats/route.ts | 3 +- admin/src/app/api/platform/ai/route.ts | 3 +- admin/src/app/api/platform/ai/sync/route.ts | 3 +- .../app/api/platform/alerts/check/route.ts | 3 +- .../src/app/api/platform/audit-logs/route.ts | 3 +- admin/src/app/api/platform/repos/route.ts | 3 +- .../rooms/[id]/messages/[msgId]/route.ts | 3 +- .../api/platform/rooms/[id]/messages/route.ts | 3 +- admin/src/app/api/platform/rooms/route.ts | 3 +- admin/src/app/api/platform/sessions/route.ts | 5 +- admin/src/app/api/platform/stats/route.ts | 3 +- .../src/app/api/platform/users/[uid]/route.ts | 5 +- admin/src/app/api/platform/users/route.ts | 5 +- .../workspaces/[id]/add-credit/route.ts | 3 +- .../workspaces/[id]/alert-config/route.ts | 5 +- .../[id]/members/[memberId]/route.ts | 5 +- .../platform/workspaces/[id]/members/route.ts | 5 +- .../app/api/platform/workspaces/[id]/route.ts | 3 +- .../src/app/api/platform/workspaces/route.ts | 5 +- admin/src/app/api/roles/[id]/route.ts | 7 +- admin/src/app/api/roles/route.ts | 5 +- admin/src/app/api/sessions/route.ts | 5 +- admin/src/app/api/users/[id]/route.ts | 7 +- admin/src/app/api/users/route.ts | 5 +- admin/src/lib/logger.ts | 70 +++++++++++++++++++ 48 files changed, 196 insertions(+), 79 deletions(-) create mode 100644 admin/src/lib/logger.ts diff --git a/admin/src/app/api/admin/ai/models/route.ts b/admin/src/app/api/admin/ai/models/route.ts index bb87549..4879dfc 100644 --- a/admin/src/app/api/admin/ai/models/route.ts +++ b/admin/src/app/api/admin/ai/models/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { createModel, updateModel, deleteModel } from "@/lib/adminrpc/client"; @@ -11,7 +12,7 @@ export async function POST(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Create model error:", msg); + logError("Create model error:", e); return NextResponse.json({ error: `创建失败: ${msg}` }, { status: 500 }); } } @@ -27,7 +28,7 @@ export async function PATCH(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Update model error:", msg); + logError("Update model error:", e); return NextResponse.json({ error: `更新失败: ${msg}` }, { status: 500 }); } } @@ -42,7 +43,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Delete model error:", msg); + logError("Delete model error:", e); return NextResponse.json({ error: `删除失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/ai/pricing/[id]/route.ts b/admin/src/app/api/admin/ai/pricing/[id]/route.ts index bc85bf4..2a1c1a2 100644 --- a/admin/src/app/api/admin/ai/pricing/[id]/route.ts +++ b/admin/src/app/api/admin/ai/pricing/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { updatePricing } from "@/lib/adminrpc/client"; @@ -15,7 +16,7 @@ export async function PATCH( return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Update pricing error:", msg); + logError("Update pricing error:", e); return NextResponse.json({ error: `更新失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/ai/providers/route.ts b/admin/src/app/api/admin/ai/providers/route.ts index 2117605..56a1d9e 100644 --- a/admin/src/app/api/admin/ai/providers/route.ts +++ b/admin/src/app/api/admin/ai/providers/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { createProvider, updateProvider, deleteProvider } from "@/lib/adminrpc/client"; @@ -11,7 +12,7 @@ export async function POST(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Create provider error:", msg); + logError("Create provider error:", e); return NextResponse.json({ error: `创建失败: ${msg}` }, { status: 500 }); } } @@ -27,7 +28,7 @@ export async function PATCH(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Update provider error:", msg); + logError("Update provider error:", e); return NextResponse.json({ error: `更新失败: ${msg}` }, { status: 500 }); } } @@ -42,7 +43,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Delete provider error:", msg); + logError("Delete provider error:", e); return NextResponse.json({ error: `删除失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/ai/versions/route.ts b/admin/src/app/api/admin/ai/versions/route.ts index 3553d0d..8d6b8ed 100644 --- a/admin/src/app/api/admin/ai/versions/route.ts +++ b/admin/src/app/api/admin/ai/versions/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { createVersion, updateVersion, deleteVersion } from "@/lib/adminrpc/client"; @@ -11,7 +12,7 @@ export async function POST(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Create version error:", msg); + logError("Create version error:", e); return NextResponse.json({ error: `创建失败: ${msg}` }, { status: 500 }); } } @@ -27,7 +28,7 @@ export async function PATCH(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Update version error:", msg); + logError("Update version error:", e); return NextResponse.json({ error: `更新失败: ${msg}` }, { status: 500 }); } } @@ -42,7 +43,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Delete version error:", msg); + logError("Delete version error:", e); return NextResponse.json({ error: `删除失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/daily-report/ai-config/route.ts b/admin/src/app/api/admin/daily-report/ai-config/route.ts index b9f52da..292f146 100644 --- a/admin/src/app/api/admin/daily-report/ai-config/route.ts +++ b/admin/src/app/api/admin/daily-report/ai-config/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -45,7 +46,7 @@ export async function GET() { return NextResponse.json({ config }); } catch (e) { - console.error("Get AI config error:", e); + logError("Get AI config error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -95,7 +96,7 @@ export async function PUT(req: NextRequest) { return NextResponse.json({ success: true }); } catch (e) { - console.error("Update AI config error:", e); + logError("Update AI config error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/daily-report/generate/route.ts b/admin/src/app/api/admin/daily-report/generate/route.ts index 42f8301..b4c57d8 100644 --- a/admin/src/app/api/admin/daily-report/generate/route.ts +++ b/admin/src/app/api/admin/daily-report/generate/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -149,7 +150,7 @@ export async function POST(req: NextRequest) { aiSummaryUsed: !!aiSummary, }); } catch (e) { - console.error("[daily-report] Error:", e); + logError("[daily-report] Error:", e); return NextResponse.json({ error: String(e) }, { status: 500 }); } } @@ -484,7 +485,7 @@ async function sendEmail(opts: { sentCount++; console.log(`[daily-report] Sent to ${recipient}`); } catch (e) { - console.error(`[daily-report] Failed to send to ${recipient}:`, e); + logError(`[daily-report] Failed to send to ${recipient}:`, e); } } diff --git a/admin/src/app/api/admin/daily-report/recipients/[id]/route.ts b/admin/src/app/api/admin/daily-report/recipients/[id]/route.ts index b266fbd..5daa304 100644 --- a/admin/src/app/api/admin/daily-report/recipients/[id]/route.ts +++ b/admin/src/app/api/admin/daily-report/recipients/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -66,7 +67,7 @@ export async function PATCH( if (err?.code === "23505") { return NextResponse.json({ error: "该邮箱已存在" }, { status: 409 }); } - console.error("Update recipient error:", e); + logError("Update recipient error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -99,7 +100,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete recipient error:", e); + logError("Delete recipient error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/daily-report/recipients/route.ts b/admin/src/app/api/admin/daily-report/recipients/route.ts index b552506..4120cf2 100644 --- a/admin/src/app/api/admin/daily-report/recipients/route.ts +++ b/admin/src/app/api/admin/daily-report/recipients/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -14,7 +15,7 @@ export async function GET() { ); return NextResponse.json({ recipients: result.rows }); } catch (e) { - console.error("[recipients] List error:", e); + logError("[recipients] List error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -53,7 +54,7 @@ export async function POST(req: NextRequest) { if (err?.code === "23505") { return NextResponse.json({ error: "该邮箱已存在" }, { status: 409 }); } - console.error("[recipients] Add error:", e); + logError("[recipients] Add error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/daily-report/route.ts b/admin/src/app/api/admin/daily-report/route.ts index 2a4b0a8..b4a7bc6 100644 --- a/admin/src/app/api/admin/daily-report/route.ts +++ b/admin/src/app/api/admin/daily-report/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -38,7 +39,7 @@ export async function GET() { ); return NextResponse.json({ recipients: result.rows }); } catch (e) { - console.error("List recipients error:", e); + logError("List recipients error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -78,7 +79,7 @@ export async function POST(req: NextRequest) { if (err?.code === "23505") { return NextResponse.json({ error: "该邮箱已存在" }, { status: 409 }); } - console.error("Add recipient error:", e); + logError("Add recipient error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/projects/[id]/billing/route.ts b/admin/src/app/api/admin/projects/[id]/billing/route.ts index 4ef6875..05e2471 100644 --- a/admin/src/app/api/admin/projects/[id]/billing/route.ts +++ b/admin/src/app/api/admin/projects/[id]/billing/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query, transaction } from "@/lib/db"; @@ -41,7 +42,7 @@ export async function GET( })), }); } catch (e) { - console.error("Project billing error:", e); + logError("Project billing error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -82,7 +83,7 @@ export async function POST( return NextResponse.json({ ok: true, amount }); } catch (e) { - console.error("Project add credit error:", e); + logError("Project add credit error:", e); return NextResponse.json({ error: "充值失败" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/projects/[id]/members/[memberId]/route.ts b/admin/src/app/api/admin/projects/[id]/members/[memberId]/route.ts index 321cdcb..c75342a 100644 --- a/admin/src/app/api/admin/projects/[id]/members/[memberId]/route.ts +++ b/admin/src/app/api/admin/projects/[id]/members/[memberId]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -48,7 +49,7 @@ export async function PATCH( return NextResponse.json({ success: true }); } catch (e) { - console.error("Update project member error:", e); + logError("Update project member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -90,7 +91,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete project member error:", e); + logError("Delete project member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/projects/[id]/members/route.ts b/admin/src/app/api/admin/projects/[id]/members/route.ts index f23abe5..fbcea8d 100644 --- a/admin/src/app/api/admin/projects/[id]/members/route.ts +++ b/admin/src/app/api/admin/projects/[id]/members/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -38,7 +39,7 @@ export async function GET( return NextResponse.json({ members }); } catch (e) { - console.error("List project members error:", e); + logError("List project members error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -108,7 +109,7 @@ export async function POST( return NextResponse.json({ success: true, id: result.rows[0]?.id }, { status: 201 }); } catch (e) { - console.error("Add project member error:", e); + logError("Add project member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/projects/[id]/route.ts b/admin/src/app/api/admin/projects/[id]/route.ts index 7c73faf..29f1fdf 100644 --- a/admin/src/app/api/admin/projects/[id]/route.ts +++ b/admin/src/app/api/admin/projects/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -56,7 +57,7 @@ export async function GET( billingHistory: billingHistoryRows.rows, }); } catch (e) { - console.error("Project detail error:", e); + logError("Project detail error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/projects/route.ts b/admin/src/app/api/admin/projects/route.ts index addb6eb..69c72d3 100644 --- a/admin/src/app/api/admin/projects/route.ts +++ b/admin/src/app/api/admin/projects/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -64,7 +65,7 @@ export async function GET(req: NextRequest) { return NextResponse.json({ projects: projects.rows, total, page, pageSize }); } catch (e) { - console.error("List projects error:", e); + logError("List projects error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/admin/repos/[id]/route.ts b/admin/src/app/api/admin/repos/[id]/route.ts index 21a5928..a246a8b 100644 --- a/admin/src/app/api/admin/repos/[id]/route.ts +++ b/admin/src/app/api/admin/repos/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -108,7 +109,7 @@ export async function GET( return NextResponse.json({ repo, branches, commits }); } catch (e) { - console.error("Repo detail error:", e); + logError("Repo detail error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/api-tokens/[id]/route.ts b/admin/src/app/api/api-tokens/[id]/route.ts index cf3561f..531ff6f 100644 --- a/admin/src/app/api/api-tokens/[id]/route.ts +++ b/admin/src/app/api/api-tokens/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { deleteApiToken } from "@/lib/api-token"; import { createAuditLog } from "@/lib/log"; @@ -29,7 +30,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete token error:", e); + logError("Delete token error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/api-tokens/route.ts b/admin/src/app/api/api-tokens/route.ts index 751c42d..d51e813 100644 --- a/admin/src/app/api/api-tokens/route.ts +++ b/admin/src/app/api/api-tokens/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { listApiTokens, @@ -11,7 +12,7 @@ export async function GET(req: NextRequest) { const tokens = await listApiTokens(); return NextResponse.json({ tokens }); } catch (e) { - console.error("List tokens error:", e); + logError("List tokens error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -58,7 +59,7 @@ export async function POST(req: NextRequest) { return NextResponse.json({ id: result.id, token, name: name.trim(), expiresAt }, { status: 201 }); } catch (e) { - console.error("Create token error:", e); + logError("Create token error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/auth/login/route.ts b/admin/src/app/api/auth/login/route.ts index fb10c21..ca3b830 100644 --- a/admin/src/app/api/auth/login/route.ts +++ b/admin/src/app/api/auth/login/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { login, buildSetCookieHeader } from "@/lib/auth"; import { createAuditLog } from "@/lib/log"; @@ -70,7 +71,7 @@ export async function POST(req: NextRequest) { return response; } catch (e) { - console.error("Login error:", e); + logError("Login error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/auth/logout/route.ts b/admin/src/app/api/auth/logout/route.ts index ce7c426..8c7bc8d 100644 --- a/admin/src/app/api/auth/logout/route.ts +++ b/admin/src/app/api/auth/logout/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { logout, parseSessionCookie, loadAdminSession, buildClearCookieHeader } from "@/lib/auth"; import { createAuditLog } from "@/lib/log"; @@ -31,7 +32,7 @@ export async function POST(req: NextRequest) { response.headers.set("Set-Cookie", buildClearCookieHeader()); return response; } catch (e) { - console.error("Logout error:", e); + logError("Logout error:", e); const response = NextResponse.json({ success: false }); response.headers.set("Set-Cookie", buildClearCookieHeader()); return response; diff --git a/admin/src/app/api/auth/me/route.ts b/admin/src/app/api/auth/me/route.ts index 5d45598..744520d 100644 --- a/admin/src/app/api/auth/me/route.ts +++ b/admin/src/app/api/auth/me/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { parseSessionCookie, loadAdminSession, touchSession } from "@/lib/auth"; @@ -29,7 +30,7 @@ export async function GET(req: NextRequest) { }, }); } catch (e) { - console.error("Session check error:", e); + logError("Session check error:", e); return NextResponse.json({ user: null }); } } diff --git a/admin/src/app/api/health/route.ts b/admin/src/app/api/health/route.ts index 5d3bba9..0b4bcf2 100644 --- a/admin/src/app/api/health/route.ts +++ b/admin/src/app/api/health/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -132,7 +133,7 @@ export async function GET() { await ensureTables(); return NextResponse.json({ status: "ok" }, { status: 200 }); } catch (e) { - console.error("[Health] DB check failed:", e); + logError("[Health] DB check failed:", e); return NextResponse.json({ status: "error", reason: String(e) }, { status: 503 }); } } diff --git a/admin/src/app/api/logs/route.ts b/admin/src/app/api/logs/route.ts index 0d9e02a..a15cf0f 100644 --- a/admin/src/app/api/logs/route.ts +++ b/admin/src/app/api/logs/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { listAuditLogs } from "@/lib/log"; @@ -87,7 +88,7 @@ export async function GET(req: NextRequest) { return NextResponse.json(result); } catch (e) { - console.error("List audit logs error:", e); + logError("List audit logs error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/permissions/route.ts b/admin/src/app/api/permissions/route.ts index 138ddbb..d7de632 100644 --- a/admin/src/app/api/permissions/route.ts +++ b/admin/src/app/api/permissions/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { listPermissions, @@ -19,7 +20,7 @@ export async function GET() { const permissions = await listPermissions(); return NextResponse.json({ permissions }); } catch (e) { - console.error("List permissions error:", e); + logError("List permissions error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -63,7 +64,7 @@ export async function POST(req: NextRequest) { if ((e as { code?: string }).code === "23505") { return NextResponse.json({ error: "权限代码已存在" }, { status: 409 }); } - console.error("Create permission error:", e); + logError("Create permission error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -97,7 +98,7 @@ export async function PUT(req: NextRequest) { return NextResponse.json(permission); } catch (e) { - console.error("Update permission error:", e); + logError("Update permission error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -125,7 +126,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete permission error:", e); + logError("Delete permission error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/activity-stats/route.ts b/admin/src/app/api/platform/activity-stats/route.ts index 9490477..6795a73 100644 --- a/admin/src/app/api/platform/activity-stats/route.ts +++ b/admin/src/app/api/platform/activity-stats/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -76,7 +77,7 @@ export async function GET() { last24h: parseInt(last24h.rows[0]?.count || "0", 10), }); } catch (e) { - console.error("Activity stats error:", e); + logError("Activity stats error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/ai/route.ts b/admin/src/app/api/platform/ai/route.ts index abddeeb..b944299 100644 --- a/admin/src/app/api/platform/ai/route.ts +++ b/admin/src/app/api/platform/ai/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -97,7 +98,7 @@ export async function GET(req: NextRequest) { versions: versionsList, }); } catch (e) { - console.error("AI data error:", e); + logError("AI data error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/ai/sync/route.ts b/admin/src/app/api/platform/ai/sync/route.ts index 0081922..f537abb 100644 --- a/admin/src/app/api/platform/ai/sync/route.ts +++ b/admin/src/app/api/platform/ai/sync/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextResponse } from "next/server"; import { syncModels } from "@/lib/adminrpc/client"; @@ -12,7 +13,7 @@ export async function POST() { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("AI sync error:", msg); + logError("AI sync error:", e); return NextResponse.json({ error: `同步失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/alerts/check/route.ts b/admin/src/app/api/platform/alerts/check/route.ts index 0e28d91..30e9ae3 100644 --- a/admin/src/app/api/platform/alerts/check/route.ts +++ b/admin/src/app/api/platform/alerts/check/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextResponse } from "next/server"; import { checkAlerts } from "@/lib/adminrpc/client"; @@ -12,7 +13,7 @@ export async function POST() { return NextResponse.json(data); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - console.error("Alert check error:", msg); + logError("Alert check error:", e); return NextResponse.json({ error: `检查失败: ${msg}` }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/audit-logs/route.ts b/admin/src/app/api/platform/audit-logs/route.ts index 68c6faa..e2efe98 100644 --- a/admin/src/app/api/platform/audit-logs/route.ts +++ b/admin/src/app/api/platform/audit-logs/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -99,7 +100,7 @@ export async function GET(req: NextRequest) { return NextResponse.json({ logs: combined.slice(0, pageSize), total, page, pageSize }); } catch (e) { - console.error("Platform audit logs error:", e); + logError("Platform audit logs error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/repos/route.ts b/admin/src/app/api/platform/repos/route.ts index 9aeb166..a2580ba 100644 --- a/admin/src/app/api/platform/repos/route.ts +++ b/admin/src/app/api/platform/repos/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -90,7 +91,7 @@ export async function GET(req: NextRequest) { return NextResponse.json({ repos, total, page, pageSize }); } catch (e) { - console.error("Repos error:", e); + logError("Repos error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/rooms/[id]/messages/[msgId]/route.ts b/admin/src/app/api/platform/rooms/[id]/messages/[msgId]/route.ts index 566faf0..a25e608 100644 --- a/admin/src/app/api/platform/rooms/[id]/messages/[msgId]/route.ts +++ b/admin/src/app/api/platform/rooms/[id]/messages/[msgId]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { getAdminUserId } from "@/lib/auth"; @@ -30,7 +31,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Revoke message error:", e); + logError("Revoke message error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/rooms/[id]/messages/route.ts b/admin/src/app/api/platform/rooms/[id]/messages/route.ts index a5126ac..bceac72 100644 --- a/admin/src/app/api/platform/rooms/[id]/messages/route.ts +++ b/admin/src/app/api/platform/rooms/[id]/messages/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -72,7 +73,7 @@ export async function GET( return NextResponse.json({ messages, total, page, pageSize }); } catch (e) { - console.error("Room messages error:", e); + logError("Room messages error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/rooms/route.ts b/admin/src/app/api/platform/rooms/route.ts index 210f063..7a93526 100644 --- a/admin/src/app/api/platform/rooms/route.ts +++ b/admin/src/app/api/platform/rooms/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -90,7 +91,7 @@ export async function GET(req: NextRequest) { return NextResponse.json({ rooms, total, page, pageSize }); } catch (e) { - console.error("Rooms error:", e); + logError("Rooms error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/sessions/route.ts b/admin/src/app/api/platform/sessions/route.ts index 4f87ffe..231eeba 100644 --- a/admin/src/app/api/platform/sessions/route.ts +++ b/admin/src/app/api/platform/sessions/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { getOnlinePlatformSessions, @@ -22,7 +23,7 @@ export async function GET() { } return NextResponse.json({ sessions }); } catch (e) { - console.error("Get platform sessions error:", e); + logError("Get platform sessions error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -51,7 +52,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json({ success: ok }); } catch (e) { - console.error("Delete platform session error:", e); + logError("Delete platform session error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/stats/route.ts b/admin/src/app/api/platform/stats/route.ts index 9518358..f08637e 100644 --- a/admin/src/app/api/platform/stats/route.ts +++ b/admin/src/app/api/platform/stats/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -73,7 +74,7 @@ export async function GET() { planDistribution, }); } catch (e) { - console.error("Stats error:", e); + logError("Stats error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/users/[uid]/route.ts b/admin/src/app/api/platform/users/[uid]/route.ts index 7b53b83..7cffae0 100644 --- a/admin/src/app/api/platform/users/[uid]/route.ts +++ b/admin/src/app/api/platform/users/[uid]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -45,7 +46,7 @@ export async function GET( }, }); } catch (e) { - console.error("Get user error:", e); + logError("Get user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -145,7 +146,7 @@ export async function PATCH( return NextResponse.json({ success: true }); } catch (e) { - console.error("Update user error:", e); + logError("Update user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/users/route.ts b/admin/src/app/api/platform/users/route.ts index c911984..1e5e18b 100644 --- a/admin/src/app/api/platform/users/route.ts +++ b/admin/src/app/api/platform/users/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -55,7 +56,7 @@ export async function GET(req: NextRequest) { return NextResponse.json({ users, total, page, pageSize }); } catch (e) { - console.error("Platform users error:", e); + logError("Platform users error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -110,7 +111,7 @@ export async function PATCH(req: NextRequest) { return NextResponse.json({ success: true, updated: uids.length }); } catch (e) { - console.error("Batch update user status error:", e); + logError("Batch update user status error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/[id]/add-credit/route.ts b/admin/src/app/api/platform/workspaces/[id]/add-credit/route.ts index a3b1a51..30b9e76 100644 --- a/admin/src/app/api/platform/workspaces/[id]/add-credit/route.ts +++ b/admin/src/app/api/platform/workspaces/[id]/add-credit/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query, getClient } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -94,7 +95,7 @@ export async function POST( return NextResponse.json({ success: true, amount, currency }); } catch (e) { - console.error("Add workspace credit error:", e); + logError("Add workspace credit error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/[id]/alert-config/route.ts b/admin/src/app/api/platform/workspaces/[id]/alert-config/route.ts index f82ceed..84e32a7 100644 --- a/admin/src/app/api/platform/workspaces/[id]/alert-config/route.ts +++ b/admin/src/app/api/platform/workspaces/[id]/alert-config/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query, getClient } from "@/lib/db"; import { getAdminUserId } from "@/lib/auth"; @@ -35,7 +36,7 @@ export async function GET( ); return NextResponse.json({ configs: result.rows }); } catch (e) { - console.error("Alert config error:", e); + logError("Alert config error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -87,7 +88,7 @@ export async function PUT( client.release(); } } catch (e) { - console.error("Alert config update error:", e); + logError("Alert config update error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/[id]/members/[memberId]/route.ts b/admin/src/app/api/platform/workspaces/[id]/members/[memberId]/route.ts index dfd8dd2..53ba06a 100644 --- a/admin/src/app/api/platform/workspaces/[id]/members/[memberId]/route.ts +++ b/admin/src/app/api/platform/workspaces/[id]/members/[memberId]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -52,7 +53,7 @@ export async function PATCH( return NextResponse.json({ success: true }); } catch (e) { - console.error("Update workspace member error:", e); + logError("Update workspace member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -94,7 +95,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete workspace member error:", e); + logError("Delete workspace member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/[id]/members/route.ts b/admin/src/app/api/platform/workspaces/[id]/members/route.ts index caf485a..8b856f4 100644 --- a/admin/src/app/api/platform/workspaces/[id]/members/route.ts +++ b/admin/src/app/api/platform/workspaces/[id]/members/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -43,7 +44,7 @@ export async function GET( return NextResponse.json({ members }); } catch (e) { - console.error("List workspace members error:", e); + logError("List workspace members error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -113,7 +114,7 @@ export async function POST( return NextResponse.json({ success: true, id: result.rows[0]?.id }, { status: 201 }); } catch (e) { - console.error("Add workspace member error:", e); + logError("Add workspace member error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/[id]/route.ts b/admin/src/app/api/platform/workspaces/[id]/route.ts index e2e4357..31518b7 100644 --- a/admin/src/app/api/platform/workspaces/[id]/route.ts +++ b/admin/src/app/api/platform/workspaces/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; @@ -59,7 +60,7 @@ export async function GET( billingHistory: billing.rows, }); } catch (e) { - console.error("Workspace detail error:", e); + logError("Workspace detail error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/platform/workspaces/route.ts b/admin/src/app/api/platform/workspaces/route.ts index deb37e4..6e872f0 100644 --- a/admin/src/app/api/platform/workspaces/route.ts +++ b/admin/src/app/api/platform/workspaces/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { query } from "@/lib/db"; import { createAuditLog } from "@/lib/log"; @@ -61,7 +62,7 @@ export async function GET(req: NextRequest) { pageSize, }); } catch (e) { - console.error("List workspaces error:", e); + logError("List workspaces error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -108,7 +109,7 @@ export async function PATCH(req: NextRequest) { return NextResponse.json({ success: true, updated: ids.length }); } catch (e) { - console.error("Batch update workspace plan error:", e); + logError("Batch update workspace plan error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/roles/[id]/route.ts b/admin/src/app/api/roles/[id]/route.ts index 7048bf5..13b4752 100644 --- a/admin/src/app/api/roles/[id]/route.ts +++ b/admin/src/app/api/roles/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { getRoleById, @@ -27,7 +28,7 @@ export async function GET( const permissions = await getRolePermissions(roleId); return NextResponse.json({ ...role, permissions }); } catch (e) { - console.error("Get role error:", e); + logError("Get role error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -66,7 +67,7 @@ export async function PUT( return NextResponse.json(role); } catch (e) { - console.error("Update role error:", e); + logError("Update role error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -94,7 +95,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete role error:", e); + logError("Delete role error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/roles/route.ts b/admin/src/app/api/roles/route.ts index f6567fe..d53b1d2 100644 --- a/admin/src/app/api/roles/route.ts +++ b/admin/src/app/api/roles/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { listRoles, @@ -19,7 +20,7 @@ export async function GET() { const roles = await listRoles(); return NextResponse.json({ roles }); } catch (e) { - console.error("List roles error:", e); + logError("List roles error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -60,7 +61,7 @@ export async function POST(req: NextRequest) { if ((e as { code?: string }).code === "23505") { return NextResponse.json({ error: "角色名已存在" }, { status: 409 }); } - console.error("Create role error:", e); + logError("Create role error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/sessions/route.ts b/admin/src/app/api/sessions/route.ts index a5f5cf3..0b27c7f 100644 --- a/admin/src/app/api/sessions/route.ts +++ b/admin/src/app/api/sessions/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { getOnlineSessions } from "@/lib/redis"; import { createAuditLog } from "@/lib/log"; @@ -14,7 +15,7 @@ export async function GET() { const sessions = await getOnlineSessions(); return NextResponse.json({ sessions }); } catch (e) { - console.error("Get sessions error:", e); + logError("Get sessions error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -44,7 +45,7 @@ export async function DELETE(req: NextRequest) { return NextResponse.json({ success: ok }); } catch (e) { - console.error("Delete session error:", e); + logError("Delete session error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/users/[id]/route.ts b/admin/src/app/api/users/[id]/route.ts index 8832315..c034f75 100644 --- a/admin/src/app/api/users/[id]/route.ts +++ b/admin/src/app/api/users/[id]/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { getUserById, @@ -32,7 +33,7 @@ export async function GET( return NextResponse.json({ ...safeUser, roles }); } catch (e) { - console.error("Get user error:", e); + logError("Get user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -80,7 +81,7 @@ export async function PUT( const { password_hash: _, ...safeUser } = user; return NextResponse.json(safeUser); } catch (e) { - console.error("Update user error:", e); + logError("Update user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -113,7 +114,7 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (e) { - console.error("Delete user error:", e); + logError("Delete user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/app/api/users/route.ts b/admin/src/app/api/users/route.ts index 4b05618..28e5e24 100644 --- a/admin/src/app/api/users/route.ts +++ b/admin/src/app/api/users/route.ts @@ -1,3 +1,4 @@ +import { logError } from "@/lib/logger"; import { NextRequest, NextResponse } from "next/server"; import { listUsers, @@ -24,7 +25,7 @@ export async function GET(req: NextRequest) { const result = await listUsers({ page, pageSize, search }); return NextResponse.json(result); } catch (e) { - console.error("List users error:", e); + logError("List users error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } @@ -70,7 +71,7 @@ export async function POST(req: NextRequest) { if ((e as { code?: string }).code === "23505") { return NextResponse.json({ error: "用户名已存在" }, { status: 409 }); } - console.error("Create user error:", e); + logError("Create user error:", e); return NextResponse.json({ error: "服务器错误" }, { status: 500 }); } } diff --git a/admin/src/lib/logger.ts b/admin/src/lib/logger.ts new file mode 100644 index 0000000..d1c2df6 --- /dev/null +++ b/admin/src/lib/logger.ts @@ -0,0 +1,70 @@ +/** + * Structured error logger for the admin module. + * + * All API route errors should use this instead of bare console.error. + * Prints: [timestamp] [ERROR] context | message | stack | extra + */ + +export interface LogExtra { + method?: string; + url?: string; + params?: Record; + body?: unknown; + [key: string]: unknown; +} + +/** + * Format and print a detailed error to stderr. + * @param context Short label describing where the error occurred (e.g. "GET /api/users") + * @param error The caught error (any type) + * @param extra Optional additional context (request method, url, params, etc.) + */ +export function logError(context: string, error: unknown, extra?: LogExtra): void { + const timestamp = new Date().toISOString(); + + // Extract best-effort message + let message = "unknown error"; + if (error instanceof Error) { + message = error.message; + } else if (typeof error === "string") { + message = error; + } else if (error && typeof error === "object" && "message" in error) { + message = String((error as { message: unknown }).message); + } + + // Extract stack trace + let stack = ""; + if (error instanceof Error && error.stack) { + stack = error.stack; + } + + const extraStr = extra + ? ` | extra: ${JSON.stringify(redact(extra))}` + : ""; + + // Multi-line format for easy grepping + console.error( + `[${timestamp}] [ERROR] ${context}` + + `\n message: ${message}` + + (stack ? `\n stack: ${stack}` : "") + + extraStr + ); +} + +/** Recursively remove sensitive fields before logging */ +function redact(obj: unknown, depth = 0): unknown { + if (depth > 4) return "[max-depth]"; + if (obj === null || obj === undefined) return obj; + if (typeof obj !== "object") return obj; + if (Array.isArray(obj)) return obj.map((v) => redact(v, depth + 1)); + const sensitive = ["password", "token", "secret", "key", "authorization", "cookie", "api_key"]; + const result: Record = {}; + for (const [k, v] of Object.entries(obj as Record)) { + if (sensitive.some((s) => k.toLowerCase().includes(s))) { + result[k] = "[REDACTED]"; + } else { + result[k] = redact(v, depth + 1); + } + } + return result; +}