Setting up Ansible for hourly Rails log rotation

By Daniele, on 2018年1月

Logs are an important part of any web application. Too few logs make debugging issues a problem. On the flip-side, too many logs can make a disk max out of space, or finding a specific error harder than it should be.

I was recently tasked with setting up hourly log rotation for a server that was running Rails, deployed via Capistrano.

Here is the Ansible setup which I used to programmatically add the rotate logic to cron. Please note that this setup is for an Ubuntu server, and requires that you input the sudo password when running the Ansible playbook. It also sets up the cron job to run under the root user's cron file. It would be possible to have it run on another user's cron file but that option could wipe out the crontab.

The directory structure

The file content


The files ./production/group_vars/all/000_cross_group_env_vars.yml and ./staging/group_vars/all/000_cross_group_env_vars.yml should be symlinks to the file 000_cross_group_env_vars.yml which is at the base of the directory tree. The latter should contain something like the following:

    - vim
    - cron
    - logrotate
  rails_file: /etc/logrotate.d/rails
You can then create the symlinks with the following commands:
cd environments/staging/group_vars/all
ln -s ../../../../000_cross_group_env_vars.yml ./000_cross_group_env_vars.yml
cd environments/production/group_vars/all
ln -s ../../../../000_cross_group_env_vars.yml ./000_cross_group_env_vars.yml

This is a simple bash file which should be executable (i.e. you should run chmod +x provision)

ansible-playbook -i ./environments/$@ playbook.yml --ask-become-pass

These files should contain a list of the staging or production servers, for example:


This should contain the rules to install the base packages which are necessary on your server:

- name: Ensure required packages installed
    update_cache: yes
    name: "{{ item }}"
    state: latest
  with_items: "{{ base_os.packages }}"

This should copy over the logrotate file and create the cron entry:

- name: Add Rails app logrotate rules
    src: templates/logrotate_rails.j2
    dest: "{{ logrotate.rails_file }}"
    owner: root
    group: root
    mode: '0644'
    force: yes

- name: Set up cron
    name: Hourly log rotation
    minute: "0"
    hour: "*"
    user: root
    job: "/usr/sbin/logrotate -f {{ logrotate.rails_file }} > /dev/null"

This file contains the template with the logrotate directives:

# {{ ansible_managed }}

# Path to your Rails app:
"/var/www/app/current/log/*.log" {
  su deploy deploy
  size 25M
  maxsize 50M
  rotate 150

This is the main entry-point that the Ansible playbook will run:

- hosts: all
  become: true
  remote_user: deploy  # The remote user that the ansible script will run as
    - base_os
    - logrotate


With this setup in place you will be able to easily add log rotation to a Rails application via Ansible, simply by running:

./bin/provision staging
# or
./bin/provision production