Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Rack::CommonLogger in Sinatra

I have a small web-server that I wrote with Sinatra. I want to be able to log messages to a log file. I've read through http://www.sinatrarb.com/api/index.html and www.sinatrarb.com/intro.html, and I see that Rack has something called Rack::CommonLogger, but I can't find any examples of how it can be accessed and used to log messages. My app is simple so I wrote it as a top-level DSL, but I can switch to subclassing it from SinatraBase if that's part of what's required.

like image 614
Lawrence I. Siden Avatar asked Feb 10 '10 18:02

Lawrence I. Siden


2 Answers

Rack::CommonLogger won't provide a logger to your main app, it will just logs the request like Apache would do.

Check the code by yourself: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb

All Rack apps have the call method that get's invoked with the HTTP Request env, if you check the call method of this middleware this is what happens:

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 

The @app in this case is the main app, the middleware is just registering the time the request began at, then it class your middleware getting the [status, header, body] triple, and then invoke a private log method with those parameters, returning the same triple that your app returned in the first place.

The logger method goes like:

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 

As you can tell, the log method just grabs some info from the request env, and logs in on a logger that is specified on the constructor call, if there is no logger instance then it goes to the rack.errors logger (it seems there is one by default)

The way to use it (in your config.ru):

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

If you want to have a common logger in all your app, you could create a simple logger middleware:

class MyLoggerMiddleware    def initialize(app, logger)     @app, @logger = app, logger   end    def call(env)     env['mylogger'] = @logger     @app.call(env)   end  end 

To use it, on your config.ru:

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

Hope this helps.

like image 196
Roman Gonzalez Avatar answered Sep 28 '22 05:09

Roman Gonzalez


In your 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 
like image 38
Phrogz Avatar answered Sep 28 '22 05:09

Phrogz