Sentry-javascript: اقتراح العقدة: تسجيل الأخطاء في "unhandledRejection"

تم إنشاؤها على ١٩ فبراير ٢٠١٩  ·  41تعليقات  ·  مصدر: getsentry/sentry-javascript

الحزمة + الإصدار

  • [] @sentry/browser
  • [x] @sentry/node
  • [] raven-js
  • [] raven-node _ (غراب للعقدة) _
  • [ ] آخر:

إصدار:

4.6.1

وصف

من خارج الصندوق ، ستسجل Node حالات رفض الوعد غير المعالجة. ومع ذلك ، بعد تهيئة تطبيق Sentry ، ستختفي هذه السجلات. يحدث هذا لأن Node لن تسجل الرفض في حالة وجود معالج unhandledRejection ، ويسجل Sentry مثل هذا المعالج.

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

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

ما زلت أجد أنه من الغريب أن يتم التعامل مع uncaughtException و unhandledRejection بشكل مختلف. يستعيد Sentry التسجيل مقابل uncaughtException —لماذا لا يفعل الشيء نفسه لـ unhandledRejection ؟ لا يجب على المستخدمين تذكر استخدام علامة العقدة هذه. 🤔

ال 41 كومينتر

يبدو هذا جيدًا ، ومع ذلك ، لست متأكدًا مما إذا كان يجب أن يكون وراء العلم debug: true .
في النهاية ، تقوم بإرفاق معالجات الأخطاء بوعي ، والتي تعيد توجيه دفق الخطأ إلى Sentry.

لست متأكدًا أيضًا.

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

عندما أقوم بتمكين Sentry ، أفهم أنه يبلغ عن أخطائي ، لكني أميل إلى التفكير في تسجيل وحدة التحكم كشيء منفصل ، خاصة في dev. 🤔

لا نقوم بتعديل سلوك التسجيل الافتراضي ، وبالنسبة للاستثناءات غير المعلنة ، فإن العقدة نفسها هي التي تؤدي إلى استدعاء السجل.

أعتقد أن أفضل حل هنا هو تدوين ملاحظة عنها في المستندات والمغادرة

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at:', p, 'reason:', reason);
});

مقتطف في حالة رغبة شخص ما في إعادة تمكين التحذير.

المستندات كافية. على الأقل إذن لا يقوم Sentry بعمل أي شيء مميز. انها حقا العقدة هذه هي المشكلة هنا.

أو استثناءات غير معلومة ، فإن العقدة نفسها هي التي تؤدي إلى استدعاء السجل.

فيما يتعلق بالأفكار الثانية ، لست متأكدًا من صحة ذلك.

يسجل Sentry معالج uncaughtException الذي يعطل سلوك العقدة الافتراضي (تسجيل + خروج).

يقوم المعالج ( defaultOnFatalError ) بتشغيل استدعاء السجل الخاص به: https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

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

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

لقد وجدت هذه المشكلة لأنني كنت قد بدأت في استخدام Sentry وتساءلت عما إذا كنت قد ارتكبت خطأ في الكود الخاص بي لأن uncaughtException كان في سجلي وليس unhandledRejection . سيكون من المنطقي جدًا التعامل مع هاتين الحالتين بنفس الطريقة.

لذلك أود أن أقول إما تسجيل كليهما أو تسجيل أي منهما.

لقد وجدت طريقة أفضل للتعامل مع هذا ، من نسخ التعليمات البرمجية من نود الأساسية.

λ: node --unhandled-rejections=warn app.js

أوضح ذلك أيضًا من خلال تضمينه في صفحة المستندات الرئيسية https://github.com/getsentry/sentry-docs/pull/1099

ما زلت أجد أنه من الغريب أن يتم التعامل مع uncaughtException و unhandledRejection بشكل مختلف. يستعيد Sentry التسجيل مقابل uncaughtException —لماذا لا يفعل الشيء نفسه لـ unhandledRejection ؟ لا يجب على المستخدمين تذكر استخدام علامة العقدة هذه. 🤔

لماذا لا تفعل الشيء نفسه بالنسبة للرفض غير المعالج

لأن أحدهما مهم ( unhandledException يقتل العملية) والآخر إعلامي (وبالتالي فهو تحذير وليس خطأ).

إذا عكسنا الترتيب وأصدرنا التحذير بشكل افتراضي ، فسنكسر سلوك CLI ، عن طريق إرسالهم بالرغم من تعيين --unhandled-rejections على none . الآن كل شيء يعمل كما هو متوقع وفقًا لوثائق العقد الرسمية. هذا التغيير _ سيجعله غير قياسي.

بمجرد أن تقرر Node أن تجعل unhandledRejection تقتل أيضًا عملية (والتي يقولون عنها لـ 4 إصدارات الآن: P) ، سنقوم بإجراء التغيير ليتوافق مع المواصفات الرسمية أيضًا.

إذا عكسنا الترتيب وأصدرنا التحذير بشكل افتراضي ، فسنكسر سلوك CLI

kamilogorek ، ولكن عند التشغيل باستخدام node ، يتم تسجيل unhandledRejection إلى console . لذلك لا أعرف ما تقوله الوثائق الرسمية للعقدة ، ولكن على الأقل هذا هو السلوك الذي ألاحظه.

freeall فقط إذا لم تقم بإرفاق معالج unhandledRejection . إذا قمت بتشغيل الكود أدناه ، حتى بدون SDK ، فلن يتم تسجيله ، وبالتالي عليك أن تكون على دراية بالشفرة التي تقوم بتشغيلها.

process.on('unhandledRejection', () => `¯\_(ツ)_/¯`);

ونذكر هنا بوضوح أننا نفعل ذلك: https://docs.sentry.io/platforms/node/default-integrations/

عمليات تكامل النظام هي عمليات تكامل يتم تمكينها افتراضيًا يتم دمجها في المكتبة القياسية أو المترجم الفوري نفسه. لقد تم توثيقهم حتى تتمكن من رؤية ما يفعلونه ويمكن تعطيلهم إذا تسببوا في حدوث مشكلات.
OnUnhandledRejection
يقوم هذا التكامل بإرفاق معالجات الرفض العالمية غير المعالجة.

أنا فقط لا أريد تغيير سلوك العقدة ، هذا كل شيء. والسلوك هو: "إذا كان هناك مستمع ، فلا ترسل. ​​إذا كنت لا تزال تريد التحذير ، فاستخدم العلم." - وهذا بالضبط ما نفعله.

kamilogorek أنا أفهم من أين أتيت. لكني أعتقد أن مستخدمي Sentry يتوقعون ألا يغير Sentry سلوك برنامجهم.

إذا كان لدي unhandledRejection بدون تطبيق Sentry ، أراه في وحدة التحكم الخاصة بي.
إذا كان لديّ unhandledRejection مع Sentry ، فلن أراه في وحدة التحكم الخاصة بي.

أنا شخصياً لا أحب أن الحارس يغير السلوك.

ولكن هذه هي الطريقة التي تم بها تصميم Node.js ¯_ (ツ) _ / ¯
إذا قمت بإضافة معالج ، فقد ذهب التحذير. يضيف SDK الخاص بنا معالجًا ، لأنه الطريقة الوحيدة للقبض على الأخطاء التي لم تتم معالجتها ، وهو الغرض الرئيسي من SDK.

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

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

freeall شكرًا أيضًا ، من الجيد دائمًا رؤية كلا الجانبين :)

فقط للتوضيح: عند تمكين Sentry ، يتم الاحتفاظ بسلوك unhandledException (خروج + سجل) ، لكن سلوك unhandledRejection (سجل) ليس كذلك:

| معالج | سجلات | مخارج |
| - | - | - |
| unhandledException افتراضي | نعم | نعم |
| unhandledException حارس | نعم | نعم |
| unhandledRejection افتراضي | نعم | لا |
| unhandledRejection حارس | لا | لا |

الآن كل شيء يعمل كما هو متوقع وفقًا لوثائق العقد الرسمية.

"كما هو متوقع" هنا يفترض أن المستخدم يفهم أن Sentry يسجل مستمعًا لـ unhandledRejection . هذه تفاصيل تنفيذ لا ينبغي على المستخدمين القلق بشأنها.

أنا لا أرى وجهة نظرك على الرغم من. يجب أن يحترم Sentry أيضًا --unhandled-rejections ، وهو ما لن يفعله إذا تم تعيين العلم على none وكان Sentry يواصل تسجيل الدخول.

تعليق freeall يلخص هذا الأمر جيدًا:

أعتقد أن مستخدمي Sentry يتوقعون ألا يغير Sentry سلوك برنامجهم.

إن رفض الوعد غير الملحوظ ليس "أخطاء من الدرجة الثانية". يمكنهم فعلاً أن يتسببوا في تعطل التطبيقات تمامًا كما تفعل الأخطاء العادية.

يبدو أن العديد من المستخدمين قد واجهوا هذه المشكلة (بمن فيهم أنا) ، وسيواجهها المزيد في المستقبل.

باختصار: Sentry يسكت الأخطاء من وحدة التحكم. وأعتقد أنه من الواضح كيف أن هذا أمر محير ، وربما لا يقصده معظم مستخدمي الحراسة. لا يقومون بتثبيت الحارس لإسكات مجموعة فرعية من الأخطاء من وحدة التحكم.

لذا فإن المنطق (بواسطة kamilogorek )

هكذا تم تصميم Node.js

هو غامض بعض الشيء بالنسبة لي. كيف يملي هذا الطريقة التي يجب أن يتصرف الحارس؟

هل نتوقع أن يعرف المستخدمون عن:

أ) أعمال الحراس الداخلية (سجلات معالجات الأحداث)

ب) الأعمال الداخلية للعقدة (تؤدي إضافة المعالجات إلى اختفاء التحذيرات)

وإذا لم يفعلوا ذلك ، فهل يجب عليهم ذلك؟

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

لا بأس بالقول "نحن لا نهتم بهذه المشكلة بالذات" ، ولكن رسمها بطريقة "ليست حشرة ، إنها ميزة" نوع من الطريقة يبدو غير صادق.

TLDR: IMOH إذا كنت ترغب في زيادة سهولة الاستخدام وتقليل المشكلات للمستخدمين المبتدئين ، فيجب إصلاح ذلك.

OliverJAsh ، freeall
ما الحلول التي استخدمتها لهذه المشكلة؟

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

...
if (isUsingSentry) {
  // Log to console because Sentry overwrites standard behavior. https://github.com/getsentry/sentry-javascript/issues/1909.
  // Note that it doesn't overwrite for uncaughtException.
  process.on('unhandledRejection', console.error)
}
...

نظرًا لأنني أستخدم الحارس في رد الفعل الأصلي ، يبدو أنني سأحتاج إلى القيام ببعض الأشياء المخترقة لإصلاح هذه المشكلة. هل يستخدم أي شخص React Native ويحل هذه المشكلة بطريقة مختلفة؟

تضمين التغريدة
هل يمكننا إعادة فتح هذا وإصلاحه؟

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

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

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

لذلك ، يكشف القليل من تصحيح الأخطاء عن سبب منع تسجيل وحدة التحكم:

image

يقوم Sentry بتعيين وظيفة لـ window.onunhandledrejection ، وكما نرى هنا ، تُرجع هذه الوظيفة false ، وبالتالي تمنع صراحة تسجيل وحدة التحكم. لذا نعم ، Sentry _does_ يغير السلوك الافتراضي - هذا ليس رائعًا.

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

window.onunhandledrejection = () => true;

الآن ، يرجى إصلاح هذا ، حتى نتمكن من الحصول على السلوك الافتراضي بدون مثل هذه الاختراقات التي لا طائل من ورائها 🙂

schumannd يرجى إعادة فتح المشكلة

@ thomas-darling أوافق على تغيير المتصفح ، يجب أن يعيد true للوعود أيضًا ويمكنني تغيير ذلك.

ومع ذلك ، بالنسبة للعقدة ، ما زلت غير مقتنع لسبب واحد. يربط الكود بتنفيذ Node الحالي. إذا قمنا بنسخ العناصر الداخلية بدلاً من الاعتماد على العلامات ، وسيتغير سلوك الرفض الوعد في الإصدار 14 ، فسيتعين علينا اكتشاف إصدار العقدة الذي نتواجد فيه والتصرف وفقًا لذلك.
لا يهم ما نعود من المستمع ، حيث أن العقدة الداخلية تتحقق فقط من مصفوفة المستمعين وتنبعث منها تحذير فقط في حالة عدم وجود مستمعين على الإطلاق ، ولا يمكن تعديل هذا الاكتشاف - https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

يبدو جيدًا ، فيما يتعلق بتغيير المتصفح: +1:

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

@ thomas-darling كيف تريد إصلاحه؟ إعادة إنتاج نفس الكود الموجود داخل كود العقدة؟

في الجزء العلوي من مستنداتنا ، توجد ملاحظة واضحة جدًا ما يجب القيام به من أجل الحصول على تسجيل افتراضي لوحدة التحكم - https://docs.sentry.io/platforms/node/

image

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

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

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

كما أراها هناك بعض الخيارات:

  1. قم بتكرار طريقة Node.js للقيام بذلك
  2. اكتب فقط إلى console.error عندما يكون هناك رفض غير معالج
  3. قم بإيقاف الخطأ حتى لا يراه المطور أبدًا

أعتقد أن الخيار 1 أو 2 كلاهما يبدو جيدًا. يرى عميلك الخطأ ويمكنه إصلاحه.
ما لا يجب عليك فعله مطلقًا هو الخيار 3 ، حيث لا يرى عميلك أخطاء ويتسبب تطبيق Sentry في حدوث أخطاء في الإنتاج (أوه ، ولكن المفارقة في أداة الإبلاغ عن الأخطاء). هذا هو السلوك الحالي ويجب أن يتوقف هذا حقًا! يجب أن يساعدني الحارس في اكتشاف الأخطاء ، وليس جعلها أسوأ.

حتى إذا اخترت الخيار 2 ، فسيرى المطورون على الأقل الرفض وسيلاحظون أنهم يريدون سلوكًا مختلفًا (مثل الانهيار) ، ويمكنهم تنفيذ ذلك. لكن دون معرفة أنه كان هناك رفض ، لا يمكنهم فعل الكثير حيال ذلك.

هذا يجب أن يقوم بالعمل. https://github.com/getsentry/sentry-javascript/pull/2312
لم أقم بإضافة طريقة لإضافة رد الاتصال الخاص بك ، لأن كتابة التعليمات البرمجية أدناه سيكون لها نفس التأثير بالضبط:

شبيبة
Sentry.init ({
عمليات الدمج: [
Sentry.Integrations.OnUnhandledRejection الجديد ({
الوضع: "لا شيء"
})
]
}) ؛

process.on ('unhandledRejection'، (السبب) => {
// رد الاتصال الخاص بك
})

بالنسبة لي ، ينتج عن ذلك TypeError: undefined is not a constructor . ربما ، لأنني الآن أستخدم الحزمة @sentry/react-native . راجع للشغل هذه الحزمة لديها نفس المشكلة؟

schumannd @sentry/react-native لا يستخدم @sentry/node ، لذلك لا يحتوي على هذا التكامل. لذلك ، ستحتاج فقط إلى تحديث إصدار بمجرد إصدار الحارس / المتصفح وسيعمل بشكل جيد (حيث أن التغيير لإرجاع true من المعالجات هو افتراضي وغير قابل للتكوين).

kamilogorek تبدو جيدة بالنسبة لي 👍

أشكركم على القيام بذلك! هل ستكون قادرًا على إجراء الأمر ping هنا بمجرد تحرير هذا؟

تضمين التغريدة

فقط للتحقق من فهمي بشكل صحيح: إذا استخدمت علامة Node's --unhandled-rejections=strict ، فستقوم Node برفع الرفض غير المعالج كاستثناء ، ثم يقوم Sentry باعتراض هذا الاستثناء والإبلاغ عنه؟ هذا ما أعتقد أنني أراه.

أسأل لأنه عندما حاولت تمكين --unhandled-rejections=strict ، بدا أن التكامل OnUnhandledRejections لم يكن له أي تأثير - لم يتم استدعاء مستمع الحدث مطلقًا.

سيكون من الرائع أن نتمكن من إضافة بعض المستندات حول هذا!

العلاقات العامة في محرر المستندات قيد التقدم بالفعل https://github.com/getsentry/sentry-docs/pull/1351/

OliverJAsh هذا التغيير لا علاقة له OnUnhandledRejection حصل على خيار جديد يسمح لك بجعله يتصرف مثل علم cli.

Sentry.init({
  integrations: [
    new Sentry.Integrations.OnUnhandledRejection({
      mode: 'none'
    })
  ]
});

(من الناحية النظرية) هي نفسها --unhandled-rejection=none ونفس الشيء ينطبق على warn و strict .
عندما تستخدم warn (وهو الخيار الافتراضي الآن) ، فسوف يقوم بتسجيل التحذير والخطأ نفسه ، ولكن العملية ستبقى حية.
عندما تستخدم strict ، فسوف يسجل الحدث ويلتقطه ويغسله (انتظر حتى يتم تسليمه) ويقتل العملية برمز الخروج 1.

منطقي. أدرك أن التكامل لا يغير سلوك علامة Node. ومع ذلك ، هل يمكنني فقط التحقق من أنني أفهم بشكل صحيح كيف يتصرف Sentry (خارج هذا التكامل) فيما يتعلق بعلامة Node؟

فقط للتحقق من فهمي بشكل صحيح: إذا استخدمت Node's - unhandled -مرفضة = علامة صارمة ، فستقوم Node برفع الرفض غير المعالج كاستثناء ، ثم يقوم Sentry باعتراض هذا الاستثناء والإبلاغ عنه؟ هذا ما أعتقد أنني أراه.

schumannd FYI ، @sentry/react-native 1.10.0 [EDIT: whoops ، يجب أن يكون 1.1.0 ] ، والذي يقوم بتحديث التبعية لاستخدام أحدث إصدار من @sentry/browser (والذي يتضمن الإرجاع - true -بدلاً من- false الإصلاح المذكور أعلاه).

lobsterkatie يبدو أن أحدث إصدار من @ sentry / رد فعل أصلي هو 1.3.7. .

لذا فإن محاولة تثبيت 1.10.0 لا تعمل. كيف أحصل على الإصلاح؟

schumanndlobsterkatie يعني 1.1.0 ، وهذا هو عندما قمنا بتحديث إلى 5.9.0 من @sentry/browser . يجب أن يعمل خيار المعالج الذي يعيّن مستوى التسجيل بشكل جيد في الإصدار الأخير من @sentry/react-native أيضًا.

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