Используйте Rack :: CommonLogger в Синатре - PullRequest
26 голосов
/ 10 февраля 2010

У меня есть небольшой веб-сервер, который я написал с помощью Sinatra. Я хочу иметь возможность записывать сообщения в файл журнала. Я прочитал http://www.sinatrarb.com/api/index.html и www.sinatrarb.com/intro.html и вижу, что в Rack есть нечто, называемое Rack :: CommonLogger, но я не могу найти примеров того, как к нему можно получить доступ, и используется для регистрации сообщений. Мое приложение простое, поэтому я написал его как DSL верхнего уровня, но я могу переключиться на его подклассы из SinatraBase, если это часть того, что требуется.

Ответы [ 5 ]

41 голосов
/ 11 февраля 2010

Rack::CommonLogger не предоставит регистратор вашему основному приложению, он просто зарегистрирует запрос, как это сделал бы Apache.

Проверьте код самостоятельно: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb

Все Rack приложения имеют метод вызова, который вызывается с помощью HTTP-запроса env, если вы проверите метод вызова этого промежуточного программного обеспечения, вот что происходит:

def call(env)
  began_at = Time.now
  status, header, body = @app.call(env)
  header = Utils::HeaderHash.new(header)
  log(env, status, header, began_at)
  [status, header, body]
end

@app в данном случае является основным приложением, промежуточное ПО просто регистрирует время начала запроса, затем оно классифицирует ваше промежуточное ПО, получая тройку [status, header, body], и затем вызывает метод приватного журнала. с этими параметрами, возвращая ту же тройку, которую ваше приложение вернуло в первую очередь.

Метод logger выглядит следующим образом:

def log(env, status, header, began_at)
  now = Time.now
  length = extract_content_length(header)

  logger = @logger || env['rack.errors']
  logger.write FORMAT % [
    env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
    env["REMOTE_USER"] || "-",
    now.strftime("%d/%b/%Y %H:%M:%S"),
    env["REQUEST_METHOD"],
    env["PATH_INFO"],
    env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
    env["HTTP_VERSION"],
    status.to_s[0..3],
    length,
    now - began_at ]
end

Как вы можете сказать, метод log просто извлекает некоторую информацию из запроса env и регистрируется в регистраторе, указанном в вызове конструктора, если нет экземпляра регистратора, он переходит к rack.errors регистратор (кажется, что он есть по умолчанию)

Способ его использования (в вашем config.ru):

logger = Logger.new('log/app.log')

use Rack::CommonLogger, logger
run YourApp

Если вы хотите, чтобы во всех приложениях был общий логгер, вы можете создать простое промежуточное программное обеспечение для логгера:

class MyLoggerMiddleware

  def initialize(app, logger)
    @app, @logger = app, logger
  end

  def call(env)
    env['mylogger'] = @logger
    @app.call(env)
  end

end

Чтобы использовать его, на вашем config.ru:

logger = Logger.new('log/app.log')
use Rack::CommonLogger, logger
use MyLoggerMiddleware, logger
run MyApp

Надеюсь, это поможет.

15 голосов
/ 17 ноября 2010

В вашем config.ru:

root = ::File.dirname(__FILE__)
logfile = ::File.join(root,'logs','requests.log')

require 'logger'
class ::Logger; alias_method :write, :<<; end
logger  = ::Logger.new(logfile,'weekly')

use Rack::CommonLogger, logger

require ::File.join(root,'myapp')
run MySinatraApp.new # Subclassed from Sinatra::Application
2 голосов
/ 10 февраля 2010

Я следовал тому, что нашел в этом блоге посте - выдержка ниже

require 'rubygems'
require 'sinatra'

disable :run
set :env, :production
set :raise_errors, true
set :views, File.dirname(__FILE__) + '/views'
set :public, File.dirname(__FILE__) + '/public'
set :app_file, __FILE__

log = File.new("log/sinatra.log", "a")
STDOUT.reopen(log)
STDERR.reopen(log)

require 'app'
run Sinatra.application

, затем используйте puts или print. У меня это сработало.

1 голос
/ 14 ноября 2014
class ErrorLogger
  def initialize(file)
    @file = ::File.new(file, "a+")
    @file.sync = true
  end

  def puts(msg)
    @file.puts
    @file.write("-- ERROR -- #{Time.now.strftime("%d %b %Y %H:%M:%S %z")}: ")
    @file.puts(msg)
  end
end


class App < Sinatra::Base

  if production?
    error_logger = ErrorLogger.new('log/error.log')

    before {
      env["rack.errors"] =  error_logger
    }
  end

  ...

end
0 голосов
/ 25 мая 2016

Повторное открытие STDOUT и перенаправление его в файл не очень хорошая идея, если вы используете Passenger. В моем случае это вызывает то, что Пассажир не запускается. Прочтите https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems#stdout-redirection для этой проблемы.

Вместо этого это будет правильный путь:

logger = ::File.open('log/sinatra.log', 'a+')
Sinatra::Application.use Rack::CommonLogger, logger
...