- Bun v1.1.5 menambahkan crash reporter
bun.reportyang menyampaikan informasi stack Zig/C++ hanya melalui URL sekitar 150 byte tanpa informasi pribadi, bahkan saat terjadi crash atau panic - Crash reporter OS dan core dump yang ada saat ini memiliki beban besar terkait debug symbol, performa, informasi pribadi, dan ukuran executable, sehingga sulit diterapkan pada Bun sebagai tool CLI
- Pendekatan baru ini mengubah alamat yang maknanya dikaburkan oleh ASLR menjadi alamat relatif terhadap modul, lalu server memulihkan nama fungsi dengan debug symbol yang sesuai commit SHA dan platform
- URL berisi platform, subcommand, commit SHA, feature flag, alamat stack, tipe crash, dan pesan; alamat stack dienkode singkat dengan base64 VLQ
- Kode sumber JavaScript/TypeScript atau environment variable tidak dikirim; tim Bun hanya mengirim informasi stack Zig/C++ dan sebagian metadata yang dibutuhkan untuk diagnosis
Mengapa Bun membuat crash reporter sendiri
- Saat penulisan, Bun memiliki lebih dari 2.600 issue GitHub terbuka, dan sebagian issue sangat sulit direproduksi dan di-debug
- Layanan crash reporting seperti Sentry cocok untuk aplikasi dan produk SaaS, tetapi jika tool CLI seperti Bun mengunggah core dump, masalah informasi pribadi, performa, dan ukuran executable menjadi besar
- Bun v1.1.5 memperkenalkan format kecil baru untuk laporan crash Zig dan C++
- Laporan crash masuk ke dalam URL sekitar 150 byte
- Tidak menyertakan informasi pribadi
Kekurangan jika hanya mengandalkan crash reporter OS
- Beberapa sistem operasi seperti macOS memiliki crash reporter bawaan, tetapi agar dapat dimanfaatkan dengan benar biasanya perlu mendistribusikan debug symbol bersama aplikasi
- Debug symbol memperbesar ukuran distribusi Bun secara signifikan
- Debug symbol Linux sekitar 30MB
- Debug symbol macOS sekitar 9MB
- File
.pdbWindows lebih dari 250MB
- Contoh executable Bun menyusut dari
60Mmenjadi51Msetelahllvm-strip - Jika crash terjadi tanpa debug symbol, stack trace hanya menyisakan
???dan alamat, sehingga kurang berguna - Karena ASLR(Address space layout randomization), alamat fungsi bercampur dengan offset acak, sehingga nama fungsi tidak dapat dipulihkan apa adanya
Cara kerja bun.report
- Saat crash atau panic terjadi di Bun v1.1.5, Bun menampilkan tautan
bun.reportbersama versi, platform, argumen eksekusi, penggunaan memori, dan pesan crash - Ketika pengguna membuka tautan itu, mereka dialihkan ke form issue GitHub yang sudah terisi sebelumnya
- Stack trace yang sudah dipetakan ulang dienkode di dalam URL
- Server memulihkan alamat stack berdasarkan informasi dalam URL, lalu mengubahnya menjadi laporan crash yang dapat dibaca tim Bun
Prosedur mengubah alamat menjadi stack trace yang bisa dibaca
- Alamat fungsi adalah pointer yang menunjuk ke lokasi kode aplikasi dimuat di memori, dan demi keamanan menyertakan offset acak
- Ide dasarnya adalah mengurangkan base address biner dari alamat mentah untuk mendapatkan alamat relatif
- Implementasi sebenarnya lebih rumit karena perbedaan API di tiap platform
- Windows menggunakan flag
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESSpadaGetModuleHandleExW, dan menjadikan pointer modul sebagai base address - Linux mengiterasi modul yang dimuat dengan
dl_iterate_phdr, lalu menggunakandl_phdr_info.dlpi_addrdari modul yang memuat alamat tersebut sebagai base address - macOS mengiterasi modul dengan
_dyld_image_count,_dyld_get_image_header, lalu mendapatkan ASLR slide dengan_dyld_get_image_vmaddr_slide- Alamat hasil di macOS masih menyisakan image offset, yang untuk Bun adalah
0x100000000 - Untuk membuat URL lebih pendek, offset ini dihapus, tetapi harus ditambahkan kembali sebelum dipetakan ulang dengan
llvm-symbolizer
- Alamat hasil di macOS masih menyisakan image offset, yang untuk Bun adalah
- Windows menggunakan flag
- Di Linux dan macOS, modul pertama menunjuk ke biner aplikasi utama
- Di Windows, modul dapat dinilai sebagai biner utama dengan membandingkan nama modul dan
peb.ProcessParameters.ImagePathName - Bun tidak mengunduh dan mem-parsing debug symbol secara lokal, melainkan menyerahkan demangling ke server
- Server dapat melakukan cache debug symbol
- Stack trace dapat di-demangle dalam beberapa detik
- Pada saat yang sama, server berperan sebagai tautan untuk membuka issue GitHub baru
Struktur URL bun.report
- URL
bun.reportmengenkode informasi berikut- Platform: satu huruf yang menunjukkan platform. Misalnya
wberarti x86_64 Windows,Mberarti aarch64 macOS - Subcommand: satu huruf yang menunjukkan subcommand seperti
bun test,bun install,bun run - Commit SHA: commit SHA dari versi Bun saat ini, digunakan nanti untuk mengambil debug symbol
- Feature Flags: penanda yang menunjukkan API dan fitur yang digunakan sebelum crash
- Stack Trace Addresses: alamat yang dihitung pada tahap sebelumnya
- Crash Type: satu huruf yang menunjukkan tipe crash
- Crash Message: pesan yang formatnya berbeda sesuai tipe crash
- Platform: satu huruf yang menunjukkan platform. Misalnya
- Nomor versi dalam URL adalah penanda agar mudah dibaca manusia, bukan untuk pemrosesan sebenarnya
- Dengan informasi ini saja, sebagian karakteristik crash dapat dikenali secara manual
- Identifier
wmembuat crash Windows cepat dikenali A2di bagian akhir string dapat digunakan untuk mengidentifikasi segmentation fault
- Identifier
Encoding VLQ untuk URL pendek
- Alamat stack trace dienkode sebagai angka base64 Variable Length Quantity(VLQ) agar URL tetap pendek
- VLQ dapat merepresentasikan angka kecil dengan lebih sedikit karakter sekaligus tetap dapat mengenkode angka besar
- Teknik yang sama juga digunakan di source map JavaScript untuk menyimpan nomor baris
- Server mendekode kembali nilai VLQ menjadi alamat relatif, mengunduh debug symbol menggunakan commit hash dan platform, lalu men-demangle nama fungsi dengan
llvm-symbolizer - Pada contoh crash, terlihat bahwa assertion gagal di
dirInfoCachedMaybeLog, bagian dari kode module resolver Windows
Encoding feature flag
- URL juga mengenkode integer 64-bit, dan tiap bit berkorespondensi dengan penggunaan fitur tertentu di Bun
- Flag ini memberi petunjuk API dan sistem mana yang mungkin memengaruhi crash
- Jika file
.envdimuat otomatis, fiturdotenvdisetel - Jika
fetch()digunakan, fiturfetchdisetel
- Jika file
- Bun melacak penggunaan fitur dengan kontainer variabel global, dan di dalam tiap API menaikkan angka terkait untuk menandai penggunaan
- Dengan metaprogramming compile-time Zig, Bun mengiterasi daftar fitur dan secara dinamis membuat packed struct yang memakai 1 bit per fitur
- Dengan
inline for, daftar fitur dapat diiterasi pada compile-time, sementara pengaturan bit sebenarnya dilakukan saat runtime - Jika fitur baru ditambahkan ke struct
Featuresyang ada, crash reporter juga menanganinya tanpa penulisan berulang - Pendekatan yang sama juga mungkin dilakukan dengan macro C atau Rust, tetapi dalam implementasi Bun,
comptimeZig digunakan sebagai cara yang lebih sederhana dan mudah dibaca
Perbedaan dengan core dump
- Core dump memuat jauh lebih banyak informasi, tetapi ukurannya besar, baru berguna jika ada debug symbol, dan dapat berisi banyak informasi sensitif atau rahasia
- Metode laporan baru Bun menghindari pengiriman kode sumber JavaScript/TypeScript, environment variable, dan informasi sensitif lainnya
- Alih-alih mengirim semuanya secara default, Bun hanya mengirim stack trace Zig/C++ dan beberapa detail yang kemungkinan besar diperlukan untuk diagnosis masalah
- Jika informasi tambahan diperlukan, pengguna dapat diminta secara terpisah
- Dibanding kondisi sebelumnya yang hanya menyisakan alamat yang tidak dipetakan, tim Bun menjadi lebih mudah mendiagnosis crash
Demo
- Webapp kecil untuk menguji crash reporter tersedia di bun.report
- Tambahkan
/viewdi akhir URL laporan crash mana pun untuk membuka layar webapp tersebut
1 komentar
Komentar Hacker News
Jika alasan memakai pendekatan ini alih-alih stack trace biasa adalah agar tidak perlu mendistribusikan simbol debug berukuran beberapa MB, rasanya mereka mengabaikan opsi yang lebih baik, yaitu hanya memasukkan nama fungsi ke dalam tabel debug
Ini jauh lebih baik daripada harus memakai layanan web untuk melihat stack trace, dan ini bukan cuma teori karena LLVM sudah mengimplementasikannya: https://clang.llvm.org/docs/UsersManual.html#cmdoption-gline...
Jika cukup memberi satu URL yang hampir otomatis mengisi hal-hal yang diperlukan, prosesnya jadi cukup mudah, dan barulah developer benar-benar mengirimkan laporan crash. Ukuran juga penting karena kami ingin menghindari kerugian bagi pengguna, tetapi inti utamanya adalah membuat seluruh proses semudah mungkin
Dalam skenario penggunaan ini, harus melihat stack trace lewat layanan web bukanlah kekurangan besar. Ini hampir sama seperti mengobfuscate/meminify bundle JavaScript frontend lalu mengunggah source map ke Sentry, kemudian memulihkan stack trace dari browser pengguna lewat Sentry. Pengguna toh tidak akan pernah melihat stack trace itu, dan saya juga tidak merasa tidak nyaman melihatnya lewat Sentry. Kalau tidak begitu, kemungkinan saya malah tidak akan bisa melihatnya sama sekali
Ada banyak cara untuk mengusulkan alternatif
Begitulah cara simbolisasi bisa menemukan nama fungsi pustaka sistem di platform tersebut tanpa simbol debug penuh
Hebat dan sangat kreatif. Banyak proyek sebaiknya meniru pendekatan ini. Intinya adalah menyimpan stack trace dengan program counter relatif terhadap executable/shared object
Sepemahaman saya Bun ditautkan secara statis, tetapi dalam sistem dynamic linking, setiap program counter yang dinormalisasi perlu diawali dengan ID shared object berbentuk angka kecil
Misalnya, crash reporter Unreal Engine sudah bisa mengirim format sederhana seperti ini selama bertahun-tahun, dan nomor fungsi/baris yang cukup akurat bisa dipulihkan dari tiap stack frame. Hanya saja, biasanya minidump lebih disukai karena jika ada variabel stack, kita bisa mendapat petunjuk tambahan tentang apa yang terjadi
Microsoft memang sangat ahli dalam hal seperti ini. Di SQL Server mereka memakai minidump yang sudah dibersihkan dari informasi pribadi, ukurannya sangat kecil dan sangat berguna
Bahkan saat itu, 15 tahun lalu pun, dump penuh dari SQL Server produksi sudah berupa file raksasa yang sulit dipindahkan
Saya mengikuti Bun selama beberapa tahun sejak melihat tweet pertamanya yang terkait Zig, lalu belakangan mulai memakainya, dan sejauh ini ia bekerja begitu saja tanpa banyak repot
Bun cukup menarik. Saya sudah mencobanya di beberapa proyek contoh kecil dan performanya bagus, dan saya suka bahwa ia menggabungkan manajemen paket dengan runtime JavaScript
Hanya saja, saya memakai Dependabot di sebagian besar proyek serius saya. Sepemahaman saya dukungan Dependabot untuk Bun masih sedang dikerjakan atau setidaknya sedang dibahas di beberapa issue repositori, jadi saya menunda pemakaian sampai dukungan itu dirilis
Kami sama sekali tidak menyesal. Penghematan dari berbagai bagian yang menjadi lebih cepat dan peningkatan besar pada pengalaman developer benar-benar sepadan dengan harapan kami
Tidak banyak orang yang akan menyadari seberapa besar perhatian yang dicurahkan ke hal seperti ini. Menyenangkan melihat betapa tim Bun peduli pada craft mereka sendiri
Bun memang mengagumkan, tetapi baru-baru ini saya mencoba membuat server HTTP/2 dengan Fastify dan ternyata tidak bisa
Muncul error
node:http2 createServer is not yet implemented in Bun, dan issue yang dirujuk pesan itu sebenarnya tentang dukungan klien HTTP/2. Dukungan klien sudah dirilis di v1.0.13: https://bun.sh/blog/bun-v1.0.13#http2-client-supportPesan
NotImplementedErrorseharusnya diubah agar menunjuk ke issue sisi server: https://github.com/oven-sh/bun/issues/8823Dukungan server HTTP/2 adalah salah satu permintaan fitur teratas: https://github.com/oven-sh/bun/issues?q=is%3Aissue+is%3Aopen...
Jika fitur ini hadir, tampaknya jauh lebih banyak orang akan bisa beralih ke Bun
Bun masih terlalu dini dalam siklus hidupnya. Meski begitu, ekspektasi saya terhadap proyek ini tetap tinggi
Saya penasaran apakah benar ada orang yang memakai Bun. Apakah sebagus hype-nya?
Menyiapkan lingkungan TypeScript Node dengan ts-node, ts-jest, dukungan ESM, top-level await, dan sebagainya terasa lebih merepotkan daripada yang seharusnya. Rilis-rilis Node terbaru memang mengurangi sebagian kerepotan itu, tetapi tetap tidak sesederhana
bun init. Saya juga senang memakai API bun shell: https://bun.sh/blog/the-bun-shellPesan error-nya juga jauh lebih buruk daripada Node. Saya sempat memakainya beberapa waktu, tetapi sekarang
—loader tsxdi Node sudah melakukan semua yang saya butuhkan tanpa kekurangan tersebut. Untuk server sederhana, misalnya memakai WebSocket dan Anda yakin tidak butuh modul native, Bun layak dipertimbangkan. Saya benar-benar menjalankan beberapa layanan seperti ituKecepatan startup yang instan masih terasa mengejutkan
Memang masih ada beberapa hal yang belum ada, tetapi bagi saya ini sudah lebih baik daripada Node
Artikel ini juga terasa sangat bagus sebagai studi kasus Zig. Menarik
Untuk memakai REPL di Bun, harus mengunduh 37 paket dulu. Kalau tidak ada internet, REPL pun tidak bisa dipakai
Saat menjalankan
bun repl, muncul error bahwa pengunduhan manifest paketbun-replgagal. Ini bukan masalah besar, tetapi saya berharap cukup menaruh satu executable di PATH lalu langsung bisa jalan tanpa instalasi, dan saya cukup menantikannyaSecara internal
bun replmelakukan hal yang sama sepertibunx bun-repl