refactor(logging): centralize console output

This commit is contained in:
2026-06-18 13:34:19 +08:00
parent f600e11d55
commit 812a3e41b9
24 changed files with 261 additions and 166 deletions
+36 -34
View File
@@ -5,7 +5,7 @@
import { fromPromise, fromCallback } from "xstate";
import { createChatWebSocket, ChatWebSocket } from "@/core/net/chat-websocket";
import { Result } from "@/utils";
import { Result, Logger } from "@/utils";
import {
PAGE_SIZE,
@@ -17,6 +17,8 @@ import {
} from "./chat-machine.helpers";
import type { ChatEvent } from "./chat-events";
const log = new Logger("StoresChatChatMachineActors");
// ============================================================
// 共享 WS 引用(chatWebSocketActor ↔ sendMessageWsActor
// ============================================================
@@ -51,9 +53,9 @@ export const loadQuotaActor = fromPromise<{
remaining: number;
total: number;
}>(async () => {
console.log("[chat-machine] loadQuotaActor ENTRY");
log.debug("[chat-machine] loadQuotaActor ENTRY");
const result = await readGuestQuota();
console.log("[chat-machine] loadQuotaActor DONE", result);
log.debug("[chat-machine] loadQuotaActor DONE", result);
return result;
});
@@ -74,9 +76,9 @@ export const loadHistoryActor = fromPromise<{
localCount: number;
networkCount: number;
}>(async () => {
console.log("[chat-machine] loadHistoryActor ENTRY");
log.debug("[chat-machine] loadHistoryActor ENTRY");
const result = await readAndSyncHistory();
console.log("[chat-machine] loadHistoryActor DONE", {
log.debug("[chat-machine] loadHistoryActor DONE", {
finalCount: result.messages.length,
localCount: result.localCount,
networkCount: result.networkCount,
@@ -99,25 +101,25 @@ export const sendMessageHttpActor = fromPromise<
{ reply: UiMessage },
{ content: string }
>(async ({ input, self }) => {
console.log("[chat-machine] sendMessageHttpActor ENTRY", {
log.debug("[chat-machine] sendMessageHttpActor ENTRY", {
contentLength: input.content.length,
contentPreview: input.content.slice(0, 50),
selfId: self.id,
selfPath: "<actor path>",
});
console.log("[chat-machine] sendMessageHttpActor calling chatRepo.sendMessage");
log.debug("[chat-machine] sendMessageHttpActor calling chatRepo.sendMessage");
const result = await chatRepo.sendMessage(input.content);
console.log("[chat-machine] sendMessageHttpActor chatRepo.sendMessage DONE", {
log.debug("[chat-machine] sendMessageHttpActor chatRepo.sendMessage DONE", {
success: result.success,
error: result.success ? null : Result.isErr(result) ? result.error : null,
});
if (Result.isErr(result)) {
console.error("[chat-machine] sendMessageHttpActor result isErr, throwing");
log.error("[chat-machine] sendMessageHttpActor result isErr, throwing");
throw result.error;
}
// 一次发送 = 一次返回 —— 直接转 reply → UiMessage
console.log("[chat-machine] sendMessageHttpActor converting reply to UiMessage", {
log.debug("[chat-machine] sendMessageHttpActor converting reply to UiMessage", {
replyLength: result.data.reply.length,
replyPreview: result.data.reply.slice(0, 50),
messageId: result.data.messageId,
@@ -125,7 +127,7 @@ export const sendMessageHttpActor = fromPromise<
});
const reply = sendResponseToUiMessage(result.data);
console.log("[chat-machine] sendMessageHttpActor done", {
log.debug("[chat-machine] sendMessageHttpActor done", {
replyContentLength: reply.content.length,
});
return { reply };
@@ -136,37 +138,37 @@ export const loadMoreHistoryActor = fromPromise<
{ messages: UiMessage[]; hasMore: boolean; newOffset: number },
{ offset: number }
>(async ({ input, self }) => {
console.log("[chat-machine] loadMoreHistoryActor ENTRY", {
log.debug("[chat-machine] loadMoreHistoryActor ENTRY", {
inputOffset: input.offset,
pageSize: PAGE_SIZE,
selfPath: "<actor path>",
});
console.log("[chat-machine] loadMoreHistoryActor calling chatRepo.getHistory", {
log.debug("[chat-machine] loadMoreHistoryActor calling chatRepo.getHistory", {
pageSize: PAGE_SIZE,
offset: input.offset,
});
const result = await chatRepo.getHistory(PAGE_SIZE, input.offset);
console.log("[chat-machine] loadMoreHistoryActor chatRepo.getHistory DONE", {
log.debug("[chat-machine] loadMoreHistoryActor chatRepo.getHistory DONE", {
success: result.success,
error: result.success ? null : Result.isErr(result) ? result.error : null,
responseType: result.success ? typeof result.data : "err",
});
if (Result.isErr(result)) {
console.error("[chat-machine] loadMoreHistoryActor result isErr, throwing", {
log.error("[chat-machine] loadMoreHistoryActor result isErr, throwing", {
error: result.error,
});
throw result.error;
}
console.log("[chat-machine] loadMoreHistoryActor result data", {
log.debug("[chat-machine] loadMoreHistoryActor result data", {
rawMessagesCount: result.data.messages.length,
});
const page = localMessagesToUi(result.data.messages);
console.log("[chat-machine] loadMoreHistoryActor AFTER UiMessage mapping", {
log.debug("[chat-machine] loadMoreHistoryActor AFTER UiMessage mapping", {
uiMessagesCount: page.length,
});
const hasMore = page.length >= PAGE_SIZE;
const newOffset = input.offset + page.length;
console.log("[chat-machine] loadMoreHistoryActor result", {
log.debug("[chat-machine] loadMoreHistoryActor result", {
pageSize: page.length,
hasMore,
newOffset,
@@ -194,33 +196,33 @@ export const loadMoreHistoryActor = fromPromise<
*/
export const chatWebSocketActor = fromCallback<ChatEvent, { token: string }>(
({ sendBack, input }) => {
console.log("[chat-machine] chatWebSocketActor ENTRY", {
log.debug("[chat-machine] chatWebSocketActor ENTRY", {
hasToken: !!input.token,
tokenLength: input.token?.length ?? 0,
tokenPrefix: input.token?.slice(0, 10) ?? "EMPTY",
selfPath: "<actor path>",
});
console.log("[chat-machine] chatWebSocketActor creating ChatWebSocket instance");
log.debug("[chat-machine] chatWebSocketActor creating ChatWebSocket instance");
const ws = createChatWebSocket(input.token);
console.log("[chat-machine] chatWebSocketActor createChatWebSocket DONE", {
log.debug("[chat-machine] chatWebSocketActor createChatWebSocket DONE", {
wsType: ws.constructor.name,
});
// 写入 module-level 共享引用 —— sendMessageWsActor 借此调 ws.sendMessage()
activeChatWebSocket = ws;
console.log("[chat-machine] chatWebSocketActor activeChatWebSocket SET", {
log.debug("[chat-machine] chatWebSocketActor activeChatWebSocket SET", {
isConnected: ws.isConnected,
});
ws.onConnected = (userId) => {
console.log("[chat-machine] WS onConnected", {
log.debug("[chat-machine] WS onConnected", {
userId,
userIdPrefix: userId?.slice(0, 8) ?? "EMPTY",
});
sendBack({ type: "ChatWebSocketConnected", userId });
};
ws.onSentence = (p) => {
console.log("[chat-machine] WS onSentence", {
log.debug("[chat-machine] WS onSentence", {
index: p.index,
total: p.total,
done: p.done,
@@ -237,23 +239,23 @@ export const chatWebSocketActor = fromCallback<ChatEvent, { token: string }>(
});
};
ws.onError = (msg) => {
console.error("[chat-machine] WS onError", {
log.error("[chat-machine] WS onError", {
errorMessage: msg,
errorLength: msg?.length ?? 0,
});
sendBack({ type: "ChatWebSocketError", errorMessage: msg });
};
console.log("[chat-machine] chatWebSocketActor calling ws.connect()");
log.debug("[chat-machine] chatWebSocketActor calling ws.connect()");
ws.connect();
console.log("[chat-machine] chatWebSocketActor ws.connect() called");
log.debug("[chat-machine] chatWebSocketActor ws.connect() called");
return () => {
console.log(
log.debug(
"[chat-machine] chatWebSocketActor CLEANUP (parent state exit / logout / cross-transition / unmount)",
);
// 清空 module-level 引用 —— 严格用 `=== ws` 判等,避免覆盖更新的实例
if (activeChatWebSocket === ws) {
activeChatWebSocket = null;
console.log("[chat-machine] chatWebSocketActor activeChatWebSocket CLEARED");
log.debug("[chat-machine] chatWebSocketActor activeChatWebSocket CLEARED");
}
ws.disconnect();
};
@@ -281,26 +283,26 @@ export const chatWebSocketActor = fromCallback<ChatEvent, { token: string }>(
*/
export const sendMessageWsActor = fromPromise<void, { content: string }>(
async ({ input }) => {
console.log("[chat-machine] sendMessageWsActor ENTRY", {
log.debug("[chat-machine] sendMessageWsActor ENTRY", {
contentLength: input.content.length,
contentPreview: input.content.slice(0, 50),
});
const ws = getActiveChatWebSocket();
if (!ws) {
console.error("[chat-machine] sendMessageWsActor no activeChatWebSocket");
log.error("[chat-machine] sendMessageWsActor no activeChatWebSocket");
throw new Error("[chat-machine] sendMessageWs: no active WebSocket (actor not running)");
}
console.log("[chat-machine] sendMessageWsActor calling ws.sendMessage", {
log.debug("[chat-machine] sendMessageWsActor calling ws.sendMessage", {
isConnected: ws.isConnected,
});
const ok = ws.sendMessage(input.content);
if (!ok) {
console.error(
log.error(
"[chat-machine] sendMessageWsActor ws.sendMessage returned false (not OPEN)",
);
throw new Error("[chat-machine] sendMessageWs: WebSocket not OPEN");
}
console.log(
log.debug(
"[chat-machine] sendMessageWsActor ws.sendMessage OK, awaiting AI sentence stream",
);
// resolve 不返值 —— AI reply 由 chatWebSocketActor 的 ChatAISentenceReceived 流回
+9 -7
View File
@@ -25,7 +25,9 @@ import { chatRepository } from "@/data/repositories/chat_repository";
import type { IChatRepository } from "@/data/repositories/interfaces";
import { ChatStorage } from "@/data/storage/chat/chat_storage";
import { ChatSendResponse } from "@/data/dto/chat/chat_send_response";
import { formatDate, Result } from "@/utils";
import { formatDate, Result, Logger } from "@/utils";
const log = new Logger("StoresChatChatMachineHelpers");
// ============================================================
// Constants
@@ -161,7 +163,7 @@ export async function readAndSyncHistory(): Promise<{
Result.isOk(localResult) && localResult.data
? localMessagesToUi(localResult.data)
: [];
console.log("[chat-machine] loadHistory LOCAL DONE", {
log.debug("[chat-machine] loadHistory LOCAL DONE", {
count: localMessages.length,
});
@@ -169,7 +171,7 @@ export async function readAndSyncHistory(): Promise<{
const networkResult = await chatRepo.getHistory(PAGE_SIZE, 0);
if (!Result.isOk(networkResult)) {
// network 失败 —— 返空 messages(不让 UI 卡住)
console.error(
log.error(
"[chat-machine] loadHistory NETWORK FAILED",
networkResult.success ? null : (networkResult as { error: unknown }).error,
);
@@ -178,7 +180,7 @@ export async function readAndSyncHistory(): Promise<{
const fallbackMessages =
localMessages.length === 0 ? [greetingMessage] : localMessages;
if (fallbackMessages[0] === greetingMessage) {
console.log(
log.debug(
"[chat-machine] loadHistory EMPTY → prepend greeting (network-failed path)",
);
}
@@ -192,14 +194,14 @@ export async function readAndSyncHistory(): Promise<{
};
}
const networkUi = localMessagesToUi(networkResult.data.messages);
console.log("[chat-machine] loadHistory NETWORK DONE", {
log.debug("[chat-machine] loadHistory NETWORK DONE", {
count: networkUi.length,
});
// 3. 用 network 覆盖 local
const saveResult = await chatRepo.saveMessagesToLocal(networkResult.data.messages);
const localOverwritten = Result.isOk(saveResult);
console.log("[chat-machine] loadHistory SAVE TO LOCAL DONE", {
log.debug("[chat-machine] loadHistory SAVE TO LOCAL DONE", {
localOverwritten,
});
@@ -207,7 +209,7 @@ export async function readAndSyncHistory(): Promise<{
const finalMessages =
networkUi.length === 0 ? [greetingMessage] : networkUi;
if (finalMessages[0] === greetingMessage) {
console.log("[chat-machine] loadHistory EMPTY → prepend greeting");
log.debug("[chat-machine] loadHistory EMPTY → prepend greeting");
}
return {
+6 -4
View File
@@ -33,7 +33,7 @@
import { setup, assign } from "xstate";
import { ChatStorage } from "@/data/storage/chat/chat_storage";
import { formatDate, todayString } from "@/utils";
import { formatDate, todayString, Logger } from "@/utils";
import { ChatState, initialState } from "./chat-state";
@@ -47,6 +47,8 @@ import {
chatWebSocketActor,
} from "./chat-machine.actors";
const log = new Logger("StoresChatChatMachine");
/** 游客配额阈值(与 Dart `GuestChatQuota` 保持一致) */
export const GuestChatQuota = {
warningThreshold: 5,
@@ -93,7 +95,7 @@ export const chatMachine = setup({
ChatStorage.getInstance().setGuestTotalQuota(newTotal);
console.log("[chat-machine] appendUserMessage", {
log.debug("[chat-machine] appendUserMessage", {
contentLength: event.content.length,
contentPreview: event.content.slice(0, 50),
quotaMode: context.wsConnected ? "ws (no decrement)" : "http (decrement)",
@@ -134,7 +136,7 @@ export const chatMachine = setup({
void ChatStorage.getInstance().setGuestTotalQuota(newTotal);
console.log("[chat-machine] appendUserImage", {
log.debug("[chat-machine] appendUserImage", {
oldMessagesCount: context.messages.length,
wsConnected: context.wsConnected,
quotaMode: context.wsConnected ? "ws (no decrement)" : "http (decrement)",
@@ -177,7 +179,7 @@ export const chatMachine = setup({
};
}
}
console.log("[chat-machine] appendOrUpdateAISentence", {
log.debug("[chat-machine] appendOrUpdateAISentence", {
index: event.index,
total: event.total,
done: event.done,