2010-02-10 15 views
26

Ho un piccolo server web che ho scritto con Sinatra. Voglio essere in grado di registrare i messaggi in un file di registro. Ho letto il numero http://www.sinatrarb.com/api/index.html e www.sinatrarb.com/intro.html e vedo che Rack ha qualcosa chiamato Rack :: CommonLogger, ma non riesco a trovare alcun esempio di come sia possibile accedere e utilizzare per registrare i messaggi. La mia app è semplice, quindi l'ho scritta come DSL di primo livello, ma posso passare a sottoclassi da SinatraBase se questo è parte di ciò che è richiesto.Usa Rack :: CommonLogger in Sinatra

risposta

41

Rack::CommonLogger non fornirà un logger all'app principale, registrerà semplicemente la richiesta come farebbe Apache.

Controllare il codice da lei: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb

Tutti Rack applicazioni hanno la chiamata al metodo che vengono sta invocato con la richiesta HTTP env, se si seleziona la chiamata di metodo di questo middleware questo è ciò che accade:

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 

Il @app in questo caso è l'app principale, il middleware sta registrando solo il momento in cui è iniziata la richiesta, quindi classifica il middleware ottenendo il [stato, intestazione, corpo] triplo e quindi richiama un metodo di registro privato con tali parametri , restituendo la stessa tripla della tua a pp restituito in primo luogo.

Il metodo logger va come:

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 

Come si può dire, il metodo log appena afferra alcune informazioni dalla richiesta env, e registra su un registratore che è specificato sulla chiamata al costruttore, se ci è alcuna istanza logger poi va al rack.errors logger (sembra che ci sia uno per impostazione predefinita)

il modo di usarlo (in config.ru):

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

use Rack::CommonLogger, logger 
run YourApp 

Se si vuole avere un logger comune in tutta la vostra app, è possibile creare un semplice middleware logger:

class MyLoggerMiddleware 

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

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

end 

Per usarlo, sul config.ru:

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

Spero che questo aiuti.

+4

La prima riga di MyLoggerMiddleware # call (env) non dovrebbe essere: env ['rack.errors'] = @logger ? –

+0

Inoltre, non voglio registrare ogni richiesta, solo avvertimenti e messaggi di errore. Ma mi piacerebbe che fosse configurabile in modo da poter impostare il livello di registrazione, come in "debug", "informazioni", "avvisi", "errori", ... BTW - La mia app non è un Rails app. Non esiste un file config.ru. È una semplice app di Sinatra. Speravo di utilizzare uno standard esistente, ma non riesco a capire di cosa si tratta. Forse dovrò prendere il CommonLogger che mi hai mostrato e filarmelo da solo? –

+0

'config.ru' è un file di configurazione per Rack, non per Rails. Sia Sinatra che Rails sono basati su rack, quindi puoi usare 'config.ru' anche nelle applicazioni Sinatra. – jafrog

2

ho seguito quello che ho trovato su questo blog post - Tratto di sotto

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 

quindi utilizzare puts o print. Ha funzionato per me.

+1

che funziona, ma mi piacerebbe davvero scoprire come utilizzare Rack :: CommonLogger per inviare messaggi formattati con timestamp. –

15

Nel vostro 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

provo la tua soluzione, e funziona. mi chiedo perché deve essere in config.ru? – Chamnap

+0

un file cose che non sono al 100% lì, ti dispiacerebbe commentare su cosa/perché alcune delle linee sono lì per favore? –

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 
Problemi correlati