Sentry-javascript: تحميل غير متزامن وأخطاء الالتقاط

تم إنشاؤها على ١٨ ديسمبر ٢٠١٣  ·  36تعليقات  ·  مصدر: getsentry/sentry-javascript

أريد أن أكون قادرًا على تحميل raven.js بشكل غير متزامن ، لكن ما زلت قادرًا على التقاط الأخطاء أثناء تحميل البرنامج النصي. (شيء مثل كيفية معالجة Google Analytics للأحداث من خلال تخزينها في متغير حتى يتم تحميل المكتبة).

هذا ما لدي حتى الآن: https://gist.github.com/karolisdzeja/8010574

لكن القيام بذلك بهذه الطريقة يفقد بعض المعلومات والتفاصيل التي يوفرها Raven عادة. هل هناك طريقة لتخزين معلومات الخطأ الكاملة بشكل مشابه لهذا؟

Feature

التعليق الأكثر فائدة

إليك المقتطف الذي نستخدمه لصف المكالمات إلى طرق Raven بشفافية: https://gist.github.com/Kl0tl/ed0a9e74462a2294f4c8842f5389d8ea.

يمكن بالتأكيد تحسين النموذج ولكننا لا نحتاج إلى تكرار المزيد من الوظائف. Object.defineProperty يسمح لنا بالربط مباشرة بعد أن يقوم Raven بإرفاق نفسه بالنافذة ولكن ربما يكون حدث تحميل البرنامج النصي كافيًا. سيكون من الجيد أن يكون لديك طريقة رسمية لتمكين هذا.

ال 36 كومينتر

+1

+1

+1

+1

كل من علق على هذا - ما الخطأ في الحل بواسطةkarolisdzeja؟

في النهاية ، لست متأكدًا من كيفية إضافة ميزة إلى مصدر Raven.js من المفترض أن تعمل عندما لا يكون مصدر Raven.js على الصفحة. أعتقد أن هذا سيكون دائمًا حلاً مخصصًا في النهاية ؛ في أحسن الأحوال يمكننا إضافة "كيفية" إلى مستنداتنا.

benvinegar الحل يبدو جيدًا ، لكن سيكون من الأفضل أن يتم دعمه وتوثيقه رسميًا. أنا أكثر سعادة لمجرد أنني أضطر إلى الوثوق بفريق Sentry على تقييم جوهر عشوائي.

في الواقع ، سيكون الحل الأفضل هو شيء مثل كود Twitter JS SDK: https://dev.twitter.com/web/javascript/loading

قم بإعداد قائمة انتظار الوظائف عند تحميل الصفحة والتي يتم استهلاكها بعد ذلك عند تحميل js الخارجية ، لتحل محل كائن الوكيل. وتأكد من أن جميع استدعاءات واجهة برمجة التطبيقات تمر عبر شيء مثل استدعاء () للخادم الوكيل.

يضمن ذلك إمكانية وضع أي مكالمة في قائمة الانتظار قبل تحميل js بدلاً من مجرد captureMessage ، دون الحاجة إلى تفويض كل وظيفة على حدة.

أود أن أكون قادرًا على تحميل raven.js بشكل غير متزامن / مؤجل ولا داعي للقلق.

مشاكل أخرى مع الجوهر: إنها clobbers window.onerror وتقدم بعض المتغيرات العالمية غير المحتواة.

كما أنه لا يستخدم وظيفة traceKitWindowOnError كاملة الميزات التي يستخدمها raven.js عند التحميل.

أعدت قليلاً إلى الجوهر أعلاه: https://gist.github.com/oroce/ec3786ba7eff59963842220c3ffc56b4

لا يوجد متغير تسريب. احتفظت بالمعالج window.onerror ، لكن لا تتردد في استخدام window.addEventListener('error', fn) .

أكبر مساعدة في هذه المرحلة هي الحصول على traceKitWindowOnError كدالة مُصدَّرة من Raven. نظرًا لأن هذه هي الوظيفة التي يتم استدعاؤها عند حدوث خطأ: https://github.com/getsentry/raven-js/blob/master/dist/raven.js#L2074

أعلم أنه لن يكون لدينا هذا التتبع الملائم للغاية ولكن سيكون لدينا شيء أفضل مما لدينا الآن.

هناك جوانب سلبية أخرى للقيام بذلك:

  • بالاعتماد على window.onerror للقبض على الأخطاء قبل تحميل Raven ، لا تتوفر Stacktraces لكل متصفح

    • إلى جانب عدم وجود تتبع مكدس ، سيؤثر ذلك على التجميع بشكل سلبي

    • هذا هو السبب في أن install() يحاول / يلتقط الأجهزة

  • لن تعمل الآثار التركيبية (ستظهر جميعها على أنها منشؤها هذا الرمز)
  • لا توجد مجموعة مسارات تنقل

لذلك ، فأنت تتداول بأداء أفضل لتقارير أخطاء أقل جودة. إذا كان التنفيذ غير المتزامن مهمًا ، فسأوصي عاجلاً بتجميع Raven مع الكود الخاص بك حتى يتم تقديمه معًا.

benvinegar أنت محق تمامًا. في التطبيقات غير العامة (المعروفة أيضًا باسم google لن تصل إلى الصفحات) ، فإن طريقة الغراب الكلاسيكية (الحظر) جيدة تمامًا ولكن بمجرد أن يكون لديك موقع مواجهة عامة حيث تكون نقاط رؤية صفحة Google مهمة ، نحتاج إلى تحسين كيف نقوم بتحميل كود الطرف الثالث (هذا هو السعر الذي نحن على استعداد لدفعه لصالح ux والسرعة وموقع أفضل لنتائج البحث).

علاوة على ذلك ، يعد تجميع الغراب في الحزمة الخاصة بنا حلاً ، ولكن بمجرد أن تبدأ في تحسين كود الواجهة الأمامية الخاص بك مع تحسينات في الجزء المرئي من الصفحة ، مثل تقسيم الحزمة الخاصة بك إلى حزم متعددة باستخدام أدوات مثل حزمة العوامل أو تضمين حزم متعددة للحصول على مزيد من السرعة ، يمكن أن يكون الحل أعلاه أفضل برنامج IMO ، لكنني منفتح على الاقتراحات.

لديهم جميعًا مقايضات ، لذلك سيكون من الرائع أن نتمكن من توثيق جميع الاستراتيجيات المتاحة ، لذلك اعتمادًا على تطبيق ويب معين ، سنطبق استراتيجيات مختلفة.
باستخدام إستراتيجية غير متزامن ، يجب علينا تحميل النص البرمجي بعد الحدث onload ، بدلاً من تحميل غير متزامن فقط ، لمنع عرض الحدث onload ، العرض.

/**
 * Setup Js error lazy tracking
 * - Pros: doesn't block rendering, onload event
 * - Cons: lower quality error reports for lazy errors
 *
 * <strong i="9">@author</strong> vinhlh
 *
 * <strong i="10">@param</strong>  {object} window
 * <strong i="11">@param</strong>  {object} labJs
 * <strong i="12">@param</strong>  {string} ravenCdn
 * <strong i="13">@param</strong>  {string} sentryDsn
 */
(function(window, labJs, ravenCdn, sentryDsn) {
  var errors = [];
  var oldOnError = window.onerror;

  window.onerror = function() {
    errors.push(arguments);
    oldOnError && oldOnError.apply(this, arguments);
  };
  window.addEventListener('load', function() {
    labJs
      .script(ravenCdn)
      .wait(function() {
        window.onerror = oldOnError;
        Raven.config(sentryDsn).install();
        errors.forEach(function(args) {
          window.onerror.apply(this, args);
        });
      });
  });
})(window, $LAB, 'raven-js-3.8.1/dist/raven.js', 'https://[email protected]/9');

أعتقد أننا سنقوم على الأرجح بتوثيق مقتطف غير متزامن ، مثل المقتطفات المذكورة أعلاه ، لكن ذكر أنه يأتي مع المفاضلات.

مجرد تعليق واحد آخر. قد تبدو هذه المقايضات مقبولة ، لكنني أتعامل مع الكثير من بطاقات الدعم من المستخدمين حول الأخطاء منخفضة الدقة التي يواجهونها والتي يعتقد (بشكل غير صحيح) أنها مشتقة من Raven.js. ما أخشاه هو أنه إذا شجعت الناس على استخدام النهج غير المتزامن ، فسوف يسألني المزيد والمزيد من الناس "لماذا لا يوجد أي أثر للمكدس" وشكاوى أخرى عندما يكون ذلك بسبب أن هذا الأسلوب أقل دقة. أنا على استعداد لقبول ذلك ، لكن من الصعب ابتلاعها. 😓

benvinegar لقد

oroce - نعم ، هذا 100٪ ليس مصدر قلق للأشخاص في هذا الموضوع ، ولكن الأشخاص الذين قد يتبعون هذه الاستراتيجية دون فهم المحاذير بشكل صحيح (على سبيل المثال ، مجرد نسخ / لصق).

سأبقي هذه المشكلة مفتوحة ، مع خطة لإضافة المقتطف إلى مستندات Install - وسأضع مجموعة من التحذيرات في كل مكان.

شكرا مرة أخرى على مشاركتك هنا / إقناعي للقيام بذلك.

إليك المقتطف الذي نستخدمه لصف المكالمات إلى طرق Raven بشفافية: https://gist.github.com/Kl0tl/ed0a9e74462a2294f4c8842f5389d8ea.

يمكن بالتأكيد تحسين النموذج ولكننا لا نحتاج إلى تكرار المزيد من الوظائف. Object.defineProperty يسمح لنا بالربط مباشرة بعد أن يقوم Raven بإرفاق نفسه بالنافذة ولكن ربما يكون حدث تحميل البرنامج النصي كافيًا. سيكون من الجيد أن يكون لديك طريقة رسمية لتمكين هذا.

مرحبًا يا رفاق ، أتساءل فقط عما إذا كان هناك أي خطأ في الطريقة التي يقوم بها Raygun بذلك بشكل غير متزامن؟
لست متأكدًا ، لكن يبدو أنه يتعامل مع حالات الحافة جيدًا؟ قد أكون على خطأ على الرغم من :)

@ Kl0tl لطيف جدا ، شكرا لك

هذا بسيط للغاية باستخدام استيراد ديناميكي . لا يزال في stage3 ولكن مدعومًا بواسطة webpack.

نحن ببساطة نستخدم الوعد كقائمة انتظار. مرة واحدة كاملة يتم تنفيذ جميع عمليات الاسترجاعات بالترتيب.

const RavenPromise = import('raven-js'); // async load raven bundle

// initial setup
RavenPromise.then(Raven => {
    Raven.config('url-to-sentry', options).install();
}):

// exported log function
export const logMessage = (level, logger, text) => {
    RavenPromise.then(Raven => {
        Raven.captureMessage(text, {level, logger});
    });
};

على غرار zanona ، أفضل أيضًا الحصول على رمز تتبع بسيط مثل Raygun أو Google Analytics . فيما يلي مثال على analytics.js :

<script async src="https://www.google-analytics.com/analytics.js"></script>
<script>
    window.ga = window.ga || function () {
        (ga.q = ga.q || []).push(arguments)
    }
    ga.l = +new Date

    ga('create', 'UA-XXXXX-Y', 'auto')
    ga('send', 'pageview')
</script>

benvinegar هل شيء مثل هذا ممكن مع Raven.js؟ ربما في المستقبل؟

kireerik سيتم تنفيذه بالتأكيد (على الأرجح كطريقة توثيق) ، لكن لا يمكنني إعطائك تقديرًا دقيقًا للتاريخ الآن.

kamilogorek يبدو رائعًا (لا أحب الحل كحل). لا مشكلة!

لأي شخص مهتم ، قدمت فكرة عن طريقة أخرى لتحميل ravenjs بشكل غير متزامن:
https://gist.github.com/MaxMilton/e2338b02b7381fc7bef2ccd96f434201

يعتمد على الكود من قبل oroce ولكن مع وجود اختلافات أساسية تتمثل في أنني أستخدم علامة <script async src'='..."> في رأس المستند للحصول على أداء أفضل (يمكن للمتصفحات جدولة جلب المورد مسبقًا) + لا أزعج نفسي في تغليفه IIFE وتعديلات صغيرة أخرى.

تضمين التغريدة لقد صنعت نكهتي الخاصة بناءً على نكهتك:

<script async src="https://cdn.ravenjs.com/3.22.1/raven.min.js" crossorigin="anonymous" id="raven"></script>
<script>
    (function (sentryDataSourceName) {
        var raven = document.getElementById('raven')
        , isNotLoaded = true
        , errors = []
        raven.onreadystatechange = raven.onload = function () {
            if (isNotLoaded) {
                Raven.config(sentryDataSourceName).install()
                isNotLoaded = !isNotLoaded
                errors.forEach(function (error) {
                    Raven.captureException(error[4] || new Error(error[0]), {
                        extra: {
                            file: error[1]
                            , line: error[2]
                            , col: error[3]
                        }
                    })
                })
            }
        }
        window.onerror = function (message, source, lineNumber, colmnNumber, error) {
            if (isNotLoaded)
                errors.push([message, source, lineNumber, colmnNumber, error])
        }
    })('https://<key>@sentry.io/<project>')
</script>

لدي أيضًا بعض الأسئلة:

  • هل يلزم تحديد السمة crossorigin على علامة script ؟
  • هل يكفي تمرير كائن الخطأ jsut بدلاً من الحل الآخر ؟

ما رأيك؟ ما رأي المؤلف (kamilogorek) في ذلك؟

kireerik عندما تضع crossorigin="anonymous" على البرامج النصية ، فإنه يسمح لك بالتقاط الأخطاء بالكامل (من هذا البرنامج النصي الخارجي) مع الحدث window.onerror . كما أنه يمنع المتصفح من إرسال بيانات الاعتماد مع طلب الجلب ، وهو ما تريده عادةً مع موارد الجهات الخارجية. مرجع MDN 1 ، مرجع MDN 2 .

يمكنك فقط تمرير الخطأ وسيعمل _ معظم_ الوقت. التحذير لكونها متصفحات قديمة (مثل Firefox قبل الإصدار 31) لا تمرر خصائص العمود No أو Error Object إلى الحدث window.onerror . لذلك إذا كنت تريد توافقًا جيدًا حقًا ، فأنت بحاجة إلى القيام بهذا الشيء الإضافي. مرجع MDN .

تحرير: نصيحة المكافأة: عندما تضع crossorigin بدون أي قيمة يتم التعامل معها مثل crossorigin="anonymous" .

لمعلوماتك ، لقد قمت بتحديث موجتي السابقة إلى شيء أكثر استعدادًا للإنتاج:

  • الكثير من التعليقات لشرح ما يحدث بالفعل
  • تنظيف كبير + استخدام أسماء المتغيرات الوصفية (دائمًا مكافأة لطيفة: غمزة:)
  • التفاف في IIFE لعدم تلويث مساحة الاسم العالمية
  • إصلاح المعلمات غير الصحيحة التي تم تمريرها إلى عنصر مصفوفة الأخطاء

انظر إلى الجوهر إذا كنت تريد فهم كل شيء أو إذا كنت تفضل النسخ السريع واللصق ، فإليك الإصدار المصغر:

<!-- Sentry JS error tracking -->
<script async src="https://cdn.ravenjs.com/3.22.0/raven.min.js" crossorigin id="raven"></script>
<script>
(function(b,e,c,d){b.onerror=function(a,b,d,f,g){c||e.push([a,b,d,f,g])};b.onunhandledrejection=function(a){c||e.push([a.reason.reason||a.reason.message,a.type,JSON.stringify(a.reason)])};d.onreadystatechange=d.onload=function(){c||(c=!0,
Raven.config("___PUBLIC_DSN___").install(),
b.onunhandledrejection=function(a){Raven.captureException(Error(a.reason.reason||a.reason.message),{extra:{type:a.type,reason:JSON.stringify(a.reason)}})},e.forEach(function(a){Raven.captureException(a[4]||Error(a[0]),{extra:{file:a[1],line:a[2],col:a[3]}})}))}})(window,[],!1,document.getElementById("raven"));
</script>

<link rel="preconnect" href="https://sentry.io">

استبدل ___PUBLIC_DSN___ بـ DSN الخاص بك والصق هذا في مكان ما في الرأس بالقرب من علامة الإغلاق </head> . أو إذا كنت من محبي موسيقى الجاز الذين لا يستخدمون علامات <head> و <body> بعد الآن ، فقم فقط بلصقها بالقرب من الجزء العلوي بعد أي موارد هامة / تطبيقات (مثل CSS). من الناحية المثالية ، يجب أن يكون قبل أي JavaScript آخر حتى تتمكن من التقاط الأخطاء من البرامج النصية التي تم تحميلها بعد هذا الرمز.

في اختباراتي السريعة ، لم تكن هناك أية مشكلات ، لذا لا أرى أي سبب لعدم استخدام هذا على الإصدار المتزامن الافتراضي.

إذا كان لدى أي شخص فكرة عن نهج أفضل ، فأنا حريص على سماعها.

تحرير: آسف لتعديل هذا التعليق مرات عديدة. إنه عند مستوى مستقر الآن. كان من الممتع الوصول إلى هذه الحالة! : مبتسم:

بمجرد تحميل مكتبة الحراسة ، تكون جودة الإبلاغ عن الخطأ هي نفسها تمامًا مثل تحميل المزامنة؟ (أفترض ذلك ، مجرد التحقق)

أيضًا في المستندات التي قد ترغب في إضافتها ، لا يمكنك استخدام Raven حتى يتم تحميل lib ، وربما توفر وظيفة رد الاتصال في الخيارات حتى تتمكن من تعيين سياق المستخدم وما إلى ذلك؟

أتفق مع @ dalyr95 . قد تكون وظيفة رد الاتصال مفيدة. ربما حدث تحميل الغراب مخصص.

لدي طلب مشابه لـ @ dalyr95. الطريقة الوحيدة الآن لاستدعاء setUserContext() هي تعديل مقتطف أداة التحميل التي ليست نظيفة مثل القدرة على تمرير رد اتصال على كائن التكوين الرئيسي.

مرحبا ، شكرا على الإبلاغ عن المشكلة.

نحن بصدد العمل على الإصدار الرئيسي التالي من SDK الخاص بنا.
لهذا السبب ، كان علينا تعليق العمل على الإصدار الحالي (باستثناء الأخطاء الرئيسية أو الأخطاء الأمنية).
سنحاول العودة إلى جميع التقارير في أسرع وقت ممكن ، لذا يُرجى التحلي بالصبر.

شكرا لتفهمك،
هتافات!

كان الحل هو إضافة 'undefined'!=k.setup&&k.setup(); فورًا بعد المكالمة إلى .install() ، ثم أضفت وظيفة تسمى setup إلى SENTRY_SDK مع رمز التعيين.

باستخدام أداة التحميل غير المتزامن ، تمكنت من تعيين سياق المستخدم ومعلومات أخرى عن طريق تمريره كمتغير ثانٍ إلى Raven.config :

<script>
    Raven.config("https://<mydsn>@sentry.io/<projectid>", 
      {"release":"0.3.1",
       "environment":"dev",
       "user": {"id":"7b031fa0-32ff-46fe-b94b-e6bc201c3c5f",
                "organisation-id":"b1a50c41-b85e-4c50-9cec-c55ff36cf6d1"}}).install();
</script>

أعتقد أن كل شيء موجود بالفعل لهذا الغرض ، ويمكن توثيقه بشكل أفضل.

يمكن لـ danielcompton الحصول على معلومات المستخدم فقط من خلال واجهة برمجة التطبيقات الخلفية؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات