Skip to content

Instantly share code, notes, and snippets.

@sjoonk
Created August 5, 2016 15:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjoonk/9cd2ca6456a3bd3dd9434bace996fa41 to your computer and use it in GitHub Desktop.
Save sjoonk/9cd2ca6456a3bd3dd9434bace996fa41 to your computer and use it in GitHub Desktop.
ruby_Sinatra logging

2012-06-15

Sinatra 소스코드에 보면 logger는 helpers부분에서 다음과 같이 간단하게 선언되어 있다.

# Access shared logger object.
def logger
  request.logger
end

결국 Sinatra에서 logging 처리는 request.logger, 즉 rack의 logger 부분에 일임하는 것이 전부다.

그럼 이번엔 Rack 에서 logging 처리를 살펴보자. Rack의 request 객체 부분에 보면 다음과 같이 정의되어 있다.

 def logger;          @env['rack.logger']                      end

결국 env['rack.logger']에 어떤 값을 주냐에 따라 결정된다는 말이다. 다시 말하면, 실제로 어떤 환경에서 rack 애플리케이션을 띄우냐에 따라 그 값이 결정된다는 말이다. 간단하게 rackup 유틸리티를 살펴보자. 다음과 같이 CommonLogger를 디폴트로 사용하고 있다.

# Options may include:
# * :app
#     a rack application to run (overrides :config)
# * :config
#     a rackup configuration file path to load (.ru)
# * :environment
#     this selects the middleware that will be wrapped around
#     your application. Default options available are:
#       - development: CommonLogger, ShowExceptions, and Lint
#       - deployment: CommonLogger

그런데 만약 rackup 대신 thin을 띄우게 되면? 그러면 당연히 default logger가 달라질 것이다. rackup은 CommonLogger를 사용하지만, thin이나 passenger 혹은 다른 컨테이너들은 어떤 Logger를 사용할지 알 수 없는 일이다.

결론(정리):

  1. Sinatra는 Rack의 logging 기능을 사용하며, Rack은 다시 내부적으로 env['rack.logger'] 값을 통해 Logger를 설정할 수 있게 되어 있다. 따라서 결국 Sinatra가 어떤 Logger를 사용하냐는 env['rack.logger'] 값을 어떻게 주냐에 따라 결정되며, 이 값은 당연히 rack 실행 환경에 따라 달라질 수 있다.

  2. Rack의 디폴트 Logger는 CommonLogger 이다.

  3. Sinatra에서는 logging을 할건지 말건지를 결정할 수 있는데, Classic App인 경우는 디폴트로 enable되어 있는 반면, Modular 앱 방식인 경우는 직접 enable :logging 해 줘야 한다.

  4. logging을 외부 로그파일로 빼기 위해서는 config.ru 파일에서 다음과 같은 식으로 처리해 주면 된다.

    if ENV['RACK_ENV'] == 'production' && !($0 =~ /(tux|ripl)/) log = File.new("log/sinatra.log", "a+") STDOUT.reopen(log) STDERR.reopen(log) end

  • Sinatra의 버그 같긴 한데, modular 스타일 앱에서 :logging 을 선언할 때

다음과 같이 configure 블럭 속에서 선언하면 enable이 먹지만,

configure :production, :development do enable :logging, :dump_errors end

다음과 같이 직접 선언할 경우는 enable이 먹질 않는다.

enable :logging

대신, set으로 선언하면 먹는다.

set :logging, true
  • Thin과 CommonLogger

rackup으로 띄우는 경우는 default로 CommonLogger를 사용하기 때문에 콘솔로 CommonLogger가 내보내는 logging 값들이 들어오지만, Thin을 사용할 경우에는 (thin이 내부적으로 CommonLogger 를 상정하기 않기 때문에) 아무런 logging 값도 출력되지 않는다. 이 때는 config.ru 파일에서 CommonLogger를 use 해 주면 된다.

use Rack::CommonLogger

몰론, CommonLogger로부터의 logging을 받고싶지 않다면 이렇게 할 필요는 없다. (아직 Sinatra 에서 logging 처리가 조금 미숙해 보인다) sinatra/sinatra#454

That's perfect, with the substitution of a Logger instance:

configure :production do set :logging, false LOGGER = Logger.new(...) use Rack::CommonLogger, LOGGER end

아래와 같은 식으로 셋팅을 하면 logging이 제대로 작동한다. http://paperairoplane.net/?p=336 http://railsillustrated.com/logger-tricks.html http://stackoverflow.com/questions/5995854/logging-in-sinatra http://www.michaelxavier.net/posts/2010-02-05-Snippet-Rack-CommonLogger-in-Sinatra.html http://stackoverflow.com/questions/2239240/use-rackcommonlogger-in-sinatra http://d.hatena.ne.jp/koseki2/20120309/SinatraAppLog

logger = Logger.new('log/production.log')
Logger.class_eval { alias :write :'<<' }
use Rack::CommonLogger, logger

config.logger = Logger.new(Rails.root.join("log",Rails.env + ".log"),3,510241024)

which will rotate the log files every 5 megabytes and leave only the three most recent log files. This will limit the total spaces used by the logs at 15 megabytes.

(이전 방식 in config.ru)

use Rack::CommonLogger if ENV['RACK_ENV'] == 'development' # for thin server

if ENV['RACK_ENV'] == 'production' && !($0 =~ /(tux|ripl)/)
  log = File.new("log/sinatra.log", "a+")
  STDOUT.reopen(log)
  STDERR.reopen(log)
end  

(새 방식)

  • 요건:

    1. production 모드에서만 파일로 logging 하고, 나머지 모드에서는 STDOUT 로깅
    2. irb나 ripl, tux 고려
    3. CommonLogger 사용(CommonLogger는 로깅 포맷을 아파치 log 파일 포맷으로 만들어 낼 뿐 그 로그 데이터를 파일에 저장하거나 하지는 않음. 따라서 파일에 저장하기 위해서는 File 또는 Logger 같은 별도의 도구가 필요)

    if ENV['RACK_ENV'] == 'production' && !($0 =~ /(irb|ripl|tux)/) logger = Logger.new('log/production.log', 'weekly') Logger.class_eval { alias :write :'<<' } else
    logger = ENV['rack.logger'] # nil
    end use Rack::CommonLogger, logger

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment