4

EventMachine と async_sinatra を使用して着信 HTTP 要求を非同期的に処理する、別の TCP ベースのサービスのフロントエンドとして、最初の Sinatra ベースの Web アプリを作成しています。アプリをテストしているとき、同期ルートへのすべてのリクエストは共通のログ形式で stdout に記録されますが、非同期リクエストはそうではありません。

ソース コードの一部を async_sinatra、Sinatra、Thin、Rack まで読みましたが、同期要求のログは CommonLogger#call を通じて行われているようです。ただし、async_sinatra または Thin の非同期コードのどこにも、ロギング ミドルウェアを介して非同期要求を渡すように見える場所を見つけることができません (async_sinatra のSinatra::Helpers#bodyThin::Connection.post_processを見ています)。 Thin の connection.rb:68 と request.rb:132 の env['.async_callback'] に書き込まれます)。

私は C の経験はありますが、Ruby には比較的慣れていないため、用語や表記法を間違って使用している場合は、修正してください。前もって感謝します。

編集:これはエラー処理にも影響します。非同期リクエストで例外が発生した場合、リクエストは終了せず、エラーはログに記録されません。

4

2 に答える 2

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 ミドルウェアを使用できる場合があります。

于 2012-11-11T12:41:16.380 に答える
1

私は走っているsinatra-synchronyので、あなたとはコアが少し異なります。しかし、基本的に私は同じ問題を解決しました。ソリューションの要約は次のとおりです。

  • を使用していませんRack::CommonLogger。独自のロガーを使用しています
  • 非同期対応ストレージにログ出力をバッファリングする必要があります
  • バッファリングされたログ出力は、リクエストの最後にフラッシュする必要があります

私の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")ログに使用できます。

于 2011-12-20T13:03:55.723 に答える