前端如何进行日志驱动开发
日志在開(kāi)發(fā)過(guò)程中的作用自不必說(shuō),一旦程序出現(xiàn)問(wèn)題,我們首先想到的是通過(guò)日志監(jiān)控去追查。
好的日志可以通過(guò)應(yīng)用程序執(zhí)行的歷史記錄模擬出用戶(hù)在使用程序的時(shí)候操作的完整過(guò)程。
想知道發(fā)生了什么
為了便于我們分析程序哪里出現(xiàn)問(wèn)題,我們將采用logrock模塊并將其鏈接到ElasticSearch,LogStash和Kibana進(jìn)行進(jìn)一步分析。
LogRock
logrock模塊源于研究Cleverbrush時(shí)候的創(chuàng)新。它是一個(gè)用于處理矢量圖形的軟件。使用圖形編輯器意味著大量的應(yīng)用程序用例。為了控制成本,不得不優(yōu)化整個(gè)開(kāi)發(fā)測(cè)試流程。減少每個(gè)環(huán)節(jié)使用測(cè)試用例帶來(lái)的額外的付出。
該模塊可以為您的應(yīng)用程序組織現(xiàn)代化的日志記錄方法。 根據(jù)日志,我們測(cè)試了我們的應(yīng)用程序。 在本文中,我將向您介紹如何組織日志系統(tǒng)以搜索錯(cuò)誤。
ElasticStack
- ElasticSearch是一個(gè)功能強(qiáng)大的全文搜索引擎。
- LogStash是一個(gè)用于從各種來(lái)源收集日志的系統(tǒng),該系統(tǒng)也可以將日志發(fā)送到ElasticSearch。
- Kibana是ElasticSearch的Web界面版,其中包含許多插件。
它是如何工作的
一旦程序出現(xiàn)錯(cuò)誤(或者用于特殊模擬),則應(yīng)用程序會(huì)將日志發(fā)送到服務(wù)器,然后將日志保存到文件中。Logstash將數(shù)據(jù)增量保存到ElasticSearch數(shù)據(jù)庫(kù)。用戶(hù)登錄到Kibana并查看保存的日志。
以上就是一個(gè)配置好的Kibana的界面,顯示了來(lái)自ElasticSearch的數(shù)據(jù)。它可以幫助您分析數(shù)據(jù)并從中了解程序發(fā)生了什么故障。
這里就不一一將如何去設(shè)置ElasticStack。
創(chuàng)建日志系統(tǒng)
這里我們將一個(gè)日志記錄系統(tǒng)集成到基于React開(kāi)發(fā)的單頁(yè)應(yīng)用程序中。
Step 1:安裝
npm install logrock --saveStep 2:集成到React應(yīng)用程序中
import { LoggerContainer } from "logrock";<LoggerContainer><App /> </LoggerContainer>LoggerContainer是一個(gè)捕捉應(yīng)用程序中的錯(cuò)誤并將它們形成堆棧的組件。
堆棧是一個(gè)對(duì)象,其中包含有關(guān)用戶(hù)的操作系統(tǒng),瀏覽器,按下的鼠標(biāo)或鍵盤(pán)按鈕的信息,當(dāng)然還有操作相關(guān)的子數(shù)組,其中記錄了用戶(hù)在系統(tǒng)中執(zhí)行的所有的操作。
LoggerContainer含有配置項(xiàng),可適當(dāng)考慮更改其中的一些設(shè)置。
<LoggerContaineractive={true|false}limit={20}onError={stack => {sendToServer(stack);}} ><App /> </LoggerContainer>- active 開(kāi)啟關(guān)閉日志功能
- limit 設(shè)置最近用戶(hù)操作的最大闕值。如果超過(guò)這個(gè)值,那么數(shù)組中的第一個(gè)值將會(huì)被刪除。數(shù)組中始終保持最近的20個(gè)操作信息。
- onError 當(dāng)錯(cuò)誤出發(fā)時(shí)的一個(gè)回調(diào)。返回參數(shù)stack對(duì)象包含環(huán)境,用戶(hù)操作等信息。在回調(diào)中我們需要將這些信息上傳到ElasticSearch,云端,或者保存到本地文件中,為后面進(jìn)行數(shù)據(jù)分析和監(jiān)控做準(zhǔn)備。
打印日志
為了生產(chǎn)高質(zhì)量的用戶(hù)操作日志,我們將日志代碼覆蓋到所有需要打印日志的地方
logrock模塊附帶一個(gè)與 LoggerContainer 連接的記錄器。
例如,我們有以下這樣一個(gè)組件:
import React, { useState } from "react";export default function Toggle(props) {const [toggleState, setToggleState] = useState("off");function toggle() {setToggleState(toggleState === "off" ? "on" : "off");}return <div className={`switch ${toggleState}`} onClick={toggle} />; }為了能讓日志正確覆蓋到,我們需要修改toggle方法:
import React, { useState } from "react"; import logger from "logrock";export default function Toggle(props) {const [toggleState, setToggleState] = useState("off");function toggle() {let state = toggleState === "off" ? "on" : "off";logger.info(`React.Toggle|Toggle component changed state ${state}`);setToggleState(state);}return <div className={`switch ${toggleState}`} onClick={toggle} />; }我們添加了一個(gè)logger方法,其中的信息分為兩部分。‘React.Toggle’用于顯示該動(dòng)作發(fā)生在React的Toggle組件級(jí)別。后面是對(duì)該動(dòng)作和發(fā)生所在組件的一些描述信息。日志級(jí)別劃分不是必須的,但是這樣有助于我們快速定位錯(cuò)誤發(fā)生的有關(guān)代碼。
我們還可以使用 React 16 中引入的“componentDidCatch”方法來(lái)捕獲異常。
日志上傳
假設(shè)我們有一個(gè)從后端收集用戶(hù)數(shù)據(jù)的方法。該方法是異步的,部分邏輯隱藏在后端中。看看如何將日志添加到代碼中?
首先,由于我們有一個(gè)客戶(hù)端應(yīng)用程序,所有發(fā)送到服務(wù)器的請(qǐng)求都將在一個(gè)用戶(hù)會(huì)話(huà)內(nèi)傳遞,而無(wú)需重新加載頁(yè)面。 為了將客戶(hù)端上的操作與服務(wù)器上的操作相關(guān)聯(lián),我們必須創(chuàng)建一個(gè)全局SessionID并將其添加到針對(duì)服務(wù)器的每個(gè)請(qǐng)求頭的標(biāo)記中。 在服務(wù)器上,我們可以使用任何記錄器來(lái)記錄我們的邏輯,如前端示例所示,如果發(fā)生錯(cuò)誤,請(qǐng)將帶有附加sessionID的數(shù)據(jù)發(fā)送到ElasticSearch,發(fā)送到后端。
Step 1:客戶(hù)端生成SessionID
window.SESSION_ID = `sessionid-${Math.random().toString(36).substr(3, 9)}`;Step 2:封裝請(qǐng)求
我們需要將SessionID添加到請(qǐng)求頭中。如果我們使用以及封裝好的請(qǐng)求庫(kù),很容易將聲明好的SessionID添加到所有的請(qǐng)求中。
let fetch = axios.create({...});fetch.defaults.headers.common.sessionId = window.SESSION_ID;Step 3:將SessionID和日志堆棧綁定
LoggerContainer有專(zhuān)門(mén)的sessionID字段
<LoggerContaineractive={true | false}sessionID={window.SESSION_ID}limit={20}onError={stack => {sendToServer(stack);}} ><App /> </LoggerContainer>Step 4:請(qǐng)求后端接口
前端請(qǐng)求類(lèi)似下面:
logger.info(`store.getData|User is ready for loading... User ID is ${id}`);getData('/api/v1/user', { id }).then(userData => {logger.info(`store.getData|User have already loaded. User count is ${JSON.stringify(userData)}`);}).catch(err => {logger.error(`store.getData|User loaded fail ${err.message}`);});它是怎么運(yùn)行的呢?
我們?cè)诳蛻?hù)端請(qǐng)求之前寫(xiě)一個(gè)日志。 從我們的代碼中,我們可以看到現(xiàn)在開(kāi)始從服務(wù)器下載數(shù)據(jù)。 我們已將SessionID附加到請(qǐng)求。 如果我們的后端日志包含此SessionID的添加而請(qǐng)求失敗,那么我們可以看到后端發(fā)生了什么。
因此,我們不僅在客戶(hù)端而且還在服務(wù)器上監(jiān)視應(yīng)用程序的整個(gè)周期。
用戶(hù)交互
有些日志對(duì)用戶(hù)是有幫助的。向用戶(hù)輸出必要的信息可以采用 stdout 方法
<LoggerContaineractive={true | false}limit={20}bsodActive={true}bsod={BSOD}onError={stack => {sendToServer(stack);}}stdout={(level, message, important) => {console[level](message);if (important) {alert(message);}}} ><App /> </LoggerContainer>- stdout 方法用于打印提示信息到頁(yè)面中
我們通過(guò)logger傳遞的第二個(gè)參數(shù)的值為true來(lái)聲明這是一個(gè)重要的信息,需要通過(guò)pop-up窗口顯示給用戶(hù)看,比如在數(shù)據(jù)加載的時(shí)候失敗了,我們將輸出以下錯(cuò)誤信息:
logger.log('Something was wrong', true);一些注意項(xiàng)
- 日志監(jiān)控(包括生產(chǎn)環(huán)境),因?yàn)闇y(cè)試人員永遠(yuǎn)無(wú)法覆蓋所有的測(cè)試用例,完全模擬到用戶(hù)操作
- 不要忘記在許可協(xié)議中提及日志收集。
- 不要在日志中記錄用戶(hù)密碼,銀行詳情地址等敏感的個(gè)人信息。
- 避免在日志中添加冗余信息,盡量保證簡(jiǎn)潔有用
總結(jié)
當(dāng)我們完成編碼對(duì)外發(fā)布應(yīng)用程序的時(shí)候,如果把程序比作一個(gè)生命,那么這個(gè)生命才剛剛開(kāi)始。收集并監(jiān)視日志可以獲得產(chǎn)品的反饋幫助更好的改善。
歡迎關(guān)注公眾號(hào)“太空編程”,帶你了解硬核的編程知識(shí)
總結(jié)
以上是生活随笔為你收集整理的前端如何进行日志驱动开发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何搭建一个内部组件共享平台
- 下一篇: 金三银四跳槽面试季,我整理前端知识做了个