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
+14 -14
View File
@@ -20,17 +20,17 @@ const authRepo: IAuthRepository = authRepository;
export const emailLoginActor = fromPromise<LoginStatus, { email: string; password: string }>(
async ({ input }) => {
console.log("[auth-machine] emailLoginActor ENTRY", {
log.debug("[auth-machine] emailLoginActor ENTRY", {
emailLength: input.email.length,
emailPreview: input.email.slice(0, 8),
passwordLength: input.password.length,
});
const guestId = await readGuestId();
console.log("[auth-machine] emailLoginActor calling authRepo.emailLogin", {
log.debug("[auth-machine] emailLoginActor calling authRepo.emailLogin", {
hasGuestId: !!guestId,
});
const result = await authRepo.emailLogin({ ...input, guestId });
console.log("[auth-machine] emailLoginActor authRepo.emailLogin DONE", {
log.debug("[auth-machine] emailLoginActor authRepo.emailLogin DONE", {
success: result.success,
hasData: result.success ? !!result.data : null,
errorName: result.success ? null : result.error?.name,
@@ -45,7 +45,7 @@ export const emailRegisterThenLoginActor = fromPromise<
LoginStatus,
{ email: string; password: string; username: string; confirmPassword: string }
>(async ({ input }) => {
console.log("[auth-machine] emailRegisterThenLoginActor ENTRY", {
log.debug("[auth-machine] emailRegisterThenLoginActor ENTRY", {
emailLength: input.email.length,
usernameLength: input.username.length,
passwordLength: input.password.length,
@@ -53,9 +53,9 @@ export const emailRegisterThenLoginActor = fromPromise<
});
const guestId = await readGuestId();
console.log("[auth-machine] emailRegisterThenLoginActor calling authRepo.register");
log.debug("[auth-machine] emailRegisterThenLoginActor calling authRepo.register");
const registerResult = await authRepo.register({ ...input, guestId });
console.log("[auth-machine] emailRegisterThenLoginActor authRepo.register DONE", {
log.debug("[auth-machine] emailRegisterThenLoginActor authRepo.register DONE", {
success: registerResult.success,
errorName: registerResult.success ? null : registerResult.error?.name,
errorMessage: registerResult.success ? null : registerResult.error?.message,
@@ -63,7 +63,7 @@ export const emailRegisterThenLoginActor = fromPromise<
if (Result.isErr(registerResult)) throw registerResult.error;
// 注册后自动登录(对齐 Dart 行为)
console.log(
log.debug(
"[auth-machine] emailRegisterThenLoginActor calling authRepo.emailLogin (post-register)",
);
const loginResult = await authRepo.emailLogin({
@@ -71,7 +71,7 @@ export const emailRegisterThenLoginActor = fromPromise<
password: input.password,
guestId,
});
console.log(
log.debug(
"[auth-machine] emailRegisterThenLoginActor authRepo.emailLogin DONE",
{
success: loginResult.success,
@@ -201,30 +201,30 @@ async function persistFacebookProfile(accessToken: string): Promise<void> {
// 受保护 API 401 会由 HTTP 层清掉 token 回到 splash,无需在此处主动校验。
export const guestLoginActor = fromPromise<LoginStatus, void>(async () => {
console.log("[auth-machine] guestLoginActor ENTRY");
log.debug("[auth-machine] guestLoginActor ENTRY");
// 1. 先查本地 guestToken —— 已有就直接进 idle(带 pendingRedirect
const hasTokenR = await AuthStorage.getInstance().hasGuestToken();
console.log("[auth-machine] guestLoginActor hasGuestToken", {
log.debug("[auth-machine] guestLoginActor hasGuestToken", {
success: hasTokenR.success,
hasData: hasTokenR.success ? !!hasTokenR.data : null,
});
if (hasTokenR.success && hasTokenR.data) {
console.log("[auth-machine] guestLoginActor SHORT-CIRCUIT (has local guestToken) → return guest");
log.debug("[auth-machine] guestLoginActor SHORT-CIRCUIT (has local guestToken) → return guest");
return "guest" as LoginStatus;
}
// Result.err(_) 时不抛 —— 落到 API 路径让真正的错误信号出现
// 2. 没有(或读不出)才走完整流程:拿 deviceId → 调后端
const deviceId = await deviceIdentifier.getDeviceId();
console.log("[auth-machine] guestLoginActor deviceId", {
log.debug("[auth-machine] guestLoginActor deviceId", {
length: deviceId.length,
prefix: deviceId.slice(0, 8),
});
console.log("[auth-machine] guestLoginActor calling authRepository.guestLogin");
log.debug("[auth-machine] guestLoginActor calling authRepository.guestLogin");
const result = await authRepository.guestLogin(deviceId);
console.log("[auth-machine] guestLoginActor authRepository.guestLogin DONE", {
log.debug("[auth-machine] guestLoginActor authRepository.guestLogin DONE", {
success: result.success,
hasData: result.success ? !!result.data : null,
errorName: result.success ? null : result.error?.name,
+4 -1
View File
@@ -11,12 +11,15 @@
import { useEffect } from "react";
import { useAuthDispatch } from "./auth-context";
import { Logger } from "@/utils";
const log = new Logger("StoresAuthAuthStatusChecker");
export function AuthStatusChecker() {
const dispatch = useAuthDispatch();
useEffect(() => {
console.log("[auth-init] mount → dispatch AuthInit");
log.debug("[auth-init] mount → dispatch AuthInit");
dispatch({ type: "AuthInit" });
}, [dispatch]);
+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,