Viết Log ra file trong Ruby on Rails

Lời nói đầu

Việc sử dụng thư viện logger trong Ruby là 1 cách dễ dàng để theo dõi những tương tác của người dùng với hệ thống của chúng ta. Thường thì mỗi khi có 1 tương tác của User với hệ thống thì ở cửa sổ Terminal chúng ta sẽ thấy Log hiện ra, về cơ bản thì Log này sẽ cung cấp cho chúng ta thấy những tương tác với Database và sau đó là việc render ra View, kiểu kiểu như thế này này 😄

Started GET "/" for 127.0.0.1 at 2017-07-28 15:59:13 +0700
  ActiveRecord::SchemaMigration Load (0.3ms)  SELECT `schema_migrations`.* FROM `schema_migrations`
Processing by StaticPagesController#home as HTML
  Rendered support/_slider.html.erb (150.0ms)
  Rendered static_pages/home.html.erb within layouts/application (159.3ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (8.3ms)
  Rendered layouts/_modal.html.erb (0.6ms)
  Rendered layouts/_footer.html.erb (1.4ms)
Completed 200 OK in 475ms (Views: 461.8ms | ActiveRecord: 0.0ms)

Dựa vào Status trả về, chúng ta có thể xác định được hệ thống đang chạy đúng không, ví dụ 200 là OK hay gặp lỗi như 404, 400 ... Với môi trường develop thì sau khi chạy rails s, thì log sẽ show ra luôn. Tuy nhiên, để xem log ở với các môi trường khác, như kiểu Staging thì chúng ta sử dụng lệnh sau:

$ tail -f log/staging.log

Các file log này được rails lưu mặc định ở thư mục log và với tên file tương ứng với các môi trường mình sử dụng, development.log, staging.log hay production.log

Tạo file Log khi hệ thống tương tác với bên thứ 3

Nói chung các tương tác của user với hệ thống của chúng ta đều sẽ được Rails lưu lại mặc định ở Log, tuy nhiên khi mà hệ thống tương tác với 1 bên thứ 3 (như request API chẳng hạn) thì Logger của Rails mặc định lại không lưu lại. Và khi việc hệ thống của chúng ta gửi Request sang bên thứ 3 gặp vấn đề, thì sẽ rất khó để tìm ra lỗi gặp phải ở đây. Hay đơn giản, chúng ta cần "bằng chứng" là đã gửi Request sang bên thứ 3 mọi thứ đều chính xác.

Như vây, chúng ta phải tìm cách để ghi lại đoạn log này. Đầu tiên, mình tạo class ApiLog để tạo mới 1 file api.log và lưu trong thư mục log như sau

class ApiLog
  def self.debug message = nil
    @api_log ||= Logger.new "#{Rails.root}/log/api.log"
    @api_log.debug(message) unless message.nil?
  end
end

Ở đây, mình gửi Request Http sang bên thứ 3 bằng cách sử dụng Faraday, nên mình sẽ ghi log như sau

def send_request post_data
    conn = Faraday.new @url
    conn.basic_auth @merchant_id + @service_id, @hashkey
    resp = conn.post do |req|
      req.headers["content-type"] = "text/xml;charset=Shift_JIS"
      req.body = post_data
    end
    ApiLog.debug resp
    resp
  end

Với đoạn khai báo ApiLog.debug resp thì những yêu cầu request sang bên thứ 3 của mình sẽ được lưu lại vào trong log/api.log Ví dụ cụ thể với hệ thống của mình sẽ kiểu như thế này, gồm có thời gian ghi lại Log và các thông tin như body, header, url ...

D, [2017-07-27T17:28:40.975204 #3398] DEBUG -- : #<Faraday::Response:0x007f2e6365ed78
@on_complete_callbacks=[], @env=#<Faraday::Env @method=:post
@body @url=# @request=#<Faraday::RequestOptions (empty)>
@request_headers={"User-Agent"=>"Faraday v0.9.2", "Authorization"=>"Basic NzIzMzYwMDE6MTQwODMyYjU4YzVhZDYzOTBiNzRhYzY1OTE3NjIyMzFhOTU4ZmM3NQ==", "content-type"=>"text/xml;charset=Shift_JIS"} @ssl=#<Faraday::SSLOptions verify=true>
@response=#<Faraday::Response:0x007f2e6365ed78 ...>
@response_headers={"date"=>"Thu, 27 Jul 2017 10:28:40 GMT", "server"=>"Apache", "set-cookie"=>"JSESSIONID=C1FF1ED1FB119EBCD420B2FB4777C537.f115; Path=/api", "pragma"=>"No-cache", "cache-control"=>"no-cache,no-store,max-age=0", "expires"=>"Thu, 01 Jan 1970 00:00:00 GMT", "content-length"=>"697", "connection"=>"close", "content-type"=>"text/xml;charset=Shift_JIS", "content-language"=>"ja"}
@status=200>>

Tài liệu tham khảo

http://guides.rubyonrails.org/debugging_rails_applications.html