Регистрация в Sinatra?

#ruby #logging #sinatra #rack

#ruby #регистрация #sinatra #стойка

Вопрос:

У меня возникли проблемы с пониманием того, как регистрировать сообщения с помощью Sinatra. Я не собираюсь регистрировать запросы, а скорее настраиваемые сообщения в определенных точках моего приложения. Например, при получении URL-адреса я хотел бы войти "Fetching #{url}" .

Вот что я хотел бы:

  • Возможность указывать уровни журнала (например: logger.info("Fetching #{url}") )
  • В средах разработки и тестирования сообщения будут записываться на консоль.
  • В рабочей среде записываются только сообщения, соответствующие текущему уровню журнала.

Я предполагаю, что это можно легко сделать в config.ru , но я не уверен на 100%, какую настройку я хочу включить, и нужно ли мне самому вручную создавать Logger объект (и, кроме того, какой класс Logger использовать: Logger , Rack::Logger или Rack::CommonLogger ).

(Я знаю, что в StackOverflow есть похожие вопросы, но, похоже, ни один из них не дает прямого ответа на мой вопрос. Если вы можете указать мне на существующий вопрос, я пометю этот как дубликат).

Ответ №1:

Sinatra 1.3 будет поставляться с таким объектом logger, который можно использовать точно так же, как указано выше. Вы можете использовать edge Sinatra, как описано в «The Bleeding Edge«. Думаю, до выпуска 1.3 осталось не так уж много времени.

Чтобы использовать его с Sinatra 1.2, сделайте что-то вроде этого:

 require 'sinatra'
use Rack::Logger

helpers do
  def logger
    request.logger
  end
end
  

Комментарии:

1. Этот ответ был бы особенно полезен, если бы вы включили информацию о том, как установить назначение регистратора (file / STDOUT) и как на самом деле вести журнал ( logger.info "foo" ?)

2. Использование описано в Sinatra README на github: logger.info("foo") . Назначение устанавливается веб-сервером (он использует поток ошибок Rack), вы можете в принципе установить его, изменив env['rack.errors'] .

3. из-за использования помощников это, похоже, работает только в контексте запроса. это не работает для вещей, происходящих в более ранних частях приложения (предварительный запрос, настройка приложения и т.д.)

4. у меня сработало, но сначала я должен использовать установочную переменную, то есть: настройки. logger.info (‘blablabla’)

Ответ №2:

Я лично захожу в Sinatra через:

 require 'sinatra'
require 'sequel'
require 'logger'
class MyApp < Sinatra::Application
  configure :production do
    set :haml, { :ugly=>true }
    set :clean_trace, true

    Dir.mkdir('logs') unless File.exist?('logs')

    $logger = Logger.new('logs/common.log','weekly')
    $logger.level = Logger::WARN

    # Spit stdout and stderr to a file during production
    # in case something goes wrong
    $stdout.reopen("logs/output.log", "w")
    $stdout.sync = true
    $stderr.reopen($stdout)
  end

  configure :development do
    $logger = Logger.new(STDOUT)
  end
end

# Log all DB commands that take more than 0.2s
DB = Sequel.postgres 'mydb', user:'dbuser', password:'dbpass', host:'localhost'
DB << "SET CLIENT_ENCODING TO 'UTF8';"
DB.loggers << $logger if $logger
DB.log_warn_duration = 0.2
  

Комментарии:

1. Почему вы используете модульное приложение, с одной стороны, но глобальную переменную для хранения регистратора?

2. @Konstantin Хороший вопрос. Я делаю первое для простого config.ru MyApp.run, но я никогда не запускаю более одного приложения в одном процессе, поэтому уродливая глобальная переменная — это пока просто удобная лень.

3. Повторное открытие стандартного вывода может привести к тому, что Passenger не запустится: github.com/phusion/passenger/wiki /…

Ответ №3:

Если вы используете что-то вроде ведения журнала unicorn или другое промежуточное программное обеспечение, которое контролирует потоки ввода-вывода, вы можете легко настроить регистратор на стандартный вывод или STDERR

 # unicorn.rb
stderr_path "#{app_root}/shared/log/unicorn.stderr.log"
stdout_path "#{app_root}/shared/log/unicorn.stdout.log"

# sinatra_app.rb
set :logger, Logger.new(STDOUT) # STDOUT amp; STDERR is captured by unicorn
logger.info('some info') # also accessible as App.settings.logger
  

это позволяет перехватывать сообщения в области приложения, а не просто иметь доступ к logger в качестве помощника по запросу

Ответ №4:

Вот другое решение:

 module MySinatraAppLogger
  extend ActiveSupport::Concern

  class << self
    def logger_instance
      @logger_instance ||= ::Logger.new(log_file).tap do |logger|
        ::Logger.class_eval { alias :write :'<<' }
        logger.level = ::Logger::INFO
      end
    end

    def log_file
      @log_file ||= File.new("#{MySinatraApp.settings.root}/log/#{MySinatraApp.settings.environment}.log", 'a ').tap do |log_file|
        log_file.sync = true
      end
    end
  end

  included do
    configure do
      enable :logging
      use Rack::CommonLogger, MySinatraAppLogger.logger_instance
    end

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

  def logger
    MySinatraAppLogger.logger_instance
  end
end

class MySinatraApp < Sinatra::Base
  include MySinatraAppLogger
  get '/' do
    logger.info params.inspect
  end
end
  

Конечно, вы можете сделать это без ActiveSupport::Concern, поместив блоки configure и before прямо в MySinatraApp, но что мне нравится в этом подходе, так это то, что он очень чистый — вся конфигурация ведения журнала полностью абстрагирована от основного класса приложения.

Также очень легко определить, где вы можете это изменить. Например, SO спросил о том, как заставить его регистрироваться в консоли при разработке. Здесь довольно очевидно, что все, что вам нужно сделать, это немного логики if-then в log_file методе.

Комментарии:

1. Rack::Logger потоки в env['rack.errors'] , кажется плохой идеей переопределять его содержимое в фильтре before rubydoc.info/github/rack/rack/Rack/Loggerhttp ://…

2. Я не уверен, почему это делает эту идею плохой. Не могли бы вы рассказать подробнее?

3. исправлена ссылка: rubydoc.info/github/rack/rack/Rack/Logger я думал, что этот ключ был зарезервирован внутри rack logger для отслеживания ошибок на основе запросов

4. Это верно. Если я правильно понимаю, это означает, что вы перенаправляете не только свои собственные инструкции журнала, но и Rack. Это именно то, что я намеревался сделать, чтобы вы могли отлаживать ошибки, основанные на запросах, и видеть все свои журналы в одном месте. Предполагая, что это цель, есть ли что-нибудь небезопасное в этом подходе? У меня это хорошо сработало.