我有一个Sinatra应用程序,我将lambda传递给外部记录器gem并为其提供当前请求的上下文,以便它可以提取会话ID。
我遇到的问题是,当我传递上下文时,它的作用域是第一个请求。我已经研究过与lambdas的动态绑定,但是还没有找到一种方法让它在这个特定的场景中工作。
记录器中的行可以在这里看到:https://github.com/BBC-News/alephant-logger-json/blob/master/lib/alephant/logger/json.rb#L18
我们的Sinatra代码的伪版本需要像:
require "alephant/logger/json"
require "sinatra/base"
class App < Sinatra::Base
set :sessions, true
attr_reader :alj
def initialize
@alj = Alephant::Logger::JSON
@logger = alj.new "./app.log"
super()
end
before do
p "session id (outside lambda): #{session[:session_id]}" # <= correct value
alj.session -> { p "session id (inside lambda): #{session[:session_id]}"; session[:session_id] } unless alj.session?
end
get "/" do
@logger.info :foo => :bar
"content"
end
end
我最初放入unless alj.session?
条件检查,因为我假设lambda只需要设置一次,并且它能够引用它的父范围(它确实如此,但不是 per请求)。
现在我可以移除unless alj.session?
部分然后理论上会工作,因为我会为每个请求重置lambda。
但我不相信这会在服务器在线程之间切换上下文的高度并发的情况下起作用。
我的意思是,我预见到如下情况:
-> user 1 request (session id: 123)
-> context switch
-> user 2 request (session id: 456)
-> context switch
-> user 1 assigns lambda to the logger (has scope/ref: 123)
-> user 1 routing goes off and gets content
-> context switch
-> user 2 assigns lambda to the logger (has scope/ref: 456)
-> context switch
-> user 1 calls 'log.info' and now user 1 (123) is recorded with id 456
我可以自由更改记录器中的代码,但我真的不想更改其API(例如,我不想说logger.info(session_id, ...orginal args...)
,因为这意味着它现在已经加入了一个id需要提供(我还必须在每次日志调用时提供会话ID,这将非常繁琐)。
我更喜欢记录器来查找该信息,如果没有,则更喜欢no-op。
我尝试过使用动态绑定,eval,屈服于块。没有任何成功。
不知道是否有解决此问题的方法。很高兴得到反馈和想法/例子。
由于