04 Umi4 插件开发 - 网友需求 - 前端数据埋点 Sentry 1/2
现在的前端埋点方案,大同小异,好一点的平台会提供 JSSDK 供用户直接调用和接入,差一点的平台会让用户直接调用接口。 但是其实原理上都差不多。这里我们不做深入的讲解,如果有朋友感兴趣的话,可以给我留言,我会专门写个文章给大家讲解。
为了看文章的朋友都能自己动手实践一遍,我们选一个免费的数据埋点平台 Sentry
作为演示。
Sentry 是一个服务,帮助你监测和修复在实时崩溃。服务器是 Python 的,但是它包含一个完整的 API,用于在任何应用程序中从任何语言发送事件。 为了简化和聚焦这篇文章的核心,我们只关注 Sentry 提供的 React 对接方案,有其他需求的朋友,可以自己浏览 Sentry 官网。
根据官网指引,我们先在业务代码中接入 Sentry SDK。
注册账号
根据官网指引在注册页面注册一个账号。
下一步选择 Install Sentry
下一步选择创建一个 REACT 项目,点击 Create Project
安装依赖
官网文章如下:
# Using yarn
yarn add @sentry/react @sentry/tracing
# Using npm
npm install --save @sentry/react @sentry/tracing
为了简化前置步骤说明,我们从上一个文章的源码归档 learn-for-umi-plugin@0.0.3 继续。
因为我们的项目用的是 pnpm ,所以我们应该在项目中执行。
pnpm i @sentry/react @sentry/tracing
初始化 Sentry
安装完成之后继续跟着官网文档进行:
// 这是官方文档
import React from "react";
import ReactDOM from "react-dom";
import * as Sentry from "@sentry/react";
import { BrowserTracing } from "@sentry/tracing";
import App from "./App";
Sentry.init({
// 此处 dsn 注意换成你自己的,直接复制页面上的代码就是正确的
dsn: "https://96620dadccb040a3a5acc998a6078212@o1378593.ingest.sentry.io/6690607",
integrations: [new BrowserTracing()],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
});
ReactDOM.render(<App />, document.getElementById("root"));
// Can also use with React Concurrent Mode
// ReactDOM.createRoot(document.getElementById('root')).render(<App />);
从文档上我们能够看出,他的期望是在 render(<App />)
之前执行 Sentry.init
,如果是 create-react-app 项目的话,你可以在 src/index
之类的文件中粘贴一样的代码,但是在 umi 中,这个入口文件是一个临时文件,是当你执行 dev
或者 build
之后才会生成的,就在 src/.umi/umi.ts
。这个文件也是构建时候的入口文件,你可以在这个文件中找到 renderClient
方法的调用,最终在 renderClient
中调用了 ReactDOM.createRoot
。这在你需要做“入口追踪游戏”的时候,是一个需要知道的常识。
当然了这个文件是临时生成的,意味着你在这里面编写的所有的内容,都会被抛弃,因此我们无法将 Sentry.init
写在这里面。
还好 Umi 提供了一个 global 文件,它也是在较靠前的执行的,因此我们可以把 Sentry.init
写在 global 中。
新建 src/global.ts
文件
import * as Sentry from "@sentry/react";
import { BrowserTracing } from "@sentry/tracing";
Sentry.init({
// 此处 dsn 注意换成你自己的,直接复制页面上的代码就是正确的
dsn: "https://acb9e155e5de4ee0a418e798570feae1@o652357.ingest.sentry.io/6683799",
integrations: [new BrowserTracing()],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
});
在 src/pages/index.tsx
中创造一个错误
Sentry 官网文档是让我们写一个 button 调用一个不存在的函数 methodDoesNotExist
,但是 umi 在编译阶段就会检测这种错误,会导致 umi 启动不起来。
因此我们可以像下面这么写,在点击时执行一个不存在的对象。
import React from 'react';
import styles from './index.less';
export default function Page() {
return (
<div>
<h1 className={styles.title} onClick={()=>{
// @ts-ignore
methodDoesNotExist
}}>Page index</h1>
</div>
);
}
当我们运行 npx umi dev
,在页面中点击 Page index
的时候,我们就会发送一个错误,此时我们停留的 Sentry 官网会自动跳转到监控页面。
你可以点击进入查看任意错误的详情信息这里面包含了,用户用的系统版本号浏览器版本号还有执行了什么操作。比如:
从上面的信息你很容易就能看到,用户在 http://localhost:8000/
点击了 div#root > div > div > div > h1.title___dUjAT
。
当然如果只是添加一个接入,那没什么必要将它写成插件,我们可以继续浏览 Sentry React 的文档,加入一些其他的我们想要的功能。
React Error Boundary
给项目加上 Error Boundary 可以在程序发生异常的时候,捕获错误。
依旧我们从官网文档中获取使用方法:
import React from "react";
import * as Sentry from "@sentry/react";
<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
<Example />
</Sentry.ErrorBoundary>;
只需要用 Sentry.ErrorBoundary
包裹 RootContainer
就可以实现,当错误被捕获时间,就会渲染 fallback
提供的 UI。
巧了,刚好 umi 就有一个运行时配置 rootContainer
,它提供了一个口子,让我们能够在外层包裹一个 Provider。
运行时配置 rootContainer
新建 src/app.tsx
,编写如下代码:
import React from "react";
import { ErrorBoundary } from "@sentry/react";
export function rootContainer(container: JSX.Element) {
const props = {
fallback: () => <p>An error has occurred</p>,
};
return React.createElement(ErrorBoundary, props, container);
}
值得注意的是 ErrorBoundary 只捕获 React 渲染错误,不捕获语法错误。
我们可以继续在 src/pages/index.tsx
中创造一个渲染错误。
import React, { useState } from "react";
import styles from "./index.less";
export default function Page() {
const [count, setCount] = useState(0);
return (
<div>
{count}
<h1
className={styles.title}
onClick={() => {
// 这里故意设置了一个错误,会触发运行时配置
// @ts-ignore
setCount({ a: 123 });
}}
>
Page index
</h1>
</div>
);
}
关键出错代码在 {count}
因为将 count 设置成对象 { a: 123 }
,保存代码之后,再次点击 Page index
的时候,就可以在页面上看到 An error has occurred
。
说明我们的错误已经被正确捕获了。
重置错误 resetError
当然了,这样虽然捕获了错误,但我们也看不到错误内容了,因此我们可以修改一个 fallback
,它可以接收一个函数,并且会传入 error, componentStack, resetError
。
import { ErrorBoundary, ErrorBoundaryProps } from "@sentry/react";
const props = {
fallback: ({ error, componentStack, resetError }) =>
(
<React.Fragment>
<div>You have encountered an error</div>
<div>{error.toString()}</div>
<div>{componentStack}</div>
<button
onClick={() => {
resetError();
}}
>
Click here to reset!
</button>
</React.Fragment>
) as React.ReactNode,
} as ErrorBoundaryProps;
再次点击触发错误,将会看到更详细的错误信息,并且点击 Click here to reset!
按钮可以将页面重置到错误发生之前。
用户反馈
当触发错误时,会有如上所示弹窗,供用户主动反馈信息,提交成功之后,可以在后台查看用户提交数据。
实现也很简单,只需要将 ErrorBoundary 的 showDialog 属性设置为 true
import React from "react";
import { ErrorBoundary, ErrorBoundaryProps } from "@sentry/react";
export function rootContainer(container: JSX.Element) {
const props = {
showDialog: true,
// fallback React.ReactNode,
} as ErrorBoundaryProps;
return React.createElement(ErrorBoundary, props, container);
}
设置用户
比如在用户登陆授权之后,全程跟踪用户发生的错误。
Sentry.setUser({ id: '123', username: 'xiaohuoni', email: '' });
设置之后用户再次触发错误,就可以从后台看到用户信息。
Sentry.setUser
你可以在任意时候调用,也可以在不需要的时候清除当前设置的用户:
Sentry.configureScope((scope) => scope.setUser(null));
源码归档 learn-for-umi-plugin@0.0.4
总结
以上是我个人觉得比较有用和有趣的功能,你也可以再找一些你想要的功能,根据官网的指引添加到项目中。 这篇文章的内容写的非常细,是希望在开始编写插件之前,能够更准确的理解需求。我们会在下一篇文章中,将上面的功能编写成插件。
感谢阅读,如果你对这个内容感兴趣,可以关注这个专栏:Umi 插件开发。如果你觉得这个文章对你有帮助,请点赞评论收藏支持我,并将这个文章分享给更多的朋友,文章的数据是我持续更新的动力。感谢。
转载自:https://juejin.cn/post/7136126695152549925