ब्लॉग पर वापस जाएं
13 अगस्त 2026Sergei Solod17 मिनट पढ़ें

मैं हर ब्राउज़र एरर पर अलर्ट भेज रहा था: शोर को उपयोगी प्रोडक्शन मॉनिटरिंग में कैसे बदला

मेरे शुरुआती फ्रंटएंड रिपोर्टर ने विज्ञापन ब्लॉक होने, GTM की विफलता, AbortError, अस्पष्ट Script error और असली Next.js चंक विफलताओं को एक जैसा माना। बाद में मैंने मॉनिटरिंग को स्वामित्व, उपयोगकर्ता पर असर, प्रमाण की गुणवत्ता, घटनाओं के सहसंबंध और रिकवरी के आधार पर दोबारा बनाया।

ब्राउज़र एरर मॉनिटरिंगफ्रंटएंड ऑब्ज़र्वेबिलिटीJavaScript एररप्रोडक्शन मॉनिटरिंगNext.jsवेब प्रदर्शन

मैंने क्लाइंट-साइड एरर रिपोर्टिंग इसलिए बनाई थी ताकि उन समस्याओं को देख सकूँ जो असली उपयोगकर्ताओं को आती थीं और जिन्हें लोकल में भरोसेमंद तरीके से दोहराना मुश्किल था। रिपोर्टर वही कर रहा था जो मैंने उससे कहा था: गड़बड़ी पकड़ो और मुझे भेजो।

समस्या यह थी कि लगभग हर घटना एक जैसी गंभीर दिखाई देती थी।

कोई बाहरी एनालिटिक्स स्क्रिप्ट लोड नहीं हुई? लाल अलर्ट। विज्ञापन स्क्रिप्ट ब्लॉक हुई? लाल अलर्ट। कोई क्रॉलर Google Analytics नहीं ला पाया? लाल अलर्ट। वीडियो प्रीव्यू ने play() चलाया और Promise पूरी होने से पहले रुक गया? लाल अलर्ट। उपयोगी स्रोत या स्टैक के बिना Script error. आया? फिर लाल अलर्ट।

उसी धारा में वे गड़बड़ियाँ भी थीं जिन पर सच में काम करना चाहिए था: मेरे ऐप का URL गलती से https://example.comhttps://example.com/... बन गया था, और ब्राउज़र /_next/static/chunks/... के भीतर मेरे ऐप की Next.js फ़ाइल लोड नहीं कर पाया था।

संग्रह परत काम कर रही थी। मॉनिटरिंग परत नहीं।

यहीं से फ्रंटएंड ऑब्ज़र्वेबिलिटी को देखने का मेरा तरीका बदला। एरर इवेंट केवल यह प्रमाण है कि कुछ हुआ। वह अभी निदान, गंभीरता का स्तर या इंसिडेंट नहीं है।

पहली गलती “एरर” को अपने-आप “तत्काल” मान लेना था

शुरुआती मानसिक मॉडल लगभग ऐसा था:

browser error रिपोर्ट करता है
        ↓
CLIENT ERROR भेजो
        ↓
developer को तुरंत देखना चाहिए

इस मॉडल में कई अलग सवाल एक साथ मिल गए थे। क्या गड़बड़ी मेरे कोड में है? क्या सक्रिय रूट सच में टूट गया? क्या यह अपेक्षित रद्दीकरण था? क्या ब्राउज़र के पास स्रोत पहचानने लायक जानकारी है? क्या ऐप रिकवर हो गया? दस संदेश दस इंसिडेंट हैं या एक इंसिडेंट के दस लक्षण?

जब तक इन सवालों के जवाब नहीं मिलते, किसी इवेंट को अपने-आप अलर्ट नहीं बनना चाहिए।

एक शुरुआती जाँच में मेरे सामने लगभग अठारह संदेश थे। ज्यादातर बाहरी सेवाओं या सामान्य लाइफ़साइकल का शोर थे। दो मामले साफ़ अलग थे: मेरे ऐप का बिगड़ा हुआ URL निश्चित बग था, और मेरे ऐप का JavaScript चंक लोड न होना पेज को जरूरी कोड से वंचित कर सकता था। फिर भी रिपोर्टर लगभग सबको ब्लॉक हुए विज्ञापन जितनी ही तत्परता से दिखा रहा था।

वहीं मैंने “हर ब्राउज़र एरर इकट्ठा करना” और “प्रोडक्शन मॉनिटरिंग बनाना” अलग समस्याएँ मानना शुरू किया। संग्रह का काम प्रमाण बचाना है; मॉनिटरिंग का काम उन्हें निर्णय में बदलना है।

ब्राउज़र के पास हर गड़बड़ी के लिए एक ही अर्थ वाला सार्वभौमिक एरर चैनल नहीं है

क्लाइंट की अलग-अलग विफलताएँ एक जैसी अर्थवत्ता के साथ नहीं आतीं।

window का error इवेंट सिंक्रोनस स्क्रिप्ट एरर के लिए इस्तेमाल होता है और रिसोर्स लोडिंग की विफलताओं में भी शामिल होता है। बिना संभाला गया Promise rejection अलग रास्ते से जाता है: ब्राउज़र unhandledrejection निकालता है। स्क्रिप्ट, इमेज या मीडिया लोड करने वाले एलिमेंट अपने error इवेंट भी भेज सकते हैं। React और Next.js इसके ऊपर फ्रेमवर्क-स्तरीय एरर बाउंड्री के संकेत जोड़ते हैं।

window.error
→ synchronous script error बाहर निकला हो सकता है

unhandledrejection
→ rejected Promise उस समय handle नहीं हुई

element error
→ resource load या use नहीं हो पाया

framework boundary
→ rendering या execution error boundary तक पहुँचा

ग्लोबल हुक सिस्टम की सीमा पर दिखाई दिया लक्षण देखता है; उसे पूरी कारण-श्रृंखला पता होना जरूरी नहीं।

यह समझने के बाद मैंने हर इवेंट को तुरंत एक सामान्य Error और एक ही गंभीरता में डालना बंद कर दिया।

स्वामित्व पहला उपयोगी फ़िल्टर है

शोर कम करने वाला पहला उपयोगी विभाजन था यह पता करना कि विफल कोड या रिसोर्स किसका है।

/_next/static/chunks/app/... का लोड न होना किसी दूसरे ओरिजिन पर विज्ञापन SDK के विफल होने जैसा नहीं है। मेरे URL बिल्डर का गलत URL बनाना ब्लॉक हुई एनालिटिक्स रिक्वेस्ट जैसा नहीं है। ब्राउज़र एक्सटेंशन की गड़बड़ी एक अलग श्रेणी है।

  • अपना ऐप: मेरा JavaScript, CSS, API, मीडिया और मेरे कोड से बने URL;
  • फ्रेमवर्क और रनटाइम: ऐप के निष्पादन पथ में आने वाले Next.js या React;
  • बाहरी इंटीग्रेशन: एनालिटिक्स, विज्ञापन, विजेट और बाहरी SDK;
  • पर्यावरण: ब्राउज़र एक्सटेंशन, क्रॉलर, नेटवर्क की स्थिति, गोपनीयता उपकरण और ब्राउज़र-विशिष्ट व्यवहार।

इसका अर्थ यह नहीं कि बाहरी सेवा महत्वहीन है। भुगतान या प्रमाणीकरण प्रदाता बेहद जरूरी हो सकता है, और विज्ञापन की विफलता आमदनी को प्रभावित कर सकती है। लेकिन इंटीग्रेशन की खराब स्थिति अपने-आप ऐप क्रैश नहीं है।

सब कुछ एक ही तत्काल अलर्ट चैनल में भेज दूँ, तो उस चैनल का अर्थ ही खत्म हो जाता है।

अपने ऐप की दो विफलताओं ने मुझे समझाया कि “कार्रवाई योग्य” संकेत क्या होता है

गलत बने URL वाला मामला आसान था:

https://example.comhttps://example.com/resource

इस मामले में AdBlock, VPN या ब्राउज़र की नीति पर शक करने की जरूरत नहीं थी। URL खुद गलत था। कहीं कोड ऐसे मान के आगे ओरिजिन जोड़ रहा था जो पहले से पूरा URL था।

यह इवेंट कार्रवाई योग्य था क्योंकि प्रमाण विशिष्ट था, रिसोर्स मेरा था और गड़बड़ी सीधे उस कोड पथ की ओर इशारा करती थी जिसे मैं नियंत्रित करता हूँ।

Next.js चंक की विफलता अलग थी:

Failed to load script:
/_next/static/chunks/9253.647385b4be0958e4.js

वह भी मेरे ऐप का था और पेज तोड़ सकता था, लेकिन इवेंट कारण साबित नहीं करता था। पुराना क्लाइंट पिछले डिप्लॉयमेंट की फ़ाइल माँग सकता था; रिक्वेस्ट टाइमआउट हो सकती थी; रिवर्स प्रॉक्सी या CDN विफल हो सकता था; कनेक्शन टूट सकता था; या फ़ाइल सच में गायब हो सकती थी।

सही प्रतिक्रिया “मुझे कारण पता है” नहीं, बल्कि “इस वर्ग की प्राथमिकता ऊँची है और अधिक संदर्भ चाहिए” थी।

कारण को लेकर भरोसा कम हो, फिर भी गंभीरता ऊँची हो सकती है।

Script error. एक सुराग है, स्टैक ट्रेस नहीं

Error: Script error.
filename: unknown
line: 0
column: 0

यह डरावना दिखता है लेकिन लगभग कुछ नहीं बताता।

ब्राउज़र क्रॉस-ओरिजिन स्क्रिप्ट एरर की जानकारी जानबूझकर सीमित रखते हैं। MDN बताता है कि सही CORS सेटिंग के बिना window.onerror को सीमित जानकारी मिलती है; <script> का crossorigin व्यवहार सीधे तय करता है कि पूरी एरर जानकारी उपलब्ध होगी या नहीं।

इसलिए मैं किसी अस्पष्ट Script error. को अपने-आप “मेरा ऐप क्रैश हो गया” नहीं मानता। स्रोत मेरा कोड, तीसरे पक्ष का कोड, इंजेक्ट किया गया कोड या ऐसा एरर हो सकता है जिसकी जानकारी ब्राउज़र क्रॉस-ओरिजिन नियमों के कारण नहीं दिखा सकता।

मैं इवेंट को रखता हूँ और उसे पेज, बिल्ड, ब्राउज़र और आसपास के इवेंट से जोड़ता हूँ, लेकिन अकेला 0:0 तत्काल अलर्ट नहीं बनाता। यदि वही पैटर्न किसी एक रिलीज़ या रूट के आसपास समूह बनने लगे, तब उसकी प्राथमिकता बदलती है।

अज्ञात का अर्थ हानिरहित नहीं। इसका अर्थ गंभीर भी नहीं।

AbortError पूरी तरह वास्तविक हो सकता है और फिर भी सामान्य लाइफ़साइकल का हिस्सा हो सकता है

वीडियो प्रीव्यू ने इसका सबसे साफ़ उदाहरण दिया:

AbortError:
The play() request was interrupted by a call to pause()

HTMLMediaElement.play() Promise लौटाता है, और वह Promise अस्वीकृत हो सकती है। मीडिया लाइफ़साइकल की क्रियाएँ लंबित प्लेबैक को जानबूझकर रोक सकती हैं; MDN यह भी साफ़ लिखता है कि load(), लंबित play() Promise को AbortError से रोक देता है

प्रीव्यू ग्रिड में यह बिना किसी दिखाई देने वाले उत्पाद बग के आसानी से हो सकता है। आइटम viewport में आता है, कोड play() चलाता है; उपयोगकर्ता स्क्रॉल करता है, आइटम बाहर जाता है; प्लेबैक शुरू होने से पहले कोड मीडिया को रोक देता है या बदल देता है।

Promise का अस्वीकृत होना वास्तविक है। उपयोगकर्ता के लिए इंसिडेंट शायद है ही नहीं।

सही समाधान आम तौर पर उसी कॉल के पास होता है: Promise वहीं संभालना और अपेक्षित रद्दीकरण को असली प्लेबैक विफलता से अलग करना। unhandledrejection सुरक्षा-जाल हो सकता है, लेकिन सामान्य मीडिया लाइफ़साइकल को पहली बार समझने की जगह नहीं।

बाहरी सेवाओं की विफलताओं के लिए अलग स्वास्थ्य मॉडल चाहिए

मेरे शुरुआती लॉग में एनालिटिक्स और विज्ञापन डोमेन की कई विफलताएँ थीं। कुछ गोपनीयता-केंद्रित ब्राउज़र से आती थीं, कुछ क्रॉलर से। खास तौर पर बेकार तत्काल अलर्ट था: कोई क्रॉलर Google Analytics लोड नहीं कर पाया।

यह केवल बताता है कि एक नेटवर्क रिक्वेस्ट विफल हुई। इससे लगभग कुछ नहीं पता चलता कि इंसानी उपयोगकर्ता ऐप चला पाया या नहीं।

इवेंट बचाना गलती नहीं थी। गलती थी उसे अपने ऐप के न लोड हुए JavaScript चंक वाले इंसिडेंट के साथ उसी धारा में डालना।

  • क्या ऐप उपयोगकर्ता के लिए सच में टूट गया है?
  • क्या बाहरी इंटीग्रेशन स्वस्थ है?

ब्लॉक हुई विज्ञापन स्क्रिप्ट विज्ञापन-डिलीवरी मेट्रिक में जा सकती है। एनालिटिक्स की विफलता एनालिटिक्स कवरेज की मेट्रिक बन सकती है। जब तक मुख्य कार्यक्षमता सच में उन पर निर्भर न हो, इनमें से किसी को “फ्रंटएंड क्रैश” कहकर तत्काल अलर्ट नहीं भेजना चाहिए।

अलग करने से बाहरी समस्याएँ और साफ़ दिखती हैं: उन्हें प्रदाता, ब्राउज़र और क्षेत्र के हिसाब से समूहीकृत किया जा सकता है, न कि यादृच्छिक लाल शोर की तरह देखा जाए।

navigator.onLine संदर्भ देता है, कनेक्टिविटी का प्रमाण नहीं

मैंने यह भी लॉग करना शुरू किया कि ब्राउज़र खुद को ऑनलाइन मानता है या नहीं। यह उपयोगी है, लेकिन केवल संकेत के रूप में।

कुछ इवेंट को अतिरिक्त लॉजिक ने नेटवर्क विफलता माना, जबकि उसी लॉग में लिखा था:

Online: true

यह विरोधाभास नहीं है। MDN साफ़ चेतावनी देता है कि navigator.onLine ब्राउज़र और ऑपरेटिंग सिस्टम के अनुमानों पर आधारित है। मशीन स्थानीय नेटवर्क से जुड़ी हो सकती है और फिर भी मेरे ओरिजिन तक न पहुँच पाए। VPN, फ़ायरवॉल, DNS और आंशिक नेटवर्क आउटेज तस्वीर को और जटिल करते हैं।

online === false
→ environment problem का मजबूत संकेत

online === true
→ origin या resource reachable होने का proof नहीं

यह छोटा अंतर मॉनिटरिंग सिस्टम को किसी संकेत को गलत लेकिन आत्मविश्वासी निदान में बदलने से रोकता है।

एक मूल विफलता कई ब्राउज़र इवेंट पैदा कर सकती है

संग्रह बेहतर होने के बाद दूसरी समस्या साफ़ हुई: एक इंसिडेंट कई संदेश पैदा कर सकता है।

JavaScript चंक पहले resource.error दे सकता है, फिर मॉड्यूल लोडर ChunkLoadError फेंक सकता है, React या Next.js एरर बाउंड्री पार कर सकते हैं और रिकवरी लॉजिक रीलोड तय कर सकता है। यदि हर परत अलग अलर्ट भेजे, तो एक उपयोगकर्ता क्रिया कई अलग प्रोडक्शन विफलताओं जैसी दिखती है।

पाँच संदेश मनोवैज्ञानिक रूप से पाँच प्रभावित उपयोगकर्ताओं जैसे लगते हैं, जबकि वे एक ही सेशन और एक ही रिसोर्स से आए हो सकते हैं।

केवल संदेश के पाठ से डुप्लिकेट हटाना पर्याप्त नहीं। इंसिडेंट के स्तर पर सहसंबंध चाहिए:

session
+ छोटा time window
+ normalized error class
+ first-party resource
+ client build
+ route

मैं कच्चे इवेंट बचाकर रखना चाहता हूँ, लेकिन इंसान को सबसे अधिक संकेत देने वाला इंसिडेंट दिखना चाहिए। अगर एरर बाउंड्री में मेरे कोड का स्टैक और चंक का सटीक URL पहले से है, तो उससे पहले आया सामान्य रिसोर्स एरर दूसरा तत्काल अलर्ट बनाने की जरूरत नहीं।

अलर्ट इंसिडेंट पर करो। इवेंट को संग्रहित करो।

एरर के आसपास का संदर्भ बाद में एरर स्ट्रिंग से ज्यादा उपयोगी हुआ

बाद की टेलीमेट्री काफी अधिक संरचित हो गई:

clientBuildId
resource URL
resourceResponseStatus
resourceTransferSize
resourceDurationMs
serviceWorkerVersion
serviceWorkerController
serviceWorkerState
chunkRecoveryScheduled
online
stack / component stack

मीडिया के लिए मैं मीडिया एरर कोड, स्वतंत्र रूप से दिखने पर HTTP स्थिति, वास्तविक Content-Type और यह भी दर्ज करता था कि विफलता HTTP की थी या नेटवर्क डिलीवरी की।

इन फ़ील्ड ने वे सवाल पूछने दिए जिनका एक सामान्य एक्सेप्शन स्ट्रिंग जवाब नहीं देता: क्या विफलताएँ एक खास बिल्ड से शुरू हुईं? क्या ब्राउज़र को HTTP रिस्पॉन्स मिला? क्या Service Worker पेज नियंत्रित कर रहा था? क्या रिकवरी लॉजिक चला? क्या कई इवेंट एक ही रिसोर्स की ओर इशारा करते हैं? क्या मौजूदा रूट सच में प्रभावित हुआ?

Resource Timing API रिसोर्स की अवधि, ट्रांसफ़र जानकारी और जहाँ समर्थित व अनुमति हो वहाँ रिस्पॉन्स स्थिति दे सकता है। इसकी सीमाएँ हैं: क्रॉस-ओरिजिन टाइमिंग प्रतिबंधित है, कैश किए गए रिसोर्स में transferSize: 0 हो सकता है और responseStatus हर जगह उपलब्ध नहीं है। इसलिए null और 0 को अर्थपूर्ण स्थितियाँ ही रहना चाहिए, नकली निश्चितता नहीं।

ChunkLoadError लक्षण है, 404 डिटेक्टर नहीं

बाद के एक इवेंट ने चंक विफलताओं को पढ़ने का मेरा तरीका बदल दिया।

ब्राउज़र ने Next.js के layout चंक के लिए ChunkLoadError बताया, और समृद्ध टेलीमेट्री में साथ ही यह था:

resourceResponseStatus: 200
resourceDurationMs: 170523
serviceWorkerState: activated
chunkRecoveryScheduled: true

दर्ज अवधि लगभग 170 सेकंड थी। उस इंसिडेंट की ठीक मूल वजह जो भी रही हो, यह डेटा एक बहुत सरल नियम को खारिज करने के लिए पर्याप्त था:

ChunkLoadError === server ने 404 दिया

दूसरी चंक विफलताओं में कोई दिखने वाली रिस्पॉन्स स्थिति नहीं थी। कुछ टाइमआउट के रूप में आईं, कुछ में ट्रांसफ़र जानकारी थी। एरर वर्ग एक था; आसपास का प्रमाण अलग।

Next.js में यह खास तौर पर महत्वपूर्ण है क्योंकि /_next/static/ के नीचे की फ़ाइलें सामान्यतः कंटेंट हैश वाली और immutable कैशिंग के लिए होती हैं। मौजूदा Next.js की self-hosting दस्तावेज़ीकरण ऐसे हैश किए गए immutable एसेट के लिए लंबे समय वाले कैश हेडर बताता है। इसलिए ChunkLoadError में डिप्लॉयमेंट असमानता, पुराना क्लाइंट, नेटवर्क डिलीवरी, रिवर्स प्रॉक्सी, CDN, कैश, Service Worker या सच में गायब बिल्ड आर्टिफैक्ट शामिल हो सकते हैं।

मैं नहीं चाहता कि अलर्टिंग परत कारण गढ़े। मैं चाहता हूँ कि वह जाँच के लिए जरूरी प्रमाण बचाए।

मीडिया एरर ने दूसरी दिशा से वही सबक दिया

कुछ इवेंट में मीडिया एलिमेंट ने बताया:

MEDIA_ELEMENT_ERROR: Format error

केवल यह संदेश देखें तो लगभग कोडेक असंगति जैसा लगता है।

लेकिन कुछ ऐसे इवेंट की अतिरिक्त डिलीवरी जाँच ने दिखाया:

HTTP status: 410
Content-Type: text/html; charset=utf-8
failure kind: http

ब्राउज़र ने वीडियो माँगा था, लेकिन उसे HTML वाली HTTP एरर रिस्पॉन्स मिली। मीडिया एलिमेंट HTML को वीडियो की तरह डिकोड नहीं कर पाया, इसलिए बाहरी लक्षण “Format error” बना। उपयोगी निदान डिलीवरी परत में था।

जिस परत ने समस्या सबसे पहले देखी, जरूरी नहीं वही परत समस्या की वजह हो।

“कोडेक विफलता”, “नेटवर्क आउटेज”, “कैश बग” और “गायब चंक” निष्कर्ष हैं। टेलीमेट्री को पहले अवलोकन दर्ज करने चाहिए।

मैं ब्राउज़र विफलताओं को पाँच आयामों पर परखता हूँ

1. स्वामित्व

क्या स्रोत मेरा ऐप है, फ्रेमवर्क/रनटाइम है, बाहरी इंटीग्रेशन है या पर्यावरण?

2. उपयोगकर्ता पर असर

क्या सक्रिय रूट, रेंडरिंग, प्रमाणीकरण, चैट, चेकआउट या कोई अन्य मुख्य प्रवाह टूट गया? या केवल वैकल्पिक विज्ञापन, एनालिटिक्स, प्रीलोड या प्रीव्यू विफल हुआ और पेज चलता रहा?

3. प्रमाण की गुणवत्ता

क्या मेरे पास अपने कोड का स्टैक, रिसोर्स URL, HTTP स्थिति, बिल्ड ID और कंपोनेंट स्टैक है? या केवल 0:0 पर Script error.?

4. दोहराव और फैलाव

क्या यह एक सेशन की एक घटना है, या वही पैटर्न उसी रिलीज़ के बाद अलग उपयोगकर्ताओं, रूट और ब्राउज़र में दिख रहा है?

5. रिकवरी

क्या ऐप अपने-आप रिकवर हुआ? क्या चंक रीलोड तय हुआ? क्या फ़ॉलबैक काम किया? क्या उपयोगकर्ता अब भी अटका है?

clear first-party
+ high user impact
+ strong evidence
+ multiple sessions
+ no recovery
= urgent incident

third-party
+ optional feature
+ weak evidence
+ isolated
+ user unaffected
= metric या low priority

इवेंट दबाने की नीति सावधान होनी चाहिए

जब शोर परेशान करने लगता है, तो दर्जनों रेगुलर एक्सप्रेशन लिखकर हर चिढ़ाने वाली चीज़ हटाने का मन होता है। यह खतरनाक है।

हर AbortError दबाने से असली रद्द हुई API रिक्वेस्ट छिप सकती है। हर Script error. हटाने से ब्राउज़र-विशिष्ट क्लस्टर छूट सकता है जो केवल समूहीकरण के बाद महत्वपूर्ण बनता है। हर बाहरी विफलता अनदेखी करने से टूटा भुगतान, प्रमाणीकरण या सहमति-प्रदाता छिप सकता है।

ALERT
→ strong incident, action required

RETAIN / AGGREGATE
→ रखो और count करो; cluster बनने पर alert

METRIC / SAMPLE
→ expected या low-impact noise; trend और examples preserve करो

सिस्टम शांत हो सकता है, अंधा नहीं।

अच्छा क्लासिफ़ायर मूलतः कोड में लिखी नीति है

नीचे का कोड मेरे प्रोडक्शन प्रोजेक्ट से कॉपी नहीं है। यह उस नीति का छोटा उदाहरण है जिससे काश मैंने शुरुआत की होती:

function classifyClientEvent(event) {
  const owner = classifyOwner(event);

  if (isExpectedMediaCancellation(event)) {
    return { severity: "metric", reason: "expected-cancellation" };
  }

  if (owner === "first-party" && breaksActiveRoute(event)) {
    return { severity: "alert", reason: "first-party-user-impact" };
  }

  if (isActiveFirstPartyChunkFailure(event)) {
    return { severity: "alert", reason: "application-chunk" };
  }

  if (owner === "third-party") {
    return { severity: "aggregate", reason: "integration-health" };
  }

  if (isOpaqueScriptError(event)) {
    return { severity: "aggregate", reason: "insufficient-evidence" };
  }

  return { severity: "aggregate", reason: "needs-correlation" };
}

असल कठिनाई breaksActiveRoute() जैसी फ़ंक्शन के भीतर है। केवल एक्सेप्शन का नाम पर्याप्त नहीं; रूट संदर्भ, रिसोर्स का स्वामित्व, एरर बाउंड्री डेटा और कभी-कभी उत्पाद-विशिष्ट जानकारी चाहिए।

फिंगरप्रिंट को इंसिडेंट का पीछा करना चाहिए, संदेश का नहीं

पूरा संदेश समान होना डुप्लिकेट हटाने की खराब रणनीति है। मिनिफ़ाइड स्टैक ऑफ़सेट बिल्ड के साथ बदलते हैं, चंक हैश बदलते हैं, URL में डायनेमिक पहचानकर्ता होते हैं और ब्राउज़र की भाषा अलग होती है।

{
  errorClass,
  normalizedFirstPartyResource,
  routeFamily,
  clientBuild,
  sessionId,
  shortTimeBucket
}

पूरे ऐप क्रैश में अपने कोड का सबसे ऊपर वाला स्टैक फ़्रेम उपयोगी हो सकता है। चंक विफलता में सामान्यीकृत चंक रिसोर्स ज्यादा उपयोगी है। मीडिया डिलीवरी इंसिडेंट में HTTP विफलता वर्ग और मीडिया रूट ब्राउज़र के बाहरी एरर संदेश से ज्यादा मूल्यवान हो सकते हैं।

resource.error
→ ChunkLoadError
→ framework boundary
→ recovery scheduled

तब जुड़े हुए इवेंट की एक श्रृंखला चार अवलोकनों वाले एक इंसिडेंट में बदल सकती है, चार अलग तत्काल विफलताओं में नहीं।

तत्काल अलर्ट चैनल का काम बहुत संकरा होना चाहिए

मैं तत्काल अलर्ट इन मामलों के लिए रखूँगा: अपने ऐप का रनटाइम एरर जिसका उपयोगी स्टैक सक्रिय रूट तोड़ता है; React/Next.js एरर बाउंड्री जो वास्तविक इंटरैक्शन को प्रभावित करती है; मौजूदा रूट के लिए जरूरी अपने ऐप की JavaScript या CSS फ़ाइल का लोड न होना; कई सेशन या बिल्ड में दोहरता ChunkLoadError; मुख्य API या डेटा विफलता जो उपयोगकर्ता को रोक दे; या अपने कोड के किसी स्पष्ट नियम का उल्लंघन, जैसे गलत URL बनना।

एक अकेला अस्पष्ट Script error., सफल रिकवरी वाला अपने ऐप का रिसोर्स एरर, अभी अज्ञात मूल परत वाला मीडिया एरर या ऐसा ब्राउज़र-विशिष्ट अपवाद जिसे पहले समूहीकरण चाहिए—इनको मैं रखूँगा, लेकिन तुरंत अलर्ट नहीं करूँगा।

और आम तौर पर मेट्रिक या सैंपल किए गए डायग्नोस्टिक में भेजूँगा: ज्ञात विज्ञापन/एनालिटिक्स रिसोर्स विफलताएँ; अपेक्षित मीडिया AbortError; केवल क्रॉलर में दिखने वाली बाहरी विफलताएँ; मजबूत ऑफ़लाइन संकेत से जुड़ी विफलताएँ; और वैकल्पिक अनुमानित रिसोर्स जो सक्रिय रूट को प्रभावित नहीं करते।

तत्काल अलर्ट का अर्थ कार्रवाई योग्य उपयोगकर्ता प्रभाव होना चाहिए, ब्राउज़र शिकायतों की कच्ची संख्या नहीं।

मैं एक कुल “एरर काउंट” के बजाय इंसिडेंट मापना पसंद करूँगा

  • हर 1,000 सेशन पर अपने ऐप के इंसिडेंट;
  • बिल्ड ID के अनुसार प्रभावित सेशन;
  • रूट के अनुसार एरर-बाउंड्री इंसिडेंट;
  • रिसोर्स और डिप्लॉयमेंट के अनुसार चंक विफलताएँ;
  • प्रदाता के अनुसार बाहरी इंटीग्रेशन की विफलता दर;
  • अपेक्षित रद्दीकरण की मात्रा, ताकि अचानक बढ़ोतरी फिर भी दिखे;
  • रिकवरी की सफलता दर;
  • अद्वितीय इंसिडेंट की संख्या और कच्चे इवेंट की संख्या अलग-अलग।

“एक इवेंट हुआ” शायद ही अच्छा प्रोडक्शन अलर्ट थ्रेशोल्ड है। “नए बिल्ड पर अपने ऐप का वही इंसिडेंट अब कई स्वतंत्र सेशन को प्रभावित कर रहा है और रिकवरी विफल है” कहीं अधिक उपयोगी संकेत है।

क्लाइंट मॉनिटरिंग अकेले मूल कारण साबित नहीं कर सकती

ब्राउज़र टेलीमेट्री की स्पष्ट सीमाएँ हैं।

HTTP स्थिति न मिलना यह बता सकता है कि API ने डेटा नहीं दिया, ब्राउज़र फ़ील्ड का समर्थन नहीं करता, क्रॉस-ओरिजिन रोक लगी, रिक्वेस्ट रद्द हुई या ऑब्ज़र्वेबिलिटी में कोई और खाली जगह है। Service Worker सक्रिय है, इससे यह साबित नहीं होता कि उसी ने पुराना रिसोर्स लौटाया। डिप्लॉयमेंट के बाद ChunkLoadError आया, इससे संस्करण असमानता साबित नहीं होती। online: true से ओरिजिन की पहुँच भी साबित नहीं होती।

क्लाइंट मॉनिटरिंग परिकल्पनाओं को छोटा करती है। कारण साबित करने के लिए सर्वर लॉग, रिवर्स-प्रॉक्सी लॉग, डिप्लॉयमेंट मैनिफ़ेस्ट, कैश की स्थिति और वास्तविक पुनरुत्पादन अब भी जरूरी हो सकते हैं।

मैं ऑब्ज़र्वेबिलिटी को असीमित उपयोगकर्ता डेटा संग्रह भी नहीं बनाना चाहता। हर फ़ील्ड का कोई स्पष्ट काम होना चाहिए: वह अलग-अलग विफलता प्रकारों को पहचानने में मदद करे।

बेहतर टेलीमेट्री का मतलब ज्यादा टेलीमेट्री नहीं; ज्यादा भेद करने वाली टेलीमेट्री है।

मेरा नियम अब: इवेंट इकट्ठा करो, इंसिडेंट की जाँच करो, प्रभाव पर अलर्ट करो

शुरुआत में मैं चाहता था कि रिपोर्टर बस पूछे: “कुछ टूटा?” प्रोडक्शन में यह सवाल इतना चौड़ा है कि बेकार हो जाता है। कहीं न कहीं क्रॉलर एनालिटिक्स तक नहीं पहुँचता, गोपनीयता उपकरण विज्ञापन रोकता है, मीडिया Promise जानबूझकर रद्द होती है, उपयोगकर्ता नेटवर्क खोता है या बाहरी SDK गलत व्यवहार करता है।

क्या यह हमारा है?
क्या user ने functionality खोई?
Evidence कितना मजबूत है?
क्या repeat हो रहा है?
क्या application recover हुई?
ये कई events हैं या एक incident?

जब मॉनिटरिंग को इन संकरे सवालों के आसपास बनाया, लाल संदेशों की बाढ़ शोर से इंजीनियरिंग उपकरण में बदल गई।

ब्राउज़र एरर एक अवलोकन है। इंसिडेंट, उपयोगकर्ता प्रभाव की सहसंबद्ध व्याख्या है। अलर्ट वह निर्णय है कि अब इंसान को कार्रवाई करनी चाहिए।

मैं इन तीनों को दोबारा एक ही चीज़ नहीं मानना चाहता।