2011-05-13 25 views
51

Tengo problemas para averiguar cómo registrar mensajes con Sinatra. No estoy buscando registrar solicitudes, sino mensajes personalizados en ciertos puntos de mi aplicación. Por ejemplo, cuando busco una URL, me gustaría ingresar al "Fetching #{url}".¿Iniciar sesión en Sinatra?

Aquí es lo que me gusta:

  • La posibilidad de especificar niveles de registro (por ejemplo: logger.info("Fetching #{url}"))
  • En entornos de desarrollo y pruebas, los mensajes se escribiría a la consola.
  • En producción, solo escriba los mensajes que coincidan con el nivel de registro actual.

supongo que esto puede hacerse fácilmente en config.ru, pero no estoy 100% seguro del valor que quiero para permitir, y si tengo que crear manualmente un objeto Logger a mí mismo (y, además, que la clase de Logger para usar: Logger, Rack::Logger, o Rack::CommonLogger).

(Sé que hay preguntas similares en StackOverflow, pero ninguna parece responder directamente a mi pregunta. Si puede dirigirme a una pregunta existente, la marcaré como un duplicado).

Respuesta

41

Sinatra 1.3 se enviará con un objeto registrador, exactamente utilizable como se indica anteriormente. Puede usar edge Sinatra como se describe en "The Bleeding Edge". No pasará tanto tiempo hasta que lanzaremos 1.3, supongo.

usarlo con Sinatra 1.2, hacer algo como esto:

require 'sinatra' 
use Rack::Logger 

helpers do 
    def logger 
    request.logger 
    end 
end 
+8

Esta respuesta sería de mucha ayuda si incluyó información sobre cómo establecer el destino del registrador (archivo/STDOUT) y cómo registrar realmente ('logger.info" foo "'?) – Phrogz

+9

El uso se describe en el README de Sinatra en github: 'logger.inf o ("foo") '. El destino lo establece el servidor web (utiliza la secuencia de error de Rack), básicamente puede configurarlo cambiando 'env ['rack.errors']'. –

+2

debido al uso de ayudantes, esto parece que solo funciona en contexto de solicitud. no funciona para las cosas que sucedieron en partes anteriores de la aplicación (solicitud previa, configuración de la aplicación, etc.) – lfender6445

15

personalmente una sesión Sinatra a través de:

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 
+8

¿Por qué? ¿Usas una aplicación modular, por una parte, pero una variable global para almacenar el registrador? –

+1

@Konstantin Buena pregunta. Hago lo primero para config.ru simple MyApp.run, pero nunca ejecuto más de una aplicación en el mismo proceso, por lo que la fea variable global es simplemente una pereza conveniente hasta ahora. – Phrogz

+1

La reapertura de STDOUT puede hacer que Passenger no se inicie: https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems – fguillen

3

Aquí hay otra solución:

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 

Por supuesto, puede hacerlo sin ActiveSupport :: Preocupación por pu conectar los bloques configure y before directamente en MySinatraApp, pero lo que me gusta de este enfoque es que está muy limpio: toda la configuración de registro está totalmente abstraída de la clase principal de aplicaciones.

También es muy fácil detectar dónde se puede cambiar. Por ejemplo, el SO preguntó acerca de hacer que inicie sesión para consolar en el desarrollo. Aquí es bastante obvio que todo lo que necesita hacer es un poco de lógica if-then en el método log_file.

+0

'Rack :: Logger' se transmite a' env ['rack.errors'] ' , parece una mala idea anular sus contenidos en el filtro anterior http://www.rubydoc.info/github/rack/rack/Rack/Loggerhttp://www.rubydoc.info/github/rack/rack/Rack/Logger – lfender6445

+0

Corrija el enlace –

+0

No estoy seguro de por qué eso hace que esto sea una mala idea. ¿Puedes darnos más detalles? –

2

Si está utilizando algo así como unicornio registro u otro middleware que las colas de IO arroyos, se puede configurar fácilmente un registrador a STDOUT o 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 & STDERR is captured by unicorn 
logger.info('some info') # also accessible as App.settings.logger 

esto le permite interceptar mensajes al ámbito de aplicación, en lugar de simplemente tener acceso al registrador como peticionario de solicitud

Cuestiones relacionadas