设置场景
为了使默认的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 threadsafe和Rails 4 is threadsafe by default,但是显然有些不对。我还想知道Rack是否是问题所在,但是Rails中的线程安全性(总的来说是对的吗?)似乎对remove Rack::Lock足够自信,那么这似乎也不对。
我想念什么?所有信息似乎都表明它是线程安全的,但我不相信这是线程安全的。
引擎盖下
引用
最佳答案
经过一些研究和实验,结果证明这根本不是线程安全性的问题。而是来自另一个请求的旧数据过时的问题。要了解此问题,您必须了解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/