เมื่อเกิดข้อผิดพลาดในแอปพลิเคชันของคุณ Ruby จะแสดงข้อยกเว้นและพิมพ์ stack trace ไปที่บันทึก ในบทความนี้ เราจะมาดูวิธีอ่านสแต็กเทรซและวิธีใช้เพื่อค้นหาแหล่งที่มาของข้อยกเว้นในแอปพลิเคชันของคุณ
คอลสแตก
เมื่อใดก็ตามที่คุณเรียกใช้เมธอด Ruby จะวาง stack frame บน คอลสแต็ก (หรือ "รันไทม์สแต็ก" แต่มักเรียกว่า "สแต็ก") สแต็กเฟรมคือการจัดสรรหน่วยความจำที่เก็บอาร์กิวเมนต์ของเมธอด พื้นที่บางส่วนสำหรับตัวแปรภายใน และที่อยู่ที่ส่งคืนของผู้โทร
# divide.rb
def divide(a, b)
"Dividing #{a} by #{b} gives #{a / b}."
end
puts divide(8, 4)
เมื่อวิธีใดวิธีหนึ่ง (divide
) เรียกวิธีอื่น (Fixnum#/
, หรือ /
สำหรับระยะสั้น) หลังถูกวางบนสแต็กเพราะจำเป็นต้องดำเนินการก่อนที่อันแรกจะเสร็จสิ้น เมื่อโทร divide(8, 4)
ในตัวอย่างนี้ Ruby จะดำเนินการตามลำดับต่อไปนี้:
- โทร
8./(4)
- รวบรวมผลการหาร (
2
) และใส่เป็นสตริง - รวบรวมสตริง (
"Dividing 8 by 4 gives 2"
) และพิมพ์ไปยังคอนโซลด้วยputs
สแต็กเทรซ
การติดตามสแต็ก (ปกติจะมีชื่อว่า "backtrace" ใน Ruby แต่ยังเรียกอีกอย่างว่า "stack backtrace" และ "stack traceback") เป็นการแสดงสแต็กที่มนุษย์อ่านได้ในช่วงเวลาหนึ่งในขณะที่รันโปรแกรมของคุณ การติดตามสแต็กสำหรับการเรียกไปยัง /
เมธอดจะออกมาประมาณนี้ แสดงว่าถูกเรียกใน divide
วิธีในบรรทัดที่ 2 ซึ่งถูกเรียกใน <main>
วิธีในบรรทัดที่ 5
divide.rb:2:in `/'
divide.rb:2:in `divide'
divide.rb:5:in `<main>'
ในตัวอย่างข้างต้น การเรียก divide
. ของเรา เมธอดที่มี 0 เป็นหนึ่งในอาร์กิวเมนต์จะส่งผลให้ ZeroDivisionError
ข้อยกเว้น
# divide_by_zero.rb
def divide(a, b)
"Dividing #{a} by #{b} gives #{a / b}."
end
puts divide(8, 0)
เมื่อสิ่งนี้เกิดขึ้น Ruby จะพิมพ์ข้อยกเว้นพร้อมกับการติดตามสแต็กไปยังคอนโซล การติดตามสแต็กจะแสดงสแต็กในรูปแบบที่มนุษย์อ่านได้ พร้อมด้วยตำแหน่งของเมธอดในโค้ดของคุณเพื่อช่วยให้คุณระบุแหล่งที่มาของข้อยกเว้นได้
$ ruby divide_by_zero.rb
divide_by_zero.rb:2:in `/': divided by 0 (ZeroDivisionError)
from divide_by_zero.rb:2:in `divide'
from divide_by_zero.rb:5:in `<main>'
-
ในบรรทัดแรกในการติดตามสแต็กด้านบน เราจะเห็นว่า
ZeroDivisionError
ถูกยกขึ้นโดย "หารด้วย 0" เป็นข้อความ นอกจากข้อยกเว้นเองแล้ว เราจะเห็นได้ว่ามันเกิดขึ้นในdivide_by_zero.rb:2:in `/'
ซึ่งหมายความว่าข้อผิดพลาดเกิดขึ้นจากบรรทัดที่สองของไฟล์ตัวอย่างของเรา จากวิธีการที่ชื่อ/
(ซึ่งก็คือFixnum#/
เนื่องจากอาร์กิวเมนต์แรกคือ Fixnum8
) -
บรรทัดที่สองของการติดตามสแต็กแสดงว่า
/
วิธีการถูกเรียกจาก ในกรณีนี้มาจากdivide
. ของเรา วิธีในบรรทัดที่ 2 -
บรรทัดสุดท้ายแสดงว่า
divide
ถูกเรียกจาก<main>
ซึ่งหมายถึงบริบทเริ่มต้นของแอปพลิเคชัน Ruby โดยทั่วไปหมายความว่ามีการเรียกจากภายนอกวิธีการ "ของจริง" ใดๆ
หมายเหตุ :ใน Ruby 2.5 เครื่องมือบันทึกจะพิมพ์สแต็กเทรซย้อนกลับเพื่อให้พอดีกับหน้าต่างเทอร์มินัล บรรทัดสุดท้ายแสดงข้อยกเว้น นำหน้าด้วยบรรทัดที่เกิดข้อยกเว้น เส้นด้านบนที่เป็นเส้นทางขึ้นกอง
ทำความเข้าใจสแต็กเทรซ
การติดตามสแต็กช่วยให้คุณดัมพ์สถานะปัจจุบันของสแต็กการโทรของคุณทุกครั้งที่มีข้อยกเว้น และมีประโยชน์ในการค้นหาว่าสิ่งใดผิดพลาด
แม้ว่าบรรทัดแรกของ stacktrace จะแสดงบรรทัดที่มีข้อยกเว้น แต่ก็ไม่ได้แสดงที่มาของข้อผิดพลาดเสมอไป ในตัวอย่างข้างต้น โปรแกรมทำงานอย่างถูกต้อง แต่ไม่สามารถจัดการข้อมูลที่ส่งไปยัง divide
กระบวนการ. การเดินขึ้นสแต็กเทรซนำไปสู่ตำแหน่งที่เรียกว่า ซึ่ง คือ ที่มาของปัญหา
เช่นเคย เราชอบที่จะรู้ว่าคุณชอบบทความนี้อย่างไร หากคุณมีคำถามเกี่ยวกับบทความนี้ และต้องการอ่านเกี่ยวกับอะไรต่อไป โปรดแจ้งให้เราทราบที่ @AppSignal