2010-02-10 20 views
26

Tengo un pequeño servidor web que escribí con Sinatra. Quiero poder registrar mensajes en un archivo de registro. He leído http://www.sinatrarb.com/api/index.html y www.sinatrarb.com/intro.html, y veo que Rack tiene algo llamado Rack :: CommonLogger, pero no puedo encontrar ningún ejemplo de cómo se puede acceder y usar para registrar mensajes. Mi aplicación es simple, así que la escribí como una DSL de nivel superior, pero puedo pasar a una subclasificación de SinatraBase si eso es parte de lo que se requiere.Usar Rack :: CommonLogger en Sinatra

Respuesta

41

Rack::CommonLogger no proporcionará un registrador a su aplicación principal, solo registrará la solicitud como lo haría Apache.

Comprobar el código en solitario: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb

Todos Rack aplicaciones tienen la llamada al método que consiguen que está invoca con la petición HTTP env, si marca el método llamado de este middleware esto es lo que sucede:

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 

El @app en este caso es la aplicación principal, el middleware solo está registrando el momento en que comenzó la solicitud, luego clasifica su middleware obteniendo el estado [encabezado, cuerpo] triple y luego invoca un método de registro privado con esos parámetros , devolviendo el mismo triple que tu a pp regresó en primer lugar.

El método logger dice así:

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 

Como se puede ver, el método log simplemente agarra algo de información de la solicitud env, e ingresa en un registrador que se especifica en la llamada al constructor, si hay se ningún caso registrador luego se va a la rack.errors registrador (parece que hay uno por defecto)

la forma de usarlo (en su config.ru):

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

use Rack::CommonLogger, logger 
run YourApp 

Si usted quiere tener un registrador común en toda su aplicación, se puede crear un simple middleware registrador:

class MyLoggerMiddleware 

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

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

end 

Para usarlo, en su config.ru:

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

Espero que esto ayude.

+4

¿No debería la primera línea de MyLoggerMiddleware # call (env) ser: env ['rack.errors'] = @logger ? –

+0

Además, no quiero registrar todas las solicitudes, solo advertencias y mensajes de error. Pero me gustaría que sea configurable para que pueda establecer el nivel de registro, como en "depuración", "información", "advertencias", "errores", ... BTW - Mi aplicación no es un rieles aplicación No hay archivo config.ru. Es una aplicación simple de Sinatra. Tenía la esperanza de utilizar un estándar existente, pero no puedo entender qué es eso. ¿Tal vez tengo que tomar el CommonLogger que me mostró y dirigirlo solo? –

+0

'config.ru' es un archivo de configuración para Rack, no para Rails. Tanto Sinatra como Rails están basados ​​en Rack, por lo que puedes usar 'config.ru' en las aplicaciones de Sinatra también. – jafrog

2

que siguieron lo que he encontrado en este blog posterior - un extracto a continuación

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 

a continuación, utilizar puts o print. Funcionó para mí

+1

que funciona, pero que realmente me gustaría averiguar cómo utilizar rack :: CommonLogger para enviar mensajes formateados con marcas de tiempo. –

15

En su 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 
+0

pruebo su solución, y funciona. Me pregunto por qué tiene que estar en config.ru? – Chamnap

+0

un archivo cosas que no estoy al 100% allí, ¿te importaría comentar sobre qué/por qué algunas de las líneas están ahí, por favor? –

1
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 
Cuestiones relacionadas