Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

การทำงานกับ Logs ใน Ruby

Logging เป็นหนึ่งใน Primary Tasks ที่ Application ปกติจัดการ Logs ใช้เมื่อคุณต้องการ เช่น

  • ดูว่าภายใน App เกิดอะไรขึ้นบ้าง
  • Monitor พวกมัน
  • Collect Metrics สำหรับ Data เฉพาะเจาะจง

ตอนเรียนภาษาใหม่ ตัวเลือกอvious สำหรับ Log ข้อมูลคือ Native Mechanism มันมัก Easy, Documented, และ Well-spread ใน Community

Log Data แตกต่างกันมากขึ้นอยู่กับ Company, Business, และ Application Type ที่คุณทำงาน ดังนั้นเข้าใจว่า Logging Solution ที่คุณและทีมเลือกจะ Impact Overall Use ยังไง จึงสำคัญมาก

ในบทความนี้ เราจะทัวร์ตัวเลือก Logging สำหรับ Ruby และ Rails ตั้งแต่ Built-in ถึง Third-party Community Frameworks ที่ได้รับความนิยม มาเริ่มกัน!

ตัวเลือก Built-in ของ Ruby

Ruby มาพร้อม 2 Built-in Options สำหรับ Handle Logging: Printing Commands (ออกแบบเฉพาะ Command-line Scenarios) และ Logger Class

มา Explore เล็กน้อย

Print ไป Console

Ruby มี 4 วิธีทั่วไป Print Text ไป Console: puts, print, p, และ pp

puts Print อะไรก็ตามที่ส่งเข้าไป ตามด้วย New Line:


2.7.0 :001 > puts "Hey, I'm a log!"
Hey, I'm a log!
=> nil

print คล้าย puts แต่ Convert Arguments เป็น Strings ด้วย to_s เสมอ

p และ pp ทั้งคู่ Print Raw Object ที่ส่งเข้าไป โดยไม่ Convert ความต่างคือ pp Format Output ให้ Indented สวยกว่า p ไม่ Format

Application Logs

สำหรับ Apps ที่รันบน Servers ไม่ควร Print ไป Console

แทนที่จะใช้ Logger Class ซึ่งยืดหยุ่นกว่า

นี่คือวิธีใช้ Print "Debug" Log:


require "logger"
logger = Logger.new(STDOUT)
logger.debug("I'm a debug log")

เราสามารถ Config ให้เก็บ Logs ไป File หรือส่งไป Log Aggregator แทน STDOUT ก็ได้

ถ้าสนใจ "debug" เป็น Log Level Log Levels ให้บอก System ว่า "Log Message นี้เกี่ยวกับ Event ประเภทไหน" มี 6 Built-in Levels: Fatal, Error, Warn, Info, Debug และ Unknown


logger.debug("I'm a debug log")
logger.info("I'm an info log")
logger.warn("I'm a warn log")
logger.error("I'm an error log: error message")
logger.fatal("I'm a fatal log")

ดู Log Output จะเห็น Log Level, Process ID และ Timestamp ถูก Append ทุกบรรทัด:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

Feature ยอดเยี่ยมอีกอย่าง: ตั้ง Logger Object ให้อยู่ Level เฉพาะ:


logger.level = Logger::WARN

ตอนนี้ Logger จะ Handle Logs ที่เท่ากับหรือสูงกว่า warn ในความสำคัญเท่านั้น มีประโยชน์มากใน Production ที่อาจไม่อยากเก็บ "debug" Logs เพราะ Size หรือ Security Reasons

Output จะเป็นแบบนี้:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

ปรับแต่ง Logs ของคุณ

อยาก Customize Logs มี Options เยอะ เปลี่ยน Date/Time แค่ Overwrite Default:


logger.datetime_format = "%Y-%m-%d %H:%M"

Output ตัวอย่าง:


W, [2020-07-28 10:50#87786] WARN -- : I'm a warn log

date_time Format ตาม Spec มาตรฐาน อ้างอิง Spec ตอนทำการเปลี่ยนแปลง

บางครั้งต้อง Modify Log Format ทั้งหมด Ruby ให้ Formatter Class มันทำงานโดยให้ Devs Overwrite Default Template ที่ Logger ใช้ Print Logs

สมมติ App ใช้ Centralized Logs Analysis Tool ต้องการ Logs ทุกตัวเป็น Format name=value โค้ด Formatter ใหม่:


logger.formatter = proc do |severity, datetime, progname, msg|
  date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
  "date=[#{date_format}] severity=#{severity.ljust(5)} pid=##{Process.pid} message='#{msg}'\n"
end

ใช้ proc Intercept Logs ทุกตัว เปลี่ยน Default Print ให้เป็น Format ที่ต้องการ ผลลัพธ์:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

เพียงไม่กี่บรรทัด App Logs ทั้งหมด Index ได้โดย Tool แล้ว

Logging เป็น JSON

ด้วยพลัง Formatter ง่ายมากที่จะ Customize Logs ให้ Output Type ใดๆ เช่น ใช้ JSON Module Output Logs เป็น JSON:


require "json"
logger.formatter = proc do |severity, datetime, progname, msg|
  date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
  JSON.dump(date: "#{date_format}", severity:"#{severity.ljust(5)}", pid:"##{Process.pid}", message: msg) + "\n"
end

Logs ผลลัพธ์:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

Logging ไป File

เห็นก่อนหน้า Logger Constructor รับ Argument แรกเป็นที่เก็บ Log

อยากเก็บ Logs ไป File บอกเลย:


require 'logger'
logger = Logger.new('my_logs.log')

จะสร้าง File my_logs.log ใน Folder เดียวกับ Ruby File ที่มีโค้ดนี้:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

แต่ Class ยังรับ Custom Options เยอะ เช่น Retention Policy Config ตัวอย่าง:


# เก็บ Data สำหรับสัปดาห์ปัจจุบัน
Logger.new('my_weekly_logs.log', 'weekly')
# เก็บ Data วันนี้และ 2 เดือนย้อนหลัง
Logger.new('my_latest_2_months_logs.log', 2, 'monthly')
# Restart Log เมื่อเกิน 26GB
Logger.new('my_custom_logs.log', 0, 20 * 1024 * 1024 * 1024)

Param ที่ 2 Logger รับ Definition ว่าเก็บ Logs บ่อยแค่ไหน หรือ ลบบ่อยแค่ไหน Object แรกเก็บ 1 สัปดาห์ Object ที่สองเก็บ Range 2 เดือน Object สุดท้ายวิเคราะห์แค่ File Size (เช่น ถึง 20GB จะ Discard) ตาม Param ที่ 3

Logging ใน Ruby on Rails

Benefits ของ Logger ที่เห็นส่วนใหญ่ ใช้ร่วมกับ Rails Apps ได้ Rails Version ของ Logger คือ Simple Extension ของ Native Class ของ Ruby

นอกจากนี้ Rails เพิ่ม Feature ให้ Devs Broadcast Logs ไป Multiple Loggers ได้ ถ้าอยากทำงานกับ Logging Libraries มากกว่าหนึ่ง ทำได้ใน Rails logger:


custom_logger = Logger.new(STDOUT)
Rails.logger.extend(ActiveSupport::Logger.broadcast(custom_logger))

มีประโยชน์ตอนต้องการ Intelligence เกี่ยวกับที่ Logs ควรไป บางส่วนของ App อาจต้องการ Logs ใน Locations หรือ Formats ต่างกัน

เลือก Third-party Logging Framework

ถ้า Built-in Logger ของ Ruby ไม่ทำให้พอใจ มี Options เยอะ

ยอดนิยมคือ Lograge มาดู!

First Steps with Lograge

Lograge ทำสำหรับ Rails Apps ถ้า Vanilla Ruby อาจไม่เหมาะ

ติดตั้งเพิ่ม Gem:


bundle add lograge

สร้าง Config File ใหม่ที่ config/initializers/lograge.rb เนื้อหา:


Rails.application.configure do
  config.lograge.enabled = true
  config.lograge.custom_options = lambda do |event|
    { time: event.time }
  end
end

Config เปิด Lograge และกำหนดเวลาที่ Log (Event ต่อ Framework) ต้อง Print

Start Rails App เข้าถึง Endpoint แรก Lograge จะ Print Request Summary เปรียบเทียบ Logs ก่อนและหลัง Setup Lograge:

เชี่ยวชาญ Ruby Logging: คู่มือผู้เชี่ยวชาญกับ Logger และ Lograge

Lograge ไม่ใช่ Silver Bullet เป็น Opinionated Framework จะต้องใช้ร่วม Built-in Logger (หรือ Frameworks อื่นที่ชอบ) ได้

สรุป

สุดท้ายชัดเจนว่า Logging ไม่ได้แค่ Crucial Part ของ Projects แต่ยัง Underestimated อีกด้วย การเข้าใจ Tools ที่ใช้ ไม่ว่าจะ Native จะช่วย Achieve Better Results ได้

Test มากๆ ก่อน Adopt Framework ใหม่ Platform บางอันมาพร้อม Built-in Options ที่ยอดเยี่ยม ถ้าไม่ใช่ ให้เช็คว่า Allow Frameworks อื่น Integrated กับที่มีอยู่ได้ไหม

Good luck!