<?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/%E9%94%99%E8%AF%AF%E7%9B%91%E6%8E%A7/</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>Fri, 03 Jul 2020 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://localhost:1313/tags/%E9%94%99%E8%AF%AF%E7%9B%91%E6%8E%A7/index.xml" rel="self" type="application/rss+xml" />
    <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>
