From bc0e95157c06ad1f68ba5bac33472e1071b2154f Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Wed, 24 Jun 2026 13:40:27 +0800 Subject: [PATCH] Log export lifecycle (start/ok/fail/lock) with stack and timing --- src/app/api/export-excel/route.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/app/api/export-excel/route.ts b/src/app/api/export-excel/route.ts index 6474a34..a76aab8 100644 --- a/src/app/api/export-excel/route.ts +++ b/src/app/api/export-excel/route.ts @@ -1,6 +1,7 @@ import { NextResponse } from "next/server"; import sql from "mssql"; import ExcelJS from "exceljs"; +import { exportLogger, formatError } from "../../../server/logger"; const dbConfig = { server: process.env.DB_SERVER!, @@ -55,7 +56,7 @@ const EXPORT_LOCK_TIMEOUT_MS = 90_000; // safety: reclaim a stuck lock after 90s function acquireExportLock(): boolean { if (exportLocked && Date.now() - exportLockedAt > EXPORT_LOCK_TIMEOUT_MS) { - console.warn("Export lock reclaimed after timeout"); + exportLogger.warn("export lock reclaimed after timeout"); exportLocked = false; } if (exportLocked) return false; @@ -70,11 +71,14 @@ function releaseExportLock() { export async function GET() { if (!acquireExportLock()) { + exportLogger.warn("export skipped: another export in progress (429)"); return NextResponse.json( { error: "正在导出,请稍候" }, { status: 429, headers: { "Retry-After": "3" } } ); } + const t0 = Date.now(); + exportLogger.info("export started"); let pool: sql.ConnectionPool | undefined; try { pool = await sql.connect(dbConfig); @@ -84,6 +88,7 @@ export async function GET() { const recordset = result.recordset; if (!recordset || recordset.length === 0) { + exportLogger.warn("export empty: no data"); return NextResponse.json({ error: "没有数据可导出" }, { status: 404 }); } @@ -151,6 +156,12 @@ export async function GET() { // Stream to buffer const buffer = await workbook.xlsx.writeBuffer(); + const bytes = + typeof buffer === "object" && buffer && "byteLength" in buffer + ? (buffer as { byteLength: number }).byteLength + : 0; + const dur = Date.now() - t0; + exportLogger.info(`export ok · rows=${recordset.length} · bytes=${bytes} · dur=${dur}ms`); return new NextResponse(buffer, { status: 200, @@ -162,8 +173,9 @@ export async function GET() { }, }); } catch (err) { + const dur = Date.now() - t0; const message = err instanceof Error ? err.message : "Unknown error"; - console.error("Excel export error:", message); + exportLogger.error(`export failed · dur=${dur}ms · ${formatError(err)}`); return NextResponse.json({ error: message }, { status: 500 }); } finally { if (pool) {