uniapp 项目接入 sentry监控

Sentry 接入使用文档

📋 目录


概述

本项目使用 sentry-uniapp 进行错误监控和上报,支持 H5、小程序、APP 多平台。Sentry 会自动捕获未处理的异常,同时提供手动上报接口用于业务错误和异常。

核心特性

  • ✅ 自动捕获全局异常
  • ✅ HTTP 请求错误自动上报
  • ✅ 业务错误码上报
  • ✅ 用户信息关联
  • ✅ 环境开关控制
  • ✅ 多平台支持

依赖安装

项目已安装 Sentry 依赖包:

json 复制代码
{
  "dependencies": {
    "sentry-uniapp": "^1.0.12"
  }
}

环境配置

1. 环境变量配置

.env 文件中配置 Sentry DSN:

bash 复制代码
# Sentry DSN(必填,用于错误上报)
VITE_SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id

# 是否启用 Sentry(可选,默认从 profile 读取)
VITE_SENTRY_ENABLE=true

类型定义 (typings/env.d.ts):

36:39:typings/env.d.ts 复制代码
  /** Sentry DSN */
  readonly VITE_SENTRY_DSN?: string
  /** 是否启用 Sentry */
  readonly VITE_SENTRY_ENABLE?: 'true' | 'false'

2. Profile 配置

env-conf.ts 中配置各环境的 Sentry 开关:

15:33:env-conf.ts 复制代码
      // 是否启用Sentry
      SENTRY_ENABLE: true,
    },
    uat: {
      DELETE_CONSOLE: false,
      SHOW_SOURCEMAP: false,
      APP_PROXY_ENABLE: false,
      CLIENT_TYPE_BUYER: 'buyer',
      CLIENT_TYPE_SELLER: 'seller',
      SENTRY_ENABLE: false,
    },
    production: {
      DELETE_CONSOLE: false,
      SHOW_SOURCEMAP: false,
      APP_PROXY_ENABLE: false,
      CLIENT_TYPE_BUYER: 'buyer',
      CLIENT_TYPE_SELLER: 'seller',
      SENTRY_ENABLE: true,
    },

配置说明

  • development: 开发环境,默认启用
  • uat: 测试环境,默认关闭
  • production: 生产环境,默认启用

核心配置

Sentry 核心文件 (src/sentry.ts)

这是 Sentry 的核心配置文件,提供了初始化、错误捕获、用户信息设置等功能。以下是完整的代码:

typescript 复制代码
import * as Sentry from 'sentry-uniapp'
import { profile } from '@/profile'

/**
 * 检查是否启用 Sentry
 */
function isSentryEnabled(): boolean {
  const { VITE_SENTRY_DSN } = import.meta.env
  // 必须同时满足:profile 中启用开关为 true 且 DSN 已配置
  return profile.SENTRY_ENABLE && !!VITE_SENTRY_DSN
}

/**
 * 初始化 Sentry
 * 在 App.vue 的 onLaunch 中调用
 */
export function initSentry() {
  const { VITE_SENTRY_DSN } = import.meta.env

  // 检查是否启用
  if (!profile.SENTRY_ENABLE) {
    return
  }

  // 检查 DSN 是否配置
  if (!VITE_SENTRY_DSN) {
    console.warn('[Sentry] 已启用但 DSN 未配置,Sentry 初始化失败')
    return
  }

  const isAppPlatform =
    String(__UNI_PLATFORM__) === 'app' || String(__UNI_PLATFORM__) === 'app-harmony'

  Sentry.init({
    dsn: VITE_SENTRY_DSN,
    // extraOptions 主要是解决平台差异问题的
    // 非 APP 平台,可以不使用
    extraOptions: isAppPlatform
      ? {
          onmemorywarning: false,
          onerror: false,
        }
      : undefined,
  })
}

/**
 * 设置 Sentry 用户信息
 * 保留此函数,因为 src/stores/user.ts 中需要使用
 */
export function setSentryUser(userInfo?: { id?: string; username?: string }) {
  if (!isSentryEnabled()) return

  if (userInfo?.id && userInfo?.username) {
    Sentry.configureScope(scope => {
      scope.setUser({
        id: String(userInfo.id), // 确保 id 是字符串
        username: userInfo.username,
      })
    })
  } else {
    Sentry.configureScope(scope => {
      scope.setUser(null)
    })
  }
}

/**
 * 捕获异常
 * 在 App.vue 的 onError 中调用
 */
export function captureException(error: unknown, extra?: Record<string, unknown>) {
  if (!isSentryEnabled()) return

  // 使用 withScope 确保额外信息能够正确附加
  Sentry.withScope(scope => {
    if (extra) {
      Object.keys(extra).forEach(key => {
        scope.setExtra(key, extra[key])
      })
    }
    Sentry.captureException(error)
  })
}

/**
 * 捕获消息
 */
export function captureMessage(message: string, extra?: Record<string, unknown>) {
  if (!isSentryEnabled()) return

  // 使用 withScope 确保额外信息(包括 traceId)能够正确附加
  Sentry.withScope(scope => {
    if (extra) {
      console.log('extra', extra)
      Object.keys(extra).forEach(key => {
        scope.setExtra(key, extra[key])
      })
    }
    Sentry.captureMessage(message)
  })
}

// 导出 Sentry 对象,以便在需要时直接使用
export { Sentry }

代码说明

  1. isSentryEnabled() : 检查是否启用 Sentry,必须同时满足 profile.SENTRY_ENABLE === trueVITE_SENTRY_DSN 已配置

  2. initSentry(): 初始化 Sentry

    • 检查启用开关和 DSN 配置
    • APP 平台需要特殊配置 extraOptions 来禁用某些钩子,避免与 App.onError 冲突
  3. setSentryUser(): 设置或清除 Sentry 用户信息

    • 用于关联错误和用户,便于问题追踪
    • 登出时传入 undefined 清除用户信息
  4. captureException(): 捕获异常

    • 用于真正的异常(网络错误、代码错误等)
    • 支持附加额外上下文信息
  5. captureMessage(): 捕获消息

    • 用于业务逻辑错误(错误码等,不是异常)
    • 支持附加额外上下文信息
  6. 导出 Sentry 对象: 允许在特殊场景下直接使用 Sentry 的原生 API


初始化流程

App.vue 中的初始化

src/App.vueonLaunch 钩子中初始化 Sentry:

87:111:src/App.vue 复制代码
onLaunch(() => {
  console.log('App Launch')

  // 初始化 Sentry
  initSentry()

  // 安全初始化埋点SDK(内部会等待 App 实例准备好)
  safeInitTrack()

  // 延迟检查和测试(给足够时间让埋点初始化完成)
  setTimeout(() => {
    if (checkTrackInit()) {
      // 开发环境下测试埋点
      if (import.meta.env.MODE === 'dev') {
        testTrack()
      }
    }

    // 设置 Sentry 用户信息
    const userStore = useUserStore()
    const { userId, username } = userStore.userInfo || {}
    if (userId && username) {
      setSentryUser({ id: userId, username })
    }
  }, 3500) // 增加到 3.5 秒,确保 waitForAppReady 完成

全局错误捕获

src/App.vueonError 钩子中捕获全局异常:

146:155:src/App.vue 复制代码
// sentry-uniapp 内部是通过 uni.onError 钩子函数捕获错误的
// 但目前 uni.onError 暂不支持 App (android / ios),各平台支持情况参考:
// https://uniapp.dcloud.net.cn/api/application.html#onerror
//
// 通用方案:
// 可用 App.onError 自己处理,但需要先禁用 sentry 里的捕获
// 方法在 sentry.init 参数里加上 extraOptions: { onerror: false }
onError((error: unknown) => {
  captureException(error)
})

注意

  • sentry-uniapp 内部通过 uni.onError 钩子捕获错误
  • uni.onError 暂不支持 APP 平台(Android/iOS)
  • APP 平台需要在 sentry.init 中配置 extraOptions: { onerror: false },然后使用 App.onError 手动捕获

使用方式

1. 导入函数

typescript 复制代码
import { captureException, captureMessage, setSentryUser } from '@/sentry'

2. 捕获异常

用于捕获真正的异常(如网络错误、代码错误等):

typescript 复制代码
try {
  // 可能出错的代码
  await someAsyncOperation()
} catch (error) {
  captureException(error, {
    // 可选的额外信息
    operation: 'someOperation',
    userId: '123',
  })
}

3. 捕获业务错误

用于捕获业务逻辑返回的错误(不是异常,而是业务错误码):

typescript 复制代码
const response = await apiCall()
if (!response.succeed) {
  captureMessage(`业务返回错误码: ${response.code}`, {
    errorCode: response.code,
    traceId: response.traceId,
    url: '/api/endpoint',
  })
}

4. 设置用户信息

typescript 复制代码
// 设置用户信息
setSentryUser({ id: '123', username: 'john_doe' })

// 清除用户信息(登出时)
setSentryUser()

错误上报场景

1. HTTP 请求错误上报

src/service/index.ts 中,HTTP 请求拦截器会自动上报错误:

业务错误上报(使用 captureMessage)
14:25:src/service/index.ts 复制代码
function reportBusinessErrorToSentry(
  message: string,
  requestOptions: CustomRequestOptions,
  extra?: Record<string, unknown>,
): void {
  captureMessage(message, {
    url: requestOptions.url,
    method: requestOptions.method || 'GET',
    requestParams: requestOptions.data || requestOptions.query || {},
    ...extra,
  })
}

使用场景

48:55:src/service/index.ts 复制代码
function handleBusinessError<T>(data: BaseRes<T>, requestOptions: CustomRequestOptions): boolean {
  globalErrorMonitor.handleError(data.code, data)
  // 业务错误使用 captureMessage(不是异常,是业务逻辑返回的错误)
  reportBusinessErrorToSentry(`业务返回错误码: ${data.code}`, requestOptions, {
    errorCode: data.code,
    traceId: data.traceId,
    errorData: data,
  })
HTTP 错误上报(使用 captureException)
30:42:src/service/index.ts 复制代码
function reportExceptionToSentry(
  message: string,
  requestOptions: CustomRequestOptions,
  extra?: Record<string, unknown>,
): void {
  const error = new Error(message)
  captureException(error, {
    url: requestOptions.url,
    method: requestOptions.method || 'GET',
    requestParams: requestOptions.data || requestOptions.query || {},
    ...extra,
  })
}

使用场景

75:85:src/service/index.ts 复制代码
function handleHttpError<T>(
  statusCode: number,
  data: BaseRes<T>,
  requestOptions: CustomRequestOptions,
): void {
  const message = data.message || (statusCode === 401 ? '未授权' : '请求错误')
  // HTTP 错误使用 captureException(是真正的异常)
  reportExceptionToSentry(`HTTP ${statusCode}: ${message}`, requestOptions, {
    statusCode,
    errorData: data,
  })
网络错误上报(使用 captureException)
95:100:src/service/index.ts 复制代码
function handleNetworkError<T>(err: unknown, requestOptions: CustomRequestOptions): BaseRes<T> {
  uni.showToast({ icon: 'none', title: '网络错误,换个网络试试' })

  const errorMessage = typeof err === 'string' ? err : JSON.stringify(err)
  // 网络错误使用 captureException(是真正的异常)
  reportExceptionToSentry(`网络请求失败: ${errorMessage}`, requestOptions, { errorData: err })

2. 全局错误监控

src/utils/globalErrorMonitor.ts 中,未处理的错误码会统一上报到 Sentry:

28:37:src/utils/globalErrorMonitor.ts 复制代码
  public handleError(errCode: string, errorData?: any): void {
    switch (errCode) {
      case 'ACOM10000':
        this.handlePermissionUpdated()
        break
      // 可以添加其他错误码的处理
      default:
        // 未处理的错误码已在 service/index.ts 中统一上报到 Sentry
        break
    }
  }

用户信息关联

自动设置用户信息

在用户登录或获取用户信息后,自动设置 Sentry 用户信息:

1. App.vue 中初始化时设置
105:110:src/App.vue 复制代码
    // 设置 Sentry 用户信息
    const userStore = useUserStore()
    const { userId, username } = userStore.userInfo || {}
    if (userId && username) {
      setSentryUser({ id: userId, username })
    }
2. User Store 中设置

src/stores/user.ts 中,设置用户信息时自动关联 Sentry:

23:32:src/stores/user.ts 复制代码
    const setUserInfo = (val: UserModel) => {
      userInfo.value = val
      // 设置 Sentry 用户信息
      if (val.userId && val.username) {
        setSentryUser({
          id: val.userId,
          username: val.username,
        })
      }
    }
3. 清除用户信息

登出时清除 Sentry 用户信息:

44:51:src/stores/user.ts 复制代码
    const clearAll = () => {
      userInfo.value = { ...initState }
      companyInfo.value = {}
      realNameInfo.value = {}
      hasCompanyList.value = false
      // 清除 Sentry 用户信息
      setSentryUser()
    }

平台差异说明

APP 平台特殊配置

APP 平台(Android/iOS)需要在初始化时禁用某些钩子,避免与 App.onError 冲突:

31:44:src/sentry.ts 复制代码
  const isAppPlatform =
    String(__UNI_PLATFORM__) === 'app' || String(__UNI_PLATFORM__) === 'app-harmony'

  Sentry.init({
    dsn: VITE_SENTRY_DSN,
    // extraOptions 主要是解决平台差异问题的
    // 非 APP 平台,可以不使用
    extraOptions: isAppPlatform
      ? {
          onmemorywarning: false,
          onerror: false,
        }
      : undefined,
  })

原因

  • uni.onError 在 APP 平台不支持
  • 需要在 App.onError 中手动捕获错误
  • 因此需要禁用 Sentry 内部的 onerror 钩子

平台支持情况

参考 uni-app 官方文档

  • ✅ H5: 支持 uni.onError
  • ✅ 小程序: 支持 uni.onError
  • ❌ APP: 不支持 uni.onError,需要使用 App.onError

总结

配置检查清单

  • .env 文件中配置 VITE_SENTRY_DSN
  • env-conf.ts 中配置各环境的 SENTRY_ENABLE
  • 确保 src/App.vue 中调用了 initSentry()
  • 确保 src/App.vue 中配置了 onError 钩子
  • 确保用户登录后调用了 setSentryUser()

最佳实践

  1. 异常 vs 业务错误

    • 真正的异常(网络错误、代码错误)使用 captureException
    • 业务逻辑错误(错误码)使用 captureMessage
  2. 用户信息关联

    • 登录后立即设置用户信息
    • 登出时清除用户信息
  3. 额外信息

    • 上报时尽量提供上下文信息(URL、参数、traceId 等)
    • 便于在 Sentry 后台快速定位问题
  4. 环境控制

    • 开发环境可以启用,方便调试
    • 测试环境建议关闭,避免测试数据污染
    • 生产环境必须启用,用于监控线上问题

相关文件清单

  • src/sentry.ts - Sentry 核心配置和工具函数
  • src/App.vue - Sentry 初始化和全局错误捕获
  • src/service/index.ts - HTTP 请求错误上报
  • src/stores/user.ts - 用户信息关联
  • env-conf.ts - 环境配置(Sentry 开关)
  • typings/env.d.ts - 环境变量类型定义
  • package.json - 依赖包配置

文档更新时间: 2025-01-24

相关推荐
●VON1 小时前
Electron 实战:纯图片尺寸调节工具(支持锁定纵横比)
前端·javascript·electron·开源鸿蒙
谁黑皮谁肘击谁在连累直升机1 小时前
包及其导入
前端·后端
在下历飞雨1 小时前
Kuikly 基础之封装自定义音频播放模块
前端
vim怎么退出1 小时前
React 项目诡异白屏事故复盘:JSON.stringify、循环引用、setState 死循环,一个都没跑
前端·debug
Danny_FD1 小时前
使用Highcharts创建3D环形图
前端·echarts
我的div丢了肿么办1 小时前
js中async和await 的详细讲解
前端·javascript·vue.js
程序员小寒2 小时前
前端性能优化之CSS篇
前端·css·性能优化
种时光的人2 小时前
关于人人开源框架renren-fast-vue前端npm install安装报错的问题解决方法
前端·vue.js·npm
Z***25802 小时前
React增强现实案例
前端·react.js·ar