サむトの゚ラヌ...どうすればいいですか

コヌドが実皌働に入るず、プログラマは䟿利な機胜ずずもに゚ラヌを倖郚にリリヌスしたす。 たずえば、特定のサむトで、小さな障害が発生する可胜性がありたす。これは、さたざたな理由に起因するものであり、その原因にはなりたせん。 自分の仕事を知っおいる開発者にずっお、自分の過ちに察凊し、耐えなければならない冒険に぀いおの圌らの話を聞いお、結果ずしおそれらを修正できるメカニズムを提䟛するこずは玠晎らしいこずです。



今日、プログラマヌのデビッド・ギルバヌト゜ンによる蚘事の翻蚳を共有したいず思いたす。圌は、Reactで曞かれたWebプロゞェクトの゚ラヌを远跡しお再珟できる実隓システムに぀いお話しおいたす。 このアプロヌチは他の環境に移すこずができるず信じおいたすが、すべおが順調です。

゚ラヌ報告のアプロヌチ


おそらく、Webプロゞェクトの゚ラヌに関する情報を収集するために、このようなシンプルなシステムを䜿甚しおいるのでしょう次の䟋では、私に石を投げないでください

window.onerror = err => fetch(`/errors/${err}`); 

゚ラヌレポヌトを確認するには、フレンドリヌなIT専門家に䟝頌しお、 /errorsで始たる404ペヌゞに関するすべおの蚘録を含むファむルを提䟛するだけで十分です。

ただし、このアプロヌチで埗られる「コヌド」は、゚ラヌが発生した正確な堎所を芋぀けるのに圹立ちたせん。 おそらく、ここで䜕かを改善し、ファむルず行番号に関する情報を含む゚ラヌメッセヌゞを生成する必芁がありたす。

 window.addEventListener('error', e => { fetch('/errors', {   method: 'POST',   body: `${e.message} (in ${e.filename} ${e.lineno}:${e.colno})`, }); }); 

このコヌドは良識のどこかでバランスを取っおいたすが、これたでのずころ、それはもっず深刻な䜕かの骚栌にすぎたせん。 ゚ラヌが特定のデヌタに関連しおいる堎合、行番号に関する情報は特に有益ではありたせん。

゚ラヌが発生した時点でナヌザヌのアクティビティに関する完党なレポヌトがあれば䟿利です。これにより、障害が発生した状況を再珟できたす。 たずえば、次のようなもの


ナヌザヌアクティビティレポヌト

最も興味深いのは、ナヌザヌが補品に関する詳现情報のペヌゞに移動しステップ4、賌入ボタン最埌の5番目のステップをクリックしたこずです。

特定の補品のデヌタに䜕か疑わしいこずが起こっおいるずすぐに掚枬できるため、同じリンクにアクセスしお、「これを$で賌入」ずいう賌入ボタンをクリックしたす。

もちろん、これを行った埌、私は同じ間違いを芋たす。 この特定のアむテムには䟡栌がないため、 toLocaleStringを呌び出すず倱敗したす。 私たちの前に、あたり経隓のない開発者の兞型的な監督がありたす。

しかし、ナヌザヌのサむトずのやり取りがはるかに耇雑な堎合はどうでしょうか ナヌザヌが䜜業をURLに反映しおいない倚くのタブの1぀であるか、フォヌムのデヌタをチェックしおいるずきに゚ラヌが発生した可胜性がありたす。 リンクをたどっおボタンをクリックしおも、このような゚ラヌは明らかになりたせん。

この状況では、゚ラヌが発生するたですべおのナヌザヌアクションを再珟できるようにしたいず考えおいたす。 理想的には、再生䞭に「次のステップ」ずいうボタンをクリックするだけです。

想像力を倱っおいないなら、これを自分自身に想像しおみおください。


DOMを芳察しおナヌザヌアクションを再珟する

画面に衚瀺される゚ラヌ情報ず゚ディタヌで開くファむルは、Reactアプリの䜜成のメリットです。

実隓の圢で、「モデレヌトされおいないナヌザビリティテスト」のようなものを実行できるシステムを実際に構築したこずに泚意しおください。 ナヌザヌのアクションを远跡しお再生するコヌドを䜜成し、知識のある1人のゞョンに、圌がこのすべおに぀いおどう思うかを尋ねたした。 圌はこれは銬鹿げたアむデアだず蚀ったが、私のコヌドぱラヌを再珟するのに圹立぀だろうず付け加えた。

実際、ここでこれに぀いおお話したいず思いたす。 ありがずう、ゞョン。

システムコア


問題のコヌドはここにありたす 。 あなたは私の話よりもそれを読むこずに興味があるかもしれたせん。 以䞋に関数の簡易バヌゞョンを瀺し、党文ぞのリンクを提䟛したす。

さたざたなナヌザヌアクションをむンタヌセプトするいく぀かの関数を含むモゞュヌルrecord.jsがありたす。 これはすべおjourneyオブゞェクトに分類され、゚ラヌが発生したずきにサヌバヌに転送できたす。

アプリケヌションの入力ポむントで、次のようなstartRecording()関数を呌び出しお情報の収集を開始したす。

 const journey = { meta: {}, steps: [], }; export const startRecording = () => { journey.meta.startTime = Date.now(); journey.meta.startUrl = document.location.href; journey.meta.screenWidth = window.innerWidth; journey.meta.screenHeight = window.innerHeight; journey.meta.userAgent = navigator.userAgent; }; 

゚ラヌが発生した堎合、 journeyオブゞェクトは、たずえば、分析のためにサヌバヌに送信できたす。 これを行うには、察応するむベントハンドラヌが接続されたす。

 window.addEventListener('error', sendErrorReport); 

sendErrorReport関数sendErrorReport 、 journeyオブゞェクトず同じモゞュヌルで宣蚀されたす。

 export const sendErrorReport = (err) => { journey.meta.endTime = Date.now(); journey.meta.error = `${err.message} (in ${err.filename} ${err.lineno}:${err.colno})`; fetch('/error', {   method: 'POST',   body: JSON.stringify(journey) }) .catch(console.error); }; 

ずころで、誰かがJSON.stringify(err)コマンドが゚ラヌの本文を提䟛しない理由を説明できれば、非垞にクヌルになりたす。

これたでのずころ、これらすべおに特別な利点はありたせん。 しかし、今では他のすべおを構築するためのフレヌムワヌクがありたす。

アプリケヌションが状態ベヌスの堎合぀たり、DOMがいく぀かの䞻芁な状態に基づいおのみ衚瀺される堎合、より簡単に生きるこずができたす゚ラヌが発生する可胜性が䜎くなるず想定しおリスクがありたす。 ゚ラヌを再珟しようずするず、単玔に状態を再䜜成できたす。これにより、この゚ラヌが発生する可胜性が高くなりたす。

アプリケヌションが最新のテクノロゞヌに基づいおいない堎合、バむンディングを䜿甚し、ナヌザヌがペヌゞず察話する方法に盎接基づいお䜕かを衚瀺するず、問題はもう少し耇雑になりたす。 ゚ラヌを再珟するには、マりスクリック、芁玠の損倱ずフォヌカスに関連するむベント、およびキヌボヌドキヌを抌すこずを再珟する必芁がありたす。 確かに、ナヌザヌがクリップボヌドからフィヌルドに䜕かを貌り付けた堎合の察凊方法を蚀うのは難しいず思いたす。 ここで私は実隓で幞運を願うこずができたす。

私は認めたいです-私は怠け者で利己的な人ですので、私が話すこずは私が扱う技術、すなわちReactずReduxで構築されたプロゞェクトに焊点を圓おたす。

これがたさに私が傍受したいものです


Reduxアクションむンタヌセプト


以䞋は、 journeyオブゞェクトのReduxアクションをむンタヌセプトしお保存するために䜿甚されるコヌドです。

 export const captureActionMiddleware = () => next => action => { journey.steps.push({   time: Date.now(),   type: INTERACTION_TYPES.REDUX_ACTION,   data: action, }); return next(action); }; 

最初に、構造= () => next => action => {を芋るこずができたす。これは、䞀芋理解できないこずはたったく䞍可胜です。 それでも理解できない堎合は、読んでください 。 確かに、これを掘り䞋げるのではなく、もっず重芁なこずをするほうがいいでしょう。たずえば、幞せな笑顔を描く緎習をしたす。これは、誕生日を祝犏するずきに圹立ちたす。

このコヌドで理解する最も重芁なこずは、プロゞェクトで果たす圹割です。 ぀たり、圌はReduxの「アクション」を実行䞭にjourneyオブゞェクトに配眮するのに忙しくしおいたす。

次に、Reduxリポゞトリを䜜成するずきに䞊蚘の関数を適甚し、リンクをこのapplyMiddleware()フレヌムワヌクの関数に枡したす。

 const store = createStore( reducers, applyMiddleware(captureActionMiddleware), ); ReactDOM.render( <Provider store={store}>   <App /> </Provider>, document.getElementById('root') ); 

URLの倉曎を蚘録する


URL倉曎キャプチャが実行される堎所は、アプリケヌションのルヌティング方法によっお異なりたす。

ReactルヌタヌはURLの倉曎を怜出するのにあたり圹に立たないので、 このアプロヌチ、たたは倚分これに頌らなければなりたせん。 Reactルヌタヌを䜿甚しお、 onRouteChangeハンドラヌを蚭定したいだけonRouteChange 。 これが私だけでなく必芁であるこずは泚目に倀したす。 たずえば、倚くは、仮想ペヌゞビュヌ情報をGoogleアナリティクスに送信する必芁に盎面しおいたす。

それはずもかく、私はほずんどのサむトのために私自身のルヌティングシステムを曞くこずを奜む、それは玄17分しかかからず、最終的に、起こるこずは非垞に高速であるこずが刀明したからだ。

URLの倉曎を傍受するために、URLが倉曎されるたびに呌び出される次の関数を準備したした。

 export const captureCurrentUrl = () => { journey.steps.push({   time: Date.now(),   type: INTERACTION_TYPES.URL_CHANGE,   data: document.location.href, }); }; 

私は圌女を2か所で呌びたす history.push()コマンドを実行しおURLを曎新するのず同じ堎所で、たたナヌザヌがブラりザの[ ]ボタンをクリックするず呌び出されるpopstateむベントでも

 window.addEventListener('popstate', () => { //  - ,     captureCurrentUrl(); }); 

ナヌザヌアクションの蚘録


おそらく、これは文字通りどこにでも埋め蟌む必芁があるため、サむトでの䜜業に関する情報を傍受するための最も「䟵入的な」メカニズムです。 それが私の欲望だけに䟝存しおいれば、私はこれを気にしたせん。 しかし、私が思ったように、ナヌザヌがどこをクリックしたかを正確に知らなければ再珟できない゚ラヌに遭遇したした。

いずれにせよ、タスクは面癜かったので、ここでその解決策に぀いお説明したす。 Reactで開発するずき、私は垞に<Link>および<Button>コンポヌネントを䜿甚したす;その結果、集䞭クリック代行受信システムの開発は非垞に簡単です。 <Link>芋おください

 const Link = props => ( <a   href={props.to}   data-interaction-id={props.interactionId} //     onClick={(e) => {     e.preventDefault();         captureInteraction(e); //           historyManager.push(props.to);   }} >   {props.children} </a> ); 

ここで話しおいるのは、 data-interaction-id={props.interactionId}およびcaptureInteraction(e); 。

セッションを再珟するずきが来たら、ナヌザヌがクリックしたものを匷調したいず思いたす。 これを行うには、䜕らかのセレクタヌが必芁です。 クリックした芁玠には識別子 id があるず自信を持っお述べるこずができたすが、䜕らかの理由で芚えおいないので、監芖システム甚に特別に蚭蚈されたものの方が良いず刀断したしたナヌザヌアクティビティ甚。

captureInteraction()関数は次のずおりです。

 export const captureInteraction = (e) => { journey.steps.push({   time: Date.now(),   type: INTERACTION_TYPES.ELEMENT_INTERACTION,   data: {     interactionId: e.target.dataset.interactionId,     textContent: e.target.textContent,   }, }); }; 

ここで完党なコヌドを芋぀けるこずができたす。このコヌドでは、セッションを再生した埌、芁玠が再び芋぀かるようにチェックされたす。

他の情報ず同様に、必芁なものを収集しお、 journey.steps.pushコマンドを実行したす。

スクロヌル


私が残しおいるのは、ナヌザヌが衚瀺しおいるペヌゞのどの郚分を正確に知るために、スクロヌルデヌタを蚘録するかだけを䌝えるこずです。 たずえば、ペヌゞが䞀番䞋に巻き戻されおフォヌムに入力し始めた堎合、スクロヌルせずにこれを再珟しおもあたりメリットはありたせん。

倚くの小さなむベントを蚘録する際にシステムリ゜ヌスを無駄にせず、 Lodashを䜿甚するために、連続するすべおのスクロヌルむベントを1぀のむベントに収集したす。

 const startScrollCapturing = () => { function handleScroll() {   journey.steps.push({     type: INTERACTION_TYPES.SCROLL,     data: window.scrollY,   }); } window.addEventListener('scroll', debounce(handleScroll, 200)); }; 

このコヌドの䜜業バヌゞョンでは 、連続スクロヌルに関連するむベントは陀倖されおいたす。

startScrollCapturing()関数は、アプリケヌションが初めお起動されたずきに呌び出されたす。

远加のアむデア


これは私のプロゞェクトで䜿甚されおいないアむデアの短いリストです。 おそらく、それらを実装する䟡倀があるず思うでしょう。


ここでは、蚘事の元のバヌゞョンを公開した埌に远加したした。 いく぀かのコメントで述べられおいるこずずは察照的に、この資料で説明されおいる方法は、個人デヌタのセキュリティたたは保護に関する远加の懞念を匕き起こさないこずに泚意できたす。 この堎合、すでにナヌザヌの機密デヌタを䜿甚しおいる堎合、そのようなデヌタの収集ず保存に適甚される芁件は、゚ラヌレポヌトを準備および送信するずきにも適甚される必芁がありたす。 たずえば、ナヌザヌに察応する質問をせずにフォヌムデヌタを自動的に保存しない堎合、ナヌザヌに質問せずに゚ラヌレポヌトを自動的に送信しないでください。 ナヌザヌの個人デヌタを送信する前に、特別なフィヌルドに蚭定されたチェックマヌクの圢でナヌザヌから同意を埗る矩務がある堎合は、゚ラヌレポヌトを送信する前に同じこずを行う必芁がありたす。 システムに登録するずきにアドレス/signupにナヌザヌデヌタを送信する堎合、たたぱラヌが発生する堎合にアドレス/errorにナヌザヌデヌタを送信する堎合、特別な違いはありたせん。 あちこちで最も重芁なこずは、デヌタを正しく合法的に扱うこずです。

おそらく、既に䌚話を終了しおいるず思われたすが、この時点では、ナヌザヌがサむトで行っおいるこずのみを蚘録したした。 次に、最も興味深い郚分、぀たり録音の再生を芋おみたしょう。

ナヌザヌアクションの再生


サむトでの䜜業䞭にナヌザヌが実行したアクションの再珟に぀いおは、次の2぀の問題に぀いお説明したす。


ナヌザヌアクションを再珟するためのむンタヌフェむス


このペヌゞでは、ナヌザヌのアクションを繰り返すために、 iFrame䜿甚されたすiFrameでは、Webサむトが開き、その䞊でjourneyオブゞェクトに以前に蚘録されたステップが再生されたす。

このペヌゞは、゚ラヌが発生したセッションに関する情報をダりンロヌドし、蚘録された各ステップをサむトに送信したす。サむトは状態を倉曎し、同じ゚ラヌが発生したす。

このペヌゞを開くず、芋苊しいシンプルなむンタヌフェむスが衚瀺されたす。その埌、iPadで衚瀺されおいるかのようにサむトが読み蟌たれたすここでは、タブレットの通垞の写真を䜿甚したした。
これは、蚘事の冒頭で瀺したのず同じアニメヌション画像です。 ここでそのコヌドを芋぀けるこずができたす。


ナヌザヌセッションを再生するプロセス

[ Next step ]ボタンをクリックするず、 iFrameにiFrame.contentWindow.postMessage(nextStep, '*')構造を䜿甚しおメッセヌゞiFrame送信されたす。 URLの倉曎に関連する䟋倖が1぀ありたす。 ぀たり、同様の状況では、 iFrame srcプロパティは単に倉曎されたす。 アプリケヌションの堎合、これは実際にはペヌゞ党䜓の曎新であるため、これが機胜するかどうかは、ペヌゞ間でアプリケヌションの状態を転送する方法によっお異なりたす。

わからない堎合、 postMessage — 、異なるりィンドり間の察話を提䟛するために䜜成されたWindowオブゞェクトのメ゜ッドです この堎合、これはペヌゞのメむンりィンドりずiFrame開かれたりィンドりです。

実際、ナヌザヌアクションを再珟するペヌゞに぀いお蚀えるこずはこれだけです。

倖郚からサむトを管理するためのメカニズム


サむトでの䜜業䞭にナヌザヌアクションを再珟するメカニズムは、 playback.jsファむルに実装されおいたす。

アプリケヌションの起動時に、リポゞトリに分類され、埌で呌び出すこずができるメッセヌゞを予期する関数を呌び出したす。 これは開発モヌドでのみ行われたす。

 const store = createStore( //     ); if (process.env.NODE_ENV === 'development') { startListeningForPlayback(store); } 

これは 、このコヌドが䜿甚される堎所です。

興味のある関数は次のようになりたす。

 export const startListeningForPlayback = (store) => { window.addEventListener('message', (message) => {   switch (message.data.type) {     case INTERACTION_TYPES.REDUX_ACTION:       store.dispatch(message.data.data);       break;     case INTERACTION_TYPES.SCROLL:       window.scrollTo(0, message.data.data);       break;     case INTERACTION_TYPES.ELEMENT_INTERACTION:       highlightElement(message.data.data.interactionId);       break;     default:       //  -   ,          return;   } }); }; 

ここでは、そのフルバヌゞョンを芋぀けるこずができたす。

Reduxアクションを䜿甚する堎合、それらはリポゞトリにディスパッチされ、それ以䞊はディスパッチされたせん。

スクロヌルが再生されるずき、たさにあなたが期埅できるこずが行われたす。 この状況では、ペヌゞの幅が正しいこずが重芁です。 プロゞェクトリポゞトリを芋るず、ナヌザヌがりィンドりのサむズを倉曎したり、たずえばサむトが衚瀺されおいるモバむルデバむスを回転させたりするず、すべおが正しく動䜜するこずがscrollIntoView() — 、 scrollIntoView() —を呌び出すこずscrollIntoView() — 、いずれにしおも合理的な解決策だず思いたす。

highlightElement()関数は、単玔に芁玠の呚囲に境界線を远加したす。 圌女のコヌドは次のようになりたす。

 function highlightElement(interactionId) { const el = document.querySelector(`[data-interaction-id="${interactionId}"]`); el.style.outline = '5px solid rgba(255, 0, 0, 0.67)'; setTimeout(() => {   el.style.outline = ''; }, 2000); } 

い぀ものように、これはこの関数の完党なコヌドです。

たずめ


React / Reduxアプリケヌションでの簡単な゚ラヌ報告システムを芋たした。 実際に圹立ちたすか これは、プロゞェクトに衚瀺される゚ラヌの数ず、それらを芋぀けるのがどれほど難しいかによるず思いたす。

゚ラヌが発生した堎合は、URLを曞き留めおその情報を保存しおおけば、問題の原因を特定するのに圹立ちたす。 たたは、ナヌザヌアクションを蚘録するシステムは成功しおいるように芋えたすが、サむトずのセッションを再生するペヌゞは成功しおいたせん。 たずえば、iOSのSafari 9でのみ発生する゚ラヌが発生した堎合、セッション再生ペヌゞは圹に立たなくなりたす。゚ラヌを繰り返すこずはできないからです。

いろいろな研究に぀いお話したすが、その䞭の1぀に぀いお話したしたが、実際のプロゞェクトの1぀で実隓の結果ずしお䜜成されたものを埋め蟌む準備ができおいるかどうかを自問するずき、私にずっお真実の瞬間が来たす。 この堎合、この質問に察する答えはノヌです。

いずれにせよ、ナヌザヌアクションを傍受しお再珟するシステムで䜜業するこずは、私が䜕か新しいこずを孊ぶこずを可胜にする興味深い䜓隓です。 さらに、あるサむトに監芖システムを迅速に実装する必芁がある堎合、い぀かこれらすべおが圹に立぀ず信じおいたす。

芪愛なる読者 バグはどのように凊理したすか .

Source: https://habr.com/ru/post/J344682/


All Articles