feat: downgrade tech stack to stable versions and integrate GA4 error monitoring

- Downgrade Next.js 16→14.2, React 19→18.3, Tailwind 4→3.4
- Add comprehensive GA4 error monitoring system
- Create Jenkins CI/CD pipeline with quality gates
- Fix build issues: ESLint, SWC conflict, config format
- Add documentation for deployment and error tracking
This commit is contained in:
张翔
2026-05-12 12:45:18 +08:00
parent f08874f5c4
commit 8840c4398a
24 changed files with 8567 additions and 3632 deletions
+615
View File
@@ -0,0 +1,615 @@
# Novalon Website 回滚流程指南(生产环境专用)
> **最后更新**: 2026-05-12
> **适用项目**: novalon-website (四川睿新致远科技有限公司官网)
> **部署架构**: 静态导出 + Docker + Nginx + CDN
> **目标恢复时间**: < 10 分钟(P0 级别故障)
>
> **⚠️ 重要提示**:本文档已针对你的实际部署环境定制,请勿使用通用模板!
---
## 📋 你的实际部署架构
```
┌─────────────────────────────────────────────────────┐
│ 开发机 (Local) │
│ - 项目路径: /Users/zhangxiang/Codes/Novalon/ │
│ novalon-website │
│ - 构建命令: npm run build:clean │
│ - 输出目录: dist/ │
│ - 部署命令: ./deploy-dist.sh │
└──────────────────────┬──────────────────────────────┘
│ rsync + SSH (root@139.155.109.62)
┌─────────────────────────────────────────────────────┐
│ 生产服务器 (139.155.109.62) │
│ └── /home/novalon/docker-app/ │
│ ├── novalon-static/ ← 当前版本 │
│ ├── novalon-static_backup_* ← 自动备份 │
│ └── docker-compose.yml │
│ └── novalon-nginx-secure ← Nginx 容器 │
└──────────────────────┬──────────────────────────────┘
│ 反向代理
┌─────────────────────────────────────────────────────┐
│ 用户访问 │
│ - 主域名: https://novalon.cn │
│ - 备用 IP: https://139.155.109.62 │
│ - HTTP → HTTPS 自动跳转 │
└─────────────────────────────────────────────────────┘
```
---
## 🚨 **触发条件(满足任一即启动回滚)**
### **P0 - 紧急故障(立即回滚,无需审批)**
- [ ] 首页完全白屏或返回 500/502/503/504
- [ ] 所有页面无法访问(HTTP 状态码非 200)
- [ ] 安全漏洞报告(XSS、数据泄露、恶意重定向)
- [ ] 域名解析失败或 SSL 证书过期
### **P1 - 严重问题(30 分钟内回滚)**
- [ ] 核心功能不可用:
- 导航栏无法点击
- 表单提交失败(联系表单、订阅等)
- 主题切换失效
- 移动端布局错乱
- [ ] 关键 SEO 元数据丢失:
- `<title>` 为空或显示 "Untitled"
- `<meta name="description">` 缺失
- Open Graph / Twitter Card 标签缺失
- [ ] 性能严重退化:
- Lighthouse Performance < 50(之前 > 90
- LCP (Largest Contentful Paint) > 5 秒
- FID (First Input Delay) > 300ms
### **P2 - 一般问题(24 小时内修复)**
- [ ] 次要页面样式异常(不影响核心功能)
- [ ] 图片资源加载失败(非首屏图片)
- [ ] 控制台有警告但无错误
---
## 🔄 **Type 1:代码回滚(最常用,推荐首选)**
### **适用场景**
- 最近一次部署引入了 bug
- 需要快速恢复到上一个稳定版本
- Git 历史清晰,可以定位到稳定的 commit
#### **Step 0:准备阶段(2 分钟)**
```bash
# 0.1 确认当前状态
echo "=== 当前时间 ==="
date '+%Y-%m-%d %H:%M:%S'
echo ""
echo "=== 当前 Git 分支和 Commit ==="
git branch --show-current
git log --oneline -3
echo ""
echo "=== 检查是否有未提交的更改 ==="
git status --short
```
**预期输出示例**:
```
=== 当前时间 ===
2026-05-12 15:30:00
=== 当前 Git 分支和 Commit ===
main
abc1234 (HEAD -> main) feat: update hero animation
def5678 fix: improve mobile layout
ghi9012 chore: upgrade dependencies
=== 检查是否有未提交的更改 ===
M src/components/Hero.tsx
```
#### **Step 1:确认问题现象(2 分钟)**
```bash
# 1.1 检查网站是否可访问
curl -I https://novalon.cn/ | head -10
# 预期输出: HTTP/2 200
# 如果看到 500/502/503/504,说明需要紧急回滚
# 1.2 检查关键页面的 HTTP 状态码
for page in "/" "/about" "/contact" "/products" "/solutions"; do
status=$(curl -s -o /dev/null -w "%{http_code}" "https://novalon.cn${page}")
echo "$page -> $status"
done
# 预期输出: 所有页面都返回 200
# 1.3 检查关键 HTML 元素是否存在
curl -s https://novalon.cn/ | grep -E '<title>|<meta name="description">|<h1'
```
**预期输出示例**:
```
/ -> 200
/about -> 200
/contact -> 200
/products -> 200
/solutions -> 200
<title>四川睿新致远科技有限公司</title>
<meta name="description" content="..." />
<h1 class="...">...</h1>
```
如果上述检查有任何一项不通过,**立即进入 Step 2**。
#### **Step 2:定位稳定版本(3 分钟)**
```bash
# 2.1 查看 Git 历史,找到最近的稳定版本
git log --oneline --graph -20
# 寻找标记为 "stable"、"fix:"、"chore:" 的 commit
# 或者查看 Git Tags
git tag -l 'v*' --sort=-v:refname | head -5
# 如果没有 Tag,根据 commit message 判断
# 推荐选择最近一次包含以下关键词的 commit:
# - "fix:" (bug 修复)
# - "release:" 或 "v*.*.*" (正式发布)
# - "chore: bump version" (版本号更新)
```
**示例输出**:
```
* abc1234 (HEAD -> main) feat: update hero animation ← 当前版本(有问题)
* def5678 fix: improve mobile layout ← 可能是稳定版本
* ghi9012 chore: upgrade dependencies ← 上一个版本
* jkl3456 release: v1.0.0-stable ← 正式发布版(最安全)
```
**决策建议**
- 如果 `def5678` 是你上次验证过的版本,回滚到它
- 如果不确定,选择 `jkl3456` (Tagged release)
#### **Step 3:执行本地代码回滚(3 分钟)**
```bash
# 3.1 备份当前版本(以防万一)
git stash push -m "backup-before-rollback-$(date +%Y%m%d_%H%M%S)"
# 或者创建一个新的分支保存当前代码
git branch backup/broken-version-$(date +%Y%m%d)
# 3.2 切换到稳定版本
# 方法 A:使用 Git Tag(推荐)
git checkout v1.0.0-stable
# 方法 B:使用 Commit Hash
git checkout def5678
# 3.3 确认已切换成功
git log --oneline -1
# 应该显示: def5678 fix: improve mobile layout
echo "✅ 已切换到稳定版本"
```
#### **Step 4:重新构建并部署(5 分钟)**
```bash
# 4.1 清理并构建
npm run build:clean
# 如果构建成功,会看到类似输出:
# ✅ Built in Xs
# 📁 生成了 XXX 个文件,总大小: XX MB
# 4.2 快速验证构建产物
if [ -d "dist" ]; then
echo "✅ dist 目录存在"
# 检查关键文件是否存在
ls -lh dist/index.html
ls -lh dist/about/index.html
ls -lh dist/contact/index.html
# 检查 HTML 内容
head -20 dist/index.html | grep '<title>'
else
echo "❌ 构建失败!dist 目录不存在"
exit 1
fi
# 4.3 部署到生产环境
./deploy-dist.sh
# 脚本会自动执行:
# 1. 检查 dist 目录
# 2. 验证 SSH 连接
# 3. 备份旧版本(在服务器上)
# 4. 上传新的 dist
# 5. 设置权限
# 6. 重载 Nginx
# 7. 验证部署结果
```
#### **Step 5:验证回滚成功(2 分钟)**
```bash
# 5.1 等待 3-5 秒让 CDN 缓存刷新
sleep 5
# 5.2 再次执行 Step 1.2 和 1.3 的检查
for page in "/" "/about" "/contact" "/products"; do
status=$(curl -s -o /dev/null -w "%{http_code}" "https://novalon.cn${page}")
if [ "$status" = "200" ]; then
echo "$page -> $status"
else
echo "$page -> $status (需要进一步排查)"
fi
done
# 5.3 浏览器手动验证(重要!)
open https://novalon.cn/
# 手动检查清单:
# □ 首页正常加载,无白屏
# □ 导航栏可点击,所有链接正常工作
# □ Logo 显示正确(应该是书法字体)
# □ 主题切换按钮可用(如果有暗色模式)
# □ 移动端布局正常(可以用 Chrome DevTools 模拟)
# □ 表单可以打开(即使不提交)
```
#### **Step 6:通知相关人员(2 分钟)**
```bash
# 6.1 记录回滚操作日志
cat << EOF >> /tmp/rollback-log.txt
==========================================
回滚记录
==========================================
时间: $(date '+%Y-%m-%d %H:%M:%S')
操作人: $(whoami)
原因: [填写具体原因]
回滚前版本: abc1234 (feat: update hero animation)
回滚后版本: $(git log --oneline -1)
验证结果: ✅ 所有关键页面正常
耗时: 约 15 分钟
==========================================
EOF
# 6.2 发送通知(钉钉/企业微信/邮件)
# 示例:发送邮件给 dev-team@novalon.cn
cat << EOF | mail -s "⚠️ 已回滚 Novalon Website" dev-team@novalon.cn
Novalon Website 已完成紧急回滚
回滚时间: $(date '+%Y-%m-%d %H:%M:%S')
回滚原因: [填写具体原因,如"首页白屏"]
回滚前版本: abc1234 (feat: update hero animation)
回滚后版本: $(git describe --tags || git log --oneline -1)
验证状态: ✅ 所有关键页面已恢复正常访问
请相关开发者尽快排查问题根因。
回滚详情:
- 操作人: $(whoami)
- 服务器: 139.155.109.62
- 域名: https://novalon.cn
- 日志位置: /tmp/rollback-log.txt
技术支持联系人:
- 值班工程师: [填写姓名] - [填写电话]
- 技术负责人: [填写姓名] - [填写电话]
EOF
echo "✅ 回滚通知已发送"
```
---
## 🐳 **Type 2Docker 容器级回滚(当 Type 1 不可用时)**
### **适用场景**
- 本地代码库损坏或不可用
- 需要立即恢复,来不及重新构建
- 服务器上有自动备份
#### **步骤(全部在服务器上执行)**
```bash
# SSH 到生产服务器
ssh root@139.155.109.62
# Step 1: 查看当前容器状态
docker ps | grep novalon
# 预期输出:
# CONTAINER ID IMAGE STATUS NAMES
# xxxxxxxxxx novalon-website:latest Up 2 hours novalon-nginx-secure
# Step 2: 查看可用的备份
ls -lth /home/novalon/docker-app/novalon-static_backup_* | head -5
# 预期输出:
# drwxr-xr-x 20260512_153000 ← 最新备份(1 小时前)
# drwxr-xr-x 20260512_140000 ← 之前的备份(2 小时前)
# drwxr-xr-x 20260511_180000 ← 昨天的备份
# Step 3: 选择最近的备份进行恢复
BACKUP_DIR=$(ls -dt /home/novalon/docker-app/novalon-static_backup_* | head -1)
CURRENT_DIR="/home/novalon/docker-app/novalon-static"
echo "将回滚到备份: $BACKUP_DIR"
# Step 4: 执行回滚
rm -rf "$CURRENT_DIR"
cp -r "$BACKUP_DIR" "$CURRENT_DIR"
# Step 5: 重载 Nginx 使更改生效
docker exec novalon-nginx-secure nginx -s reload
# Step 6: 验证
curl -I https://novalon.cn/ | head -1
# 预期: HTTP/2 200
echo "✅ Docker 容器级回滚完成"
```
---
## 🌐 **Type 3CDN 缓存清理(配合 Type 1 或 Type 2 使用)**
### **何时需要?**
- 回滚后用户仍看到旧版本的缓存内容
- 更新了 CSS/JS 文件但浏览器未加载最新版本
#### **方法 A:强制刷新 Nginx 缓存(推荐)**
```bash
# 在服务器上执行
ssh root@139.155.109.62
# 临时禁用缓存(5 分钟后记得改回来)
cat > /tmp/disable-cache.conf << 'EOF'
location / {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
expires 0;
# ... 其他配置保持不变
}
EOF
# 应用配置并重载 Nginx
docker exec novalon-nginx-secure nginx -s reload
# 等待 5 分钟让所有用户的缓存过期
sleep 300
# 恢复正常缓存策略(重要!否则影响性能)
# 将原来的 nginx.conf 放回去
docker exec novalon-nginx-secure nginx -s reload
```
#### **方法 B:版本化静态资源(长期方案)**
如果你的项目使用了 `next.config.ts` 中的 `assetPrefix`,Next.js 会自动为静态资源添加 hash:
```
旧版本: /_next/static/css/abc123.css
新版本: /_next/static/css/def456.css
```
这样浏览器会自动请求新的 URL,无需手动清除缓存。
---
## 📞 **紧急联系人列表**
| 角色 | 姓名 | 电话/微信 | 职责 | 备注 |
|------|------|-----------|------|------|
| **值班工程师** | 待填写 | 待填写 | 执行回滚操作 | 第一响应人 |
| **技术负责人** | 待填写 | 待填写 | 决策是否回滚 | P0/P1 故障需其批准 |
| **产品负责人** | 待填写 | 待填写 | 评估业务影响 | P1/P2 故障需通知 |
| **运维支持** | 待填写 | 待填写 | 服务器/DNS 层面支持 | 当涉及基础设施问题时 |
| **Sentry 告警接收人** | dev-team@novalon.cn | - | 错误监控告警 | Sentry 配置 |
---
## 📊 **回滚后复盘模板(必填!)**
每次回滚完成后,**必须在 24 小时内**填写此模板并发送到团队群:
```markdown
## Novalon Website 回滚复盘报告
**基本信息**
- 回滚日期和时间:
- 发现问题时间:
- 开始回滚时间:
- 回滚完成时间:
- 总宕机时间: ___ 分钟
**问题分类**
- [ ] 代码 Bug(哪个 commit 引入的?commit hash: _____
- [ ] 依赖兼容性问题(哪个包升级导致?包名及版本: _____
- [ ] 配置错误(nginx/docker/env?具体是哪个配置?)
- [ ] 第三方服务故障(CDN/DNS/SSL 证书?服务商是谁?)
- [ ] 其他: _____
**问题根因分析**
(详细描述为什么会出现这个问题)
**影响范围评估**
- 影响用户数估算: 约 ___ 人
- 受影响的页面/功能:
- 是否造成数据丢失: 是/否(如果是,哪些数据?)
- 业务损失估算:
**回滚操作详情**
- 回滚类型: Type 1 (代码回滚) / Type 2 (Docker 容器级) / Type 3 (CDN 清理)
- 回滚前版本:
- 回滚后版本:
- 是否成功恢复: 是/否
- 是否需要后续修复: 是/否
**改进措施(防止再次发生)**
1.
2.
3.
**如何改进测试/CI 流程以提前发现问题**
- [ ] 补充单元测试覆盖(具体是哪个模块?)
- [ ] 增加 E2E 测试用例(具体场景是什么?)
- [ ] 在 CI Pipeline 中增加质量门禁(什么条件?)
- [ ] 接入 Sentry 错误监控(已完成 ✓)
- [ ] 完善 Code Review 流程(什么标准?)
- [ ] 其他:
**经验教训总结**
(用一两句话总结这次回滚学到了什么)
**附件**
- 截图/日志: (如有)
- 相关 Issue/PR 链接: (如有)
```
---
## 🔧 **常见问题排查(FAQ**
### **Q1:回滚后网站仍然显示旧内容?**
**ACDN 缓存未刷新。解决方案:**
1. 执行 Type 3: CDN 缓存清理
2. 或等待 CDN TTL 过期(通常 1-2 小时)
3. 或使用 Ctrl+Shift+R 强制刷新浏览器缓存
### **Q2Git checkout 失败,提示"有未提交的更改"**
**A:先暂存或丢弃这些更改:**
```bash
# 查看有哪些未提交的更改
git status
# 方案 A:暂时保存(推荐)
git stash push -m "temp-save"
# 方案 B:直接丢弃(谨慎!不可逆)
git reset --hard HEAD
# 然后再执行 git checkout
```
### **Q3npm run build:clean 构建失败?**
**A:可能的原因及解决方法:**
1. **依赖未安装完全**:运行 `rm -rf node_modules && npm install`
2. **TypeScript 类型错误**:运行 `npx tsc --noEmit` 查看详细错误
3. **ESLint 错误**:运行 `npm run lint` 查看详情
4. **内存不足**:增加 Node.js 内存限制 `NODE_OPTIONS=--max-old-space-size=4096 npm run build:clean`
### **Q4SSH 连接到服务器失败?**
**A:检查以下几点:**
1. **网络连接**`ping 139.155.109.62`
2. **SSH 服务**`ssh -v root@139.155.109.62`(查看详细日志)
3. **防火墙**:确认端口 22 未被封锁
4. **SSH Key**:确认私钥文件权限正确 (`chmod 600 ~/.ssh/id_rsa`)
### **Q5:回滚后发现数据库或其他动态内容丢失?**
**A:对于纯静态网站(你的情况),不存在这个问题!**
- Novalon Website 是纯静态导出,不依赖数据库
- 所有内容都在 `dist/` 目录中
- 回滚只是替换静态文件,不会影响任何持久化数据
---
## ⚡ **快速参考卡片(打印出来贴在工位上)**
```
╔══════════════════════════════════════════╗
║ Novalon Website 紧急回滚速查表 ║
╠══════════════════════════════════════════╣
║ ║
║ P0 触发条件: ║
║ • 首页白屏 / 5xx 错误 ║
║ • 安全漏洞 ║
║ • 域名/SSL 问题 ║
║ ║
║ 快速回滚命令(3 步完成): ║
║ ║
║ 1. git log --oneline -10 ║
║ # 找到稳定版本的 commit ║
║ ║
║ 2. git checkout <stable-commit-hash> ║
║ # 切换到稳定版本 ║
║ ║
║ 3. ./deploy-dist.sh ║
║ # 重新构建并部署 ║
║ ║
║ 验证命令: ║
║ curl -I https://novalon.cn/ ║
║ # 预期: HTTP/2 200 ║
║ ║
║ 紧急联系人: ║
║ • 值班工程师: [姓名] - [电话] ║
║ • 技术负责人: [姓名] - [电话] ║
║ • 运维支持: [姓名] - [电话] ║
║ ║
║ 服务器信息: ║
║ IP: 139.155.109.62 ║
║ 用户: root ║
║ 域名: novalon.cn ║
║ 容器: novalon-nginx-secure ║
║ ║
║ 目标恢复时间: < 10 分钟 ║
╚══════════════════════════════════════════╝
```
---
## ✅ **回滚完成清单**
请在回滚完成后逐项确认:
**立即确认(回滚后 5 分钟内)**
- [ ] 网站首页可访问,无白屏
- [ ] HTTP 状态码返回 200
- [ ] 关键页面(About, Contact, Products)可访问
- [ ] 导航栏正常工作
- [ ] SEO 元数据完整(title, description, OG tags
- [ ] 已通知相关人员(邮件/群消息)
**后续确认(回滚后 24 小时内)**
- [ ] 填写回滚复盘报告
- [ ] 分析问题根因并记录
- [ ] 制定预防措施
- [ ] 更新 CI/CD Pipeline(如有必要)
- [ ] 团队内部分享经验教训
---
## 📚 **相关文档链接**
- **部署脚本**: [deploy-dist.sh](./deploy-dist.sh)
- **Jenkins Pipeline**: [Jenkinsfile](./Jenkinsfile)
- **Sentry 监控指南**: [docs/sentry-setup-guide.md](./docs/sentry-setup-guide.md)
- **技术栈降级指南**: [scripts/downgrade-stack.sh](./scripts/downgrade-stack.sh)
- **CONTEXT.md**: [CONTEXT.md](./CONTEXT.md)(领域术语和关键决策)
---
**💡 最后提醒**
- 保持冷静,按照步骤执行
- 每一步都要验证再继续
- 记录所有操作,方便事后复盘
- 回滚不是失败,是负责任的表现!
**祝你好运!🍀**
+347
View File
@@ -0,0 +1,347 @@
# GA4 错误监控集成完成报告
## 📊 集成概述
**日期**: 2026-01-15
**技术方案**: Google Analytics 4 (GA4) 异常事件追踪
**成本**: 完全免费(使用现有 GA4 账户)
**状态**: ✅ 已完成并验证
---
## 🎯 实现目标
1. **零成本错误监控** - 利用现有 GA4 账户,无需额外付费服务
2. **全自动错误捕获** - 无需手动埋点,自动捕获所有 JavaScript 错误
3. **生产环境可用** - 已通过 TypeScript 检查和构建测试
4. **智能过滤** - 自动忽略无关错误(ResizeObserver、Script error 等)
---
## 📁 新增/修改的文件
### 核心文件
| 文件 | 操作 | 说明 |
|------|------|------|
| `src/lib/analytics.ts` | **新建** | Analytics 核心模块,包含所有追踪函数 |
| `src/components/analytics/GlobalErrorTracker.tsx` | **新建** | 全局错误追踪器组件 |
| `src/app/layout.tsx` | **修改** | 集成 GlobalErrorTracker |
| `src/app/test-error-tracking/page.tsx` | **新建** | 错误监控测试页面 |
### 辅助文件
| 文件 | 操作 | 说明 |
|------|------|------|
| `src/components/analytics/CookieConsent.tsx` | **修改** | 修复 CookiePreferences 类型定义 |
---
## 🔧 技术实现细节
### 1. 错误捕获机制
```
GlobalErrorTracker 组件(客户端)
useEffect 初始化时添加事件监听器:
├── window.addEventListener('error', handleGlobalError)
│ └── 捕获 JavaScript 运行时错误
│ └── trackError('javascript_error', message, false, {filename, lineno, colno, stack})
├── window.addEventListener('unhandledrejection', handleUnhandledRejection)
│ └── 捕获 Promise 未捕获异常
│ └── trackError('unhandled_promise_rejection', message, false, {reason_type, stack})
└── document.addEventListener('error', handleResourceError, true)
└── 捕获资源加载失败(图片、脚本、样式等)
└── trackError('resource_loading_error', 'Failed to load resource', false)
```
### 2. GA4 事件数据结构
每个错误都会作为 `exception` 事件发送到 GA4,包含以下参数:
```javascript
{
event_name: 'exception', // 固定事件名
description: '[error_type] msg', // 错误描述(包含类型前缀)
fatal: 'true' | 'false', // 是否致命错误
url: '当前页面URL', // 发生错误的页面
timestamp: 'ISO时间戳', // 发生时间
// ... 其他上下文信息(可选)
}
```
### 3. ErrorBoundary 集成
React 组件渲染错误会自动被 [ErrorBoundary](src/components/ui/error-boundary.tsx) 捕获并上报:
```typescript
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
trackError('react_error', error.message, true); // 标记为致命错误
}
```
---
## 🧪 测试与验证
### 快速测试步骤
1. **启动开发服务器**
```bash
npm run dev
```
2. **访问测试页面**
```
http://localhost:3000/test-error-tracking
```
3. **点击测试按钮**
- 📛 测试 JavaScript 错误
- ⚠️ 测试 Promise 异常
- 💥 测试 React 致命错误
- 🌐 测试网络错误
4. **查看控制台日志**(开发模式)
```
[GA4] Error tracked: {
description: "[javascript_error] 测试错误...",
fatal: "false",
url: "http://localhost:3000/test-error-tracking",
...
}
```
5. **在 GA4 后台验证**
- 登录 [Google Analytics](https://analytics.google.com/)
- 报告 → 实时 → 事件计数
- 搜索 `exception`
- 应该能在 30 秒内看到错误事件
---
## 📈 在生产环境使用
### 1. 确保环境变量已配置
检查 `.env.local` 或 `.env.production` 文件:
```env
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-LGTLCR15KM
```
### 2. 构建并部署
```bash
npm run build:clean
# 然后执行部署脚本
./deploy-dist.sh
```
### 3. 监控错误报告
#### 方法 A:实时监控(推荐用于上线初期)
- GA4 后台 → 报告 → 实时
- 查看实时错误流
#### 方法 B:定期审查(日常运维)
- GA4 后台 → 报告 → 参与度 → 事件
- 筛选 `exception` 事件
- 导出数据进行分析
#### 方法 C:设置自动告警(高级)
- 使用 Google Data Studio 创建仪表盘
- 设置异常检测规则
- 配置邮件通知
---
## 🎨 自定义配置
### 忽略特定错误
编辑 [GlobalErrorTracker.tsx](src/components/analytics/GlobalErrorTracker.tsx)
```typescript
const IGNORED_ERRORS = [
/_AutofillCallbackHandler/,
/ResizeObserver loop limit exceeded/,
// 添加你想要忽略的错误模式...
];
```
### 添加自定义错误上下文
```typescript
trackError('custom_error', 'Something went wrong', false, {
user_id: '12345',
feature_name: 'checkout',
session_id: 'abc-xyz',
});
```
### 修改致命错误阈值
默认情况下,React 渲染错误会被标记为 `fatal: true`。你可以根据业务需求调整:
```typescript
// ErrorBoundary 中
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
const isFatal = error.message.includes('critical');
trackError('react_error', error.message, isFatal);
}
```
---
## ⚠️ 注意事项与限制
### GA4 错误监控的限制
1. **数据延迟**GA4 数据通常有 24-48 小时的处理延迟(实时报告除外)
2. **采样率**:高流量网站可能会有数据采样
3. **数据保留**:GA4 免费版数据保留 2 个月(付费版 14 个月)
4. **事件限制**:每个 session 最多 500 个事件
5. **参数限制**:每个事件最多 25 个参数
### 与专业错误监控工具对比
| 特性 | GA4 错误监控 | Sentry (免费版) | Fundebug (免费版) |
|------|-------------|----------------|------------------|
| **成本** | ✅ 免费 | ✅ 免费(5K 次/月) | ✅ 免费(3K 次/月) |
| **国内访问** | ✅ 可访问(需 VPN) | ❌ 受限 | ✅ 可访问 |
| **错误聚合** | ⚠️ 基础 | ✅ 高级 | ✅ 高级 |
| **Source Map** | ❌ 不支持 | ✅ 支持 | ✅ 支持 |
| **性能影响** | ✅ 低 | ⚠️ 中等 | ⚠️ 中等 |
| **告警通知** | ⚠️ 有限 | ✅ 完善 | ✅ 完善 |
| **团队协作** | ⚠️ 基础 | ✅ 完善 | ✅ 完善 |
### 建议
- **适合场景**:个人项目、小型网站、预算有限的项目
- **升级时机**:当需要更专业的错误分析、Source Map 支持、团队协作功能时,考虑迁移到 Sentry 或 Fundebug
- **混合方案**:同时使用 GA4 + Sentry/FundebugGA4 用于业务分析,专业工具用于错误调试
---
## 🔄 后续优化建议
### 短期优化(1-2 周)
1. **设置 GA4 告警**
- 配置自定义异常检测
- 设置每日错误摘要邮件
2. **创建错误仪表盘**
- 使用 Google Data Studio
- 可视化错误趋势、类型分布
3. **添加用户标识**
- 在错误上下文中包含用户 ID(如果适用)
- 便于复现问题
### 中期优化(1-3 个月)
1. **错误分类体系**
- 定义错误严重级别(P0/P1/P2/P3
- 建立响应 SLA
2. **与 CI/CD 集成**
- 将错误率纳入质量门禁
- 自动化回归测试
3. **性能关联分析**
- 关联 Core Web Vitals 与错误率
- 发现性能瓶颈
### 长期优化(3-6 个月)
1. **A/B 测试影响评估**
- 分析新功能上线后的错误变化
- 量化代码质量改进效果
2. **预测性错误预防**
- 基于历史数据预测潜在问题
- 主动修复高风险代码路径
3. **考虑迁移到专业工具**
- 如果错误量增长或需求复杂化
- 评估 Sentry/Fundebug 的 ROI
---
## 📞 支持与故障排除
### 常见问题
**Q: 为什么我在 GA4 后台看不到错误?**
A: 请检查以下几点:
1. 确保 `NEXT_PUBLIC_GA_MEASUREMENT_ID` 环境变量已正确设置
2. 使用"实时"报告而非普通报告(有 24-48 小时延迟)
3. 检查浏览器控制台是否有 `[GA4] Error tracked:` 日志
4. 确认没有广告拦截器阻止 gtag.js 加载
**Q: 如何区分开发和生产环境的错误?**
A: 可以在错误上下文中添加环境标识:
```typescript
trackError('test_error', 'Test message', false, {
environment: process.env.NODE_ENV,
});
```
**Q: 错误数据量太大怎么办?**
A: GA4 免费版每个属性每月最多 1000 万次事件。如果超出:
1. 调整 IGNORED_ERRORS 过滤更多无关错误
2. 降低采样率(只上报部分错误)
3. 升级到 GA4 360 或迁移到专业错误监控工具
---
## 📊 成功指标
### 上线后应关注的核心指标
1. **错误率**< 1% 的 session 包含至少一个错误
2. **致命错误率**< 0.1% 的 session 包含致命错误
3. **平均修复时间 (MTTR)**< 24 小时(P0 错误 < 4 小时)
4. **错误趋势**:周环比下降或持平
### 基准线建立建议
上线第一周:
- 收集基准数据
- 识别主要错误类型
- 建立监控仪表盘
第二周起:
- 设定改善目标
- 定期审查错误报告
- 持续优化代码质量
---
## 🎉 总结
✅ **已完成**:GA4 错误监控完全集成
✅ **已验证**TypeScript 检查通过,构建成功
✅ **可测试**:提供专用测试页面 `/test-error-tracking`
**可扩展**:支持自定义错误过滤和上下文
**零成本**:利用现有 GA4 账户,无需额外费用
**下一步行动**
1. 访问测试页面验证功能
2. 部署到生产环境
3. 在 GA4 后台设置监控
4. 建立定期审查流程
---
**文档版本**: v1.0
**最后更新**: 2026-01-15
**维护者**: 张翔 (Zhang Xiang)
+448
View File
@@ -0,0 +1,448 @@
# Sentry 错误监控快速接入指南(免费版)
> **适用场景**: Novalon Website 项目
> **Sentry 版本**: 免费版 (5,000 errors/month)
> **预计耗时**: 15-30 分钟
## 📋 前置条件
- ✅ Sentry 账号 (如果没有,见下方注册步骤)
- ✅ 项目已安装 `@sentry/nextjs` 依赖
- ✅ 已创建 `sentry.*.config.ts` 配置文件
## 🚀 步骤 1:注册 Sentry 免费账号(如果还没有)
### 1.1 访问 Sentry 官网
打开浏览器访问: **https://sentry.io/signup**
### 1.2 注册账号
**推荐方式(最快)**
- 点击 "Sign up with GitHub" 或 "Sign up with Google"
- 使用你的 Gitea/GitHub 账号直接登录
**或者使用邮箱注册**
1. 输入工作邮箱(建议用 `dev-team@novalon.cn`
2. 设置密码
3. 验证邮箱(检查收件箱,点击验证链接)
### 1.3 创建组织(Organization
注册成功后:
1. 进入 Dashboard
2. 点击 "Create Organization"
3. 组织名称填写: `Novalon``Novalon-Tech`
4. 选择团队类型: **Developer Team**(免费)
5. 点击 "Create Organization"
### 1.4 创建项目(Project
在组织内创建新项目:
1. 点击 "Create Project"
2. 搜索并选择框架: **Next.js**
3. 项目名称填写: `novalon-website`
4. 团队选择: 默认团队即可
5. 点击 "Create Project"
### 1.5 获取 DSNData Source Name
项目创建完成后:
1. 进入项目 → **Settings****Client Keys (DSN)**
2. 复制 **DSN** 值,格式如下:
```
https://examplePublicKey@o0.ingest.sentry.io/123456
```
3. **保存这个 DSN 值**,下一步会用到!
---
## ⚙️ 步骤 2:配置环境变量
### 2.1 编辑 `.env.local` 文件
在项目根目录下创建或编辑 `.env.local`
```bash
# 复制示例配置
cp .env.example .env.local
```
编辑 `.env.local`
```bash
# Google Analytics (如果有真实值,请替换)
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
# Sentry DSN (替换为你在步骤 1.5 中获取的真实 DSN)
NEXT_PUBLIC_SENTRY_DSN=https://your-real-dsn@o0.ingest.sentry.io/your-project-id
SENTRY_DSN=https://your-real-dsn@o0.ingest.sentry.io/your-project-id
# CDN 配置(可选)
CDN_DOMAIN=
```
**⚠️ 重要提醒:**
- ❌ 不要将 `.env.local` 提交到 Git!它已经在 `.gitignore` 中
- ✅ 只在本地开发环境和生产服务器上配置此文件
- 🔒 DSN 是公开的,不包含敏感信息(可以安全地用在客户端)
---
## 📦 步骤 3:安装 Sentry SDK
```bash
# 安装 @sentry/nextjs 及其依赖
npm install @sentry/nextjs @sentry/tracing
# 或者使用 pnpm(如果你用 pnpm)
pnpm add @sentry/nextjs @sentry/tracing
```
---
## 🔄 步骤 4:修改 next.config.ts 以集成 Sentry
当前你的 [next.config.ts](./next.config.ts) 需要添加 Sentry wrapper
```typescript
import type { NextConfig } from "next";
import { withSentryConfig } from "@sentry/nextjs";
const cdnDomain = process.env.CDN_DOMAIN || '';
const nextConfig: NextConfig = {
distDir: 'dist',
output: 'export',
assetPrefix: cdnDomain || undefined,
images: {
unoptimized: true,
},
compress: true,
poweredByHeader: false,
reactStrictMode: true,
experimental: {
optimizePackageImports: ['lucide-react'],
},
compiler: {
removeConsole: process.env.NODE_ENV === 'production',
},
};
export default withSentryConfig(
nextConfig,
{
silent: true,
disableLogger: true,
hideSourceMaps: true,
// 自动上传 source maps 到 Sentry(推荐生产环境开启)
disableClientWebpackPlugin: process.env.NODE_ENV !== 'production',
disableServerWebpackPlugin: process.env.NODE_ENV !== 'production',
},
);
```
**注意**:我已经为你创建了修改后的版本,可以直接替换原文件。
---
## ✅ 步骤 5:验证 Sentry 是否正常工作
### 5.1 启动开发服务器
```bash
npm run dev
```
### 5.2 触发测试错误
浏览器访问以下地址之一:
```bash
# 方法 A:访问 Sentry 内置的错误页面
http://localhost:3000/sentry-example-error
# 方法 B:在浏览器控制台手动触发(更灵活)
# 打开 http://localhost:3000,然后在控制台执行:
throw new TestError('Sentry 测试错误 - 如果你能看到这条错误,说明 Sentry 工作正常!');
```
### 5.3 在 Sentry Dashboard 验证
1. 登录 https://sentry.io
2. 进入你的组织 → `novalon-website` 项目
3. 点击左侧菜单 **Issues**
4. 应该能看到刚刚触发的测试错误!
**预期结果**
```
✅ Issues 列表中显示:
- Error Type: Error (或 TestError)
- Message: "Sentry 测试错误..."
- First Seen: 几秒钟前
- Events: 1
```
---
## 🎯 步骤 6:配置告警规则(可选但强烈推荐)
### 6.1 创建错误数量告警
1. 在 Sentry Dashboard 中,点击 **Alerts** → **Create Alert**
2. 选择 alert 类型: **"When an issue is created"** 或 **"Number of errors is high"**
3. 配置阈值:
```
Alert Type: Number of Errors
Threshold: > 10 errors in 5 minutes
Environment: production
```
4. 配置通知方式:
- **Email**: 发送到 dev-team@novalon.cn
- **Slack/DingTalk**: 如果集成了的话
5. 保存告警规则
### 6.2 创建性能退化告警(进阶)
如果你想监控 Core Web Vitals
1. 进入 **Settings** → **Performance**
2. 开启 **Web Vitals** 监控
3. 设置阈值:
- LCP (Largest Contentful Paint): > 2.5 秒
- FID (First Input Delay): > 100 ms
- CLS (Cumulative Layout Shift): > 0.1
---
## 🛠️ 步骤 7:在生产环境中启用 Sentry
当你准备部署到生产环境时:
### 7.1 在生产服务器上配置环境变量
SSH 到你的生产服务器 (139.155.109.62)
```bash
ssh root@139.155.109.62
# 编辑 Docker 环境变量或 .env 文件
nano /home/novalon/docker-app/.env.production
```
添加以下内容:
```bash
NODE_ENV=production
NEXT_PUBLIC_GA_MEASUREMENT_ID=你的真实GA_ID
NEXT_PUBLIC_SENTRY_DSN=你的真实SENTRY_DSN
SENTRY_DSN=你的真实SENTRY_DSN
```
### 7.2 重新构建和部署
```bash
# 回到本地开发机
./deploy-dist.sh
```
Jenkins Pipeline 会自动:
1. 运行测试
2. 构建生产版本
3. 部署到服务器
4. Sentry 开始收集生产环境的错误数据
---
## 📊 步骤 8:查看和分析错误报告
### 8.1 Issues 页面(问题列表)
进入 **Issues** 标签页,你可以看到:
| 列 | 说明 | 示例 |
|---|------|------|
| **Issue Title** | 错误标题 | TypeError: Cannot read property 'x' of undefined |
| **First Seen** | 首次发生时间 | 2 hours ago |
| **Events** | 发生次数 | 23 users, 45 events |
| **Users Affected** | 影响用户数 | 23 users |
| **Level** | 严重程度 | error / warning / info |
### 8.2 Performance 页面(性能监控)
如果你的应用开启了性能监控:
- **Transaction**(事务):每个页面加载的详细耗时
- **Span**(时间跨度):具体操作的时间分解
- **Web Vitals**LCP、FID、CLS 的趋势图
### 8.3 Releases 页面(版本追踪)
每次部署后,Sentry 会自动关联到 Git commit
```
Release: v1.0.0-stable
Commit: abc1234 (feat: downgrade to stable stack)
Deploy Time: 2026-05-12 14:30:00
Errors: 0 (or X if any)
```
---
## 💡 高级用法(按需启用)
### #1:标记用户身份(提升错误排查效率)
在你的业务代码中(如用户登录后):
```typescript
import * as Sentry from '@sentry/nextjs';
// 当用户登录后
Sentry.setUser({
id: user.id,
email: user.email,
segment: 'premium', // or 'free'
});
```
**收益**:当某个用户报错时,你可以直接看到是哪个用户遇到的问题。
### #2:附加自定义上下文(业务相关信息)
```typescript
// 在关键操作中添加上下文
Sentry.setContext('order', {
orderId: 'ORD-20260512-001',
amount: 999,
product: 'Enterprise License',
});
// 如果这里出错,Sentry 会自动附带这些信息
```
### #3:手动捕获特定错误
```typescript
try {
const response = await fetch('/api/contact');
if (!response.ok) {
throw new Error(`Contact form submission failed: ${response.status}`);
}
} catch (error) {
// 手动发送到 Sentry,并附加额外信息
Sentry.captureException(error, {
tags: { feature: 'contact-form' },
extra: { formData: { name, email, subject } },
});
}
```
### #4:设置面包屑导航(Breadcrumbs)—— 记录用户操作路径
Sentry 会自动记录:
- UI 交互(click、input、keypress
- 导航变化(URL 变化)
- Console 日志
- HTTP 请求(XHR/Fetch
- DOM 变化
你还可以手动添加:
```typescript
Sentry.addBreadcrumb({
category: 'ui',
message: 'User clicked "Submit" on contact form',
level: 'info',
});
```
---
## 🔧 故障排除
### 问题 1Sentry Dashboard 看不到任何错误
**可能原因及解决方案**
| 原因 | 解决方案 |
|------|---------|
| DSN 未正确配置 | 检查 `.env.local` 中的 `NEXT_PUBLIC_SENTRY_DSN` 是否有值 |
| 环境变量未生效 | 重启开发服务器 (`npm run dev`) |
| `enabled: false` 在开发环境 | 检查 `sentry.client.config.ts` 中的 `enabled` 条件 |
| 网络问题 | 检查是否能访问 `o0.ingest.sentry.io` |
**调试方法**
```typescript
// 在 sentry.client.config.ts 中临时添加
console.log('[Sentry] DSN:', SENTRY_DSN);
console.log('[Sentry] Enabled:', process.env.NODE_ENV !== 'development');
```
### 问题 2Source Maps 未上传
**现象**:Sentry 显示的错误堆栈是压缩后的代码,难以阅读。
**解决方案**
1. 安装 `@sentry/webpack-plugin`
```bash
npm install --save-dev @sentry/webpack-plugin
```
2. 在 `next.config.ts` 中配置:
```typescript
export default withSentryConfig(
nextConfig,
{
silent: true,
hideSourceMaps: false, // 改为 false
// 其他配置...
},
{
include: './dist/**',
ignore: ['node_modules'],
urlPrefix: '~/_next',
}
);
```
### 问题 3:免费额度超限
**Sentry 免费版限制**
- 每月 5,000 个错误事件
- 保留 30 天的数据
- 5 个团队成员
**如果超限**
1. 升级到 Developer 版本 ($26/月,50,000 errors/month)
2. 或者优化错误过滤(减少噪音)
3. 或者在 `ignoreErrors` 中添加更多模式
---
## 📚 相关文档链接
- **Sentry 官方文档**: https://docs.sentry.io/platforms/javascript/guides/nextjs/
- **Next.js 集成指南**: https://docs.sentry.io/platforms/javascript/guides/nextjs/
- **最佳实践**: https://docs.sentry.io/product/best-practices/event-grouping/
---
## ✅ 接入完成清单
请逐项确认:
- [ ] 已注册 Sentry 账号并创建项目
- [ ] 已获取 DSN 并配置到 `.env.local`
- [ ] 已安装 `@sentry/nextjs` 和 `@sentry/tracing`
- [ ] 已修改 `next.config.ts` 添加 `withSentryConfig`
- [ ] 已运行 `npm run dev` 并访问 `/sentry-example-error`
- [ ] 已在 Sentry Dashboard 看到测试错误
- [ ] (可选)已配置告警规则
- [ ] (可选)已部署到生产环境并验证
全部完成后,你的 Novalon Website 就拥有了**企业级的错误监控能力**!🎉