我正在编写我的第一个基于Sinatra的Web应用程序作为另一个基于TCP的服务的前端,使用EventMachine和async_sinatra异步处理传入的HTTP请求。当我测试我的应用程序时,所有对同步路由的请求都以通用日志格式记录到stdout,但不是异步请求。
我已经阅读了一些源代码到async_sinatra,Sinatra,Thin和Rack,看起来同步请求的记录是通过CommonLogger#calls来完成的。但是,我在async_sinatra或Thin中的异步代码中找不到任何似乎通过日志记录中间件传递异步请求的东西(我在async_sinatra和Sinatra::Helpers#body处查看Thin::Connection.post_process瘦的connection.rb:68和request.rb:132)中的env ['。async_callback']。
我对C有经验但对Ruby来说比较新,所以如果我使用了一些术语或符号错误,请纠正我。提前谢谢。
编辑:这也会影响错误处理。如果在异步请求中引发异常,则永远不会完成请求,并且永远不会记录错误。
答案 0 :(得分:2)
我最终发现使用与async_sinatra的rack-async会导致404页面,异常处理和日志记录出现问题:
!! Unexpected error while processing request: undefined method `bytesize' for nil:NilClass
相反,我在aroute
周围使用了以下包装来记录:
module Sinatra::Async
alias :oldaroute :aroute
def aroute verb, path, opts = {}, &block
# Based on aroute from async_sinatra
run_method = :"RunA#{verb} #{path} #{opts.hash}"
define_method run_method, &block
log_method = :"LogA#{verb} #{path} #{opts.hash}"
define_method(log_method) { |*a|
puts "#{request.ip} - #{status} #{verb} #{path}"
}
oldaroute verb, path, opts do |*a|
oldcb = request.env['async.callback']
request.env['async.callback'] = proc { |*args|
async_runner(log_method, *a)
oldcb[*args]
}
async_runner(run_method, *a)
end
end
end
这是针对我去年提出这个问题时使用的async_sinatra,Thin和Rack的相同版本;较新的版本可能允许使用常见的Rack中间件进行日志记录。
答案 1 :(得分:1)
我正在sinatra-synchrony
上运行,因此我的核心与你略有不同。
但基本上我解决了同样的问题。
以下是解决方案的摘要:
Rack::CommonLogger
,我使用自己的Logger 在我的sinatra-synchrony
应用程序中,我正在运行以下用于记录的中间件:
# in app.rb I register Logger::Middleware as the first middleware
use Logger::Middleware
# in logger.rb
module Logger
attr_accessor :messages
def log(message)
stack << message
end
def stack
# This is the important async awareness
# It stores messages for each fiber separately
messages[Fiber.current.object_id] ||= []
end
def flush
STDERR.puts stack.join("\n") unless stack.empty?
messages.delete Fiber.current.object_id
end
extend self
class Middleware
def initialize(app)
@app = app
end
def call(env)
# before the request
Logger.log "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']}"
result = @app.call(env)
# after the request
Logger.flush
result
end
end
end
Logger.messages = {} # initialize the message storage
应用程序中的任何地方我都可以使用Logger.log("message")
进行日志记录。