light-sentry-sdk/docs/INTEGRATION.md

19 KiB
Raw Blame History

业务接入指南

本文档说明如何将前端/后端业务接入 light-sentry 日志分析系统。


目录

  1. 系统架构
  2. 接入方式概览
  3. 前端接入Browser SDK
  4. 后端接入Node.js SDK
  5. Python 接入
  6. 容器日志接入
  7. 项目与容器关联
  8. 一键部署业务机
  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-frontendbackend-api
host 本系统的入口地址 log.starseekai.cn
projectId 必须是纯数字 100110021003

重要: Sentry SDK 要求 projectId 必须是纯数字,不支持字母或字符串 ID。

示例 DSN

# 前端项目
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

安装

npm install @sentry/browser
# 或
yarn add @sentry/browser
# 或
pnpm add @sentry/browser

基础接入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

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

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,
});

手动上报错误

// 手动捕获并上报
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' },
});

添加用户上下文

// 登录时设置
Sentry.setUser({
  id: 'user_12345',
  email: 'user@example.com',
  username: 'john_doe',
  ip_address: '{{auto}}',  // 自动采集 IP
});

// 登出时清除
Sentry.setUser(null);

4. 后端接入Node.js SDK

安装

npm install @sentry/node
# 或
yarn add @sentry/node

Express 接入

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

// 在 Sentry.init() 之后添加

// 捕获未处理的 Promise rejection
process.on('unhandledRejection', (reason, promise) => {
  Sentry.captureException(reason);
});

// 捕获未处理的同步异常
process.on('uncaughtException', (err) => {
  Sentry.captureException(err);
  process.exit(1);
});

手动上报错误

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 接入

安装

pip install sentry-sdk

Django / Flask 接入

Django

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

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',
)

手动上报

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,修改容器白名单:

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 可调整:

# 格式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 服务名

查询示例:

# 按容器名查询
{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 删除项目

创建项目示例:

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 中直接查询原始日志:
{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: 如何添加自定义标签?

// 设置全局标签(所有事件都会带)
Sentry.setTag('server', 'production');
Sentry.setTag('region', 'cn-hangzhou');

// 设置用户级别标签
Sentry.setContext('order', {
  orderId: 'ORD_12345',
  amount: 99.9,
  currency: 'CNY',
});