前端業務的監控與埋點數據的上報
- 2020 年 9 月 4 日
- 筆記
- javascript, 前端技術, 監控
我曾經在 2018 年 12 月底的時候,發表過Vue 單頁面中進行業務數據的上報,現在這 1 年多以來,我對此也有了更深的理解。
這裡,我們還是主要探討業務數據的上報,關於頁面性能和錯誤日誌的收集上報,不在此討論範圍內。
我們前端團隊的業務數據上報功能,主要集中在新聞客戶端內部,依賴於新聞客戶端提供的特性,因此其他團隊的前端上報組件是沒辦法適應我們的需求的,這裡我本人基於之前上報的經驗,開發了一套完整的前端業務埋點數據上報組件。
在開發這套組件之前,我們要先明確幾個問題:
- 哪些數據是可以自行收集的,哪些數據需要開發者埋點上報;
- 開發者進行數據埋點的方式有哪些?
- 如何保障設備的唯一性;
- 跳轉前的上報丟失如何處理;
- 在新聞客戶端、微信、QQ 等環境都可以進行上報;
- 單頁面應用中,切換頁面時如何上報;
- 用戶並未退出頁面,而是切換了 APP,又重新切換回來怎麼辦?
- 是否支援自定義上報的方式?
上面的這些疑問,我們一一進行了解決。
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. 總結
通過這次業務埋點數據的上報,也了解了很多基礎功能的實現,同時還有如何提供自定義的能力。
歡迎我的公眾號,多多交流: