乐趣区

关于前端:编写谷歌扩展便捷自测埋点上报信息是否正确

编写 ” 谷歌扩大 ” 便捷 ” 自测 ” 埋点上报信息是否正确

举荐我之前写的谷歌扩大入门 &svelte 入门文章:

记一次前端 ”chrome 扩大 ” 简略易懂的实战分享会 (上)
记一次前端 ”chrome 插件 ” 根底实战分享会 (倡议珍藏)(下篇)
聊聊 Svelte.js 技术它做了什么以及如何实现的 (上)
聊聊 Svelte.js 技术它做了什么以及如何实现的(下)

背景

     每次开发完我的项目的埋点性能后都须要进行埋点自测, 此时我只能通过在控制台的 Network 上进行筛选, 因为埋点的申请参数是个 ” 对象类型 ”, 须要将传参逐一点开并且找到 params 这个 key, 然而 params 是一个被 json 序列化的字符串, 须要进行 JSON.parse(xxxxx.params);, 而后再关上它外面的 数组构造 因为可能是多个埋点信息一起上报所以 JSON.parse 后是个数据, 最初还要将外面的十个固有参数过滤掉只看咱们新增的埋点参数。

     上述过程很有法则所以能够形象成一个工具查找的逻辑, 那咱们能够把问题拆解成 3 步:

  1. (展现)有适合的界面不便显示你想要的申请数据。
  2. (获取)拦挡到你想要的申请。
  3. (解决)将申请的参数按固定规定解析, 剔除不须要查看的参数与父级。
  4. (配置)可配置哪些申请须要被监测。

     当然不只是 埋点 这个性能, 只有你有剖析 api 数据的需要都能够做相似的插件。

最终成果

一、模仿数据的定义

     埋点上报数据我这里展现一个大略的数据结构, 大家依据业务自行调节, 假如上面的数据结构就是埋点上报 api 的上报参数

[
  {
    events: [
      {
        eventName: "事件名: 点击事件",
        params:
          '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx","new1":"nnnnnn1","new2":"nnnnnn2"}',
        xxxxxxxx: 1636179764881,
        xxxxxxx: 0,
      },
      {
        eventName: "事件名: 勾销事件",
        params:
          '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx","new1":"nnnnnn2","new3":"nnnnnn3"}',
        xxxxxxxx: 1636179764881,
        xxxxxxx: 0,
      },
    ],
    user: {
      userId: 123,
      userName: "lulu",
    },
    header: {
      app_id: 999,
      os_name: "mac",
      os_version: "10_15_7",
      device_model: "Macintosh",
      language: "zh-CN",
    },
  },
];
  1. 传参自身是个 ” 对象类型 ”
  2. 第一层次要是 ” 埋点事件 ”, “ 用户信息 ”, “ 设施信息 & 更多 ”
  3. “events” 是事件数组
  4. “eventName” 事件名称, “params” 外面是被 ”JSON 序列化 ” 的事件参数
  5. “params” 里有一些咱们不必看的默认值, 因为每个埋点都会带一些像 ” 门路信息 ”&” 停留事件 ”&” 用户操作门路 ” 等等的默认信息, 这些信息不必咱们手动退出所以也就不必每次都看他的正确性。
  6. “new1, new2, new3″ 是咱们新退出的参数, 也就是咱们这次重点验证的参数

二、模仿埋点数据的收回

     编写两个按钮负责上报埋点申请, 不便咱们后续的验证, 新建一个 html 文件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button onclick="send(`https://zhangzhaosong1.com/`)"> 点击上报 1 </button>
    <button onclick="send(`https://zhangzhaosong2.com/`)"> 点击上报 2 </button>
    <script>
      function send(url) {
        fetch(url, {
          method: "post",
          headers: {"Content-Type": "application/json;charset=utf-8;",},
          body: JSON.stringify([
            {
              events: [
                {
                  eventName: "事件名: 点击事件",
                  params:
                    '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx","new1":"nnnnnn1","new2":"nnnnnn2"}',
                  xxxxxxxx: 1636179764881,
                  xxxxxxx: 0,
                },
                {
                  eventName: "事件名: 勾销事件",
                  params:
                    '{"default1":"xxxxx","default2":"xxxxx","default3":"xxxxx","default4":"xxxxx","default5":"xxxxx","default6":"xxxxx","startTime":"xxxxx","endTime":"xxxxxxx","new1":"nnnnnn2","new3":"nnnnnn3"}',
                  xxxxxxxx: 1636179764881,
                  xxxxxxx: 0,
                },
              ],
              user: {
                userId: 123,
                userName: "lulu",
              },
              header: {
                app_id: 999,
                os_name: "mac",
                os_version: "10_15_7",
                device_model: "Macintosh",
                language: "zh-CN",
              },
            },
          ]),
        }).then(() => {});
      }
    </script>
  </body>
</html>

     下面 html 外面次要做的工作是增加两个 ” 按钮 ”, 每次点击收回埋点的模仿上报的 post 申请, 每个按钮上报的不一样所以有两个按钮。

三、创立一个谷歌插件我的项目 & 定义图标

     没看过基础课的同学肯定要先看看根底文章, 否则没法转换思维。

主文件

manifest.json

{
  "manifest_version": 2,
  "name": "埋: 更不便的察看埋点数据",
  "description": "更不便的察看埋点数据",
  "version": "0.1",
  "browser_action": {"default_icon": "images/logo.png"}
}

上述的图标大家自由发挥哈

引入插件

四、定义控制台 tab

     在 manifest.json 文件外面减少

{
  "manifest_version": 2,
  "name": "埋: 更不便的察看埋点数据",
  "description": "更不便的察看埋点数据",
  "version": "0.1",
  "browser_action": {"default_icon": "images/logo.png"},
  "devtools_page": "devtools/index.html" // 这句是新增的
}

devtools/index.html次要性能只是引入 js 文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="./index.js"></script>
</body>
</html>

devtools/index.js次要性能是创立 tab

chrome.devtools.panels.create(
  "埋点验证 tab, 还原埋点上报信息",
  null,
  "../panel/index.html",
  function () {console.log("自定义面板创立胜利!");
  }
);

panel/index.html 外面才是 tab 的内容区款式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div> 创立胜利 </div>
</body>
</html>

五、初始化 svelte 我的项目

     tab 外面的内容咱们懒得原生操作 dom, 应用 ”react” 框架有点重, 所以这次我抉择了 ”svelte 框架 ”, 具体它的益处能够看看我之前写的文章(文章放在文章头部了)。

初始我的项目
npx degit sveltejs/template devpanel

cd ./devpanel

yarn

咱们编辑一下 rollup.config.js文件, 使得打包后的文件间接放入 panel 文件夹里。

  output: {
    sourcemap: false,
    format: "iife",
    name: "app",
    file: production ? "../panel/index.js" : "public/build/bundle.js",
  },

并且将 panel 外面的 index.html 文件的文件援用指向咱们的index.js 文件, 以及引入款式 <link rel="stylesheet" href="./bundle.css">

在这里运行命令 yarn build 后的成果如下, 请点击刷新插件并且 ”F12″ 从新关上控制台:

开发时候在localhost:5000/, 开发完打包就能够和插件一起上线了。

六、拦挡申请

     外围性能就是拦挡申请, 让咱们应用onRequestFinishedapi

chrome.devtools.network.onRequestFinished.addListener((res) => {})

     下面的返回值 res 的数据格式如下图:

     要害信息都有, 申请办法与 url 能够用来比对是否为须要拦挡的申请, 而咱们剩下的工作就是对 ”text” 的解析了。

     要留神的是, svelte外面无奈读取到 chrome 的值, 所以须要用 if (chrome) {} 包裹起来, 所以在 svelte 外面开发时我应用的是 mock 数据调试。

七、解决数据

<script>
  const path = "https://zhangzhaosong.com/";
  import getNowTime from "./getNowTime";

  if (chrome) {
    let checkEvent = "";
    let dataList = [];
    const baseKeyArr = [
      "default1",
      "default2",
      "default3",
      "default4",
      "default5",
      "default6",
      "startTime",
      "endTime",
    ];
    chrome.devtools.network.onRequestFinished.addListener((res) => {
      const req = res.request;
      if (req.method === "POST" && req.url === path) {const eventsArr = JSON.parse(req.postData.text);
        eventsArr.forEach((item) => {if (item.events) {item.events.forEach((event) => {const params = JSON.parse(event.params);
              const res = {};
              for (let i in params) {if (!baseKeyArr.includes(i)) {res[i] = params[i];
                }
              }
              dataList.unshift({
                res,
                time: getNowTime(),
                eventName: event.eventName,
              });
              dataList = dataList;
            });
          }
        });
        console.log("---", dataList);
      }
    });
  }
</script>

<main>
  <div>list</div>
</main>

<style>
</style>

  1. baseKeyArr这个数组外面是一些埋点默认的key, 用来过滤掉咱们不关怀的值
  2. path是要拦挡的申请地址, 当然也能够换成正则之类的
  3. getNowTime获取以后的工夫

八、简略设计个款式

     将下面失去的数组循环显示进去, 造成一个被拦挡的埋点事件的参数 list:

<main>
  {#each Object.keys(dataList) as item}
    <div>
      <header>
        <span>{dataList[item].time} : </span>
        <span class="title">{dataList[item].eventName}</span>
      </header>
      <ul>
        {#each Object.keys(dataList[item].res) as key}
          <li>
            <span>{key} :</span>
            <span>{dataList[item].res[key]}</span>
          </li>
        {/each}
      </ul>
    </div>
  {/each}
</main>

<style>
  .title {background-color: bisque;}
</style>

九、过滤性能与革除性能

     为了好用咱们能够增加一个过滤性能与革除性能, 这样查看起来更难受:

end

     网站快卡炸了, 这次就是这样, 心愿与你一起提高。

退出移动版