2012-05-30 3 views

ответ

21

Я нашел это небольшое сложное, но работающее решение.

Warden хранит информацию о пользователе в сеансе, но req.session недоступна для ведения журнала.

Таким образом, вы должны добавить это в конфиг/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) 

Затем создайте файл конфигурации/инициализаторами/протоколирования.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 
] 

Теперь я вижу, это для Anonymous:

[Anonym] Served asset ... 

и это для пользователя:

[user_id:1] Served asset ... 
+0

@CharlesBergeron Вы выяснили, подходит ли этот подход или нет? – rit

+1

@rit Да, пошел с вставляя наш собственный пользовательский протоколирования Middleware, как это: 'require_relative» ../ Библиотека/my_app/log_user_id'' 'config.middleware.insert_after (ActiveRecord :: SessionStore, MyApp :: LogUserId) ' –

+0

@CharlesBergeron Спасибо! – rit

2

К сожалению войти теги оцениваются только один раз в самом начале запроса делегации (в Rails::Rack::Logger промежуточного слоя). На этом этапе контроллер отсутствует, поэтому никакой помощник current_user пока недоступен. Нет еще начальника или даже сеанса, но, по крайней мере, есть cookiejar, поэтому, если вы храните свой session_id, вы можете напрямую восстановить сеанс или log 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' } ] 

НЕ РАБОТАЕТ:

Но если вы используете завещать, он использует Warden raack промежуточное программное обеспечение, так env['warden'] должны быть доступны, так что вы можете попробовать?

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

Даже без надзирателя, поскольку у вас есть сеанс можно получить через env['rack.session'], если хранить идентификатор пользователя в сессии, вы можете сделать что-то вроде

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

Спасибо за ответ. Я попробовал свой первый пример, но он не работает для меня. Я получаю «Внутренняя ошибка сервера». – boblin

+0

а теперь как? channelge to req.env –

+0

Отсутствует окончательный ']', но я все еще получаю «Внутренняя ошибка сервера». – boblin

2

Вот что я просто добавил к 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: Смотрите, если ваши куки имеют достаточно информации, используя ту же технику:

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

(хит запроса)

В стороне: Не беспокоиться о вводе в именах пользователей/сообщений электронной почты в логах - идентификатор пользователя достаточно хорош, и вы можете найти его в базе данных, чтобы получить какие-либо дополнительные метаданные, которые вам нужны.

+0

Спасибо за ответ. К сожалению, Devise не использует файлы cookie для хранения пользовательской информации. – boblin

5

Добавлено 2013-03-07:

В Rails 4 encrypted_cookie_store является хранилище сеансов по умолчанию. Это, как вы можете получить доступ к данным сеанса:

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

И это выглядит как warden_data выглядит по-разному в моем новом приложении, например .: [[542], "$2a$10$e5aYxr/PIp6OOj8jzE7mke"], где первый элемент является идентификатор пользователя.

Вот мой текущий фрагмент: 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.

Это грязно, но это не влияет на обычный процесс аутентификации, порядок стеков промежуточного программного обеспечения и т. Д. Если он ломается во время некоторого обновления, будут затронуты только тегированные журналы, которые я должен заметить при просмотре журналов разработки.

+0

Является ли «qnaire» для «анкеты»? –

+1

@AndrewGrimm yes (-: –

1

Как @viktortron сказал в his answer на log_tags время инициализации мы не имеем надлежащего session Objet доступны, но 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] <the log line> 
-2

Для тех, кто, используя ответ REDIS :: Сторож @ fjuillen выглядит следующим образом:

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

протестирован на рельсах 4.

0

В качестве быстрого и уродливого обходного пути, возможно, можно было бы зарегистрировать вторую строку после обработки запроса.

Это 500 ServerError было представлено: # {имя пользователя}

12

Я использовал это решение от Войтек Крушевских: https://gist.github.com/WojtekKruszewski

Я подправили немного для моего проекта, чтобы включать только идентификатор, но в основном то же самое ,

# 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 
+0

Это самый чистый подход. – Fabio

1

Я использую Swards solution и он работает как шарм. Однако используя 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 
1

Что почти работал для меня (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}" 
    } 
] 
1

Вот печенье Decrypter я использую в Rails 5.1 помечать журналы с user_id, который хранится в куки. Это в основном позволяет мне получать доступ к контроллеру эквиваленту 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 
Смежные вопросы