Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Làm Việc Với Log Trong Ruby

Logging là một trong những nhiệm vụ chính mà một ứng dụng thường giải quyết. Log được dùng khi bạn cần, ví dụ:

  • xem điều gì đang xảy ra bên trong apps của bạn,
  • giám sát chúng, hoặc
  • thu thập metrics cho một số dữ liệu cụ thể.

Khi học một ngôn ngữ lập trình mới, lựa chọn rõ ràng đầu tiên để log thông tin là cơ chế native. Nó thường dễ dàng, được documented tốt, và phổ biến khắp cộng đồng.

Dữ liệu log thay đổi rất nhiều tùy thuộc vào công ty, business, và loại ứng dụng bạn đang làm việc. Do đó, rất quan trọng để hiểu giải pháp logging bạn và team chọn sẽ ảnh hưởng như thế nào đến việc sử dụng tổng thể.

Trong bài viết này, chúng ta sẽ đi qua các tùy chọn logging có sẵn cho Ruby và Rails, từ built-in đến các framework cộng đồng third-party được yêu thích. Let's go!

Lựa Chọn Built-In Của Ruby

Ruby đi kèm với hai lựa chọn built-in để xử lý logging: printing commands (được thiết kế đặc biệt cho kịch bản command-line) và class Logger.

Hãy khám phá chúng một chút.

In Ra Console

Ruby có bốn cách phổ biến để in text ra console: puts, print, p, và pp.

Phương thức puts in bất cứ thứ gì bạn pass cho nó, theo sau bởi một dòng mới:

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

Phương thức print tương tự puts, tuy nhiên nó luôn convert arguments thành strings dùng phương thức to_s.

Cuối cùng, phương thức p và pp đều sẽ in raw object bạn pass cho chúng mà không thực hiện conversion; sự khác biệt duy nhất là cái sau format output theo cách indent hơn, trong khi cái trước không.

Application Logs

Đối với ứng dụng chạy trên server, không có lý do để in ra console.

Thay vào đó, chúng ta dùng class Logger, linh hoạt hơn nhiều.

Đây là cách bạn có thể dùng nó để in một log "debug":

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

Chúng ta cũng có thể cấu hình nó để lưu log vào file, hoặc gửi chúng đến log aggregator thay vì in ra STDOUT nếu muốn.

Nếu bạn đang thắc mắc, "debug" là một log level. Log levels cho phép bạn nói cho hệ thống "thông điệp log này liên quan đến một loại event nhất định." Có sáu built-in log levels: Fatal, Error, Warn, Info, Debug và 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")

Khi chúng ta nhìn output log, chúng ta thấy log level, process id và timestamp đã được appended vào mỗi dòng:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Tính năng tuyệt vời khác là khả năng set Logger object ở một level cụ thể:

logger.level = Logger::WARN

Khi bạn làm điều này, Logger sẽ chỉ handle các log bằng hoặc cao hơn warn về độ quan trọng. Điều này rất hữu ích trong production, nơi chúng ta có thể không muốn lưu log "debug" do lý do kích thước hoặc bảo mật.

Đây nên là output:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Tùy Chỉnh Log Của Bạn

Nếu bạn muốn tùy chỉnh log của mình, có rất nhiều option. Để thay đổi date và time, ví dụ, chỉ cần ghi đè default:

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

Đây là ví dụ output:

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

Định dạng date_time tuân theo spec chuẩn, vì vậy hãy chắc chắn tham khảo nó khi thực hiện thay đổi như vậy.

Đôi khi, tuy nhiên, bạn có thể cần fully modify format log của mình. Cho mục đích này, Ruby cung cấp class Formatter. Nó hoạt động bằng cách cho phép dev ghi đè default template mà Logger dùng để in log.

Hãy tưởng tượng app của bạn dùng centralized logs analysis tool và cần tất cả log được in theo format name=value. Đây sẽ là code formatter mới:

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

Ở đây, chúng ta dùng proc để intercept tất cả log và thay đổi cách mặc định chúng được in thành cái mong muốn. Bây giờ, chúng ta có kết quả sau:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Chỉ với vài dòng code, tất cả app log của bạn bây giờ có thể được indexed bởi tool.

Logging Ra JSON

Với sức mạnh của Formatter trong tay, dễ dàng tùy chỉnh log của bạn thành bất kỳ output type nào bạn muốn. Ví dụ, chúng ta có thể dùng module JSON để output log theo format đó.

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

Và, đây là log kết quả:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Logging Vào File

Như đã thấy trước, constructor Logger nhận, như first argument, nơi log nên được lưu trữ.

Nếu bạn muốn lưu log vào file, chỉ cần nói vậy:

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

Điều này sẽ tạo file mới my_logs.log trong cùng folder nơi file Ruby chứa code này nằm:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Tuy nhiên, class cũng cho phép một loạt custom option, như config retention policy. Xem ví dụ sau:

# Giữ data cho tuần hiện tại.
Logger.new('my_weekly_logs.log', 'weekly')
# Giữ data cho hôm nay và 2 tháng qua.
Logger.new('my_latest_2_months_logs.log', 2, 'monthly')
# Restart log khi nó vượt quá 26GB size.
Logger.new('my_custom_logs.log', 0, 20 * 1024 * 1024 * 1024)

Là second param, Logger chấp nhận định nghĩa về tần suất nó nên giữ log hoặc xóa chúng.

Trong object đầu tiên, log sẽ được giữ một tuần. Thứ hai sẽ lưu chúng cho khoảng hai tháng, trong khi cái mới nhất sẽ chỉ phân tích size của file (ví dụ, bất cứ khi nào nó đạt 20GB, nó sẽ bị discard) dựa trên third param.

Logging Trong Ruby On Rails

Hầu hết benefit của Logger chúng ta đã thấy đến nay đều có thể dùng cùng với Rails apps. Phiên bản Rails của Logger chỉ là một extension đơn giản của class native Ruby.

Ngoài ra, Rails cũng thêm một tính năng hay cho phép dev broadcast log của họ đến multiple logger. Vì vậy, nếu bạn muốn làm việc với nhiều logging library hơn một, bạn có thể làm vậy trong Rails logger:

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

Điều này cũng hữu ích khi bạn cần một số intelligence về nơi log nên đi. Một số phần app của bạn có thể cần log ở vị trí khác nhau hoặc format khác nhau.

Chọn Framework Logging Third-party

Nếu built-in logger của Ruby không làm chính xác những gì bạn cần, bạn có options.

Có rất nhiều lựa chọn khi chọn framework logging third-party. Phổ biến nhất trong số đó là Lograge. Hãy nhìn vào nó!

Bước Đầu Với Lograge

Lograge được làm cho Rails apps. Nếu bạn đang làm việc với vanilla Ruby, nó có thể không phải lựa chọn tốt.

Để cài đặt, chỉ cần thêm gem sau:

bundle add lograge

Sau đó, tạo file config mới tại config/initializers/lograge.rb với code sau:

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

Config này enable Lograge và định nghĩa thời gian một log, được coi là event bởi framework, phải được in.

Khi bạn start Rails app và truy cập endpoint đầu tiên, Lograge sẽ in request summary. So sánh log trước và sau setup Lograge, tương ứng, cho kết quả như dưới đây:

Làm Chủ Logging Ruby: Hướng Dẫn Chuyên Gia Với Logger Và Lograge

Lại, Lograge không phải silver bullet; nó thực sự là framework rất opinionated. Vì vậy, bạn có thể sẽ cần dùng nó cùng với built-in Logger (hoặc framework khác theo sở thích).

Kết Thúc

Cuối cùng, rõ ràng logging không chỉ là phần quan trọng của project mà còn bị underrated. Để hiểu tốt hơn các tool bạn đang dùng, bất kể chúng là native, sẽ giúp bạn đạt kết quả tốt hơn.

Hãy chắc chắn luôn thực hiện nhiều test trước khi adopt framework mới. Đôi khi platform của bạn đã bundled sẵn built-in option tuyệt vời. Nếu không phải trường hợp đó, hãy xác định xem nó có cho phép dùng framework khác integrated với cái đã có bên trong không.

Best of luck!