如何在Rails中生成唯一的请求ID?

我的记录器需要一个唯一的请求ID,因此我可以跟踪日志文件中的每个请求。

到目前为止我得到了这个

REQUEST_ID = Digest::MD5.hexdigest(Time.now.to_f.to_s + $PID.to_s) 

问题是我不知道在哪里放这个。 我尝试将它放在我的自定义记录器文件中,在类外面。 但它必须被缓存或其他东西,因为我总是得到相同的哈希。

有任何想法吗?

注意。 我正在使用Rails 3和Passenger独立版

更新:

Rails 3.2:uuid标签不起作用。 看看日志的格式是多么糟糕:

 [0909413851b79676cb06e0842d21c466] [127.0.0.1] Started HEAD "/" for 127.0.0.1 at Tue Feb 21 14:08:25 -0300 2012 [0909413851b79676cb06e0842d21c466] [127.0.0.1] Processing by PagesController#home as HTML [0909413851b79676cb06e0842d21c466] [127.0.0.1] bla [0909413851b79676cb06e0842d21c466] [127.0.0.1] Rendered pages/home.html.erb within layouts/application (2.0ms) 

在生产中,这将是一个烂摊子。 请注意第一行之后的换行符? 现在想象一下在每秒处理许多请求的服务器中日志的样子。 将请求与URI关联起来很困难

如果要在Started GET "/" for 127.0.0.1 at Tue Feb 21 14:00:00 -0300 2012的日志行Started GET "/" for 127.0.0.1 at Tue Feb 21 14:00:00 -0300 2012插入请求UUID,您可以修补或子类Rails::Rack::Logger来修改call_app方法:

 def call_app(env) request = ActionDispatch::Request.new(env) path = request.filtered_path Rails.logger.info "\n\nStarted #{request.request_method} \"#{path}\" for #{request.ip} at #{Time.now.to_default_s}" @app.call(env) ensure ActiveSupport::LogSubscriber.flush_all! end 

请求对象在日志记录语句之前创建,因此您可以更改logging语句以包含request.uuid

Rails核心团队为您服务!

Rails 3.2引入了request.uuid方法,该方法返回唯一的请求标识符,如下所示: ab939dfca5d57843ea4c695cab6f721d

请参阅此处的发行说明

另外,请看一下这个精彩的截屏video ,了解如何在记录时使用这种新方法。

 # config/environments/development.rb config.log_tags = [:uuid, :remote_ip] # log file [ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Started GET "/" for 127.0.0.1 at 2012-01-27 21:52:58 +0000 [ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Processing by ProductsController#index as HTML [ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Product Load (0.3ms) SELECT "products".* FROM "products" [ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Rendered products/index.html.erb within layouts/application (22.0ms) [ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Completed 200 OK in 81ms (Views: 73.1ms | ActiveRecord: 0.3ms) [98eec5f8976586c1165b981797086b6a] [127.0.0.1] 

使用log_tags对答案进行log_tags ,因为:uuid在请求中仅是唯一的,因此很难将其与会话跟踪一起使用。

我发现log_tags接受Proc,并将请求对象作为参数传递。 因此,以下代码将使用session_id标记所有日志条目(假设您正在使用基于ActiveRecord的会话存储)

 config.log_tags = [ lambda {|req| "#{req.cookie_jar["_session_id"]}" }, :remote_ip, :uuid ]