light-sentry-sdk/docs/INTEGRATION.md

659 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 业务接入指南
本文档说明如何将前端/后端业务接入 light-sentry 日志分析系统。
---
## 目录
1. [系统架构](#1-系统架构)
2. [接入方式概览](#2-接入方式概览)
3. [前端接入Browser SDK](#3-前端接入browser-sdk)
4. [后端接入Node.js SDK](#4-后端接入nodejs-sdk)
5. [Python 接入](#5-python-接入)
6. [容器日志接入](#6-容器日志接入)
7. [项目与容器关联](#7-项目与容器关联)
8. [一键部署业务机](#8-一键部署业务机)
9. [常见问题](#9-常见问题)
---
## 1. 系统架构
```
┌─────────────────────────────────────────────────────────────┐
│ log.starseekai.cn │
│ │
│ ┌──────────┐ ┌────────────┐ ┌──────────────┐ │
│ │ /manage/ │ │ /grafana/ │ │ /dozzle/ │ │
│ │ 项目管理 │ │ 仪表盘 │ │ 容器日志查看 │ │
│ └────┬─────┘ └─────┬──────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌────▼────────────────▼────────────────▼───────┐ │
│ │ Nginx 反向代理 │ │
│ │ /api/* → API 服务 (9000) │ │
│ │ /loki/* → Loki (3100) │ │
│ └────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌────────────────▼───────────────────────┐ │
│ │ Light-Sentry API 服务 │ │
│ │ - Sentry SDK 兼容网关 │ │
│ │ - 项目管理 API │ │
│ │ - 一键部署 Agent │ │
│ └────────┬──────────────┬─────────────────┘ │
│ │ │ │
│ ┌────────▼───┐ ┌───────▼──────┐ ┌─────────────┐ │
│ │ Loki │ │ Promtail │ │ Dozzle │ │
│ │ 日志存储 │ │ 中心日志采集 │ │ 容器日志查看 │ │
│ └─────────────┘ └──────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
业务机部署:
┌─────────────────────────────────────────────────┐
│ 业务 ECS 服务器 │
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Promtail │───►│ 中心 Loki │ │
│ │ (采集容器日志) │ │ log.starseekai.cn│ │
│ └──────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ Dozzle │───► 远程连接中心 Dozzle Agent │
│ │ (本地容器日志) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────┘
```
### 服务入口
| 服务 | 地址 | 说明 |
|------|------|------|
| 项目管理 | `https://log.starseekai.cn/manage/` | 可视化管理项目、容器关联、一键部署 |
| Grafana 仪表盘 | `https://log.starseekai.cn/grafana/` | 查询 Sentry 日志、容器日志、链路追踪 |
| Dozzle 容器日志 | `https://log.starseekai.cn/dozzle/` | 实时查看业务机 Docker 容器日志 |
| Loki 查询 API | `https://log.starseekai.cn/loki/loki/api/v1/` | Loki 原生查询 API |
| SDK 上报地址 | `https://log.starseekai.cn/api/{projectId}/store/` | Sentry SDK 上报端点 |
---
## 2. 接入方式概览
light-sentry 完全兼容 Sentry SDK 协议,只需将 SDK 的 **DSNData Source Name** 指向本系统即可。
### 接入矩阵
| 场景 | 推荐 SDK | 支持协议 |
|------|---------|---------|
| 前端浏览器 | Sentry Browser SDK | Store API + Envelope |
| Node.js 后端服务 | Sentry Node SDK | Store API + Envelope |
| Python 后端服务 | Sentry Python SDK | Store API + Envelope |
| Java Spring Boot | Sentry Java SDK | Store API + Envelope |
| Go 服务 | Sentry Go SDK | Store API + Envelope |
### DSN 格式
Sentry SDK 要求 DSN 格式为:
```
https://{public_key}@{host}/{projectId}
```
| 参数 | 说明 | 示例 |
|------|------|------|
| `public_key` | 认证公钥(可自定义,建议用项目名) | `order-frontend`、`backend-api` |
| `host` | 本系统的入口地址 | `log.starseekai.cn` |
| `projectId` | **必须是纯数字** | `1001`、`1002`、`1003` |
**重要:** Sentry SDK 要求 `projectId` 必须是纯数字,不支持字母或字符串 ID。
**示例 DSN**
```bash
# 前端项目
https://order-frontend@log.starseekai.cn/1001
# 后端项目
https://order-backend@log.starseekai.cn/1002
# Python 服务
https://payment-service@log.starseekai.cn/1003
```
### 接入流程
```
1. 在项目管理页面 (https://log.starseekai.cn/manage/) 创建项目
2. 填写纯数字项目 ID如 1001
3. 填写 Public Key可自定义或留空自动生成
4. 获取生成的 DSN
5. 在业务代码中配置 SDK
6. 容器日志:通过一键部署或手动配置 Promtail
7. 在 Grafana 仪表盘查看日志
```
### 接入建议:前后端分开
**建议将前端和后端作为两个独立项目接入:**
```
业务系统
├── 前端项目 → projectId: 1001, publicKey: myapp-frontend
└── 后端项目 → projectId: 1002, publicKey: myapp-backend
```
**分开的好处:**
| 维度 | 说明 |
|------|------|
| **日志区分** | 前后端错误分开,一目了然 |
| **采样率** | 前端可设置更高采样(用户行为重要),后端可更低(日志量大) |
| **告警规则** | 前端错误率 > 1% 告警,后端 > 5% 告警 |
| **链路追踪** | 通过 trace_id 仍能串联前后端日志 |
---
## 3. 前端接入Browser SDK
### 安装
```bash
npm install @sentry/browser
# 或
yarn add @sentry/browser
# 或
pnpm add @sentry/browser
```
### 基础接入HTML 单页)
```html
<script src="https://browser.sentry-cdn.com/7.x.x/bundle.min.js" crossorigin="anonymous"></script>
<script>
Sentry.init({
dsn: 'https://frontend@log.starseekai.cn/1001',
// 推荐采样率:生产环境 10%~50%
tracesSampleRate: 0.1,
// 生产环境关闭调试
debug: false,
// 环境
environment: 'production',
// 版本(用于按版本筛选错误)
release: 'v1.2.3',
});
</script>
```
### React / Vue / Next.js 接入
**ReactCreate React App / Next.js**
```javascript
import * as Sentry from '@sentry/browser';
import { BrowserTracing } from '@sentry/tracing';
Sentry.init({
dsn: 'https://frontend@log.starseekai.cn/1001',
integrations: [new BrowserTracing()],
tracesSampleRate: 0.1,
environment: process.env.NODE_ENV,
release: process.env.npm_package_version,
});
```
**Vue 3**
```javascript
import { createApp } from 'vue';
import * as Sentry from '@sentry/browser';
import { VueIntegration } from '@sentry/integrations';
Sentry.init({
dsn: 'https://frontend@log.starseekai.cn/1001',
integrations: [new VueIntegration({ app })],
tracesSampleRate: 0.1,
environment: process.env.NODE_ENV,
});
```
### 手动上报错误
```javascript
// 手动捕获并上报
try {
// 业务代码
JSON.parse('not valid json');
} catch (err) {
Sentry.captureException(err, {
// 自定义额外数据
extra: {
userId: currentUser.id,
action: 'checkout',
},
});
}
// 上报自定义消息
Sentry.captureMessage('用户注册成功', {
level: 'info',
extra: { userId: 12345, plan: 'pro' },
});
```
### 添加用户上下文
```javascript
// 登录时设置
Sentry.setUser({
id: 'user_12345',
email: 'user@example.com',
username: 'john_doe',
ip_address: '{{auto}}', // 自动采集 IP
});
// 登出时清除
Sentry.setUser(null);
```
---
## 4. 后端接入Node.js SDK
### 安装
```bash
npm install @sentry/node
# 或
yarn add @sentry/node
```
### Express 接入
```javascript
const express = require('express');
const Sentry = require('@sentry/node');
const { ExpressIntegration } = require('@sentry/integrations');
const app = express();
// Sentry 必须在其他中间件之前初始化
Sentry.init({
dsn: 'https://backend@log.starseekai.cn/1002',
integrations: [new ExpressIntegration({ app })],
tracesSampleRate: 0.1,
environment: process.env.NODE_ENV,
release: process.env.npm_package_version,
});
// 请求处理中间件(必须)
app.use(Sentry.Handlers.requestHandler());
// 你的业务路由
app.get('/api/order', (req, res) => {
// 业务代码
res.json({ orderId: 'ORD_12345' });
});
// 错误处理中间件(必须)
app.use(Sentry.Handlers.errorHandler());
app.listen(3000);
```
### 自动捕获未处理错误和 Promise rejections
```javascript
// 在 Sentry.init() 之后添加
// 捕获未处理的 Promise rejection
process.on('unhandledRejection', (reason, promise) => {
Sentry.captureException(reason);
});
// 捕获未处理的同步异常
process.on('uncaughtException', (err) => {
Sentry.captureException(err);
process.exit(1);
});
```
### 手动上报错误
```javascript
const Sentry = require('@sentry/node');
async function createOrder(req, res) {
try {
const order = await db.orders.create(req.body);
Sentry.addBreadcrumb({
category: 'db',
message: 'Order created',
data: { orderId: order.id },
});
res.json(order);
} catch (err) {
Sentry.captureException(err, {
// 附加请求上下文
contexts: {
request: {
method: req.method,
url: req.url,
headers: req.headers,
},
},
});
throw err; // 仍需抛出,让 Express 错误中间件处理
}
}
```
---
## 5. Python 接入
### 安装
```bash
pip install sentry-sdk
```
### Django / Flask 接入
**Django**
```python
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn='https://python-service@log.starseekai.cn/1003',
integrations=[DjangoIntegration()],
traces_sample_rate=0.1,
environment='production',
release='v1.2.3',
)
```
**Flask**
```python
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init(
dsn='https://python-service@log.starseekai.cn/1003',
integrations=[FlaskIntegration()],
traces_sample_rate=0.1,
environment='production',
)
```
### 手动上报
```python
from sentry_sdk import capture_exception, capture_message
try:
1 / 0
except Exception as e:
capture_exception(e)
capture_message('用户登录成功', level='info', extra={'user_id': 12345})
```
---
## 6. 容器日志接入
容器日志通过 Promtail 采集,存储到 Loki可在 Grafana 和 Dozzle 中查看。
### 6.1 中心 Promtail采集本机日志
适用于日志分析系统所在的 ECS 服务器。
编辑 `promtail/promtail-config.yml`,修改容器白名单:
```yaml
scrape_configs:
- docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
# 白名单:只收集以下前缀的容器(多个用 | 分隔)
- source_labels: ['__meta_docker_container_name']
regex: '/(light-sentry-.+|myapp-.+|nginx)'
action: keep
```
### 6.2 业务机 Promtail一键部署
通过项目管理页面的「一键部署」功能,自动将 Promtail Agent 部署到业务 ECS 服务器。
**部署步骤:**
1. 打开 `https://log.starseekai.cn/manage/`
2. 编辑项目,填写「关联容器名称」或「容器过滤正则」
3. 点击「一键部署」,填写业务机 SSH 信息
4. 系统自动完成SSH 连接 → 生成配置 → 部署 Promtail → 重启 Dozzle Agent
### 6.3 Dozzle 容器过滤
Dozzle 默认只显示 `light-sentry-*` 前缀的容器。修改 `.env` 可调整:
```bash
# 格式key=value支持正则多个用逗号分隔
DOZZLE_FILTER=name=light-sentry-.+|myapp-.+|nginx
```
### 6.4 Grafana 中查询容器日志
Promtail 采集的日志带以下标签:
| 标签 | 说明 |
|------|------|
| `host` | 主机名 |
| `source` | `container` 标识为容器日志 |
| `container_name` | Docker 容器名称 |
| `container_image` | Docker 镜像名称 |
| `composed_project` | Docker Compose 项目名 |
| `docker_service` | Docker Compose 服务名 |
**查询示例:**
```logql
# 按容器名查询
{container_name="myapp-web"}
# 按镜像名查询
{container_image=~"nginx.*"}
# 组合 Sentry 项目 + 容器日志
{container_name=~"myapp-.*", host="prod-ecs"}
# 查看该容器最近 1 小时的日志
{container_name="myapp-web"} |= "ERROR" | __error__!="JSONErr"
```
---
## 7. 项目与容器关联
### 7.1 关联步骤
1. 打开项目管理页面 `https://log.starseekai.cn/manage/`
2. 编辑项目,填写容器信息:
- **关联容器名称**:精确匹配容器名,多个用逗号分隔
- **容器过滤正则**(可选):支持正则表达式,优先级更高
| 关联方式 | 示例 | 说明 |
|---------|------|------|
| 单容器 | `myapp-web` | 只采集指定容器 |
| 多容器 | `myapp-web, myapp-api` | 逗号分隔 |
| 正则匹配 | `myapp-.*` | 匹配所有 myapp- 开头的容器 |
### 7.2 接入声明
项目管理页面提供一键复制功能,包含:
- SDK 接入代码片段
- 完整的 DSN 地址
- Grafana 仪表盘跳转链接
- Dozzle 容器日志跳转链接
### 7.3 项目管理 API
| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/projects/` | 列出所有项目 |
| `GET` | `/api/projects/:id` | 获取单个项目详情 |
| `POST` | `/api/projects/` | 创建新项目 |
| `PUT` | `/api/projects/:id` | 更新项目信息 |
| `DELETE` | `/api/projects/:id` | 删除项目 |
**创建项目示例:**
```bash
curl -X POST https://log.starseekai.cn/api/projects/ \
-H "Content-Type: application/json" \
-d '{
"id": "order-service",
"name": "订单服务",
"platform": "node",
"environment": "production",
"description": "处理订单创建和支付",
"containerName": "order-service-web, order-service-worker"
}'
```
---
## 8. 一键部署业务机
通过项目管理页面的「一键部署」功能,将 Promtail Agent 和 Dozzle Agent 自动部署到业务 ECS 服务器。
### 8.1 部署流程
```
1. 用户在页面填写业务机 SSH 信息IP、用户名、密码
2. 后端启动异步部署任务
3. SSH 连接业务机
4. 创建部署目录、生成 Promtail/Dozzle 配置
5. SCP 上传配置文件和 docker-compose.yml
6. 启动容器
7. 同步 Agent 信息到中心 Dozzle
8. 实时 SSE 推送部署日志到前端
```
### 8.2 部署配置说明
**Loki Push 地址**:由项目管理页面的「中心 Loki 地址」配置,默认为 `https://log.starseekai.cn/loki/loki/api/v1/push`
**部署目录**:默认 `/opt/light-sentry-agent`,可在部署时自定义
**容器过滤**:根据项目关联的容器名自动生成 Promtail 过滤正则
### 8.3 部署目录结构
```
/opt/light-sentry-agent/
├── docker-compose.yml # Dozzle Agent
├── promtail/
│ └── promtail-config.yml # Promtail 配置
└── .env # 环境变量DOZZLE_REMOTE_AGENT
```
### 8.4 查看部署历史
部署历史可在项目管理页面查看,包含:
- 部署时间、目标主机
- 部署状态(成功/失败)
- 实时部署日志
- 容器过滤配置
---
## 9. 常见问题
### Q: SDK 上报后看不到日志
**排查步骤:**
1. 检查浏览器控制台是否有 Sentry 报错
2. 确认 DSN 是否正确:`https://{publicKey}@log.starseekai.cn/{projectId}`
3. 确认 `projectId` 是否是纯数字(如 `1001`
4. 在 Grafana Explore 中直接查询原始日志:
```logql
{platform="javascript"}
```
### Q: 容器日志没有采集到
**排查步骤:**
1. 确认 Promtail 容器是否在运行:`docker ps | grep promtail`
2. 检查 Promtail 日志:`docker logs light-sentry-promtail`
3. 确认容器名是否在白名单中
4. 检查 Loki 是否收到数据:`curl http://localhost:3100/loki/api/v1/label/container_name/values`
### Q: 一键部署失败
**常见原因:**
1. SSH 密码错误或 IP 无法连接
2. 目标目录权限不足(确保 SSH 用户有 `/opt` 写权限)
3. Docker 未安装或未启动
**解决方案:**
- 手动检查 SSH 连接:`ssh user@host`
- 检查目标目录权限:`ls -la /opt/`
- 查看部署日志中的详细错误信息
### Q: 生产环境建议采样率是多少?
| 环境 | tracesSampleRate | 说明 |
|------|-----------------|------|
| 开发/测试 | `1.0` | 全量采集,方便调试 |
| 预发/灰度 | `0.5` | 采集一半 |
| 生产 | `0.05 ~ 0.2` | 5%~20%,平衡性能和数据量 |
### Q: 如何在 Grafana 中切换项目查看?
在 Grafana 仪表盘顶部有 **项目** 下拉框,选择后可按项目过滤日志。仪表盘地址格式:
```
https://log.starseekai.cn/grafana/d/light-sentry-logs?var-project=1
```
其中 `var-project` 参数值为项目 ID。
### Q: 日志量会不会太大?
假设:
- 每小时 10000 次 API 请求
- tracesSampleRate = 0.110%
- 每条 trace 上报 3~5 条日志
- 每条日志约 2KB
```
月流量 ≈ 10000 × 0.1 × 4 × 2KB × 24h × 30d ≈ 57 MB
```
非常轻量2核2G 完全没压力。
### Q: 如何添加自定义标签?
```javascript
// 设置全局标签(所有事件都会带)
Sentry.setTag('server', 'production');
Sentry.setTag('region', 'cn-hangzhou');
// 设置用户级别标签
Sentry.setContext('order', {
orderId: 'ORD_12345',
amount: 99.9,
currency: 'CNY',
});
```