refactor(logging): centralize console output
This commit is contained in:
@@ -19,6 +19,9 @@ import { SUBSCRIPTION_PLANS } from "@/data/constants/subscription-plans";
|
||||
import type { SubscriptionPlanId } from "@/data/constants/subscription-plans";
|
||||
import { getPlanPriceId } from "@/lib/stripe/stripe-products";
|
||||
import { getStripeClient } from "@/lib/stripe/stripe-client";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppApiPaymentCreateCheckoutSessionRoute");
|
||||
|
||||
interface CreateCheckoutRequestBody {
|
||||
planId: SubscriptionPlanId;
|
||||
@@ -86,7 +89,7 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ url: session.url });
|
||||
} catch (e) {
|
||||
const err = e as { message?: string; type?: string; code?: string };
|
||||
console.error("[api/create-checkout-session] Stripe error", {
|
||||
log.error("[api/create-checkout-session] Stripe error", {
|
||||
message: err.message,
|
||||
type: err.type,
|
||||
code: err.code,
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
import { getStripeClient } from "@/lib/stripe/stripe-client";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppApiPaymentCustomerPortalRoute");
|
||||
|
||||
interface CreatePortalRequestBody {
|
||||
customerId: string | null;
|
||||
@@ -56,7 +59,7 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ url: session.url });
|
||||
} catch (e) {
|
||||
const err = e as { message?: string; type?: string; code?: string };
|
||||
console.error("[api/customer-portal] Stripe error", {
|
||||
log.error("[api/customer-portal] Stripe error", {
|
||||
customerId: body.customerId,
|
||||
message: err.message,
|
||||
type: err.type,
|
||||
|
||||
@@ -27,11 +27,14 @@ import type Stripe from "stripe";
|
||||
|
||||
import { dispatchStripeEvent } from "@/lib/stripe/stripe-events";
|
||||
import { getStripeClient } from "@/lib/stripe/stripe-client";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppApiPaymentWebhookRoute");
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
|
||||
if (!webhookSecret) {
|
||||
console.error("[api/webhook] STRIPE_WEBHOOK_SECRET is not set");
|
||||
log.error("[api/webhook] STRIPE_WEBHOOK_SECRET is not set");
|
||||
return NextResponse.json(
|
||||
{ error: "Webhook secret not configured" },
|
||||
{ status: 500 },
|
||||
@@ -42,7 +45,7 @@ export async function POST(req: NextRequest) {
|
||||
const rawBody = await req.text();
|
||||
const sigHeader = req.headers.get("stripe-signature");
|
||||
if (!sigHeader) {
|
||||
console.error("[api/webhook] Missing stripe-signature header");
|
||||
log.error("[api/webhook] Missing stripe-signature header");
|
||||
return NextResponse.json(
|
||||
{ error: "Missing stripe-signature header" },
|
||||
{ status: 400 },
|
||||
@@ -56,7 +59,7 @@ export async function POST(req: NextRequest) {
|
||||
event = stripe.webhooks.constructEvent(rawBody, sigHeader, webhookSecret);
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.error("[api/webhook] Signature verification failed", {
|
||||
log.error("[api/webhook] Signature verification failed", {
|
||||
message: err.message,
|
||||
});
|
||||
return NextResponse.json(
|
||||
@@ -66,7 +69,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
// 分发到 handler
|
||||
console.log("[api/webhook] Received event", {
|
||||
log.debug("[api/webhook] Received event", {
|
||||
eventId: event.id,
|
||||
type: event.type,
|
||||
created: new Date(event.created * 1000).toISOString(),
|
||||
@@ -75,11 +78,11 @@ export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const handled = await dispatchStripeEvent(event);
|
||||
if (!handled) {
|
||||
console.log(`[api/webhook] Ignored event type: ${event.type}`);
|
||||
log.debug(`[api/webhook] Ignored event type: ${event.type}`);
|
||||
}
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.error("[api/webhook] Handler error", {
|
||||
log.error("[api/webhook] Handler error", {
|
||||
eventId: event.id,
|
||||
type: event.type,
|
||||
message: err.message,
|
||||
|
||||
@@ -13,6 +13,9 @@ import { ROUTES } from "@/router/routes";
|
||||
|
||||
import { AuthBackground, AuthPanel } from "./components";
|
||||
import styles from "./components/auth-screen.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppAuthAuthScreen");
|
||||
|
||||
export function AuthScreen() {
|
||||
const state = useAuthState();
|
||||
@@ -23,7 +26,7 @@ export function AuthScreen() {
|
||||
// 用 pendingRedirect flag(不是 useRef transition detection)——
|
||||
// re-mount 时 flag 在 auth context 里持久,区分"刚按了"和"re-visit"准确无误。
|
||||
useEffect(() => {
|
||||
console.log("[auth-screen] useEffect (loginStatus + pendingRedirect)", {
|
||||
log.debug("[auth-screen] useEffect (loginStatus + pendingRedirect)", {
|
||||
pending: state.pendingRedirect,
|
||||
loginStatus: state.loginStatus,
|
||||
willRedirect:
|
||||
@@ -31,7 +34,7 @@ export function AuthScreen() {
|
||||
});
|
||||
|
||||
if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") {
|
||||
console.log(
|
||||
log.debug(
|
||||
"[auth-screen] useEffect → router.replace(/chat) [via pendingRedirect flag]",
|
||||
);
|
||||
authDispatch({ type: "AuthClearPendingRedirect" });
|
||||
|
||||
@@ -14,6 +14,9 @@ import { AuthTextField } from "./auth-text-field";
|
||||
import { AuthPrimaryButton } from "./auth-primary-button";
|
||||
import { AuthErrorMessage } from "./auth-error-message";
|
||||
import styles from "./email-form.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppAuthComponentsEmailLoginForm");
|
||||
|
||||
export interface EmailLoginFormProps {
|
||||
globalError?: string | null;
|
||||
@@ -44,7 +47,7 @@ export function EmailLoginForm({
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
console.log("[email-login-form] submit ENTRY", {
|
||||
log.debug("[email-login-form] submit ENTRY", {
|
||||
emailLength: email.length,
|
||||
emailPreview: email.slice(0, 8),
|
||||
passwordLength: password.length,
|
||||
@@ -53,7 +56,7 @@ export function EmailLoginForm({
|
||||
const passwordErr = validatePassword(password);
|
||||
if (emailErr || passwordErr) {
|
||||
const firstErr = emailErr ?? passwordErr ?? null;
|
||||
console.warn(
|
||||
log.warn(
|
||||
"[email-login-form] submit VALIDATION FAILED (silent return)",
|
||||
{ emailErr, passwordErr, surfaced: firstErr },
|
||||
);
|
||||
@@ -61,7 +64,7 @@ export function EmailLoginForm({
|
||||
return;
|
||||
}
|
||||
setValidationError(null);
|
||||
console.log("[email-login-form] submit dispatching AuthEmailLoginSubmitted");
|
||||
log.debug("[email-login-form] submit dispatching AuthEmailLoginSubmitted");
|
||||
dispatch({ type: "AuthEmailLoginSubmitted", email, password });
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ import { AuthTextField } from "./auth-text-field";
|
||||
import { AuthPrimaryButton } from "./auth-primary-button";
|
||||
import { AuthErrorMessage } from "./auth-error-message";
|
||||
import styles from "./email-form.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppAuthComponentsEmailRegisterForm");
|
||||
|
||||
export interface EmailRegisterFormProps {
|
||||
globalError?: string | null;
|
||||
@@ -66,7 +69,7 @@ export function EmailRegisterForm({
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
console.log("[email-register-form] submit ENTRY", {
|
||||
log.debug("[email-register-form] submit ENTRY", {
|
||||
emailLength: email.length,
|
||||
emailPreview: email.slice(0, 8),
|
||||
passwordLength: password.length,
|
||||
@@ -81,7 +84,7 @@ export function EmailRegisterForm({
|
||||
// 按 username → email → password → confirm 顺序挑第一个错(与字段顺序一致)
|
||||
const firstErr =
|
||||
usernameErr ?? emailErr ?? passwordErr ?? confirmErr ?? null;
|
||||
console.warn(
|
||||
log.warn(
|
||||
"[email-register-form] submit VALIDATION FAILED (silent return)",
|
||||
{
|
||||
emailErr,
|
||||
@@ -95,7 +98,7 @@ export function EmailRegisterForm({
|
||||
return;
|
||||
}
|
||||
setValidationError(null);
|
||||
console.log(
|
||||
log.debug(
|
||||
"[email-register-form] submit dispatching AuthEmailRegisterSubmitted",
|
||||
);
|
||||
dispatch({
|
||||
|
||||
@@ -27,6 +27,9 @@ import { useChatDispatch } from "@/stores/chat/chat-context";
|
||||
import { ChatInputTextField } from "./chat-input-text-field";
|
||||
import { ChatSendButton } from "./chat-send-button";
|
||||
import styles from "./chat-input-bar.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppChatComponentsChatInputBar");
|
||||
|
||||
export interface ChatInputBarProps {
|
||||
disabled?: boolean;
|
||||
@@ -42,7 +45,7 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
|
||||
const handleSend = () => {
|
||||
if (!hasContent) return;
|
||||
console.log("[chat-input-bar] handleSend", {
|
||||
log.debug("[chat-input-bar] handleSend", {
|
||||
contentLength: input.length,
|
||||
contentPreview: input.slice(0, 50),
|
||||
hasContent,
|
||||
|
||||
@@ -16,6 +16,9 @@ import { useRouter } from "next/navigation";
|
||||
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||
import { UserStorage } from "@/data/storage/user/user_storage";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppChatDeviceidDeviceIdDeepLinkPersist");
|
||||
|
||||
interface DeepLinkPersistProps {
|
||||
deviceId: string;
|
||||
@@ -43,7 +46,7 @@ export default function DeepLinkPersist({
|
||||
}
|
||||
} catch (err) {
|
||||
// 写不进 localStorage 时(例如隐私模式)也不阻塞跳转;记录到 console 即可。
|
||||
console.warn("[DeepLinkPersist] failed to persist", err);
|
||||
log.warn("[DeepLinkPersist] failed to persist", err);
|
||||
} finally {
|
||||
setDone(true);
|
||||
router.replace(ROUTES.chat);
|
||||
|
||||
+4
-1
@@ -14,6 +14,9 @@ import { useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppError");
|
||||
|
||||
interface ErrorProps {
|
||||
error: Error & { digest?: string };
|
||||
@@ -23,7 +26,7 @@ interface ErrorProps {
|
||||
export default function GlobalError({ error, unstable_retry }: ErrorProps) {
|
||||
useEffect(() => {
|
||||
// 把错误送到 console;后续接 Sentry/Datadog 时改这里。
|
||||
console.error("[app/error.tsx]", error);
|
||||
log.error("[app/error.tsx]", error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MobileShell } from "@/app/_components/core";
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { pwaUtil } from "@/utils";
|
||||
import { pwaUtil, Logger } from "@/utils";
|
||||
|
||||
import {
|
||||
SplashBackground,
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
} from "./components";
|
||||
import styles from "./components/splash-screen.module.css";
|
||||
|
||||
const log = new Logger("AppSplashSplashScreen");
|
||||
|
||||
// 尽量早地缓存 beforeinstallprompt,避免用户停留 splash 时浏览器事件已触发并丢失。
|
||||
if (typeof window !== "undefined") {
|
||||
pwaUtil.prepareInstallPrompt();
|
||||
@@ -67,7 +69,7 @@ export function SplashScreen() {
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
// 调试日志(保留,不删 —— 用于排查"re-mount 误跳 /chat"问题)
|
||||
console.log("[splash] useEffect ② (loginStatus + pendingRedirect)", {
|
||||
log.debug("[splash] useEffect ② (loginStatus + pendingRedirect)", {
|
||||
pending: state.pendingRedirect,
|
||||
loginStatus: state.loginStatus,
|
||||
willRedirect:
|
||||
@@ -75,7 +77,7 @@ export function SplashScreen() {
|
||||
});
|
||||
|
||||
if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") {
|
||||
console.log(
|
||||
log.debug(
|
||||
"[splash] useEffect ② → router.replace(/chat) [via pendingRedirect flag]",
|
||||
);
|
||||
authDispatch({ type: "AuthClearPendingRedirect" });
|
||||
|
||||
@@ -18,6 +18,9 @@ import { ROUTES } from "@/router/routes";
|
||||
|
||||
import { SubscriptionCtaButton } from "./subscription-cta-button";
|
||||
import styles from "./subscription-cta-button.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppSubscriptionComponentsSubscriptionCheckoutButton");
|
||||
|
||||
export interface SubscriptionCheckoutButtonProps {
|
||||
planId: SubscriptionPlanId;
|
||||
@@ -64,7 +67,7 @@ export function SubscriptionCheckoutButton({
|
||||
window.location.href = url;
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.error("[subscription-checkout-button] error", err);
|
||||
log.error("[subscription-checkout-button] error", err);
|
||||
setError(err.message);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ import { ROUTES } from "@/router/routes";
|
||||
|
||||
import { SubscriptionCtaButton } from "./subscription-cta-button";
|
||||
import styles from "./subscription-cta-button.module.css";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppSubscriptionComponentsSubscriptionManageButton");
|
||||
|
||||
export interface SubscriptionManageButtonProps {
|
||||
/** 从 User.stripeCustomerId 取(webhook 设置) */
|
||||
@@ -63,7 +66,7 @@ export function SubscriptionManageButton({ customerId }: SubscriptionManageButto
|
||||
window.location.href = url;
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.error("[subscription-manage-button] error", err);
|
||||
log.error("[subscription-manage-button] error", err);
|
||||
setError(err.message);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user