<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>埋点 on Saiga</title>
    <link>http://localhost:1313/tags/%E5%9F%8B%E7%82%B9/</link>
    <description>Recent content in 埋点 on Saiga</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <managingEditor>wuwenzen@outlook.com (wuwj)</managingEditor>
    <webMaster>wuwenzen@outlook.com (wuwj)</webMaster>
    <lastBuildDate>Thu, 20 Apr 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://localhost:1313/tags/%E5%9F%8B%E7%82%B9/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>前端视角下的 A/B Test：埋点、分流与验证</title>
      <link>http://localhost:1313/posts/2023-04-20-ab-testing-in-frontend/</link>
      <pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate><author>wuwenzen@outlook.com (wuwj)</author>
      <guid>http://localhost:1313/posts/2023-04-20-ab-testing-in-frontend/</guid>
      <description>&lt;p&gt;「做个 A/B 实验看看」这句话听起来很轻松，真正落地时会发现：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;指标怎么算？&lt;/li&gt;&#xA;&lt;li&gt;实验人群怎么分？&lt;/li&gt;&#xA;&lt;li&gt;前端要怎么接入实验配置？&lt;/li&gt;&#xA;&lt;li&gt;实验结束之后，代码怎么收口？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这篇文章从前端的角度，讲一次相对完整的 A/B 实验闭环。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-先确定为什么要做这个实验&#34;&gt;1. 先确定：为什么要做这个实验？&lt;/h2&gt;&#xA;&lt;p&gt;我们当时的实验目标是：&lt;strong&gt;提高某投资流程的转化率&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;假设是：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;把原本一个超长的单页表单拆成多步引导，是否能提高「填写完成率」。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;因此：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;实验对象：访问该流程的真实用户；&lt;/li&gt;&#xA;&lt;li&gt;对照组：看到旧版「单页表单」；&lt;/li&gt;&#xA;&lt;li&gt;实验组：看到新版「多步引导」；&lt;/li&gt;&#xA;&lt;li&gt;观测指标：完成率、平均耗时、中途流失位置等。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;只有先把这些定义清楚，后续埋点和分流才有方向。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-埋点设计先有指标再谈实现&#34;&gt;2. 埋点设计：先有指标，再谈实现&lt;/h2&gt;&#xA;&lt;p&gt;这次我们重点关心几个指标：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;flow_enter&lt;/code&gt;：进入流程的人数；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;flow_complete&lt;/code&gt;：完成流程的人数；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;step_view&lt;/code&gt;：在多步表单中，每一步的曝光；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;step_error&lt;/code&gt;：每一步表单提交失败次数。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在前端埋点上做了几件事：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有埋点带上 &lt;code&gt;experiment_id&lt;/code&gt; 和 &lt;code&gt;variant&lt;/code&gt;（A / B）；&lt;/li&gt;&#xA;&lt;li&gt;关键事件使用统一的 &lt;code&gt;event_name&lt;/code&gt; + &lt;code&gt;event_params&lt;/code&gt; 格式；&lt;/li&gt;&#xA;&lt;li&gt;尽量避免把业务逻辑硬编码到埋点名里。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;示例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;track&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;flow_enter&amp;#39;&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;experimentId&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;exp_split_form_v1&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;variant&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;currentVariant&lt;/span&gt;, &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#39;A&amp;#39; 或 &amp;#39;B&amp;#39;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;track&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;step_view&amp;#39;&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;experimentId&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;exp_split_form_v1&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;variant&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;currentVariant&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;step&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;1&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;track&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;flow_complete&amp;#39;&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;experimentId&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;exp_split_form_v1&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;variant&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;currentVariant&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;3-分流让实验公平且可控&#34;&gt;3. 分流：让实验「公平」且可控&lt;/h2&gt;&#xA;&lt;h3 id=&#34;31-基本原则&#34;&gt;3.1 基本原则&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;同一用户体验稳定&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;被分到 A 组，就一直看 A；&lt;/li&gt;&#xA;&lt;li&gt;避免一次访问是 A，刷新变 B。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;分配近似均匀&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>前端监控闭环：采集、告警到问题跟踪</title>
      <link>http://localhost:1313/posts/2022-09-05-monitoring-and-alert/</link>
      <pubDate>Mon, 05 Sep 2022 00:00:00 +0000</pubDate><author>wuwenzen@outlook.com (wuwj)</author>
      <guid>http://localhost:1313/posts/2022-09-05-monitoring-and-alert/</guid>
      <description>&lt;p&gt;很多团队做前端监控的姿势是：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;先接一个 SDK，看到了几个报错，然后就没然后了。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;最后变成：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;告警群天天响，大家学会了「静音」；&lt;/li&gt;&#xA;&lt;li&gt;仪表盘很酷，但没人看；&lt;/li&gt;&#xA;&lt;li&gt;真出大问题时，还是靠用户截图。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这篇文章想聊的是：&lt;strong&gt;怎么从「有监控」升级到「有闭环」&lt;/strong&gt;：采集、告警、问题跟踪、复盘一条链路打通。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-前端到底要监什么&#34;&gt;1. 前端到底要监什么？&lt;/h2&gt;&#xA;&lt;p&gt;可以按三个维度来想：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;可用性&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;JS 运行错误（Error、Promise 未捕获）；&lt;/li&gt;&#xA;&lt;li&gt;资源加载失败（JS/CSS/图片）；&lt;/li&gt;&#xA;&lt;li&gt;页面白屏/异常重定向。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;性能&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;首屏指标（FCP/FP/TTI 等的近似值）；&lt;/li&gt;&#xA;&lt;li&gt;接口耗时、失败率；&lt;/li&gt;&#xA;&lt;li&gt;静态资源加载时间。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;行为 &amp;amp; 转化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;关键路径的曝光/点击/完成；&lt;/li&gt;&#xA;&lt;li&gt;异常行为（频繁刷新、某步流失明显）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;实践上，可以先从：&lt;strong&gt;错误 + 性能 + 关键链路打点&lt;/strong&gt; 三件事做起。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-采集埋点--sdk-一起用&#34;&gt;2. 采集：埋点 &amp;amp; SDK 一起用&lt;/h2&gt;&#xA;&lt;h3 id=&#34;21-错误采集&#34;&gt;2.1 错误采集&lt;/h3&gt;&#xA;&lt;p&gt;典型方式：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;addEventListener&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, (&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;reportError&lt;/span&gt;({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;event.message&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;filename&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;event.filename&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;lineno&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;event.lineno&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;colno&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;event.colno&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;stack&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;event.error?.stack&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;addEventListener&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;unhandledrejection&amp;#39;&lt;/span&gt;, (&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;reportError&lt;/span&gt;({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;unhandledrejection&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;reason&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reason&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结合 sourcemap 上传，可以把错误还原到源代码行。&lt;/p&gt;&#xA;&lt;h3 id=&#34;22-性能采集&#34;&gt;2.2 性能采集&lt;/h3&gt;&#xA;&lt;p&gt;利用 Performance API：&lt;/p&gt;</description>
    </item>
    <item>
      <title>别再只 console.log 了：前端错误收集与日志治理</title>
      <link>http://localhost:1313/posts/2020-07-03-error-handling-and-logging/</link>
      <pubDate>Fri, 03 Jul 2020 00:00:00 +0000</pubDate><author>wuwenzen@outlook.com (wuwj)</author>
      <guid>http://localhost:1313/posts/2020-07-03-error-handling-and-logging/</guid>
      <description>&lt;p&gt;大部分前端开发一开始排查问题都是靠：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;看看这里是什么&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这没问题，但当项目变大、用户变多、场景变复杂时，只靠 &lt;code&gt;console.log&lt;/code&gt; 就完全不够用了——&lt;strong&gt;用户出问题时你根本看不到现场。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这篇文章聊聊我在实际项目里做前端错误收集和日志治理的一些经验。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-我们到底需要记录什么&#34;&gt;1. 我们到底需要记录什么？&lt;/h2&gt;&#xA;&lt;p&gt;先看一个真实场景：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户反馈：&lt;strong&gt;「页面有时候会白屏」&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;操作步骤：「我就是正常点点点，突然就白了」&lt;/li&gt;&#xA;&lt;li&gt;浏览器：未知&lt;/li&gt;&#xA;&lt;li&gt;系统：未知&lt;/li&gt;&#xA;&lt;li&gt;URL：未知&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果我们没有任何前端错误监控工具，这个问题几乎无从排查。&lt;/p&gt;&#xA;&lt;p&gt;所以，一套基础的前端日志/错误系统至少要能回答：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;什么时间？&lt;/li&gt;&#xA;&lt;li&gt;哪个用户？&lt;/li&gt;&#xA;&lt;li&gt;在哪个页面？&lt;/li&gt;&#xA;&lt;li&gt;用的什么浏览器/系统？&lt;/li&gt;&#xA;&lt;li&gt;做了什么操作？&lt;/li&gt;&#xA;&lt;li&gt;报了什么错（堆栈、接口信息等）？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以日志结构（特别是错误日志）要包含几个核心字段：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FrontendLog&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;info&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;warn&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;stack?&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;userId?&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;number&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;ua&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// user agent&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;extra?&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;Record&lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;any&lt;/span&gt;&amp;gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-捕获错误的几个入口&#34;&gt;2. 捕获错误的几个入口&lt;/h2&gt;&#xA;&lt;h3 id=&#34;21-全局-js-运行时错误&#34;&gt;2.1 全局 JS 运行时错误&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;onerror&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lineno&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;colno&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;reportError&lt;/span&gt;({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;stack&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stack&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; window.&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;extra&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lineno&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;colno&lt;/span&gt; },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;这个能捕获&lt;strong&gt;同步脚本错误&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;对跨域脚本，如果没有正确配置，会只得到 &lt;code&gt;Script error.&lt;/code&gt;，需要在 script 标签上加 &lt;code&gt;crossorigin&lt;/code&gt; 且服务端正确设置 CORS/SourceMap。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h3 id=&#34;22-promise-未处理异常&#34;&gt;2.2 Promise 未处理异常&lt;/h3&gt;&#xA;&lt;p&gt;现代前端很多逻辑是基于 Promise / async 的，&lt;code&gt;window.onerror&lt;/code&gt; 捕不到，需要监听：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
