如何在Rails中记录user_name?

我在Rails 3中使用Devise。我想在production.log中看到current_user的名称。

我想像这样配置rails:

config.log_tags = [:user_name] 

我发现这个小巧但有效的解决方案。

Warden在会话中存储用户信息,但req.session不可用于记录。

所以你必须将它添加到config / application.rb

 config.middleware.delete(ActionDispatch::Cookies) config.middleware.delete(ActionDispatch::Session::CookieStore) config.middleware.insert_before(Rails::Rack::Logger, ActionDispatch::Session::CookieStore) config.middleware.insert_before(ActionDispatch::Session::CookieStore, ActionDispatch::Cookies) 

然后创建文件config / initializers / logging.rb

 Rails.configuration.log_tags = [ proc do |req| if req.session["warden.user.user.key"].nil? "Anonym" else "user_id:#{req.session["warden.user.user.key"][0][0]}" end end ] 

现在我看到匿名:

 [Anonym] Served asset ... 

这对用户来说:

 [user_id:1] Served asset ... 

我使用了Wojtek Kruszewski的这个解决方案: https ://gist.github.com/WojtekKruszewski

我为我的项目调整了一点,只包括id,但基本相同。

 # config/application.rb config.log_tags = [ ->(req){ if user_id = WardenTaggedLogger.extract_user_id_from_request(req) user_id.to_s else "?" end } ] 

并创建此初始化程序

 # initializers/warden_tagged_logger.rb module WardenTaggedLogger def self.extract_user_id_from_request(req) session_key = Rails.application.config.session_options[:key] session_data = req.cookie_jar.encrypted[session_key] warden_data = session_data["warden.user.user.key"] warden_data[0][0] rescue nil end end 

新增2013-03-07:

在Rails 4中,encrypted_cookie_store是默认的会话存储。 这是您访问会话数据的方法:

 session_data = req.cookie_jar.signed[ "_qnaire_session" ] 

看起来warden_data在我的新应用中看起来有所不同,例如: [[542], "$2a$10$e5aYxr/PIp6OOj8jzE7mke"] ,其中第一项是用户ID。

这是我目前的片段: https : //gist.github.com/wojt-eu/5109643

以前的版本:

这就是我提出的:

 config.log_tags = [ :remote_ip, ->(req){ session_data = req.cookie_jar.signed[ "_qnaire_session" ] warden_data = session_data["warden.user.provider_user.key"] if warden_data '#' + warden_data[1][0].to_s else "guest" end } ] 

_qnaire_session可以替换为instance.config.session_options[:key]或通过singleton: Rails.application.config.session_options[:key]

我有ProviderUser模型,因此warden.user.provider_user.key 。 我想用User模型这将是warden.user.user.key

这很麻烦,但它不会影响正常的身份validation过程,中间件堆栈顺序等。如果在某些更新过程中它只会中断标记日志会受到影响,我应该在查看开发日志时快速注意到这一点。

这是我刚刚添加到config/initializers/logging.rb

 Rails.configuration.log_tags = [ :uuid, # request UUID lambda { |req| # Credentials are (currently) in the format of: # # :: # # So we have to split by '::' to obtain the user_id for logging. # # This will just output "User: nil" if there is no current session. "User: #{req.cookies['user_credentials'].to_s.split('::')[1]}" } ] 

这适用于Authlogic。 您需要做的事情可能会有所不同,因此您应该深入了解您的数据已经暴露给您的内容。

步骤1:

查看req对象的可用内容。 将其添加到config/initializers/logging.rb

 Rails.configuration.log_tags = [ lambda { |req| req.inspect } ] 

然后点击页面,看看什么被转储。

第2步:使用相同的技术查看您的cookiejar是否有足够的信息:

 Rails.configuration.log_tags = [ lambda { |req| req.cookies.inspect } ] 

(点击请求)

旁白:不要担心将用户名/电子邮件放入日志中 – 用户ID足够好,您可以在数据库中查找它以获取所需的任何额外元数据。

遗憾的是,日志标记仅在请求委托开始时(在Rails::Rack::Logger中间件中)评估一次。 在此阶段没有控制器,因此任何current_user帮助程序都不可用。 还没有设置warden甚至会话,但至少有一个cookiejar,所以如果你存储session_id,你可以直接恢复会话或记录session_id。

 config.log_tags = [ lambda { |req| req.cookie_jar["_session_id"].to_s } ] 

我认为最好的选择是直接在log_in中将用户名存储在cookie中,并使用会话将其销毁。

 config.log_tags = [ lambda { |req| req.cookie_jar["user_name"] || 'Noone' } ] 

不工作:

但如果你使用设计,它使用warden raack中间件,所以env['warden']应该可用,所以你能试试吗?

 config.log_tags = [ lambda { |req| user = req.env['warden'].user; user && user.name || 'Noone'; } ] 

即使没有看守,因为你确实通过env['rack.session']提供会话,如果你在会话中存储用户ID,你可以做类似的事情

 config.log_tags = [ lambda { |req| user = User.find_by_id(req.env['rack.session']['user_id']); user && user.name || 'Noone'; } 

几乎对我有用的东西(Rails 3.2.22.2)就是这里的答案: http ://benjit.com/rails/logger/2016/02/26/getting-admin-user-into-rails-logfile/

这假设cookie_jar对象响应encrypted 。 但事实并非如此。 最终对我有用的是:

config/initializers/logging.rb

 Rails.configuration.log_tags = [ lambda { |req| session_key = Rails.application.config.session_options[:key] session_data = req.cookie_jar.signed[Rails.application.config.session_options[:key] ] warden_data = ( session_data["warden.user.user.key"]|| [[]]) admin_user = warden_data[0][0] "u: #{admin_user || 0}" } ] 

正如@viktortron在log_tags初始化时的回答中所说,我们没有适当的session对象可用,但session_id在请求中。

如果您正在使用_database session_store_,就像我的情况一样,您可以ad-hoc重建会话

 session = ActiveRecord::SessionStore::Session.find_by_session_id(request.cookie_jar["_session_id"]) 

这就是我的log_tags的定义方式:

 # config/initializers/rails_log.rb def get_user_id(req) session = ActiveRecord::SessionStore::Session.find_by_session_id(req.cookie_jar["_session_id"]) result = session ? session.data["user_id"] : 0 "%07d" % result end log_tags = [] log_tags << lambda { |req| Time.now.strftime("%F %T.%L") } log_tags << lambda { |req| req.uuid.first(8) } log_tags << lambda { |req| get_user_id(req) } Rails.configuration.log_tags = log_tags 

结果如下:

 [2013-01-22 13:51:36.659] [e52435d1] [0036484]  

现在完全不同的东西……

https://github.com/roidrage/lograge/issues/23#issuecomment-11709861

我刚刚尝试使用Rails 4,最新的Devise和Lograge。

我正在使用Swards解决方案 ,它就像一个魅力。 但是使用begin..rescue而不是Hash# begin..rescue ? 是一个性能杀手

 require 'benchmark/ips' good_hash = { 'warden.user.admin_user.key' => [[1]]} bad_hash = {} Benchmark.ips do |x| x.report('begin+rescue good hash') { good_hash['warden.user.admin_user.key'][0][0] } x.report('has_key good hash') do good_hash.has_key?('warden.user.admin_user.key') && good_hash['warden.user.admin_user.key'][0][0] end x.report('begin+rescue bad hash') { bad_hash['warden.user.admin_user.key'][0][0] rescue nil } x.report('has_key bad hash') do if bad_hash.has_key?('warden.user.admin_user.key') bad_hash['warden.user.admin_user.key'][0][0] end end # Compare the iterations per second of the various reports! x.compare! end 

结果不言而喻

 Comparison: has_key bad hash: 4870164.1 i/s begin+rescue good hash: 3544134.7 i/s - 1.37x slower has_key good hash: 2127500.6 i/s - 2.29x slower begin+rescue bad hash: 4468.2 i/s - 1089.95x slower 

这是我在Rails 5.1中使用的cookie解密器,用user_id标记日志, user_id存储在cookie中。 它基本上允许我从原始cookie访问控制器等同于session[:user_id]

环境/ production.rb:

 config.log_tags = [ :request_id, :remote_ip, lambda do |req| session_data = CookieDecrypter.new(req).session_data "user_id:#{session_data['user_id']}" end ] 

应用程序/模型/ cookie_decrypter.rb:

 class CookieDecrypter attr_reader :request def initialize(request) @request = request end def session_data cookie = request.cookies[session_key] return {} unless cookie.present? cookie = CGI::unescape(cookie) key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000) secret = key_generator.generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len] sign_secret = key_generator.generate_key(signed_salt) encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) encryptor.decrypt_and_verify(cookie) || {} end private def session_key Rails.application.config.session_options[:key] end def secret_key_base Rails.application.secrets[:secret_key_base] end def salt Rails.application.config.action_dispatch.encrypted_cookie_salt end def signed_salt Rails.application.config.action_dispatch.encrypted_signed_cookie_salt end end 

作为一种快速而丑陋的解决方法,也许可以在处理请求后记录第二行。

此500 ServerError已显示为:#{username}

对于任何使用Redis :: Store @ fjuillen的人来说,答案如下:

 redis = Redis::Store.new redis.select 3 # only if you use a different database result = redis.get req.cookie_jar["_session_id"] 

在轨道上测试4。