前端監控系列,SDK,服務、存儲 ,會全部總結一遍,寫文不易,點個贊吧
監控的內容我們已經說了很多了,那麼我們一般上報一條監控內容都具體包含什麼數據呢
今天就來詳細列舉一下
本文列出的數據會這樣說明
1、有什麼數據
2、作用是什麼
3、怎麼獲取
我會給每個具體分個類,按分類來逐個說明
數據大概分爲下面幾類
1、監控點數據
2、用戶信息
3、設備信息
4、項目信息
5、日誌信息
下面就按這個分類來說明裏麪包含的詳細數據
這個就是每個監控點類型相應的數據,像接口請求信息,靜態資源,首屏測速等等
具體可以在相應的文章中查看
3、頁面錯誤監控
4、單頁首屏測速
所以這裏就不一一列舉了,本文主要是講一些公共的監控數據
不過這裏簡單說個接口信息的監控數據
cgi | 接口鏈接 |
status | 狀態碼 |
body | 請求體 |
responce | 響應 |
reqHeader |
請求header |
code |
接口狀態碼 |
cost_time |
接口耗時 |
包括用戶的特徵,唯一標識等等
uin
用戶的賬號信息。如果是QQ 登陸,就是QQ 號,微信登陸就是 微信uin(不是微信號),或者你們公司自己登錄體系下的賬號
下面是獲取 qq 或者 微信uin
function getCookie(name) {
const cookieReg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
const matches = document.cookie.match(cookieReg);
return !matches ? '' : decodeURIComponent(matches[2]);
}
function getQQUin() {
const uin = getCookie('p_luin') || getCookie('p_uin') || getCookie('uin');
return uin ? parseInt(uin.replace(/[^\d]/g, ''), 10).toString() : null;
}
function getWeixinUin() {
const uidUin = getCookie('uid_uin');
return uidUin || null;
}
微信uin 是創建微信時分配的獨有的uin,不是微信號,因爲微信號能改,並不唯一。大概像這樣 14411xxxxxxxx134
地區
國家、省、市 這些位置信息,在服務端通過客戶端ip 做解析
可以使用 npm 包 node-ip2region 來解析
簡單使用如下
const searcher = require('node-ip2region').create();
const res = searcher.btreeSearchSync('120.68.22.68');
console.log(res);
返回結果如下
{
city: 0,
region: '中國|0|新疆|伊犁|電信',
}
具體可以看
設備標識 - aid
頁面初始化的時候,會給用戶分配一個儘可能唯一的id標識,存在localstorage 中。
可以使用 uuid 生成,或者自己寫一個
const getRandomId = () => {
const aid = 'xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
return aid;
}
會話標識 - sessionId
同樣也是唯一的id 標識,但是表示的是會話id,存在 sessionStorage 中。
比如你這次打開頁面,爲你生成一個,接着你的任何操作都會帶上這個id。
下次再打開頁面時,會重新生成。
生成方式和 aid 一樣
關於設備信息的數據就比較多了,對於前端比較重要,前端看重兼容性,各端的支持五花八門,定位問題需要考慮這一點
設備信息,一般我們可以通過 navigator.userAgent 來獲取,拿到以下這些字段
os | 系統以及版本 |
brand | 品牌(蘋果,華爲,小米 等) |
device |
產品型號(Huawei P30、Mate40...等等) |
engine | 瀏覽器渲染引擎 |
browser | 瀏覽器以及版本 |
具體我們會使用一個 npm 包來解析拿到相應的數據
https://github.com/faisalman/ua-parser-js
使用方式如下
const parser = require('ua-parser-js');
const sliceVersion = (version, count = 2) => {
if (!version) return '';
return version.split('.').slice(0, count).join('.');
};
const parserUa = (ua) => {
const { browser = {}, os = {}, engine = {}, device = {} } = parser(ua);
return {
browser: browser.name
? `${browser.name}(${sliceVersion(browser.version)})`
: '',
device: device.vendor ? `${device.vendor} - ${device.model || ''}` : '',
os: os.name ? `${os.name} - ${os.version || ''}` : '',
engine: engine.name
? `${engine.name}(${sliceVersion(engine.version)})`
: '',
brand: device.vendor || '',
};
};
比如 userAgent 是
Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
可以解析得到
關於渲染引擎,大概有這麼幾種
1、IE瀏覽器 (Trident內核)
2、Firefox (Gecko內核)
3、Safari (Webkit內核)
4、Chrome (Blink內核)
5、Opera (原爲Presto內核,現爲Blink內核)
6、QQ/WX (原爲Webkit內核,現爲Blink內核)
網絡狀態 netType
用戶網絡狀態很重要,有可能用戶加載慢時因爲網絡不行,所以需要記錄這個指標
具體先從 navigator.userAgent 中獲取,因爲微信會將網絡類型注入 ua。
看一個 wx 的 userAgent 例子
Mozilla/5.0 (Linux; Android 10; VOG-AL00 Build/HUAWEIVOG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/045811 Mobile Safari/537.36 MMWEBID/2264 MicroMessenger/8.0.11.1980(0x28000B3B) Process/tools WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64
其次我們再從 navigator.connection 中獲取,但是兼容性有點問題,iOS 不支持這個。
代碼如下
const NetworkTypeNum = {
unknown: 'unknown',
wifi: 'wifi',
net2g: '2g',
net3g: '3g',
net4g: '4g',
net5g: '5g',
net6g: '6g',
};
const parseNumberType = (net) => {
net = String(net).toLowerCase();
if (net.indexOf('4g') >= 0) return NetworkTypeNum.net4g;
if (net.indexOf('wifi') >= 0) return NetworkTypeNum.wifi;
if (net.indexOf('5g') >= 0) return NetworkTypeNum.net5g;
if (net.indexOf('6g') >= 0) return NetworkTypeNum.net6g;
if (net.indexOf('3g') >= 0) return NetworkTypeNum.net3g;
if (net.indexOf('2g') >= 0) return NetworkTypeNum.net2g;
return NetworkTypeNum.unknown;
};
const getNetworkType = function () {
let netType = '';
// 優先從 ua 中獲取(微信會將網絡類型注入 ua)
const arr = navigator.userAgent.match(/NetType\/(\w+)/);
if (arr) {
[, netType] = arr;
} else if (navigator.connection) {
// navigator.connection 存在兼容性問題,當前不支持 ios
netType = navigator.connection.effectiveType || navigator.connection.type;
}
if (!netType) {
netType = 'unknown';
}
const net = parseNumberType(netType);
return;
}
客戶端 ip
客戶端ip 需要在服務端獲取了
function getClientIp(req) {
try {
const xff = (
req.headers['X-Forwarded-For']
|| req.headers['x-forwarded-for']
|| ''
).split(',')[0].trim();
return xff
|| req.connection.remoteAddress
|| req.socket.remoteAddress
|| req.connection.socket.remoteAddress;
} catch (ex) {
}
return '0.0.0.0';
}
網絡運營商 ISP
就是 中國移動,聯通,電信 那些數據,在服務端通過 ip 解析拿到,和上面解析省市區一樣
可以使用 npm 包 node-ip2region 來解析
簡單使用如下
const searcher = require('node-ip2region').create();
const res = searcher.btreeSearchSync('120.68.22.68');
console.log(res);
返回結果如下,最後一個就是運營商
{
city: 0,
region: '中國|0|新疆|伊犁|電信',
}
這一類數據可以幫助你查看用戶畫像,比如建立像下面這些可視化圖
主要是頁面相關的信息
頁面 url
就是頁面url 。可以便於根據 url 定位出所有數據,包括錯誤、資源、請求、性能 等數據,全方位評測出一個頁面的質量。
環境 env
一般環境分爲 local 本地開發環境、test 線上測試環境、pre 預發佈環境、prod 正式環境。
告警都是設置正式環境,測試環境錯誤日誌可不要浪費時間排查
項目 project
團隊有很多項目,上報的數據肯定要帶上項目名。便於你排查過濾日誌
監控npm包版本 sdk_version
項目引入的 監控 sdk 的版本也要記錄。
如果因爲sdk 導致日誌記錄的數據有問題,sdk 修復更新了版本之後,還存在有問題的日誌。需要查看它依賴的是否是更新之後的版本
項目更新標識 build_time | project_version
這個很重要,作用和上面差不多
比如你線上出現了一個很嚴重的bug,已經觸發告警了。
你修復之後,需要看線上運作情況
因爲仍然會存在錯誤日誌,所以需要一個字段去篩選修復之後的線上日誌。
可以使用項目打包構建的世界,可以使用項目版本號。不過考慮到一般的業務項目,不太會更新版本號
所以最好是在構建配置中注入一個構建時間變量,供SDK 獲取上報
日誌等級 level
在 離線日誌 中說過,日誌一般分有等級,來區分重要性,是否需要請求上報,存到本地作爲離線日誌
const LOG_LEVEL = {
trace: 10,
debug: 20,
info: 30,
warn: 40,
error: 50,
fatal: 60,
};
日誌類型 log_type
上報的日誌有很多類型,就像我們之前說的各種監控點一樣
1、離線日誌
2、頁面錯誤(細分很多種)
3、接口信息
4、靜態資源(細分很多種)
5、首屏時間
等等
const LOG_TYPE = {
pv: 'pv',
promise_error: 'promise_error',
offline: 'offline',
cgi_speed: 'cgi_speed',
resource_speed: 'resource_speed',
....
}
日誌時間 log_time
日誌發生的時間,一般是時間戳 Date.now()
日誌信息 message
一般用於項目內自定義上報存放文字信息的,便於查找對應日誌
比如上報 message="報名按鈕點擊",你就會搜索這個條件,看活動上線一共有多少人報名點擊
日誌數據 addition
一般用於項目內自定義上報存放 調試數據,便於排查哪個環節出了問題,類似於debug一樣,是否在處理數據過程中出現了問題
比如說項目中 catch 拿到的error,或者 表單提交時的數據。
你可能會說,提交的數據,我直接看接口請求的body 不就好了嗎,但是其實有時你的函數處理出問題,甚至都沒走到請求的這一步。
數據出問題的概率是很大的,不是像你本地開發調試一樣規規矩矩的數據,每一步的數據處理都要記錄下來,特別是那種format 的處理函數,入口和出口的數據都必須要記錄上報
看完上面這些字段,可以基本清楚,字段的設置無非是爲了方便你篩選合適日誌幫助排查,儘可能幫助還原問題場景,實打實從數據定位問題,不要靠猜想,靠自己偶然復現
鑑於本人能力有限,難免會有疏漏錯誤的地方,請大家多多包涵, 如果有任何描述不當的地方,歡迎後臺聯繫本人,領取紅包
本文分享自微信公衆號 - 神仙朱(skying-zhu)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。