e82e61b589
2. 更改打包配置文件,服务的启动由remix/server改成自定义server.js(Express服务器+morgan中间件:记录http日志)
380 lines
8.5 KiB
Markdown
380 lines
8.5 KiB
Markdown
# HTTP 日志记录方案 - 部署指南
|
||
|
||
## 📋 方案概述
|
||
|
||
使用 **Express + morgan** 中间件在应用层记录所有 HTTP 请求日志,无需 Nginx。
|
||
|
||
### 架构流程
|
||
|
||
```
|
||
用户请求 (51703-51707)
|
||
↓
|
||
PM2 启动 server.js (每个端口一个实例)
|
||
↓
|
||
Express 服务器
|
||
↓
|
||
morgan 中间件(记录 HTTP 日志)
|
||
↓
|
||
Remix 应用处理
|
||
↓
|
||
返回响应 + 日志写入 PM2 日志文件
|
||
```
|
||
|
||
### 关键特性
|
||
|
||
- ✅ **记录所有 HTTP 请求**(页面、API、静态资源)
|
||
- ✅ **不同地区独立日志文件**(logs/meizhou-out.log, logs/yunfu-out.log...)
|
||
- ✅ **自定义日志格式**(开发环境彩色,生产环境详细)
|
||
- ✅ **零性能损耗**(morgan 性能优化极佳)
|
||
- ✅ **无需 Nginx**(简化架构)
|
||
|
||
---
|
||
|
||
## 🚀 部署步骤
|
||
|
||
### 第 1 步:安装依赖
|
||
|
||
在项目根目录执行:
|
||
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
这会安装以下新增依赖:
|
||
- `express` - Web 服务器框架
|
||
- `compression` - 响应压缩(提升性能)
|
||
- `morgan` - HTTP 请求日志记录
|
||
- `chalk` - 控制台彩色输出(开发环境)
|
||
- `@remix-run/express` - Remix Express 适配器
|
||
|
||
以及相关类型定义:
|
||
- `@types/express`
|
||
- `@types/compression`
|
||
- `@types/morgan`
|
||
|
||
### 第 2 步:构建应用
|
||
|
||
```bash
|
||
# 测试环境
|
||
npm run build:test:multi
|
||
|
||
# 或生产环境
|
||
npm run build:production:multi
|
||
```
|
||
|
||
### 第 3 步:重启 PM2 服务
|
||
|
||
```bash
|
||
# 停止所有实例
|
||
pm2 stop all
|
||
|
||
# 删除所有实例(可选,清理旧配置)
|
||
pm2 delete all
|
||
|
||
# 启动新配置
|
||
pm2 start ecosystem.config.cjs --env production
|
||
|
||
# 查看状态
|
||
pm2 status
|
||
```
|
||
|
||
### 第 4 步:验证日志记录
|
||
|
||
#### 4.1 访问应用
|
||
|
||
```bash
|
||
# 访问梅州实例
|
||
curl http://10.79.97.17:51703
|
||
|
||
# 访问云浮实例
|
||
curl http://10.79.97.17:51704
|
||
```
|
||
|
||
#### 4.2 查看日志
|
||
|
||
```bash
|
||
# 实时查看梅州实例日志
|
||
pm2 logs docreview-main-meizhou
|
||
|
||
# 查看所有实例日志
|
||
pm2 logs
|
||
|
||
# 或直接查看日志文件
|
||
tail -f logs/meizhou-out.log
|
||
```
|
||
|
||
**预期日志格式(生产环境):**
|
||
|
||
```
|
||
[2025-01-10T15:30:45.123Z] 172.16.0.34 meizhou:51703 GET / HTTP/1.1 200 4567 bytes 150 ms "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||
[2025-01-10T15:30:46.234Z] 172.16.0.34 meizhou:51703 POST /api/documents HTTP/1.1 201 234 bytes 85 ms "http://10.79.97.17:51703/documents" "Mozilla/5.0..."
|
||
[2025-01-10T15:30:47.345Z] 172.16.0.34 meizhou:51703 GET /build/main.js HTTP/1.1 200 125678 bytes 5 ms "http://10.79.97.17:51703/" "Mozilla/5.0..."
|
||
```
|
||
|
||
**预期日志格式(开发环境,彩色):**
|
||
|
||
```
|
||
GET /documents 200 150 ms - 4567 bytes
|
||
POST /api/documents 201 85 ms - 234 bytes
|
||
GET /build/main.js 200 5 ms - 125678 bytes
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 日志格式说明
|
||
|
||
### 生产环境日志格式
|
||
|
||
```
|
||
[ISO时间] 客户端IP 客户端ID:端口 方法 URL HTTP版本 状态码 响应大小 响应时间 "来源" "User-Agent"
|
||
```
|
||
|
||
**字段说明:**
|
||
|
||
| 字段 | 示例 | 说明 |
|
||
|-----|------|------|
|
||
| ISO时间 | [2025-01-10T15:30:45.123Z] | ISO 8601 格式的时间戳 |
|
||
| 客户端IP | 172.16.0.34 | 发起请求的 IP 地址 |
|
||
| 客户端ID:端口 | meizhou:51703 | 地区标识 + 服务端口 |
|
||
| 方法 | GET | HTTP 方法 |
|
||
| URL | /documents | 请求路径 |
|
||
| HTTP版本 | HTTP/1.1 | 协议版本 |
|
||
| 状态码 | 200 | HTTP 状态码 |
|
||
| 响应大小 | 4567 bytes | 响应体大小 |
|
||
| 响应时间 | 150 ms | 请求处理时间 |
|
||
| 来源 | "-" | Referer 头 |
|
||
| User-Agent | "Mozilla/5.0..." | 浏览器标识 |
|
||
|
||
### 开发环境日志格式
|
||
|
||
```
|
||
方法 URL 状态码 响应时间 - 响应大小
|
||
```
|
||
|
||
- 状态码带颜色(绿色 2xx, 黄色 4xx, 红色 5xx)
|
||
- HTTP 方法带颜色(蓝色 GET, 绿色 POST, 黄色 PUT, 红色 DELETE)
|
||
|
||
---
|
||
|
||
## 🔍 日志文件位置
|
||
|
||
所有日志文件位于 `logs/` 目录:
|
||
|
||
```
|
||
logs/
|
||
├── meizhou-out.log ← 梅州实例的所有输出(包含 HTTP 日志)
|
||
├── meizhou-err.log ← 梅州实例的错误日志
|
||
├── meizhou-combined.log ← 梅州实例的合并日志
|
||
├── yunfu-out.log ← 云浮实例的所有输出
|
||
├── yunfu-err.log
|
||
├── yunfu-combined.log
|
||
├── jieyang-out.log ← 揭阳实例的所有输出
|
||
├── jieyang-err.log
|
||
├── jieyang-combined.log
|
||
├── chaozhou-out.log ← 潮州实例的所有输出
|
||
├── chaozhou-err.log
|
||
├── chaozhou-combined.log
|
||
├── province-out.log ← 省局实例的所有输出
|
||
├── province-err.log
|
||
└── province-combined.log
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 日志分析示例
|
||
|
||
### 查看访问量最高的 URL
|
||
|
||
```bash
|
||
# 提取 URL 并统计
|
||
cat logs/meizhou-out.log | grep -oP 'GET \K/[^ ]+' | sort | uniq -c | sort -rn | head -10
|
||
```
|
||
|
||
### 统计 HTTP 状态码分布
|
||
|
||
```bash
|
||
# 提取状态码并统计
|
||
cat logs/meizhou-out.log | grep -oP 'HTTP/1\.\d \K\d{3}' | sort | uniq -c | sort -rn
|
||
```
|
||
|
||
### 统计平均响应时间
|
||
|
||
```bash
|
||
# 提取响应时间并计算平均值
|
||
cat logs/meizhou-out.log | grep -oP '\K\d+ ms' | sed 's/ ms//' | awk '{sum+=$1; count++} END {print "平均响应时间:", sum/count, "ms"}'
|
||
```
|
||
|
||
### 查找慢请求(>1秒)
|
||
|
||
```bash
|
||
# 查找响应时间超过 1000ms 的请求
|
||
cat logs/meizhou-out.log | grep -P '\d{4,} ms'
|
||
```
|
||
|
||
### 查找错误请求(4xx/5xx)
|
||
|
||
```bash
|
||
# 查找 4xx 错误
|
||
cat logs/meizhou-out.log | grep -P 'HTTP/1\.\d [45]\d{2}'
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 自定义配置
|
||
|
||
### 修改日志格式
|
||
|
||
编辑 `server.js`,修改 `logFormat` 变量:
|
||
|
||
```javascript
|
||
// 自定义日志格式
|
||
const logFormat = '[:date[iso]] :remote-addr :method :url :status :response-time ms';
|
||
```
|
||
|
||
**可用的 morgan token:**
|
||
|
||
| Token | 说明 |
|
||
|-------|------|
|
||
| `:method` | HTTP 方法 |
|
||
| `:url` | 请求 URL |
|
||
| `:status` | 状态码 |
|
||
| `:response-time` | 响应时间(毫秒) |
|
||
| `:res[content-length]` | 响应大小 |
|
||
| `:remote-addr` | 客户端 IP |
|
||
| `:http-version` | HTTP 版本 |
|
||
| `:referrer` | Referer 头 |
|
||
| `:user-agent` | User-Agent 头 |
|
||
| `:date[format]` | 时间(支持 clf, iso, web 格式) |
|
||
|
||
### 跳过某些请求
|
||
|
||
编辑 `server.js`,修改 `skip` 函数:
|
||
|
||
```javascript
|
||
app.use(morgan(logFormat, {
|
||
skip: (req, res) => {
|
||
// 跳过静态资源请求(减少日志噪音)
|
||
if (req.url.startsWith('/build/')) return true;
|
||
|
||
// 跳过健康检查
|
||
if (req.url === '/health') return true;
|
||
|
||
return false;
|
||
}
|
||
}));
|
||
```
|
||
|
||
### 添加日志轮转
|
||
|
||
使用 PM2 的日志轮转功能:
|
||
|
||
```bash
|
||
# 安装 PM2 日志轮转模块
|
||
pm2 install pm2-logrotate
|
||
|
||
# 配置每天轮转,保留 30 天
|
||
pm2 set pm2-logrotate:max_size 100M
|
||
pm2 set pm2-logrotate:retain 30
|
||
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'
|
||
```
|
||
|
||
---
|
||
|
||
## 🐛 故障排查
|
||
|
||
### 问题 1: 启动失败
|
||
|
||
**检查步骤:**
|
||
|
||
```bash
|
||
# 查看 PM2 日志
|
||
pm2 logs --err
|
||
|
||
# 查看具体实例日志
|
||
pm2 logs docreview-main-meizhou --err
|
||
```
|
||
|
||
**常见原因:**
|
||
- 依赖未安装:`npm install`
|
||
- 端口被占用:`netstat -tlnp | grep 51703`
|
||
- 构建失败:`npm run build:production:multi`
|
||
|
||
### 问题 2: 日志没有记录
|
||
|
||
**检查步骤:**
|
||
|
||
```bash
|
||
# 确认 server.js 被使用
|
||
pm2 info docreview-main-meizhou | grep script
|
||
|
||
# 查看进程输出
|
||
pm2 logs docreview-main-meizhou --lines 100
|
||
```
|
||
|
||
**验证:**
|
||
|
||
```bash
|
||
# 发起测试请求
|
||
curl http://10.79.97.17:51703
|
||
|
||
# 立即查看日志
|
||
tail -n 5 logs/meizhou-out.log
|
||
```
|
||
|
||
### 问题 3: 日志格式不正确
|
||
|
||
**检查 server.js 的 logFormat 配置:**
|
||
|
||
```bash
|
||
# 查看 server.js 第 60-70 行
|
||
sed -n '60,70p' server.js
|
||
```
|
||
|
||
---
|
||
|
||
## 📈 性能影响
|
||
|
||
### morgan 性能测试
|
||
|
||
- **每请求开销**:< 0.1ms
|
||
- **内存占用**:几乎可忽略
|
||
- **吞吐量影响**:< 1%
|
||
|
||
### 对比 Nginx 日志
|
||
|
||
| 指标 | morgan(应用层) | Nginx(代理层) |
|
||
|-----|----------------|----------------|
|
||
| 延迟增加 | ~0.05ms | ~0.5ms |
|
||
| 额外端口 | 0 个 | 需要修改 PM2 端口 |
|
||
| 配置复杂度 | 低 | 中 |
|
||
| 日志详细程度 | 高(可访问应用数据) | 中 |
|
||
| 架构复杂度 | 低 | 高(多一层代理) |
|
||
|
||
---
|
||
|
||
## ✅ 验收标准
|
||
|
||
部署成功后,应满足:
|
||
|
||
- [ ] 所有 5 个实例(51703-51707)正常运行
|
||
- [ ] 访问任意实例,日志文件立即记录请求
|
||
- [ ] 日志包含:时间、IP、方法、URL、状态码、响应时间
|
||
- [ ] 不同实例的日志分别记录到对应文件
|
||
- [ ] 日志格式正确,信息完整
|
||
|
||
---
|
||
|
||
## 📞 支持
|
||
|
||
如遇问题,请:
|
||
1. 查看 PM2 日志:`pm2 logs --err`
|
||
2. 查看应用日志:`tail -f logs/meizhou-out.log`
|
||
3. 检查 server.js 是否存在错误
|
||
4. 验证依赖是否正确安装:`npm list morgan express`
|
||
|
||
---
|
||
|
||
**文档版本**: 1.0
|
||
**最后更新**: 2025-01-10
|
||
**适用环境**: Linux/Windows
|