"use client"; /** * 可观测性 Provider 组件(P6 硬化) * * 整合 Sentry + Web Vitals + OTel 初始化,在应用启动时调用各 init 函数。 * - "use client" 客户端组件 * - 在 useEffect 中按需初始化各可观测性模块(动态 import 避免未安装包问题) * - 不渲染任何可见 UI(返回 children) * - 条件初始化:根据环境变量决定是否启用各模块 * * 关联:02-architecture-design.md §12 可观测性 / project_rules §12 可观测性规范 */ import { useEffect, type ReactNode } from "react"; /** * 可观测性 Provider。 * * 在客户端挂载时初始化 Sentry / Web Vitals / OTel。 * 所有初始化均为条件性:未配置对应环境变量时跳过,未安装包时降级。 * * 不渲染任何可见 UI,仅透传 children。 */ export function ObservabilityProvider({ children, }: { children: ReactNode; }): ReactNode { useEffect(() => { // 并行初始化各可观测性模块(互不依赖) const initObservability = async (): Promise => { // 1. Sentry 错误追踪(条件:NEXT_PUBLIC_SENTRY_DSN 配置时) try { const { initSentry } = await import( "@/lib/observability/sentry" ); await initSentry(); } catch (err) { if (typeof console !== "undefined") { console.warn("[teacher-portal] Sentry 初始化失败", err); } } // 2. Web Vitals RUM 采集(生产环境启用) if (process.env.NODE_ENV === "production") { try { const { initWebVitals } = await import( "@/lib/observability/web-vitals" ); await initWebVitals(); } catch (err) { if (typeof console !== "undefined") { console.warn("[teacher-portal] Web Vitals 初始化失败", err); } } } // 3. OTel browser SDK(条件:NEXT_PUBLIC_OTEL_ENABLED=true 时) try { const { initOTel } = await import("@/lib/observability/otel"); await initOTel(); } catch (err) { if (typeof console !== "undefined") { console.warn("[teacher-portal] OTel 初始化失败", err); } } // 4. Cookie 迁移(条件:NEXT_PUBLIC_COOKIE_MIGRATION_ENABLED=true 时) // 实际迁移在 iam refresh cookie 端点就绪后启用,此处仅做准备 try { const { migrateTokenToCookie } = await import( "@/lib/observability/cookie-migration" ); // 后台执行迁移,不阻塞应用渲染 void migrateTokenToCookie(); } catch { // 迁移失败不影响应用功能,静默忽略 } }; // 后台初始化,不阻塞渲染 void initObservability(); }, []); // 不渲染任何可见 UI,仅透传 children return children; } export default ObservabilityProvider;