从无到有<前端异常监控系统>落地

本文介绍了一个前端异常监控系统的实现过程,包括如何监听JS错误、生成和解析sourcemap、优化存储及发送邮件提醒等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

导火索

  有一天一个测试同事的一个移动端页面白屏了,看样子是页面哪里报错了。  我自己打开页面并没有报错,最后发现报错只存在于他的手机,移动端项目又是在微信环境下,调试起来会比较麻烦,最后用他手机调试才发现问题: 是他账户下面有个对话的消息数据有问题导致页面报错了。  一般遇到这种情况只有用他的手机或者账户调试能很快查到问题,如果是外部的用户怎么办,我没法拿他的手机去测试。

 

  其实这个问题很常见,但是这次我觉得这个问题如果不是我们自己同事发现的,那就很恐怖,可能废很大精力才能查出问题,甚至会导致很严重的线上bug,细思极恐,刚好前不久成都FCC的大前端交流会上叶小钗谈到了监控这块,也让我有所启发,这些公共服务才是公司的核心财富,目前公司业务发展处在上升阶段,未来用户肯定会越来越多,对系统的稳定性要求也会越来越高,那既然我们还缺乏这块的服务,现在做正合适。

 

前期准备

   从提出这个想法的一开始就知道,落地才是关键,否则一切空谈。  刚好半个多月以后,我们前端组需要在公司做一次分享,我现在做个题材就挺适合分享的,其他后端和测试同事也容易听进去一点。  最开始我考虑了后端存储和可视化的情况,想找个现成后端集成工具帮我处理后端的工作。  就找后端同事问了一下,同事推荐了 Elasticsearch+Fluentd+Kibana 。  然后稍微研究了一下,总觉得哪里不对,反正研究了之后发现可能还是需要做一些定制开发才能解决需求,后端同事听了我的需求也是这么说的。  一人之力有限,并且公司业务上的事情也多,找一个后端同事配合极好,利用各自的优势可以更快落地,这样我也可以专注前端的工作和把控整个项目落地。  就这样,我和后端同事商量了一下,他也答应抽空和我一起搞了。   抛开后端的事情,我开始思考前端的工作,去调研一下别人的方案和这块的知识。  有一些三方库或者开源项目提供类似的功能的,做了很简单的了解。  最后想着自己开发更容易去适应自身的业务,并且目前第一版的需求功能也并没有那么大的开发量,那就自己做吧。  前期遇见了一些需要解决和实现的功能点: 生成sourcemap,监听js报错和信息上报,压缩的js代码上报后sourcemap解析问题,如何更平滑的应用在业务项目中,数据存储优化等。

 

基本实现

前端

  •   js报错事件监听+处理上报
  •   构建工具生成sourcemap文件
  •   sourcemap文件上传

后端

  •   提供接口收集报错
  •   读取sourcemap文件,解析上传的报错(解析发生时间:接口收集到后马上处理,后期提取的时候处理)
  •   存储数据

 

监听js报错和信息上报

通过onerror我们能监听和拿到js的报错信息, 可以拿到如下代码的五个参数。  columnNo, error这两个参数在一些老版本的IE8-9浏览器和opera低版本等浏览器上可能拿不到,但是没有关系,我们在代码上兼容拿不到参数的情况,如果缺少后两个参数,传空值就行了。  也可以通过其他方式拿到这些老版本浏览器的columnNo和error参数,目前监控主要是针对移动端,也没太大必要去兼容老版本的浏览器。

window.onerror = function (msg, fileUrl, lineNo, columnNo, error) {}

 

onerror方法大致实现如下:

//如果之前其他代码有绑定onerror,需要替换执行一下,如果没有定义window.error===null。
var oldError = window.onerror;
window.onerror = function (msg, fileUrl, lineNo, columnNo, error) {//最后两个参数有些部分浏览器拿不到,依然需要记录

    var args = Array.prototype.slice.call(arguments);
    
    if (oldError) {
      oldError.apply(window, args)
    }
  var stack = null; if(error && error.stack) stack = error.stack; var json = { msg: msg || null, fileUrl: fileUrl || null, lineNo: lineNo || null, columnNo: columnNo || null, error: stack } var userAgent = navigator.userAgent; if(XMLHttpRequest){ var xhr = new XMLHttpRequest(); xhr.open('post', 'urlxxx', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send("message="+JSON.stringify(json)+"&userAgent="+encodeURIComponent(userAgent)) } }

可能存在跨域问题,不同域下的js需要配置script属性 crossorigin="anonymous" 和后端配置 Access-Control-Allow-Origin,但是目前我们的项目不存在js跨域问题。

提示一下onerror并不能拿到所有报错信息,比如网络报错等

现在我们能通过onerror拿到报错信息了,可是线上的代码是经过压缩的,报错的时候我们能拿到的的行列数和变量命都不能告诉我们源代码哪里出错了。这里我们需要用到sourcemap,下面来讲讲它。

 

sourcemap

sourcemap就是一个信息文件,里面储存着位置信息。  也就是说,sourcemap文件记录了代码转换前的位置和转换后对应的位置(http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html 阮一峰详解)。  下面图1是login.js的压缩版本,第二行的注释指定了map文件的相对路径,浏览器根据注释会找到map文件然后自动解析出来,在调试器里就可以看到源码了;  图2是map文件(json格式);  图3图4介绍sourcemap文件。  图2我们生成的map文件sourcesContent字段直接引入了源文件代码(构建工具可以配置是否给map文件引入源文件),这样可以方便后端解析,如果没有源文件对应的话后端是解析不出正确结果的。

(图1)

(图2)

(图3)

 

 

(图4)

 

 

grunt生成sourcemap:

  我们的移动端项目构建工具比较老了,统一用的grunt作为打包工具。  之前没有在压缩代码时使用sourceMap,因为开发和测试环境没有压缩,所以也不需要在浏览器用sourceMap调试。  然后我就再去修改gruntfile文件(之前不是我写的),sourceMap配置感觉和官方文档对不上,老是报错,最后才发现之前的打包工具的依赖版本是13年的了,也暂时没必要去折腾版本问题了,把老版本的文档翻出来再配置了一下sourcemap文件就成功的生成在源文件的同级目录下了,比如源文件叫xx.js,map文件就是xx.js.map。  我们给js文件加上了md5版本号,所以实际的文件是xx.md5.js和xx.md5.js.map(md5是根据内容变化的)。

 

sourcemap解析问题

思考的时候发现最大的难点应该在sourcemap解析。  最开始后端同事以为sourcemap是nodejs生成的文件,他们后端用的go或者php似乎不能解析吧,如果知道了sourcemap原理就应该知道,它只是一种数据格式和开发语言没关系。  我把map文件和报错信息交给后端同事,他们用go语言的一个工具成功解析出了答案,实现了本地文件的解析。  但是我们需要的是自动化解析,不可能每次都去把存储的报错信息手动的拿出来再去找对应的map文件做人工解析。  所以需要我们后端程序自己去找到map文件,并解析报错信息。

如此一来,后端解析存在两个关键问题:

  1. map文件存储在哪里
  2. 什么时候解析

①map文件存储在哪里

这里只说我们的方案,map文件和源js文件打包到同级目录下,一起上传到服务器(比如js的路径是www.xxx.com/dist/index.md5.js,那map文件的地址就是www.xxx.com/dist/index.md5.js.map),服务端就可以根据报错的js路径再加上.map后缀找到map文件。  压缩文件有一段注释描述sourceMappongURL指定了map文件的位置,打开浏览器之后调试器会找到这个map文件,在浏览器里就能看到源代码,为了避免这种情况,需要服务器配置 .js.map 后缀的文件不可访问。  如果这样的话,服务器解析的时候不能直接去下载静态资源.map文件,而是需要去找到服务器本地对应的map文件,这样要单独配置路径和写逻辑很麻烦,而且文件夹结构有变动的话也不灵活。  所以我们的方案是做token权限校验,map文件必须加正确的token参数,服务器才会返回资源(xxx.js.map?token=xxxx),否则nginx会屏蔽没有token或者token错误的请求。

 

②什么时候解析

两种方法,一种是后端接口收到报错信息之后,马上找到map文件,并解析存储到数据库。  一种是先保留上报信息,通过接口查询的时候再去解析。  我们选择了前者,接口收到数据之后,后端根据当前报错文件的url,去查查本地是否已经下载过当前文件,如果已经存在这个文件,就直接用本地的文件解析,如果本地没有,路径加上.map和token参数,下载对应的map文件到本地,然后再去读取当前本地文件并解析,解析的数据和上报的数据就存为一条记录。  如果是后者的方法,存在很多麻烦的问题,这里不多说了。

 一张图详细描述我们的解析流程:

 

有一种情况可能发生: 当前项目已经更新到1.1版本了,1.0版本的一个报错以前没被触发,这个时候有个用户缓存了1.0版本的代码,并且触发了一个新的报错,这个时候服务器本地存储的map文件里没有这个文件,就会带上token去下载map文件,因为当前已经是1.1版本了,原js文件发生过变动,md5的版本已经对应不上了,这个时候就没法找到map文件了,无法解析,所以这种特殊情况只能存储上报的errorInfo信息。

 

如何更平滑的应用在业务项目中

目前js的onerror方法只有代码量不大,后期还会有叠加。现在的想法是尽量不和业务代码做过多接触,只需要直接引入当前js到各个业务项目中去,每个项目不用对它太多任何配置,让它尽量单纯一点。

 

存储优化

后期是会做管理后台来查询和统计这些异常日志的,同一个错误可能上传报错数据到服务端,后端查询出来是一条条独立的记录,我们不能区分这条记录的报错是不是有重复数据,也不应该让后端去做字段对比。  后来想到给 报错的文件路径+行+列 信息拼在一起字段做md5生成,根据这个唯一值生成md5,最后查询的时候只需要查询当前md5字段就能知道这一条报错一个有多少条记录。  不过我想的太天真了,不同的浏览器报错行列信息有点不一样,同一报错就可能生成不同的md5字符串,即便这里有点问题,我还是继续用这个方案保存了md5(因为内核原因,移动端的差异还是比较小,当前字段也能有一定的区分性)。

我们第一版存储的主要数据(还有一些常规的就不说) :

{
    "businessInfo": "{}",//业务项目自定义的数据
    "errorMd5": "80bb86b86da0607c0dc5c3a77e16eab6",//根据报错部分信息生成的md5
    "manualSendError": "{}",//手动上传的报错信息
    "pageUrl": "http://www.xxx.com/xxx.html",//放生报错的页面url
    "parseError": true,//解释是否失败
    "parsed": '{"col":0,"errKey":"list","file":"xxx.js","line":105}',//解析后的行列、文件路径和变量
    "raw": '{"msg":'', "fileUrl":'', "lineNo":'', "columnNo":'', "error":''}',//onerror的五个参数
    "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4X Build/MMB29M; wv)..." //navigator.userAgent
}

 

 

发送邮件

邮件提醒是很有必要的一个功能,目前已经实现实时邮件提醒功能。 公司企业邮箱建个单独的邮箱就叫frontendmonitor@吧,当后端接口收到报错后,把解析数据通过这个邮箱发送给前端,达到提醒效果。   如果是用QQ邮箱或者个人邮箱应该需要在账户里开启smtp服务,QQ企业邮箱是默认开启此功能的。  邮件功能要注意性能和优化问题,不能因为前端报错太多导致服务器挂掉。

 

实际使用后的优化

  • 我们发现不同的浏览器报错的变量可能不一样,同一个报错在chrome浏览器和firefox上 columnNo 参数一点偏差。  用两种报错解析了一下,如下图,报错的代码都是18行,是没问题的,Firefox报错是下图第一个:console 18 0 true,chrome是testBase 18 0 true,行数没问题,偏差不影响我们最终查错,我的18行源代码是:console.log(testBase)。  testBase是故意没有申明,testBase是undefined,出问题的应该是testBase这个变量,过从报错情况上看,确实是谷歌浏览器更精准一点。  虽然不在意IE,不过IE11报错列数和firefox一致。

    

  • 页面触发事件报错,用户一直触发按钮,这时就会不停上报错误信息。解决:存储上一个报错信息和时间,进行比对,同一个报错,短时间内避免一直重复发送。
  • 框架模板报错,被框架本身捕获,不会触发window.onerror,需要使用框架本身的全局监听捕获信息后手动上传,这里需要加手动上传错误信息的方法。
  • 引入监控的项目,由于业务原因可能需要上传一些业务信息方便分析,所以预留一个配置字段,上传错误的时候请求会带上业务相关信息。

 

总结

这种非业务服务,来源于个人兴趣和思考,并没有上层压力需要你做或者什么时候做完。  从最开始有个想法、去调研、去找后端同事求助、 开干到最终落地。  这个过程需要自己坚持做下去,因为害怕自己不能最终落地,所以抓紧时间,一步步去实现每个细节的想法,让事情尽快落地和上线,以免自己对这个事情越拖越久。  作为需求方,更好的把握整个项目,加上自己的兴趣,所以这次自己也学习了一点go语言,保证能看懂后端代码和了解后端逻辑,最好能做一点开发,这次在后端同事代码的基础上,实现了发邮件的小功能,我称之为浅入浅出,装完逼就跑路~  现在第一版已经上线,并且在刚上线不到两个小时,就收到了报错邮件,吓得我急忙查找bug,很快查出来了问题来,这个bug应该存在很久了,但是因为没有阻塞性,并且没有影响到业务,也一直没被发现,结论是我们这个前端异常监控功能还是很成功!  后期还有很多功能需要开发,统计、数据可视化、智能报警等等。  第一版落地,就为以后的迭代和进化打下了良好基础。

在做这个事情的过程中,我是想尽快把事情落地,时间也很紧张,也并没有做非常充分的调研,比如现成的一些开源项目是怎么做的。  后来从同事那里了解到 sentry 这些三方开源项目之后,也有一点失落过,虽然我也解决了我的需求,但是三方的开源项目是一个非常完善的系统,提供了很多功能,比我这个强大多了,那我做这个到底有什么意义, 感觉完全和别人比拼不上,未来我这个项目会继续迭代吗,有继续迭代的必要吗?   以后有特殊定制化的需求的时候,也许自己开发的才容易更适应业务,可是有那个机会吗?  这一次落地已经达到我最初的要求了,也能帮我解决目前问题,未来还有很多挑战和迭代等待着,我会带着它一路过关斩将,还是半路死掉?   我想说:

 

最后大力地感谢我司后端同事的大力支持!!~

 

<h3 id="sec3.1">3.1 涉及底层JIRA流程</h3> <!-- 提示用户可以查看详情页 --> <div class="note"> <p>点击左侧目录中的“详细”图标查看该内容的独立详情页,适合完整阅读。</p> </div> <!-- 添加完整详细3.1.1 --> <div class="detail-section"> <h3>3.1.1 背景与目标</h3> <h4>3.1.1.1 背景</h4> <p>随着项目规模扩大和团队人数增加,原有的问题处理流程暴露出以下痛点:</p> <ul> <li> <h5>问题分类不明确,流转效率低下</h5> <p>缺乏统一的问题归类标准,导致问题在项目或多个团队流转时增加不确定性。</p> </li> <li> <h5>责任归属不清晰,团队间推诿</h5> <p>问题分配机制和责任人界定不完善,问题解决的推动效率降低。</p> </li> <li> <h5>缺乏标准化字段,统计分析困难</h5> <p>没有标准化字段体系支撑,无法轻松完成问题类型、数量或原因的数据统计分析。</p> </li> <li> <h5>新成员学习成本高,流程掌握时间长</h5> <p>流程不直观,新成员需要时间熟悉复杂的分类或操作。</p> </li> </ul> <h4>3.1.1.2 目标</h4> <div class="field-detail"> <ol> <li><strong>定义标准化操作步骤</strong>:为底层工程师提供清晰的问题处理流程</li> <li><strong>优化问题流转效率</strong>:通过字段分类实现问题快速分配</li> <li><strong>确保数据可追溯</strong>:完整记录问题处理过程,便于后续分析</li> <li><strong>降低学习曲线</strong>:新成员可快速掌握团队工作流程</li> </ol> </div> </div> <!-- 添加完整详细3.1.2 --> <div class="detail-section"> <h3>3.1.2 JIRA流程相关字段属性介绍</h3> <h4>字段属性介绍</h4> <table> <thead> <tr> <th>字段名称</th> <th>字段说明</th> <th>填写要求</th> </tr> </thead> <tbody> <tr> <td><strong>Component/s</strong></td> <td>用于指定涉及底层问题所对应的技术栈,例如 IoHwAb_Stack, Com_Stack 等。</td> <td>必填字段,至少选一个技术栈模块。如果Custom_2不是“非BSW问题”,需要重新检查Component/s选择正确的协议栈来匹配问题。(流程的任何阶段都可以修改属性)</td> </tr> <tr> <td><strong>Custom_1</strong></td> <td>用于问题的快速流转。需要处理问题的部门分类,例如 BSW(基础软件)、HW(硬件)、ASW(应用层软件)、Other(其他)。</td> <td>试点项目必填字段(建jira和流转问题时关注),确保问题建立时明确责任归属或下一步流转对象。</td> </tr> <tr> <td><strong>Custom_2</strong></td> <td>涉及底层问题分析的结果归类</td> <td>必填字段,根据问题分析结果选择适当选项,支持动态调整。(流程的任何阶段都可以修改属性)</td> </tr> <tr> <td><strong>Assignee</strong></td> <td>问题的任务负责人或分配人,它表示当前任务或者工作项(如 Story、Task、Bug 等)被分配给了谁,需要由这个人来完成任务或处理问题。。</td> <td>在确定问题分类后指派给合适的责任人,例如底层开发工程师或平台工程师。</td> </tr> <tr> <td><strong>Comment</strong></td> <td>自由文本,记录问题的描述、分析说明以及责任转交原因。</td> <td>重要字段,用以清晰记录问题处理过程,便于后续问题追踪或评估。</td> </tr> </tbody> </table> </div> <!-- 添加完整详细3.1.3 --> <div class="detail-section"> <h3>3.1.3 字段属性的具体类别</h3> <h4>3.1.3.1 Component/s 属性</h4> <ol> <p><strong>定义:</strong> 表示问题的初步分类,例如 BSW、HW、ASW 等。</p> <p><strong>适用范围:</strong> 全部项目。</p> <p><strong>类型列表:</strong> 用于简单分类问题所涉及的技术栈模块,以规范问题范围。</p> <table> <thead> <tr> <th>类型</th> <th>说明</th> <th>关键模块</th> </tr> </thead> <tbody> <tr> <td><strong>Cdd_Stack</strong></td> <td>为特定硬件设备或自定义硬件提供支持,针对复杂设备功能,满足标准化 API 无法实现的需求。</td> <td> <p>• 自定义设备驱动(CDD): 根据具体设备需求开发的驱动模块。</p> <p>• RTE(运行时环境): 确保与上层通信。</p> <p>• 直接与硬件寄存器交互以实现底层逻辑。</p> </td> </tr> <tr> <td><strong>Com_Stack</strong></td> <td>管理 ECU 间及 ECU 与外部工具的通信,确保信号与数据高效、稳定传输。</td> <td> <p>• Com(通信管理器): 应用层管理信号与 PDU。</p> <p>• PduR(PDU 路由模块): 管理上下层模块的数据路由。</p> <p>• 接口模块(CAN/LIN/FlexRay/Ethernet): 如 CanIf、LinIf。</p> <p>• SoAd 和 TcpIp: 提供以太网通信功能。</p> </td> </tr> <tr> <td><strong>Diag_Stack</strong></td> <td>提供 ECU 的诊断支持,包括故障记录、诊断服务和外部工具交互,符合 UDS(ISO 14229)标准。</td> <td> <p>• Dcm(诊断通信管理器): 提供诊断服务(如读取故障码)。</p> <p>• Dem(诊断事件管理器): 记录并存储故障信息。</p> <p>• FIM(故障禁用管理): 管理功能禁用逻辑。</p> </td> </tr> <tr> <td><strong>CybSec_Stack</strong></td> <td>提升 ECU 通信安全性,保证数据完整性、机密性,并防护潜在的恶意攻击。</td> <td> <p>• SecOC(安全本地通信模块): 确保通信完整性和真实性。</p> <p>• CryIf(加密接口模块): 提供通用的加密接口。</p> <p>• Csm(加密服务管理器): 调度加密算法。</p> <p>• KeyM(密钥管理模块): 管理密钥生成与分配。</p> <p>• 防火墙模块: 过滤并保护数据流。</p> </td> </tr> <tr> <td><strong>Fbl_Stack</strong></td> <td>符合 ISO 26262 标准,提供功能安全支持,避免关键系统由于故障进入危险的运行状态。</td> <td> <p>• WDG(看门狗模块): 防止死锁并监控硬件运行状况。</p> <p>• E2E(端到端保护模块): 提供通信完整性和一致性保护</p> <p>• SafeM(安全管理模块): 检测并处理系统威胁。</p> </td> </tr> <tr> <td><strong>IoHwAb_Stack</strong></td> <td>提供硬件与上层的标准化接口,屏蔽硬件差异,适用于传感器与执行器的控制需求。</td> <td> <p>• IoHwAb(硬件抽象层): 屏蔽底层硬件差异化。</p> <p>• ADC(模数转换模块): 负责信号数字化。</p> <p>• PWM: 提供执行器的信号控制。</p> <p>• DIO: 处理数字 I/O 信号。</p> <p>• Gpt: 软硬件定时功能支持。</p> </td> </tr> <tr> <td><strong>Mem_Stack</strong></td> <td>管理 ECU 中非易失性数据(如 EEPROM 和 Flash)的读写,保障数据一致性和可靠性。</td> <td> <p>• MemIf(存储接口): 提供统一访问接口。</p> <p>• NvM(非易失性存储管理模块): 管理重要数据存储。</p> <p>• Fee(Flash EEPROM 仿真模块): 负责模拟 EEPROM 功能。</p> <p>• Ea(EEPROM 抽象层): 提供直接存储支持。</p> </td> </tr> <tr> <td><strong>ModeMgm_Stack</strong></td> <td>管理 ECU 的运行模式切换(如启动、运行、休眠等),协调多模块模式同步。</td> <td> <p>• BswM(基础软件模式管理器): 协调 BSW 的模式切换。</p> <p>• EcuM(ECU 管理模块): 控制运行模式切换。</p> <p>• ModeSwitch: 提供统一切换接口。</p> <p>• RTE: 支持应用与基础软件运行协调。</p> </td> </tr> <tr> <td><strong>Sys_Stack</strong></td> <td>系统服务栈:提供基础服务支持(如断电保护、中断管理等),保障 ECU 系统运行稳定性与效率。</td> <td> <p>• RTE(运行时环境): 负责系统接口协调。</p> <p>• Scheduler(调度模块): 提供任务调度支持。</p> <p>• EcuM: 支持 ECU 生命周期管理。</p> <p>• Diagnostic Services: 提供核心诊断功能。</p> </td> </tr> <tr> <td><strong>OS_Stack</strong></td> <td>操作系统栈:提供基于 AUTOSAR 标准的实时操作系统(RTOS),用于实现任务管理、调度以及多任务间的通讯和同步。</td> <td> <p>• OSEK/VDX 兼容 OS: 支持多任务调度与优先级管理。</p> <p>• 资源管理模块: 确保任务安全访问硬件资源。</p> <p>• 任务调度模块: 依据优先级或时间分片执行任务分配。</p> </td> </tr> </tbody> </table> </ol> <br> <h4>3.1.3.2 Custom_1 属性</h4> <ol> <li><strong>定义:</strong> 表示问题的初步分类,例如 BSW(基础软件)、HW(硬件)、ASW(应用软件)等。</li> <li><strong>适用范围:</strong> 仅在 <strong>试点项目流程</strong> 中使用。</li> <li><strong>定义:</strong> 用于简单分类问题所涉及的技术栈模块,以规范问题范围。</li> <table> <thead> <tr> <th>类型</th> <th>说明</th> <th>示例场景</th> </tr> </thead> <tbody> <tr> <td><strong>BSW</strong></td> <td>基础软件问题</td> <td>Timer 配置错误</td> </tr> <tr> <td><strong>HW</strong></td> <td>硬件相关问题</td> <td>电路问题导致功能失效。</td> </tr> <tr> <td><strong>ASW</strong></td> <td>应用软件问题。</td> <td>软件控制逻辑失效</td> </tr> <tr> <td><strong>Other</strong></td> <td>其他问题。</td> <td>无法明确定位的问题场景</td> </tr> </tbody> </table> </ol> <br> <h4>3.1.3.3 Custom_2 属性</h4> <ol> <li><strong>定义:</strong> 在底层问题处理过程中,进一步对问题进行详细分类,辅助后续分析和统计。</li> <li><strong>适用范围:</strong> 全部项目</li> <li><strong>定义:</strong> ?。</li> <table> <thead> <tr> <th>类型</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td><strong>开发设计问题</strong></td> <td>底层代码或设计中的缺陷导致的问题。</td> </tr> <tr> <td><strong>需求问题</strong></td> <td>客户需求逻辑不明确,存在设计问题或错误。 没有明确给到底层</td> </tr> <tr> <td><strong>平台问题</strong></td> <td>问题涉及平台设计相关问题。 非项目Base。</td> </tr> <tr> <td><strong>三方包问题</strong></td> <td>第三方软件包相关问题。。</td> </tr> <tr> <td><strong>非BSW问题</strong></td> <td>问题非底层问题,应用层或非问题。</td> </tr> </tbody> </table> </ol> </div> <!-- 添加完整详细3.1.4 --> <div class="detail-section"> <h3>3.1.4 流程说明</h3> <h4>3.1.4.1 常规项目流程(无Custom_1属性)</h4> <div class="flowchart-container"> <div class="mermaid"> flowchart TD A[创建 JIRA] --> B[将任务分配给底层工程师] B --> C[底层工程师根据问题描述填写 Component/s] C --> D[底层工程师分析问题并填写 Custom_2] D --> E{问题分类是否为底层问题?} E -- 是 --> F[检查并更新 Component/s 的正确性] E -- 否 --> G[无需更新 Component/s] F --> H[流程完成或流转至下一节点] G --> H[流程完成或流转至下一节点] </div> </div> <br> <h4>3.1.4.2 试点项目流程(有Custom_1属性)</h4> <div class="flowchart-container"> <div class="mermaid"> flowchart TD A[创建 JIRA] --> B[填写 Custom_1 属性进行问题初步分类] B --> C{问题分类是否为 BSW?} C -- 是 --> D[流程流转到 BSW TL 负责人] C -- 否 --> E[流转非BSW处理] D --> F[BSW TL 审核并分配给对应底层工程师] F --> G[底层工程师根据问题描述填写 Component/s 属性] G --> H[底层工程师分析问题并填写 Custom_2] H --> I{问题分类是否为底层问题?} I -- 是 --> J[检查并更新 Component/s 属性的正确性] I -- 否 --> K[无需更新 Component/s 属性] J --> L[底层工程师将问题回传给 BSW TL] K --> L[底层工程师将问题回传给 BSW TL] L --> M[BSW TL 检查并流转至下一个步骤] </div> </div> </div> <!-- 添加完整详细3.1.5 --> <div class="detail-section"> <h3>3.1.5 底层JIRA闭环</h3> <h4>3.1.5.1 重点Satck复盘</h4> <ol> <p><strong>定义:</strong> http://10.190.3.206:8080/cb/wiki/895157。</p> <p><strong>适用范围:</strong> 全部项目。</p> <p><strong>类型列表:</strong> 用于简单分类问题所涉及的技术栈模块,以规范问题范围。</p> <table> <thead> <tr> <th>类型</th> <th>说明</th> <th>关键模块</th> </tr> </thead> <tbody> <tr> <td><strong>Cdd_Stack</strong></td> <td>为特定硬件设备或自定义硬件提供支持,针对复杂设备功能,满足标准化 API 无法实现的需求。</td> <td> <p>• 自定义设备驱动(CDD): 根据具体设备需求开发的驱动模块。</p> <p>• RTE(运行时环境): 确保与上层通信。</p> <p>• 直接与硬件寄存器交互以实现底层逻辑。</p> </td> </tr> </tbody> </table> </ol> <br> <h4>3.1.5.2 项目 JIRA 底层健康度</h4> <br> <h5>3.1.5.2.1 说明</h5> <ol> <p><strong>定义:</strong> 项目 JIRA 健康度是衡量项目运行状态和质量的一种综合性指标。通过分析 JIRA 系统中的关键属性(如问题类型、任务状态、流转效率等),评估项目的执行情况和管理水平。</p> <p><strong>数据来源:</strong><a href="https://superset.cn.kostal.int/superset/dashboard/81/?native_filters_key=sFUtjAalYPrgQTk65C9T5ERbP2ZbcDJnl82bQ2-X9N4paTeyNIL-dpl89MjyFCSZ" target="_blank">BSW_JIRA Superset</a></p> <p><strong>适用范围:</strong> Superset 监控的项目。</p> <p><strong>健康度组成:</strong></p> <table border="1" style="border-collapse: collapse; width: 100%; text-align: left;"> <thead> <tr style="background-color: #f0f0f0;"> <th>组成部分</th> <th>来源</th> <th>健康度占比</th> <th>具体公式计算</th> </tr> </thead> <tbody> <tr> <td><strong>初步分析完成度</strong></td> <td>涉及底层JIRA的Component/s的完成情况,完成标签的个数占涉及底层的jira数</td> <td>20%</td> <td> - 如果无底层参与,得分为 20%。<br> - 否则:完成数量 / 总数量 * 20%。 </td> </tr> <tr> <td><strong>底层分析结束完成度</strong></td> <td>涉及底层JIRA的Custom_2的完成情况,完成标签的个数占涉及底层的jira数</td> <td>40%</td> <td> - 如果无底层参与,得分为 40%。<br> - 否则:分析完成数量 / 总数量 * 40%。 </td> </tr> <tr> <td><strong>底层问题占比</strong></td> <td>Custom_2为底层问题jira数占总jira的比例</td> <td>30%</td> <td> - 如果无总数量,则得分为 30%。<br> - 如果计算结果 > 1,得分为 30%。<br> - 如果计算结果 < 0,得分为 0。<br> - 否则:动态得分 = (1.4 - (底层问题数 + 涉及底层jira未分析数)/总数*2) * 30%。 </td> <tr> <td><strong>长期不流转</strong></td> <td>当前jira的assignee在底层工程师,超过7天没有处理或超过15天没有处理</td> <td>10%</td> <td> - 如果无底层参与,得分为 10%。<br> - 若 7 天未处理占比 > 30% 或 15 天未流转占比 > 10%,得分为 0。<br> - 否则,根据惩罚公式:1 - 2 * (7 天未处理占比) - 5 * (15 天未流转占比),结果乘 10%。 </td> </tr> </tbody> </table> <br> <p><strong>备注:</strong></p> <ul> <li><strong>涉及底层jira:</strong> 项目中assignee给底层工程师的jira,包括当前和过去</li> <li><strong>不规范填写:</strong> 由于Custom_2是文本格式,所以不能主观修改定义好的类别。写过一次 Custom_2 的类别后,系统会记住该类别,下一次可以直接选择之前使用过的类别。</li> </ul> </ol> <br> <h5>3.1.5.2.2 不规范提醒及健康值公布</h5> <ol> <p><strong>周提醒:</strong> 实时健康值(2025/5/1之后到当前)+每月健康值(-60天到-30天的)+超期提醒(全部时间范围内)</p> <ol> <p><strong>提醒内容:</strong> 包含ProjectNo+Responsible+健康度,按照assignee划分的时效性报告</p> <p><strong>备注:</strong>周提醒邮件收到之后,项目的底层责任人会收到当前负责的项目未处理jira清单,发件人:底层JIRA处理提示no-reply@kostal.com</p> </ol> <br> <p><strong>月汇报:</strong> 健康值度+上个月重点Stack复盘说明</p> <ol> <p><strong>提醒内容:</strong> 月度底层总jira健康度及存在的问题点,每个项目的健康度和改进意见</p> </ol> </ol> </div>
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值