我在 Rails 3 中使用 Devise。我想在 production.log 中查看 current_user 的名称。
我想像这样配置rails:
config.log_tags = [:user_name]
我在 Rails 3 中使用 Devise。我想在 production.log 中查看 current_user 的名称。
我想像这样配置rails:
config.log_tags = [:user_name]
我发现这个有点棘手但有效的解决方案。
Warden 将用户信息存储在 session 中,但 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
在 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]
或通过单例替换:Rails.application.config.session_options[:key]
我有 ProviderUser 模型,因此warden.user.provider_user.key
. 我想对于用户模型,这将是warden.user.user.key
.
它很乱,但不会影响正常的身份验证过程、中间件堆栈顺序等。如果在某些更新期间中断,只会影响标记日志,我在查看开发日志时应该很快注意到这一点。
这是我在 Rails 5.1 中使用的 cookie 解密器,用于用 标记日志user_id
,它存储在 cookie 中。它基本上让我可以访问相当于session[:user_id]
原始 cookie的控制器
环境/生产.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
而现在完全不同的东西......
https://github.com/roidrage/lograge/issues/23#issuecomment-11709861
我刚刚使用 Rails 4、最新的 Devise 和 Lograge 进行了尝试。
不幸的是,日志标签只在请求委托的一开始就被评估一次(在Rails::Rack::Logger
中间件中)。在这个阶段没有控制器,所以任何 current_user 帮助器都不可用。还没有设置守望者甚至会话,但至少有一个 cookiejar,所以如果您将 session_id 存储在那里,您可以直接恢复会话或记录 session_id。
config.log_tags = [ lambda { |req| req.cookie_jar["_session_id"].to_s } ]
我认为最好的选择是将用户名直接存储在 cookie 中的 log_in 中,并在会话中销毁它。
config.log_tags = [ lambda { |req| req.cookie_jar["user_name"] || 'Noone' } ]
不工作:
但是如果你使用devise,它使用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'; }
这是我刚刚添加的内容config/initializers/logging.rb
:
Rails.configuration.log_tags = [
:uuid, # request UUID
lambda { |req|
# Credentials are (currently) in the format of:
#
# <session_hash>::<user_id>
#
# 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 步:查看您的 cookie jar 是否有足够的信息,使用相同的技术:
Rails.configuration.log_tags = [
lambda { |req|
req.cookies.inspect
}
]
(点击请求)
顺便说一句:不要担心将用户名/电子邮件放入日志 - 用户 ID 就足够了,您可以在数据库中查找它以获得所需的任何额外元数据。
几乎对我有用的(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_,就像我的情况一样,您可以临时重建会话:
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] <the log line>
我正在使用Swards 解决方案,它就像一个魅力。但是使用begin..rescue
而不是Hash#has_key?是性能杀手
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
As a quick and ugly workaround, maybe one could log a second line after the request has been processed.
This 500 ServerError has been presented by: #{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 上测试。