เคยเจอ error ใน production และ ลองอะไรก็ตาม ไม่สามารถ replicate issue บน development หรือ staging environments ได้เลย บ่อยครั้งขั้นตอนต่อไปคือเก็บข้อมูลเพิ่มด้วยการทิ้ง debug log ที่ production ถ้าไม่มีวิธี correlate logs กับ request จะ frustrating มาก โดยเฉพาะระหว่าง incident
เราเพิ่ม feature ช่วย เรียกว่า Breadcrumbs

Breadcrumb คล้าย log event แต่ stored และ reported alongside error เหมือน log Breadcrumb มี message แต่ยังเก็บ metadata (hashmap) ได้ ชุด breadcrumbs ถูกเก็บทลอด request (หรือ job invocation) และทิ้งทันที ถ้าไม่มี error reported
เพิ่ม breadcrumbs ของตัวเองเข้า stack ง่าย แค่เรียก Honeybadger.add_breadcrumb ที่ไหนก็ได้ในโค้ด:
Honeybadger.add_breadcrumb("Loading User", metadata: { user_name: user_name, })
ถ้า error reported หลังจากนั้น ควรเห็นใน Breadcrumb stack:

Oh user_name ดูว่าง อาจก่อให้เกิดปัญหา
Automatic breadcrumbs
Honeybadger Ruby library มี hooks เข้า Ruby & Rails เพื่อ collect breadcrumbs อัตโนมัติ เช่น log messages ทั้งหมดใน Production (ส่งผ่าน class Logger) ถูก capture และสร้างเป็น breadcrumbs เรายัง tie เข้า Rails Instrumentation เก็บ breadcrumbs สำหรับ Controller Actions, SQL Queries, Active Job invocations ฯลฯ
ใช้ได้อย่างไร?
Breadcrumbs ใช้ได้ผ่าน Ruby client ต้อง update version 4.4.0 และ enable ใน config เพราะจะ disabled โดย default จนกว่าเราจะ release 5.0.0 เพื่อ ensure เราแก้ kinks หมด
ลองใช้และแจ้งถ้ามีปัญหา
Extending Breadcrumbs (ขยาย Breadcrumbs)
ตอน Breadcrumbs introduced แล้ว มาดูตัวอย่างเร็วๆ ว่าขยายยังไง ถ้า enable Breadcrumbs ใน Rails app จะได้ standard instrumentation breadcrumbs ฟรี แตถ้าอยากได้มากกว่านี้?
สมมติอยากสร้าง Breadcrumb ทุกครั้งที่แอปส่ง HTTP request ข้อมูลนี้อาจช่วย debug
วิธีง่าย เรียก Honeybadger.add_breadcrumb ทุก request invocation
def send_a_message
res = conn.post("/message", { user: user.id, body: "Hey!" }.to_json)
Honeybadger.add_breadcrumb("Request: /message", metadata: { user: user.id })
res
end
เก็บ breadcrumb หลัง POST ไป /message ครั้งหน้า app throw error หลังส่ง message ควรเห็นว่า user ไหนส่ง message และเมื่อไหร่ relative กับ error
แต่วิธีนี้ cumbersome ต้อง add_breadcrumb ทุก location ที่ส่ง request ผมอยาก note มี advantages ในการสร้าง breadcrumbs แบบนี้ สามารถ specific เกี่ยวกับ metadata ที่อยาก capture บ่อยครั้งเป็นวิธีดีเก็บ targeted information から bug ใน production
ผมแค่อยากรู้ว่า request ออกเมื่อไหร่ ที่ไหน ยังไงหละถ้า library ทำให้ส่วนใหญ่ ;)
Instrumenting with Faraday
เราจะ cheat นิดหน่อย สมมติคุณใช้ Faraday request library ยอดนิยม
เราสามารถสร้าง middleware เอง แต่จะใช้ Rails instrumentation เป็น broker โชคดีที่ faraday_middleware gem มี middleware ที่ emit events ให้ ใส่ gem ใน Gemfile และแน่ใจว่า instrumentation middleware injected เข้า connection
connection = Faraday.new do |conn|
conn.use :instrumentation
conn.adapter Faraday.default_adapter
end
อาจต้องทำงานนิดหน่อยถ้าไม่ share connection ในแอป ถ้าขี้เกียจ prepend ConnectionOptions ให้ทุก requests มี middleware enabled ระวังด้วย จะ instrument ทุก Faraday requests ในแอปและ gems ที่ include (ซึ่งคุณอาจอยากได้)!
Rails instrumentation มี side effects ดี หนึ่งคือ multiple subscriptions สำหรับ use cases อื่น (เช่น general logging)
Binge watching our requests (ดู requests แบบต่อเนื่อง)
ตอน Faraday requests instrumented แล้ว subscribe และสร้าง breadcrumbs:
ActiveSupport::Notifications.subscribe "request.faraday" do |_, _, _, _, data|
method = data[:method].to_s.upcase
metadata = data.to_h.slice(:url, :status).merge({method: method})
Honeybadger.add_breadcrumb("#{method}: #{metadata[:url]}", category: "request", metadata: metadata)
end
Honeybadger เพิ่ม breadcrumb สำหรับ outgoing request ทุกครั้ง!

สังเกตเรา inspect แค่ few data points จาก requests ไม่ add outgoing/response body payloads เพราะโอกาส leak sensitive data เข้า breadcrumb metadata มาก
บอกเราว่าเป็นอย่างไร!
หวังว่า Breadcrumbs จะเป็นการเพิ่มที่ช่วยใน debugging toolbox ลองใช้ และแจ้งถ้าอยากให้เพิ่มอะไร