diff --git a/app/api/canvas/world/tasks/[taskId]/route.ts b/app/api/canvas/world/tasks/[taskId]/route.ts index dabdd98f5..5ebc876e4 100644 --- a/app/api/canvas/world/tasks/[taskId]/route.ts +++ b/app/api/canvas/world/tasks/[taskId]/route.ts @@ -5,6 +5,7 @@ import { db } from "@/lib/db"; import { model3dAsset } from "@/lib/db/schema"; import { resolveThreeDModelAliasId } from "@/lib/model3d/model-alias-config"; import { getThreeDModelAliasConfigForRuntime } from "@/lib/model3d/model-alias-config-server"; +import { createLogger } from "@/lib/observability/logger"; import { uploadFile } from "@/lib/storage/service"; import { WorldLabsApiError, worldLabsRequest } from "@/lib/worldlabs/client"; import { getWorldLabsProviderConfig } from "@/lib/worldlabs/server"; @@ -17,6 +18,8 @@ import type { export const runtime = "nodejs"; export const maxDuration = 120; +const logger = createLogger("world-labs-task-status"); + type ArchiveCacheItem = { sourceUrl: string; archivedUrl: string; @@ -209,7 +212,7 @@ async function archiveRemoteAssetIfNeeded(params: { const contentType = upstream.headers.get("content-type"); if (params.skipHtml && /\btext\/html\b/i.test(String(contentType || ""))) { - console.warn("[WorldLabsArchive] skip html viewer url", { + logger.warn("archive skipped html viewer", { cacheKey: params.cacheKey, sourceUrl, }); @@ -236,10 +239,10 @@ async function archiveRemoteAssetIfNeeded(params: { }); return uploaded.url; } catch (error) { - console.error("[WorldLabsArchive] failed", { + logger.warn("archive failed", { cacheKey: params.cacheKey, sourceUrl, - error: error instanceof Error ? error.message : String(error), + error, }); return null; } finally { @@ -477,9 +480,9 @@ export async function GET(request: Request, { params }: RouteParams) { error: operation.error.message, assetPayload: failedAssetPayload, }); - console.warn("[WorldLabsTask] failed status", { + logger.warn("task failed status", { elapsedMs: Date.now() - startedAt, - taskId: normalizedTaskId, + taskIdLength: normalizedTaskId.length, providerId: config.providerId || null, error: operation.error.message, }); @@ -536,11 +539,11 @@ export async function GET(request: Request, { params }: RouteParams) { operationMetadata: operation.metadata ?? null, }, }); - console.info("[WorldLabsTask] assets pending", { + logger.info("task assets pending", { elapsedMs: Date.now() - startedAt, - taskId: normalizedTaskId, + taskIdLength: normalizedTaskId.length, providerId: config.providerId || null, - worldId: getStringValue(world.world_id) || worldId || null, + worldIdLength: String(getStringValue(world.world_id) || worldId || "").length, }); return NextResponse.json({ success: true, @@ -648,11 +651,11 @@ export async function GET(request: Request, { params }: RouteParams) { ? new Date().toISOString() : null; - console.info("[WorldLabsTask] success status", { + logger.info("task success status", { elapsedMs: Date.now() - startedAt, - taskId: normalizedTaskId, + taskIdLength: normalizedTaskId.length, providerId: config.providerId || null, - worldId: assetPayload.worldId, + worldIdLength: String(assetPayload.worldId || "").length, hasMesh: Boolean(stableModelUrl), hasPano: Boolean(stablePanoUrl), hasThumbnail: Boolean(stableThumbnailUrl), @@ -723,11 +726,10 @@ export async function GET(request: Request, { params }: RouteParams) { }, }); } catch (error) { - console.error("[WorldLabsTask] status failed", { + logger.error("task status failed", error, { elapsedMs: Date.now() - startedAt, - taskId: normalizedTaskIdForLog, + taskIdLength: String(normalizedTaskIdForLog || "").length, providerId: providerForLog, - error: error instanceof Error ? error.message : String(error), }); if (error instanceof WorldLabsApiError) { return NextResponse.json( diff --git a/app/api/canvas/world/tasks/route.ts b/app/api/canvas/world/tasks/route.ts index 1e6cff05e..8ef6e773d 100644 --- a/app/api/canvas/world/tasks/route.ts +++ b/app/api/canvas/world/tasks/route.ts @@ -10,6 +10,7 @@ import { resolveThreeDModelRealId, } from "@/lib/model3d/model-alias-config"; import { getThreeDModelAliasConfigForRuntime } from "@/lib/model3d/model-alias-config-server"; +import { createLogger } from "@/lib/observability/logger"; import { get3DWorldCreditCost } from "@/lib/points/config"; import { WorldLabsApiError, worldLabsRequest } from "@/lib/worldlabs/client"; import { @@ -22,6 +23,8 @@ import type { WorldLabsModel, WorldLabsOperation } from "@/lib/worldlabs/types"; export const runtime = "nodejs"; export const maxDuration = 60; +const logger = createLogger("world-labs-task-create"); + type WorldTaskMode = "text" | "image" | "multi-image" | "video"; type CreateWorldTaskRequest = { @@ -287,13 +290,18 @@ export async function POST(request: Request) { note: `3D世界生成消耗积分(${worldModelDisplayName})`, }); } catch (error) { - console.error("[Points] Failed to consume World Labs 3D points:", error); + logger.error("points consume failed", error, { + userId: session.user.id, + unitCost, + mode, + model: resolvedWorldModel || "marble-1.1", + }); } } - console.info("[WorldLabsTask] created", { + logger.info("task created", { elapsedMs: Date.now() - startedAt, - taskId, + taskIdLength: taskId.length, mode, model: resolvedWorldModel || "marble-1.1", providerId: usedProvider.providerId || null, @@ -314,12 +322,11 @@ export async function POST(request: Request) { }, }); } catch (error) { - console.error("[WorldLabsTask] create failed", { + logger.error("task create failed", error, { elapsedMs: Date.now() - startedAt, mode: modeForLog, model: modelForLog, providerId: providerForLog, - error: error instanceof Error ? error.message : String(error), }); if (error instanceof WorldLabsApiError) { return NextResponse.json( diff --git a/scripts/check-log-hygiene.mjs b/scripts/check-log-hygiene.mjs index f306be16b..401f8f55c 100644 --- a/scripts/check-log-hygiene.mjs +++ b/scripts/check-log-hygiene.mjs @@ -35,6 +35,8 @@ const files = [ "app/api/canvas/world/upload/route.ts", "app/api/canvas/3d/tasks/route.ts", "app/api/canvas/3d/tasks/[taskId]/route.ts", + "app/api/canvas/world/tasks/route.ts", + "app/api/canvas/world/tasks/[taskId]/route.ts", ]; const consolePattern = /\bconsole\.(log|warn|error|info|debug)\b/g;