设置场景

为了使默认的Rails日志在生产环境中更有用,我一直在使用Log4r及其诊断上下文,尤其是MDC。除了从Rails应用程序本身发出的日志外,我还将插入一些自己的中间件,以便即使在Rack中间件中也可以获得一致的日志记录。

例如,一旦我通过Warden获得登录用户的访问权限,就添加该作品所需的MDC条目。

def call(env)
  user = env['warden'].user
  user_context = user ? user.to_log_format : 'indetermined'
  MDC.put :user, user_context

  @app.call(env)
end

Rack中间件中其他已记录的内容是父PID,请求ID等。

问题

问题是我的日志条目明显不正确。在负载下,我始终看到一个用户的身份与请求混为一谈,如果请求之间的距离足够近的话,一个完全不同的用户会对API发出请求。

有人告诉我Log4r MDC is threadsafeRails 4 is threadsafe by default,但是显然有些不对。我还想知道Rack是否是问题所在,但是Rails中的线程安全性(总的来说是对的吗?)似乎对remove Rack::Lock足够自信,那么这似乎也不对。

我想念什么?所有信息似乎都表明它是线程安全的,但我不相信这是线程安全的。

引擎盖下
  • Rails 4.1.10
  • Log4r 1.1.10
  • 乘客4.0.59

  • 引用
  • http://www.rubydoc.info/github/colbygk/log4r/Log4r/MDC
  • http://log4r.rubyforge.org/rdoc/log4r/rdoc/MDC.html
  • https://cb.platan.us/multithreading-rails-4
  • https://tenderlovemaking.com/2012/06/18/removing-config-threadsafe.html
  • 最佳答案

    经过一些研究和实验,结果证明这根本不是线程安全性的问题。而是来自另一个请求的旧数据过时的问题。要了解此问题,您必须了解Log4r MDC内容的存储方式以了解问题所在:

    MDC片段与线程一起存储,以便可以访问它们以记录整个请求。

    def self.put( a_key, a_value )
      self.check_thread_instance()
      Thread.current[MDCNAME][a_key] = a_value
    end
    

    因此,当线程完全完成对请求的处理后,它将接听另一个请求。不幸的是,它似乎仍在携带上一个请求的详细信息-尚未清除任何内容。因此,所有这些旧的,无关的细节都可能最终作为无关请求的诊断上下文。

    然后,解决方案是确保在开始向新请求中添加新上下文之前清除MDC片段:
    MDC.get_context.keys.each { |k| MDC.remove(k) }
    

    哎呀。

    关于ruby - Log4r实际上在Rails 4应用程序中是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36943709/

    10-09 20:17