web-dev-qa-db-fra.com

Utilisez Rack :: CommonLogger dans Sinatra

J'ai un petit serveur web que j'ai écrit avec Sinatra. Je veux pouvoir enregistrer des messages dans un fichier journal. J'ai lu http://www.sinatrarb.com/api/index.html et www.sinatrarb.com/intro.html, et je vois que Rack a quelque chose qui s'appelle Rack :: CommonLogger, mais je ne trouve aucun exemple de la façon dont il peut être consulté et utilisé pour enregistrer les messages. Mon application est simple, alors je l'ai écrite en tant que DSL de niveau supérieur, mais je peux passer à SinatraBase si elle en fait partie.

26
Lawrence I. Siden

Rack::CommonLogger ne fournira pas d'enregistreur à votre application principale, il enregistrera simplement la demande comme le ferait Apache.

Vérifiez le code vous-même: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb

Toutes les applications Rack ont la méthode call qui est invoquée avec l'en-tête de requête HTTP. Si vous vérifiez la méthode call de ce middleware, voici ce qui se produit:

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

Le @app dans ce cas est l’application principale, le middleware enregistre simplement l’heure à laquelle la requête a commencé, puis il classe le middleware qui obtient le triple [statut, en-tête, corps], puis invoque une méthode de journal privé avec ces paramètres, en renvoyant le même triple que votre application est retournée en premier lieu.

La méthode logger va comme ceci: 

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

Comme vous pouvez le constater, la méthode log récupère simplement certaines informations de l’env de la demande et se connecte à un consignateur spécifié dans l’appel du constructeur. S'il n’y a pas d’instance de consignation, elle passe au consignateur rack.errors par défaut)

La façon de l'utiliser (dans votre config.ru):

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

use Rack::CommonLogger, logger
run YourApp

Si vous souhaitez avoir un enregistreur commun dans toute votre application, vous pouvez créer un middleware d'enregistreur simple:

class MyLoggerMiddleware

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

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

end

Pour l'utiliser, sur votre config.ru:

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

J'espère que cela t'aides.

41
Roman Gonzalez

Dans votre 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
15
Phrogz

J'ai suivi ce que j'ai trouvé sur ce blog post - extrait ci-dessous

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

utilisez ensuite puts ou print. Cela a fonctionné pour moi.

2
dbrown0708
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
1
davidhq

Réouvrir STDOUT et le rediriger vers un fichier n'est pas une bonne idée si vous utilisez Passenger. Cela provoque dans mon cas que Passager ne démarre pas. Lisez https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems#stdout-redirection pour ce problème.

Ce serait la bonne façon à la place:

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