Sentry-javascript: Saran simpul: kesalahan log di `unhandledRejection`

Dibuat pada 19 Feb 2019  ·  41Komentar  ·  Sumber: getsentry/sentry-javascript

Paket + Versi

  • [ ] @sentry/browser
  • [x] @sentry/node
  • [ ] raven-js
  • [ ] raven-node _(gagak untuk simpul)_
  • [ ] lainnya:

Versi: kapan:

4.6.1

Keterangan

Di luar kotak, Node akan mencatat penolakan janji yang tidak tertangani. Namun, setelah menginisialisasi Sentry, log ini akan hilang. Ini terjadi karena Node tidak akan mencatat penolakan jika ada handler unhandledRejection , dan Sentry mendaftarkan handler tersebut.

Saya ingin menyarankan agar Sentry menambahkan logging ke handlernya, untuk memberikan keseimbangan dengan pengalaman yang disediakan di luar kotak. Paling tidak, dokumen harus menyebutkan perilaku ini dan kebutuhan untuk menambahkan penangan tambahan secara manual untuk memulihkan pencatatan.

Komentar yang paling membantu

Saya masih merasa aneh bahwa uncaughtException dan unhandledRejection ditangani secara berbeda. Sentry mengembalikan logging untuk uncaughtException —mengapa tidak melakukan hal yang sama untuk unhandledRejection ? Pengguna tidak harus ingat untuk menggunakan flag Node itu. 🤔

Semua 41 komentar

Kedengarannya bagus, namun, saya tidak yakin apakah ini harus berada di belakang bendera debug: true .
Pada akhirnya, Anda secara sadar memasang penangan kesalahan, yang mengarahkan aliran kesalahan ke Sentry.

Saya juga tidak yakin.

Mengaktifkan Sentry tidak memiliki efek menonaktifkan logging untuk pengecualian yang tidak tertangkap, jadi mungkin hal yang sama berlaku untuk penolakan janji yang tidak ditangani. (Meskipun perbedaan perilaku ini lebih merupakan inkonsistensi dalam Node daripada Sentry.)

Ketika saya mengaktifkan Sentry, saya mengerti itu melaporkan kesalahan saya, tetapi saya cenderung menganggap logging konsol sebagai hal yang terpisah, terutama di dev. 🤔

Kami tidak mengubah perilaku logging default, dan untuk pengecualian yang tidak tertangkap, node itu sendiri yang memicu panggilan log.

Saya pikir solusi terbaik di sini adalah dengan membuat catatan tentangnya di dokumen dan pergi

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

snippet jika seseorang ingin mengaktifkan kembali peringatan tersebut.

Dokumen sudah cukup. Setidaknya Sentry tidak melakukan sesuatu yang istimewa. Ini benar-benar Node itulah masalahnya di sini.

atau pengecualian yang tidak tertangkap, simpul itu sendiri yang memicu panggilan log.

Setelah dipikir-pikir, saya tidak yakin itu benar.

Sentry mendaftarkan handler uncaughtException yang menonaktifkan perilaku Node default (log + exit).

Handler ( defaultOnFatalError ) memicu panggilan lognya sendiri: https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

Jika kita "memulihkan" logging untuk pengecualian yang tidak tertangkap, saya yakin kita harus melakukan hal yang sama untuk penolakan janji yang tidak tertangani.

Bisakah kita membuka kembali ini? Sesuai komentar terakhir saya, saya sekarang percaya Sentry harus memulihkan pencatatan untuk penolakan janji yang tidak tertangani, seperti halnya untuk pengecualian yang tidak tertangkap.

Saya menemukan masalah ini karena saya mulai menggunakan Sentry dan bertanya-tanya apakah saya telah membuat kesalahan dalam kode saya karena hanya uncaughtException ada di log saya dan bukan unhandledRejection . Akan sangat masuk akal jika kedua kasus ini ditangani dengan cara yang sama.

Jadi saya akan mengatakan login keduanya atau tidak keduanya.

Saya menemukan cara yang lebih baik untuk menangani ini, daripada menyalin kode dari inti Node.

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

Juga membuatnya jelas dengan memasukkan pada halaman dokumen utama https://github.com/getsentry/sentry-docs/pull/1099

Saya masih merasa aneh bahwa uncaughtException dan unhandledRejection ditangani secara berbeda. Sentry mengembalikan logging untuk uncaughtException —mengapa tidak melakukan hal yang sama untuk unhandledRejection ? Pengguna tidak harus ingat untuk menggunakan flag Node itu. 🤔

mengapa tidak melakukan hal yang sama untuk UnhandledRejection

Karena yang satu kritis ( unhandledException mematikan proses), dan yang satu bersifat informasi (jadi ini peringatan, bukan kesalahan).

Jika kita membalik urutan dan mengeluarkan peringatan secara default, kita akan mematahkan perilaku CLI, dengan memancarkannya meskipun --unhandled-rejections disetel ke none . Saat ini semuanya berfungsi seperti yang diharapkan menurut dokumentasi simpul resmi. Perubahan ini _would_ membuatnya tidak standar.

Setelah Node memutuskan untuk membuat unhandledRejection juga mematikan proses (yang mereka katakan untuk 4 versi sekarang :P), kami akan membuat perubahan agar sejalan dengan spesifikasi resmi juga.

Jika kami membalikkan urutan dan mengeluarkan peringatan secara default, kami akan mematahkan perilaku CLI

@kamilogorek , tetapi ketika dijalankan dengan node ia mencatat unhandledRejection ke console . Jadi saya tidak tahu apa yang dikatakan dokumentasi simpul resmi, tetapi setidaknya itulah perilaku yang saya perhatikan.

@freeall hanya jika Anda tidak melampirkan handler unhandledRejection . Jika Anda menjalankan kode di bawah ini, bahkan tanpa SDK, itu tetap tidak akan masuk, jadi Anda harus mengetahui kode apa yang Anda jalankan.

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

Dan kami menyatakan dengan sangat jelas di sini bahwa kami melakukannya: https://docs.sentry.io/platforms/node/default-integrations/

Integrasi sistem adalah integrasi yang diaktifkan secara default yang digabungkan ke dalam pustaka standar atau penerjemah itu sendiri. Mereka didokumentasikan sehingga Anda dapat melihat apa yang mereka lakukan dan mereka dapat dinonaktifkan jika menyebabkan masalah.
OnUnhandledRejection
Integrasi ini melampirkan penangan penolakan global yang tidak tertangani.

Saya hanya tidak ingin mengubah perilaku node, itu saja. Dan perilakunya adalah: "jika ada pendengar, jangan keluarkan. Jika Anda masih menginginkan peringatan, gunakan bendera." - dan inilah yang kami lakukan.

@kamilogorek Saya mengerti dari mana Anda berasal. Tapi saya pikir pengguna Sentry akan mengharapkan Sentry untuk tidak mengubah perilaku program mereka.

Jika saya memiliki unhandledRejection tanpa Sentry, saya melihatnya di konsol saya.
Jika saya memiliki unhandledRejection dengan Sentry, saya tidak melihatnya di konsol saya.

Saya pribadi tidak suka Sentry mengubah perilaku.

Tapi begitulah Node.js dirancang _(ツ)_/¯
Jika Anda menambahkan handler, peringatan hilang. SDK kami menambahkan penangan, karena ini adalah satu-satunya cara untuk menangkap kesalahan yang tidak tertangani, yang merupakan tujuan utama SDK.

Anda tentu saja benar tentang bagaimana node dirancang. Saat Anda memasang pawang, peringatan itu hilang.
Yang ditanyakan orang adalah Anda meniru perilaku default node dan mencatatnya ke konsol. Perilaku yang berubah bukanlah yang Anda harapkan dari alat seperti Sentry

Bagaimanapun, sepertinya Anda sudah siap dengan perilaku ini, jadi tidak ada gunanya melanjutkan diskusi. Tapi terima kasih telah meluangkan waktu untuk menjawab :)

@freeall terima kasih juga, selalu menyenangkan melihat kedua sisi :)

Hanya untuk memperjelas: saat mengaktifkan Sentry, perilaku unhandledException (keluar + log) dipertahankan, tetapi perilaku unhandledRejection (log) tidak:

|penangan|log|keluar|
|-|-|-|
| unhandledException default|ya|ya|
| unhandledException Penjaga|ya|ya|
| unhandledRejection default|ya|tidak|
| unhandledRejection Penjaga|tidak|tidak|

Saat ini semuanya berfungsi seperti yang diharapkan menurut dokumentasi simpul resmi.

"Seperti yang diharapkan" di sini mengasumsikan pengguna memahami bahwa Sentry mendaftarkan pendengar untuk unhandledRejection . Itu adalah detail implementasi yang tidak perlu dikhawatirkan oleh pengguna.

Saya melihat poin Anda sekalipun. Sentry juga harus menghormati --unhandled-rejections , yang tidak akan dilakukan jika flag disetel ke none dan Sentry terus login.

@freeall komentar meringkas ini dengan cukup baik:

Saya pikir pengguna Sentry akan mengharapkan Sentry untuk tidak mengubah perilaku program mereka.

Penolakan janji yang tidak tertangkap bukanlah "kesalahan kelas dua". Mereka dapat dan memang menyebabkan aplikasi rusak seperti halnya kesalahan normal.

Sepertinya beberapa pengguna mengalami masalah ini (termasuk saya), dan akan lebih banyak lagi yang mengalaminya di masa mendatang.

Jadi secara ringkas: Sentry membungkam kesalahan dari konsol. Dan saya pikir sudah jelas bagaimana ini membingungkan, dan mungkin tidak dimaksudkan oleh sebagian besar pengguna penjaga. Mereka tidak menginstal penjaga agar beberapa bagian kesalahan dibungkam dari konsol.

Jadi alasannya (oleh @kamilogorek )

begitulah Node.js dirancang

Agak samar bagi saya. Bagaimana ini menentukan cara penjaga harus bersikap?

Haruskah kita mengharapkan pengguna untuk mengetahui tentang:

a) penjaga bagian dalam (mendaftarkan event handler)

b) cara kerja simpul dalam (menambahkan penangan menyebabkan peringatan menghilang)

Dan jika tidak, apakah mereka harus melakukannya?

Tentu saja Anda benar dalam mengatakan "baik, pengguna harus tahu, apa yang dilakukan kode di bawah tenda", tetapi kenyataannya terlihat berbeda. Dan Anda memiliki kesempatan di sini untuk meningkatkan kemudahan penggunaan penjaga, atau tidak.

Tidak apa-apa untuk mengatakan "kami tidak peduli dengan masalah khusus ini", tetapi melukisnya dengan cara "ini bukan bug, ini fitur" tampaknya tidak tulus.

TLDR: IMOH Jika Anda ingin meningkatkan kemudahan penggunaan, dan mengurangi masalah bagi pengguna pemula, maka ini harus diperbaiki.

@OliverJAsh , @freeall
Solusi apa yang Anda gunakan untuk masalah ini?

@schhumannd Saya telah menambahkan cuplikan dari cara saya memuatnya. Dan saya setuju dengan Anda bahwa jawaban "ini bukan bug, ini fitur" tampaknya tidak memuaskan. Saya khawatir banyak programmer tidak akan menangkap beberapa bug dalam program mereka karena Sentry memakannya. Bagi saya, prioritas pertama alat seperti Sentry adalah menangkap bug, dan bukan membuatnya.

...
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)
}
...

Karena saya menggunakan penjaga dalam reaksi asli, sepertinya saya perlu melakukan beberapa hal peretasan untuk memperbaiki masalah ini. Adakah yang menggunakan React Native dan menyelesaikan masalah ini dengan cara yang berbeda?

@OliverJAsh , @kamilogorek
Bisakah ini dibuka kembali dan diperbaiki?

Penjaga benar-benar tidak boleh mengacaukan bagaimana kesalahan dicatat di konsol - dan ini bukan hanya masalah dengan Node, karena pencatatan konsol juga ditekan di browser.

Ini sangat menjengkelkan ketika mencoba men-debug sesuatu, dan karena Anda tidak repot-repot menyebutkan ini di dokumen untuk JavaScript, saya sebenarnya berpikir saya tidak memiliki kesalahan ketika saya melihat di konsol saat menguji staging build, dan karena itu tidak menyadarinya memiliki kesalahan, sampai setelah dikerahkan ke produksi. Itu adalah pengalaman pengguna yang sangat buruk untuk layanan pelaporan kesalahan, dan yang perlu Anda perbaiki jika Anda ingin pelanggan yang puas.

Dan seperti yang dikatakan sebelumnya, penolakan janji bukanlah kesalahan kelas dua - mereka bisa sama fatalnya dengan kesalahan lain yang tidak tertangani, dan tidak boleh ditekan dengan cara apa pun.

Jadi, sedikit debugging mengungkapkan alasan logging konsol ditekan:

image

Sentry menetapkan fungsi ke window.onunhandledrejection , dan seperti yang kita lihat di sini, fungsi itu mengembalikan false , sehingga secara eksplisit menekan logging konsol. Jadi ya, Sentry _does_ mengubah perilaku default - itu tidak keren.

Untungnya, ini menyimpan referensi ke fungsi yang ada, dan memanggilnya jika ada.
Jadi, solusi hacky untuk mengaktifkan kembali logging konsol, adalah dengan menambahkan baris ini, sebelum menginisialisasi Sentry:

window.onunhandledrejection = () => true;

Sekarang, tolong perbaiki ini, sehingga kami dapat memiliki perilaku default tanpa peretasan yang tidak berguna seperti itu

@schhumannd tolong buka kembali masalah

@thomas-darling Saya setuju dengan perubahan browser, itu harus mengembalikan true untuk janji juga dan saya dapat mengubahnya.

Namun, untuk node, saya masih belum yakin karena satu alasan. Ini mengikat kode ke implementasi Node saat ini. Jika kita akan menyalin internal daripada mengandalkan flag, dan perilaku penolakan janji akan berubah di v14, kita harus mendeteksi versi node yang kita gunakan dan bertindak sesuai dengan itu.
Tidak masalah apa yang kami kembalikan dari pendengar, karena simpul internal hanya memeriksa array pendengar dan mengeluarkan peringatan hanya jika tidak ada pendengar sama sekali, dan deteksi ini tidak dapat dimodifikasi - https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

Kedengarannya bagus, mengenai perubahan browser :+1:

Adapun Node, jika Anda tidak memperbaiki logging di Sentry, pada dasarnya Anda hanya memaksa semua pengguna Anda untuk melakukannya sendiri - dengan risiko tambahan bahwa beberapa akan melakukan kesalahan, dan beberapa bahkan tidak akan menyadari bahwa mereka membutuhkannya, sampai setelah mereka digigit oleh bug produksi, seperti yang saya lakukan. Itu bukan pengalaman pengembang yang baik...

@thomas-darling bagaimana Anda ingin memperbaikinya? Reproduksi kode yang sama yang ada di dalam kode simpul?

Di bagian paling atas dari dokumen kami ada catatan yang sangat terlihat apa yang harus dilakukan untuk mendapatkan log konsol default - https://docs.sentry.io/platforms/node/

image

Saya mengerti maksud Anda - harus mereplikasi perilaku node akan menjadi masalah pemeliharaan potensial, dan itu membantu bahwa ini, untuk node, diselesaikan dengan flag baris perintah sederhana.

Tetapi jika Anda tidak ingin mereplikasi perilaku node, maka setidaknya catat peringatan ke konsol saat flag tersebut tidak ditentukan, sehingga pengguna mengetahui bahwa kesalahan sedang ditekan, dan bagaimana cara menghindarinya.

Ini menjadi lebih penting di versi node berikutnya, di mana penolakan yang tidak tertangani akan, secara default, merusak proses - yang, seperti yang saya pahami, tidak akan terjadi ketika Sentry menambahkan penangannya.
Pengguna yang mengandalkan perilaku default baru di node, berpotensi mendapat kejutan yang tidak menyenangkan, jika mereka kemudian menginstal Sentry dan prosesnya kemudian tiba-tiba berlanjut, meskipun telah terjadi kesalahan fatal.
Hal seperti itulah yang dapat menyebabkan hilangnya data atau bencana lainnya.

Seperti yang saya lihat, ada beberapa opsi:

  1. Replikasi cara Node.js untuk melakukannya
  2. Cukup tulis ke console.error saat ada penolakan yang tidak tertangani
  3. Tekan kesalahan sehingga pengembang tidak akan pernah melihatnya

Saya pikir opsi 1 atau 2 keduanya tampak baik-baik saja. Pelanggan Anda melihat kesalahan dan dapat memperbaikinya.
Apa yang benar-benar tidak boleh Anda lakukan adalah opsi 3, di mana pelanggan Anda tidak melihat kesalahan dan Sentry menyebabkan kesalahan masuk ke produksi (oh, tetapi ironi untuk alat pelaporan kesalahan). Ini adalah perilaku saat ini dan ini harus benar-benar dihentikan! Penjaga harus membantu saya menangkap kesalahan, bukan memperburuknya.

Bahkan jika Anda memilih opsi 2, setidaknya pengembang akan melihat penolakan dan akan melihat bahwa mereka menginginkan perilaku yang berbeda (seperti crash), dan dapat mengimplementasikannya. Tapi tanpa mengetahui bahkan ada penolakan, mereka tidak bisa berbuat banyak.

Ini harus melakukan pekerjaan. https://github.com/getsentry/sentry-javascript/pull/2312
Saya tidak menambahkan cara untuk menambahkan panggilan balik Anda sendiri, karena menulis kode di bawah ini akan memiliki efek yang sama persis:

```js
Penjaga.init({
integrasi: [
Sentry.Integrations.OnUnhandledRejection baru({
modus: 'tidak ada'
})
]
});

process.on('unhandledRejection', (alasan) => {
// panggilan balik Anda
})

bagi saya itu menghasilkan TypeError: undefined is not a constructor . Mungkin, karena saya sekarang menggunakan paket @sentry/react-native . Btw apakah paket itu memiliki masalah yang sama?

@schhumannd @sentry/react-native tidak menggunakan @sentry/node , jadi tidak memiliki integrasi ini. Untuk itu, Anda hanya perlu memperbarui versi setelah kami merilis sentry/browser dan itu akan berfungsi dengan baik (karena perubahan untuk mengembalikan true dari penangan adalah default dan tidak dapat dikonfigurasi).

@kamilogorek terlihat baik bagi saya 👍

Terima kasih telah melakukan ini! Apakah Anda dapat melakukan ping di sini setelah ini dirilis?

@OliverJAsh ping :)

Hanya untuk memeriksa, saya mengerti dengan benar: jika saya menggunakan flag --unhandled-rejections=strict Node, Node akan memunculkan penolakan yang tidak tertangani sebagai pengecualian, dan kemudian Sentry akan mencegat pengecualian itu dan melaporkannya? Itulah yang saya pikir saya lihat.

Saya bertanya karena ketika saya mencoba mengaktifkan --unhandled-rejections=strict , sepertinya integrasi OnUnhandledRejections tidak berpengaruh—event listener tidak pernah dipanggil.

Akan sangat bagus jika kita bisa menambahkan beberapa dokumen di sekitar ini!

PR Dokumen sedang dalam proses https://github.com/getsentry/sentry-docs/pull/1351/

@OliverJAsh perubahan ini tidak ada hubungannya dengan bendera cli. Perilakunya tidak tersentuh. Hal yang berubah adalah integrasi OnUnhandledRejection mendapat opsi baru yang memungkinkan Anda membuatnya berperilaku seperti flag cli.

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

adalah (secara konseptual) sama dengan --unhandled-rejection=none dan hal yang sama berlaku untuk warn dan strict .
Ketika Anda menggunakan warn (yang merupakan default sekarang), itu akan mencatat peringatan dan kesalahan itu sendiri, tetapi prosesnya akan tetap hidup.
Saat Anda menggunakan strict , itu akan masuk, merekam acara, menyiramnya (tunggu sampai terkirim) dan mematikan proses dengan kode keluar 1.

Itu masuk akal. Saya mengerti integrasi tidak mengubah perilaku flag Node. Namun, dapatkah saya memeriksa bahwa saya benar-benar memahami bagaimana Sentry berperilaku (di luar integrasi ini) sehubungan dengan flag Node?

Hanya untuk memeriksa, saya mengerti dengan benar: jika saya menggunakan flag --unhandled-rejections=strict dari Node, Node akan menaikkan penolakan yang tidak ditangani sebagai pengecualian, dan kemudian Sentry akan mencegat pengecualian itu dan melaporkannya? Itulah yang saya pikir saya lihat.

@schhumannd FYI, pagi ini kami merilis @sentry/react-native 1.10.0 [EDIT: ups, seharusnya 1.1.0 ], yang memperbarui ketergantungannya untuk menggunakan versi terbaru @sentry/browser (termasuk pengembalian - true -instead-of- false fix yang disebutkan di atas).

@lobsterkatie rilis terbaru dari @sentry/react-native tampaknya 1.3.7. .

Jadi mencoba menginstal 1.10.0 tidak berhasil. Bagaimana cara mendapatkan perbaikannya?

@schhumannd @lobsterkatie berarti 1.1.0 , karena ini adalah saat kami memperbarui ke 5.9.0 dari @sentry/browser . Opsi handler yang mengatur level logging juga akan berfungsi dengan baik di versi terbaru @sentry/react-native .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat