186

What is the best way to enable log rotation on a Ruby on Rails production app?

Is it by using logrotate on the hosting server or is there a set of options to use when initializing logger from the app?

Jai Chauhan
  • 4,035
  • 3
  • 36
  • 62
cnikolaou
  • 3,782
  • 4
  • 25
  • 32
  • I see that there is already an answer on this, but I wanted to ask what your environment is. I use the syslog + logrotate method myself, but obviously the kind of environment (whether dedicated, shared; what kind *ix OS is hosting, or is another, etc.) would have some bearing here. – ylluminate Sep 22 '14 at 14:23

6 Answers6

208

Option 1: syslog + logrotate

You can configure rails, to use the systems log tools.

An example in config/environments/production.rb.

# Use a different logger for distributed setups
config.logger = SyslogLogger.new

That way, you log to syslog, and can use default logrotate tools to rotate the logs.

Option 2: normal Rails logs + logrotate

Another option is to simply configure logrotate to pick up the logs left by rails. On Ubuntu and Debian that would be, for example, in a file called /etc/logrotate.d/rails_example_com.

/path/to/rails.example.com/tmp/log/*.log {
    weekly
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    copytruncate
}

As per suggestions below, in Rails it is advised to use copytruncate, to avoid having to restart the Rails app.

Edit: removed "sharedscripts/endscript" since they are not used here and cause problems according to comment. And removed create 640 root adm as per comment suggested.

berkes
  • 26,996
  • 27
  • 115
  • 206
  • 3
    In order to use logrotate, should the "config.logger = SyslogLogger.new" line in config/environments/production.rb remain commented out, or should it be uncommented? – robertwbradford Jun 10 '11 at 15:53
  • 2
    It should remain commented out, so that the log files are written in (for example): /var/www/myrailsapp/current/log/production.log – Luca Spiller Sep 08 '11 at 15:36
  • 4
    If using the `logrotate` solution, it's worth @amit-saxena's answer -- suggests use of `copytruncate` over the `create` directive. – Tom Harrison Oct 11 '12 at 01:51
  • I got an error with your example as there is an `endscript` without a `prescript` or `postscript` – Carson Reinke Dec 10 '12 at 19:05
  • @CarsonReinke, the `sharedscripts` requires an `endscript`. But both are not really needed and can, indeed, be removed. But only if both are removed. – berkes Dec 11 '12 at 09:13
  • @berkes, logrotate complained about that, `sharedscripts` does not require anything, check the man. This is the error: error: redis:9 unknown option 'endscript' -- ignoring line – Carson Reinke Dec 11 '12 at 20:43
  • 3
    When you use `copytruncate`, `create` has no effect, so you should probably remove it from your example – Michaël Witrant May 04 '13 at 06:13
  • 5
    You may also have to add the line `su your_rails_user your_rails_group` with the owner and group of your log files (i.e., those of the Rails/Passenger process) or (recent versions of?) logrotate may complain about permissions. – oseiskar Aug 22 '14 at 13:12
  • 1
    if log files are large enough, wouldn't sending USR1 signal as lastaction have less of a performance impact than copytruncate? https://github.com/phusion/unicorn/blob/master/examples/logrotate.conf – ives Feb 18 '15 at 18:50
  • Given what copytruncate does, is delaycompress actually needed? I'd say no. – user3183018 Mar 20 '15 at 11:00
  • if you're going to use `copytruncate` you probably want to also use `nocreate` depending on what your main logrotate settings are, as in, do they have `create` present. Look at `/etc/logrotate.conf` – cdmo Sep 14 '18 at 18:20
  • 2
    It's a good idea to test your logrotation file so you can see whether it throws any errors: `sudo logrotate -f /etc/logrotate.d/rails_example_com`. This way I found out I had to add `su rails_user rails_user_group` like oseiskar suggested. – Bram Mar 22 '20 at 13:17
58

If you are using logrotate then you can choose either of the options shown below by placing a conf file in the /etc/logrotate.d/ directory.

# Rotate Rails application logs based on file size
# Rotate log if file greater than 20 MB
/path/to/your/rails/applicaton/log/*.log {
    size=20M
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    copytruncate
}

Or

# Rotate Rails application logs weekly
/path/to/your/rails/applicaton/log/*.log {
  weekly
  missingok
  rotate 52
  compress
  delaycompress
  notifempty
  copytruncate
}

Please note that copytruncate makes a backup copy of the current log and then clears the log file for continued writing. The alternative is to use create which will perform the rotation by renaming the current file and then creating a new log file with the same name as the old file. I strongly recommend that you use copytruncate unless you know that you need create. The reason why is that Rails may still keep pointing to the old log file even though its name has changed and they may require restarting to locate the new log file. copytruncate avoids this by keeping the same file as the active file.

amit_saxena
  • 7,450
  • 5
  • 49
  • 64
  • But shouldn't I restart rails everytime logrotate runs? – lzap Jan 26 '12 at 10:12
  • 2
    Truncate the original log file in place after creating a copy, instead of moving the old log file and optionally creating a new one, It can be used when some program can not be told to close its logfile and thus might continue writing (appending) to the previous log file forever. Note that there is a very small time slice between copying the file and truncating it, so some log- ging data might be lost. When this option is used, the create option will have no effect, as the old log file stays in place. – lzap Jan 26 '12 at 10:16
  • 1
    You don't need to restart rails if you are using copytruncate because it still points to the same log file. – amit_saxena Jan 30 '12 at 11:04
  • Does the configuration require you to state when to rotate the logs? such as "weekly" or "size=20M" ? Or can you omit that, in case you only want to run logrotate manually? – Damainman Aug 07 '13 at 08:54
  • 1
    I am not sure if I understood your question correctly, but you need to specify a criterion for auto log rotation. If you don't want it to be automatic, don't put the file in /etc/logrotate.d/ directory, keep it some place else. You could then run `logrotate --force $CONFIG_FILE` by specifying the config file location to run it manually. – amit_saxena Aug 07 '13 at 10:53
36

For Rails 5, this is what I had to do to limit log size and don't change server output in the console:

According to the documentation, if you want to limit the size of the log folder, put this in your environment-file ('development.rb'/'production.rb').

config.logger = ActiveSupport::Logger.new(config.paths['log'].first, 1, 50 * 1024 * 1024)

With this, your log files will never grow bigger than 50Mb. You can change the size to your own preference. The ‘1’ in the second parameter means that 1 historic log file will be kept, so you’ll have up to 100Mb of logs – the current log and the previous chunk of 50Mb.

Source to this solution.

jethro
  • 168
  • 3
  • 13
Fellow Stranger
  • 32,129
  • 35
  • 168
  • 232
  • 2
    First argument is filename, simply speaking, i.e. 'log/development.log'. So I'd prefer longer, but transparent way. Instead of `config.paths['log'].first`I'd put `Rails.root.join('log', "#{Rails.env}.log")` – Mikhail Chuprynski Sep 03 '16 at 18:28
  • 1
    @ZiaUlRehmanMughal Yes, it working with Rails 4. I'm using Rails 4.2.3, with config like this: `config.logger = ActiveSupport::Logger.new(config.log_file, 1, 20*1024*1024)` – ThienSuBS Apr 18 '17 at 05:03
  • 2
    To make this easier to read, it's worth mentioning that you can rely on the ActiveSupport bytes extensions : `50.megabytes` is the same as `50 * 1024 * 1024`, but much easier to understand. See [ActiveSupport core extensions](https://edgeguides.rubyonrails.org/active_support_core_extensions.html#bytes) for more details. – Pierre-Adrien Jan 22 '19 at 16:08
  • 1
    Got here again after some googling(programmer life :D ). I was wondering if we can configure this line to rotate all log files in log folder? Apparently this line will only rotate first line. – Zia Ul Rehman Mughal Mar 20 '19 at 10:56
  • Note that this will only rotate you log/production.log file as `Rails.application.config.paths['log'].first` return exactly this file – valachi May 28 '20 at 16:36
8

For Rails 5, if you want daily log rotation, you only need this:

  config.logger = ActiveSupport::Logger.new(config.paths['log'].first, shift_age = 'daily')

According the documentation, you can use daily, weekly or monthly.

Rael Gugelmin Cunha
  • 3,327
  • 30
  • 25
5

For every log: Rails log, Rpush log, ... You can use like this in your config file of service:

 config.log_file = 'log/rpush.log'
 config.logger = ActiveSupport::Logger.new(config.log_file, 1, 20.megabytes)

It means: only save 1 previous log file after split. Main log size never over 20 MB.

Pere Joan Martorell
  • 2,608
  • 30
  • 29
ThienSuBS
  • 1,574
  • 18
  • 26
-9

Enable to send logs to the loggly using rails logglier as following in my environments/production.rb file. rails version is 4.1.0

RailsApplication::Application.configure do
require 'logglier'
config.logger = Logglier.new(<https://logs-01.loggly.com/inputs/inputkey>)
log.info("hello from logglier")
end
Tomasz Kowalczyk
  • 10,472
  • 6
  • 52
  • 68