在 Sinatra 中使用 Rack::CommonLogger

发布于 2024-08-20 14:16:17 字数 322 浏览 12 评论 0原文

我有一个用 Sinatra 编写的小型网络服务器。我希望能够将消息记录到日志文件中。我已通读 http://www.sinatrarb.com/api/index.html 和 www.sinatrarb.com/intro.html,我看到 Rack 有一个名为 Rack::CommonLogger 的东西,但我找不到任何关于如何访问它并使用它来记录消息的示例。我的应用程序很简单,因此我将其编写为顶级 DSL,但如果需要的话,我可以切换到从 SinatraBase 对其进行子类化。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

青芜 2024-08-27 14:16:17

Rack::CommonLogger 不会向您的主应用程序提供记录器,它只会像 Apache 那样记录请求。

自行查看代码:https://github.com/ rack/rack/blob/master/lib/rack/common_logger.rb

所有 Rack 应用程序都有使用 HTTP 请求环境调用的 call 方法,如果您检查此调用方法中间件是这样的:

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

在这种情况下,@app是主应用程序,中间件只是注册请求开始的时间,然后它对您的中间件进行分类,获取[状态,标头,正文]三元组,然后使用这些参数调用私有日志方法,返回与您的应用程序首先返回的相同的三元组。

logger 方法如下所示:

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

如您所知,log 方法只是从请求环境中获取一些信息,并登录在构造函数调用中指定的记录器上,如果没有记录器实例,那么它会转到rack.errors记录器(默认情况下似乎有一个)

使用它的方法(在您的config.ru中) ):

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

use Rack::CommonLogger, logger
run YourApp

如果您想在所有应用程序中使用通用记录器,您可以创建一个简单的记录器中间件:

class MyLoggerMiddleware

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

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

end

要在您的 config.ru 上使用它:

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

希望这会有所帮助。

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.

救赎№ 2024-08-27 14:16:17

在您的 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

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
微暖i 2024-08-27 14:16:17

我按照我在这个 博客上找到的内容< /a> post - 摘录如下

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

,然后使用 putsprint。这对我有用。

I followed what I found on this blog post - excerpted below

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

then use puts or print. It worked for me.

远山浅 2024-08-27 14:16:17
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
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
生活了然无味 2024-08-27 14:16:17

如果您使用 Passenger,重新打开 STDOUT 并将其重定向到文件并不是一个好主意。在我的情况下,这导致乘客无法启动。阅读 https://github.com/phusion/passenger/ wiki/Debugging-application-startup-problems#stdout-redirection 解决此问题。

这将是正确的方法:

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

Reopening STDOUT and redirecting it to a file is not a good idea if you use Passenger. It causes in my case that Passenger does not start. Read https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems#stdout-redirection for this issue.

This would be the right way instead:

logger = ::File.open('log/sinatra.log', 'a+')
Sinatra::Application.use Rack::CommonLogger, logger
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文