前端業務的監控與埋點數據的上報

我曾經在 2018 年 12 月底的時候,發表過Vue 單頁面中進行業務數據的上報,現在這 1 年多以來,我對此也有了更深的理解。

這裡,我們還是主要探討業務數據的上報,關於頁面性能和錯誤日誌的收集上報,不在此討論範圍內。

我們前端團隊的業務數據上報功能,主要集中在新聞客戶端內部,依賴於新聞客戶端提供的特性,因此其他團隊的前端上報組件是沒辦法適應我們的需求的,這裡我本人基於之前上報的經驗,開發了一套完整的前端業務埋點數據上報組件。

在開發這套組件之前,我們要先明確幾個問題:

  1. 哪些數據是可以自行收集的,哪些數據需要開發者埋點上報;
  2. 開發者進行數據埋點的方式有哪些?
  3. 如何保障設備的唯一性;
  4. 跳轉前的上報丟失如何處理;
  5. 在新聞客戶端、微信、QQ 等環境都可以進行上報;
  6. 單頁面應用中,切換頁面時如何上報;
  7. 用戶並未退出頁面,而是切換了 APP,又重新切換回來怎麼辦?
  8. 是否支援自定義上報的方式?

上面的這些疑問,我們一一進行了解決。

1. 可以自行收集的資訊與設備唯一性

很多資訊都是可以自行收集,而不用每個開發者都收集一遍,例如基於新聞客戶端提供的能力,可以拿到設備資訊,已登錄用戶的個人資訊,ua 等,都是可以自行收集的,然後存儲起來。

不過在新聞客戶端外,就無法拿到設備資訊了。我在這裡,通過前端生成一個盡量唯一 的碼來標識設備,並存儲到 cookie 和 localStorage 中,若存在則使用,若不存在則生成一個新的。以此來保證設備的唯一性。

let uid = cookie.getCookie('wzpuser') || localStorage.getItem('wzpuser');
if (!uid) {
    uid = 'gh' + Date.now() + (Math.random() + '').substr(-6);
    cookie.setCookie('wzpuser', uid, 360);
    localStorage.setItem('wzpuser', uid);
}
this.__data.uid = uid;
return Promise.resolve(this.__data);

開發者可以更加關注在頁面和用戶行為上。

2. 開發者進行數據埋點的方式有哪些?

主要有 2 種方式,一個是開發者的主動上報:

reporter.send({
    pagename: 'mainpage',
    event_id: 'banner_click',
});

還有一種方式,是在 html 元素上添加data-reporter屬性,然後進行事件冒泡,若遇到 data-reporter 後,則進行上報;若一直冒泡到 document 上都沒有該屬性,則不上報。

// 渲染每一個專場
const renderItem = (item: SpecialItem) => (
    <div
        data-reporter={JSON.stringify({
            pagename: 'mainpage',
            event_id: 'item_click',
        })}
    >
        <div
            className="cover"
            onClick={() => handleAnswer(item.ename, item.zhname, item)}
        >
    </div>
);

3. 跳轉前的上報丟失如何處理

我們經常需要上報點擊某個鏈接的 pv,但通常會存在上報還沒有完成,頁面已經卸載了,導致上報失敗。

針對這種情況,我是在跳轉前,先存儲到本地,等下次重新回到這個頁面時,將存儲的數據進行上報。為了方便傳入和存儲,我對欄位也進行了過濾,沒有數據的欄位全部去掉,只上報有數據的欄位。

reporter.send(
    {
        pagename: 'mainpage',
        event_id: 'link_click',
    },
    'save'
); // 先進行存儲
window.location.href = '//www.xiabingbao.com';

4. 在新聞客戶端、微信、QQ 等環境都可以進行上報

新聞客戶端中提供了一些獲取設備資訊和用戶資訊的能力,而微信、QQ、瀏覽器等環境,只能使用前端的一些騷操作了,例如分析 cookie 中的欄位,ua 中的一些欄位等等。

這裡我也編寫了一個工具方法//github.com/wenzi0github/utils,將這些能力獨立出來。歡迎 star。

5. 單頁面應用中,切換頁面時如何上報

這個問題沒有很好地解決,雖然能監聽到 history 路由和 hash 路由的變化(前端中的 hash 和 history 路由),但頁面的名稱需要提前定義好,而組件是不知道的,因此這裡交給開發者開進行監聽路由的變化並上報數據。

// 每個hash路由的PV上報
router.afterEach((to) => {
    // to為當前已打開的頁面,to.name為在router/index.ts中設定的name
    reporter.send({
        pagename: to.name,
        event_id: 'pv',
    });
});

6. 用戶並未退出頁面,而是切換了 APP,又重新切換回來怎麼辦?

用戶沒有退出頁面,而是使用了系統級的 home 鍵,進行了 APP 的切換,其實用戶也是真實的離開了,若用戶重新回來,其實 page view 應該是要+1 的,然而頁面沒有刷新,會產生丟失 PV 的情況。

這裡我們可以監聽頁面的可見性,當頁面重新可見時,我們就把 pv+1。當然還有一種情況要考慮到:用戶可能只是在多個 APP 中切換,當前頁面只是其中的過客而已,而用戶並沒有真的進入到這個頁面中。因此我們需要設置下重新上報 PV 的條件:

  • 距離上次可見時有 30 分鐘左右;
  • 當前可見已有 5 秒以上;
let lastShowTime = 0; // 上次可見時的時間

const visibility = new PageVisibility();
visibility.visibilityChange((isShow) => {
    let timer;
    if (isShow && Date.now() - lastShowTime >= 1000 * 60 * 30) {
        // 頁面可見時
        timer = setTimeout(() => {
            report.send({
                pagename: 'mainpage',
                event_id: 'pv',
            });
        }, 5000); // 5秒後上報
    } else {
        clearTimeout(timer);
    }
});

7. 是否支援自定義上報的方式

組件中提供了 img 標籤上報和 post 方式的方式,如果這兩種方式也不滿足上報要求,可以自定義上報方式,並上報到對應的伺服器上。

const report = new Report({
    actid: 56,
    adapter: (data) => {
        // 要上報的數據
        console.log(data);
    },
});

8. 總結

埋點數據上報

通過這次業務埋點數據的上報,也了解了很多基礎功能的實現,同時還有如何提供自定義的能力。

歡迎我的公眾號,多多交流:
蚊子的部落格