简体   繁体   中英

How do I access Sinatra's Logger outside the Request Scope

It seems that Sinatra's logger is only available inside request handlers (See https://github.com/sinatra/sinatra#logging ), but what if I want to use a logger in other places, for example in helper methods or in the configure hook? Is the Sinatra logger available through other means?

The docs give some examples on scope, but you can see the logger helper within methods defined in the helper block, as the helper block has Application scope. Within configure it's not available, but what I tend to do is set up my own logging anyway, within the rackup file as a constant or class instance variable, and then it's available within configure (and anywhere else). As an example for just a single application:

require 'sinatra'
require 'logger'

configure do
  set :logging, nil
  logger = Logger.new STDOUT
  logger.level = Logger::INFO
  logger.datetime_format = '%a %d-%m-%Y %H%M '
  set :logger, logger
end

helpers do
  def check
    settings.logger.info "I'm inside a helper"
    # if you were using Sinatra's logger, you could just call
    # logger.info "I'm inside a helper"
    # and it would work, but only if you've not done the stuff above
    # in the configure block
  end
end

get "/" do
  check # this would work for the way above, or with the Sinatra logger
  "Hello, World!"
end

get "/another" do
  settings.logger.info "Using the settings helper this time" # this only works
  # when you've defined your own logger
  "Hello again"
end

An example as a class instance variable as a better "global":

class MyLogger
  def self.logger
    if @_logger.nil?
      @_logger = Logger.new STDOUT
      @_logger.level = Logger::INFO
      @_logger.datetime_format = '%a %d-%m-%Y %H%M '
    end
    @_logger
  end
end

and then use wherever needed:

configure do
  set :logging, nil
  logger = MyLogger.logger
  set :logger, logger
end

or in a class:

class AnotherClass

  def some_method
    MyLogger.logger.warn "I'm in some method"
  end

Sinatra also comes (since 1.3) with a helper for logging , and here is a recipe for logging to STDOUT and a file that you may find useful too.

The accepted answer didn't quite work for me, so I came up with the following:

class AppLogger
  extend SingleForwardable

  def_delegators :logger, :info, :error, :warn, :level

  class << self
    def logger
      return @_logger if @_logger

      @_logger = Logger.new STDOUT
      @_logger.level = Logger::INFO
    end

    def suppress_logging
      logger.level = Logger::FATAL
    end
  end
end

suppress_logging is useful for keeping specs quiet.

In the app init:

set :logging, AppLogger.logger

From a request:

logger.info "Can't touch this."

From a class that does not have access to the logger :

AppLogger.info "You've got mail."

And, RSpec mock:

let( :logger ){ double 'logger' }

before do
  allow( AppLogger ).to receive( :logger ).and_return logger
  allow( logger ).to receive :error
end

specify 'logs error' do
  post '/raise/error'

  expect( logger ).to have_received( :error ).with 'An error has occured.'
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM