前端监控之sourcemap精准定位和还原错误源码

news2024/11/22 19:50:39

一、概述

在前端开发中,监控和错误追踪是确保应用稳定性和用户体验的重要环节。

随着前端应用的复杂性增加,JavaScript错误监控变得尤为重要。在生产环境中,为了优化加载速度和性能,前端代码通常会被压缩和混淆。这虽然提升了性能,但也给错误追踪带来了挑战,因为错误报告中显示的代码位置和实际代码不一致,使得开发者难以定位和修复问题。

Sourcemap技术应运而生,它是一种将压缩后的代码映射回原始源代码的工具。通过sourcemap,开发者可以准确地从错误报告中找到原始代码中的问题所在,即使这些代码已经被压缩或混淆。这种映射关系使得错误追踪变得更加精确和高效。

在这篇文章中,将探讨如何在前端项目中集成sourcemap,以及如何利用sourcemap进行错误监控和代码还原。我将介绍sourcemap的生成、部署和使用,以及它在前端监控中的最佳实践。通过这些内容,同学们将能够理解sourcemap在前端错误监控中的重要性,并学会如何利用这一工具提高开发效率和应用质量。

二、实践

通过sourcemap技术实现对前端代码中错误位置的精确定位和还原。

2.1、Sourcemap结构

Sourcemap文件通常包含以下字段:

  • version:Sourcemap的版本,目前常用的是版本3。
  • file:转换后的文件名。
  • sourceRoot:源文件的根目录路径,用于重新定位源文件。
  • sources:源文件列表,可能包含多个文件。
  • sourcesContent:源文件的内容列表(可选)。
  • names:转换前的变量名和属性名列表。
  • mappings:一个编码的字符串,记录了源代码和转换后代码之间的详细映射关系。

2.2、初始化项目

使用我自己实现的前端action-cli脚手架,从自己GitHub仓库拉取模板并初始化一个Vite+Vue3+TS项目,安装依赖运行项目。

更多关于action-cli可以查看这两篇文章

实现一个自定义前端脚手架_前端自定义脚手架-CSDN博客

重构Action-cli前端脚手架-CSDN博客

添加下面两个路由

const routes=[
  {
    path: '/errorView',
    name: 'ErrorView',
    component: () => import('@/views/sourcemap/ErrorView.vue'),
    meta: {
      title: '生产错误'
    }
  },
  {
    path: '/errorList',
    name: 'ErrorList',
    component: () => import('@/views/sourcemap/ErrorList.vue'),
    meta: {
      title: '错误列表'
    }
  }
];

// https://github.com/Topskys/admin-pro/tree/monitor

2.3、生产Js错误

创建./views/sourcemap/ErrorView.vue页面,通过throw模拟抛出Js代码错误。

// ./views/sourcemap/ErrorView.vue
<template>
  <div>
    <h1>Error</h1>
    <button @click="triggerTypeError()">触发TypeError</button>
    <button @click="triggerReferenceError">触发ReferenceError</button>
    <button @click="triggerSyntaxError">触发SyntaxError</button>
  </div>
</template>
<script setup lang="ts">
const triggerTypeError = () => {
  throw new TypeError('This is a type error');
};

const triggerReferenceError = () => {
  throw new ReferenceError('This is a reference error');
};

const triggerSyntaxError = () => {
  throw new SyntaxError('This is a syntax error');
};
</script>

配置vite.config.ts,将该页面打包成单个文件,并且需要开启sourcemap,方便测试。

// ...
build: {
      sourcemap: true,
      rollupOptions: {
        input: {
          index: fileURLToPath(new URL('./index.html', import.meta.url))
        },
        output: {
          // 将依赖单独打包
          manualChunks: (id: string) => {
            if (id.includes('node_modules')) {
              return 'vendor';
            }
            if (id.includes('src/views/sourcemap/ErrorView')) {
              return 'errorView';
            }
            return 'index';
          },
        }
      }
},

2.4、捕捉Js错误

这里需要安装两个依赖包,分别用于解析错误和解析sourcemap文件。

pnpm i error-stack-parser source-map-js

Vue3提供了一个捕捉全局错误的回调函数app.config.errorHandler,去main.ts实现这个方法的回调函数。

// main.ts
// ...

// 捕捉错误
app.config.errorHandler = (err: any, vm, info) => {
  console.log('err', err, '\nvm', vm, '\ninfo', info);
  const errorStack = ErrorStackParser.parse(err as Error);
  console.log('errorStack', errorStack);
}

点击触发TypeError,errorHandler函数就会捕捉到错误,并打印出错误和 error-stack-parser处理err后的效果

把错误信息存储到localStorage,方便其他页面展示错误列表信息。 

import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import ErrorStackParser from 'error-stack-parser';

const app = createApp(App);
app.use(router);

// 捕捉错误
app.config.errorHandler = (err: any, vm, info) => {
  const errorStack = ErrorStackParser.parse(err as Error);
  const jsError = {
    stack_frames: errorStack,
    message: err.message,
    stack: err.stack,
    error_name: err.name
  };
  console.error(`触发一个${err.name}错误`);
  localStorage.setItem('jsErrorList', JSON.stringify(jsError));
}

app.mount('#app');

2.5、展示错误列表

新建./views/sourcemap/ErrorList.vue错误列表页面,用于展示错误信息和映射到源码操作。

<template>
  <div v-if="isErr">
    <pre>
      {{ js_error.stack }}
    </pre>
    <el-collapse v-model="activeNames" @change="handleChange">
      <el-collapse-item v-for="(item, index) in js_error.stack_frames" :key="index" :title="item.source" :name="index">
        <el-row :gutter="20">
          <el-col :span="20">{{ item.fileName }}</el-col>
          <el-col :span="4">
            <el-button type="primary" size="small" @click="openDialog(item, index)">映射源码</el-button>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <template v-if="item.originalSource">
            {{ item.originalSource }}
            <!-- <Preview :origin="item.originalSource" /> -->
          </template>
          <template v-else>{{ item.functionName }}</template>
        </el-row>
      </el-collapse-item>
    </el-collapse>
    <el-dialog v-model="dialogVisible" title="SourceMap源码映射" width="500">
      <el-tabs v-model="tabActiveName">
        <el-tab-pane label="本地上传" name="local">
          <el-upload drag :before-upload="sourcemapUpload">
            <i class="el-icon-upload"></i>
            <div>将文件拖拽到此处,或者<em>点击上传</em></div>
          </el-upload>
        </el-tab-pane>
        <el-tab-pane label="远程加载" name="remote"> </el-tab-pane>
      </el-tabs>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
// https://github.com/Topskys/admin-pro/tree/monitor/src/views/sourcemap
</script>

从localStorage获取错误数据初始化列表

const getErrorList = () => {
  try {
    const errorString = localStorage.getItem('jsErrorList');
    if (!errorString) return;
    js_error.value = JSON.parse(errorString);
    isErr.value = true;
  } catch (error: any) {
    console.log('获取错误列表失败', error);
  }
};

onMounted(() => {
  getErrorList();
});

弹窗用于上传本地打包后的sourcemap文件。

// 打开弹窗
const openDialog = (item: any, index: number) => {
  dialogVisible.value = true;
  stackFrameObj = {
    line: item.lineNumber, // 错误代码行号
    column: item.columnNumber, // 错误代码列号
    index: index // 列表需序号
  };
};

 错误列表

处理sourcemap上传事件和解析 

const sourcemapUpload = async (file: any) => {
  if (file.name.substring(file.name.lastIndexOf('.') + 1) !== 'map') {
    ElMessage({
      message: '请上传正确的sourcemap文件',
      type: 'error'
    });
    return;
  }
  const reader = new FileReader();
  reader.readAsText(file);
  reader.onload = async function (e: any) {
    const code = await getSource(e?.target?.result, stackFrameObj.line, stackFrameObj.column);
    js_error.value.stack_frames[stackFrameObj.index].originalSource = code;
    dialogVisible.value = false;
  };
  return false; // 不写这一行会报错
};

获取报错ErrorView.vue页面的sourcemap文件,一般真实项目会把打包后的源码和sourcemap文件分别部署到不同的服务器,来提升安全性。 注意在本地不能还原,上传sourcemap后会报错404,因此需要把项目部署到github 静态资源服务器。

// 请求并解析sourcemap文件
const getSource = async (sourcemap: any, line: number, column: number) => {
  try {
    const consumer = await new sourceMap.SourceMapConsumer(JSON.parse(sourcemap));
    const originalPosition = consumer.originalPositionFor({ line, column });
    const source = consumer.sourceContentFor(originalPosition.source);
    // console.log('本地报错404source', source);
    return {
      source: source,
      line: originalPosition.line,
      column: originalPosition.column
    };
  } catch (e) {
    ElMessage.error('sourcemap解析失败');
  }
};

2.6、错误源代码展示

新建./views/sourcemap/Preview.vue组件,用于处理和展示还原后的源代码。

<template>
  <div class="pre-code">
    <div class="error-detail">
      <pre class="error-code" v-html="preLine()"></pre>
    </div>
  </div>
</template>
// js部分可参考github仓库monitor分支
// https://github.com/Topskys/admin-pro/tree/monitor

2.7、构建CI/CD

基于github actions构建ci/cd流水线,这里就不详细赘述了,不知道的同学可以阅读这篇文章基于Github Actions实现前端CI/CD持续集成与部署_github cicd-CSDN博客 

把触发流水线的分支改成monitor分支,因为当前是在monitor发开并测试sourcemap映射源代码。

三、效果

3.1、触发ci/cd

运行打包命令

提交代码到monitor分支触发流水线自动化部署。

3.2、测试还原

测试sourcemap还原错误源代码,访问https://topskys.github.io/admin-pro/#/生产错误页面,点击触发错误按钮触发错误。

打开错误列表页面,可以看到错误信息生成。展开列表第一个错误,点击映射源码。

 选择上传errorView.vue报错页面对应的map文件(真正项目线上环境从其它服务器获取map文件),以解析出源代码。

 上传之后,就能看到错误列表中已经还原出精准的行错误源代码(标红行)了,行号和源代码都一致。

 具体代码实现过程可前往github仓库的monitor分支查看

admin-pro/src/views/sourcemap at monitor · Topskys/admin-proicon-default.png?t=O83Ahttps://github.com/Topskys/admin-pro/tree/monitor/src/views/sourcemap

四、参考

基于Github Actions实现前端CI/CD持续集成与部署_github cicd-CSDN博客

重构Action-cli前端脚手架-CSDN博客

实现一个自定义前端脚手架_前端自定义脚手架-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2245516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法编程题-排序

算法编程题-排序 比较型排序算法冒泡排序选择排序插入排序希尔排序堆排序快速排序归并排序 非比较型排序算法计数排序基数排序 本文将对七中经典比较型排序算法进行介绍&#xff0c;并且给出golang语言的实现&#xff0c;还包括基数排序、计数排序等非比较型的算法的介绍和实现…

Jenkins修改LOGO

重启看的LOGO和登录页面左上角的LOGO 进入LOGO存在的目录 [roottest-server01 svgs]# pwd /opt/jenkins_data/war/images/svgs [roottest-server01 svgs]# ll logo.svg -rw-r--r-- 1 jenkins jenkins 29819 Oct 21 10:58 logo.svg #jenkins_data目录是我挂载到了/opt目录&…

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…

云讷科技Kerloud无人飞车专利发布

云讷科技Kerloud无人飞车获得了“一种室内外两用的四旋翼无人飞车”的实用新型专利证书&#xff0c;作为科教社区第一款四旋翼飞车&#xff0c;这项技术结合了无人机和无人车的优势&#xff0c;提供了一种能够在多种环境下使用的多功能飞行器。 这项设计的优势如下&#xff…

Applied Intelligence投稿

一、关于手稿格式&#xff1a; 1、该期刊是一个二区的&#xff0c;模板使用Springer nature格式&#xff0c; 期刊投稿要求&#xff0c;详细期刊投稿指南&#xff0c;大部分按Soringernature模板即可&#xff0c;图片表格声明参考文献命名要求需注意。 2、参考文献&#xff…

Spark SQL大数据分析快速上手-完全分布模式安装

【图书介绍】《Spark SQL大数据分析快速上手》-CSDN博客 《Spark SQL大数据分析快速上手》【摘要 书评 试读】- 京东图书 大数据与数据分析_夏天又到了的博客-CSDN博客 Hadoop完全分布式环境搭建步骤-CSDN博客,前置环境安装参看此博文 完全分布模式也叫集群模式。将Spark目…

零基础上手WebGIS+智慧校园实例(1)【html by js】

请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01; 等下再更新一下1. WebGIS矢量图形的绘制&#xff08;超级详细&#xff01;&#xff01;&#xff09;&#xff0c;2. WebGIS计算距离&#xff0c; 以及智慧校园实例 with 3个例子&#xff01;&#xff01;…

[开源] 告别黑苹果!用docker安装MacOS体验苹果系统

没用过苹果电脑的朋友可能会对苹果系统好奇&#xff0c;有人甚至会为了尝鲜MacOS去折腾黑苹果。如果你只是想体验一下MacOS&#xff0c;这里有个更简单更优雅的解决方案&#xff0c;用docker安装MacOS来体验苹果系统。 一、项目简介 项目描述 Docker 容器内的 OSX&#xff08…

IDEA:2023版远程服务器debug

很简单&#xff0c;但是很多文档没有写清楚&#xff0c;wocao 一、首先新建一个远程jvm 二、配置 三、把上面的参数复制出来 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 四、然后把这串代码放到服务器中&#xff08;这里的0.0.0.0意思是所有IP都能访问&a…

卷积神经网络的padding是什么?如何计算?

文章目录 为什么需要padding&#xff1f;1.Valid Padding&#xff08;有效填充&#xff09;2.Same Padding&#xff08;相同填充&#xff09;2.1.如何计算padding&#xff1f;1. 计算总 padding2. 分配 padding&#xff1a; 2.2.举例子1. 步幅为 1 的 Same Padding2. 步幅不为 …

介绍一下strncmp(c基础)

strncmp是strcmp的进阶版 链接介绍一下strcmp(c基础)-CSDN博客 作用 比较两个字符串的前n位 格式 #include <string.h> strncmp (arr1,arr2,n); 工作原理&#xff1a;strcmp函数按照ACII&#xff08;字符编码顺序&#xff09;比较两个字符串。它从两个字符串的第一…

列出D3的所有交互方法,并给出示例

D3.js 提供了丰富的交互方法&#xff0c;可以用来增强图表的用户交互体验。以下是一些常用的交互方法及其示例&#xff1a; 1. 鼠标事件 on("mouseover", function) 用途: 当鼠标悬停在元素上时触发。示例:svg.selectAll(".bar").on("mouseover&qu…

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL&#xff08;丹摩智算&#xff09; 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…

基于大数据爬虫数据挖掘技术+Python的网络用户购物行为分析与可视化平台(源码+论文+PPT+部署文档教程等)

#1024程序员节&#xff5c;征文# 博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老…

六、卷积神经网络(CNN)基础

卷积神经网络&#xff08;CNN&#xff09;基础 前言一、CNN概述二、卷积层2.1 卷积2.2 步幅(Stride)2.3 填充(Padding)2.4 多通道卷积2.5 多卷积计算2.6 特征图大小计算2.7 代码演示 三、池化层3.1 池化层计算3.1.1 最大池化层3.1.2 平均池化层 3.2 填充(Padding)3.3 步幅(Stri…

国标GB28181视频平台EasyCVR视频融合平台H.265/H.264转码业务流程

在当今数字化、网络化的视频监控领域&#xff0c;大中型项目对于视频监控管理平台的需求日益增长&#xff0c;特别是在跨区域、多设备、高并发的复杂环境中。EasyCVR视频监控汇聚管理平台正是为了满足这些需求而设计的&#xff0c;它不仅提供了全面的管理功能&#xff0c;还支持…

Jmeter中的断言(四)

13--XPath断言 功能特点 数据验证&#xff1a;验证 XML 响应数据是否包含或不包含特定的字段或值。支持 XPath 表达式&#xff1a;使用 XPath 表达式定位和验证 XML 数据中的字段。灵活配置&#xff1a;可以设置多个断言条件&#xff0c;满足复杂的测试需求。 配置步骤 添加…

实验室管理解决方案:Spring Boot技术

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…

【STM32】USART串口数据包

数据包的作用是将一个个单独的数据打包起来&#xff0c;方便进行多字节的数据通信 数据包格式 HEX数据包 文本数据包 数据包接收 HEX数据包接收&#xff08;固定包长&#xff09; 文本数据包接收&#xff08;可变包长&#xff09; 串口收发HEX数据包 接线图 Serial模块 se…

Ubuntu下的Eigen库的安装及基本使用教程

一、Eigen库介绍 简介 Eigen [1]目前最新的版本是3.4&#xff0c;除了C标准库以外&#xff0c;不需要任何其他的依赖包。Eigen使用的CMake建立配置文件和单元测试&#xff0c;并自动安装。如果使用Eigen库&#xff0c;只需包特定模块的的头文件即可。 基本功能 Eigen适用范…