ruby-on-railsloggingpumapuma-dev

Puma not logging when running daemon


When running Puma as a daemon (i.e. using the -d flag), Puma does not seem to log to the location specified by stdout_redirect.

Has anyone seen this behavior before and if so, found a workaround to generate the proper log files for Puma (specifically with the stdout_redirect in place, and specifically for a Ruby on Rails application)?


Solution

  • The reason stdout_redirect is not working is because config/puma.rb is never run when you run rails server -d. You can demonstrate this for yourself by changing the port number or even introducing a syntax error in the file.

    Puma runs as a Rack server and is thus launched by the Rack middleware. The Rack code just uses the core Ruby Process class to detach the process:

    def daemonize_app
      Process.daemon
    end
    

    Unfortunately, Process.daemon does two things by default:

    1. Changes the current working directory to root ('/').
    2. Redirects stdout and stderr to /dev/null.

    So, when the Puma server initializes, all process output is binned and since /config/puma.rb doesn't exist, puma falls back to its hardcoded default settings.

    You can actually demonstrate the behavior you want if you temporarily hack the rack code to override the chdir behaviour:

    def daemonize_app
      Process.daemon(true)
    end
    

    If the first parameter to .daemon is true it does not change the current working directory, and thus the config/puma.rb gets run.

    Short of some kind of ugly monkey-patch to Rack, a (possibly also ugly) workaround would be to skip the -d option and roll your own in config/puma.rb. For example:

    # ... rest of the puma config
    
    return unless ENV['DAEMONIZE_PUMA'].present?
    
    puts 'Running puma as a daemon...'
    Process.daemon(true)
    

    Then:

    % export DAEMONIZE_PUMA=true
    % rails server
    => Booting Puma
    => Rails 6.1.4 application starting in development
    => Run `bin/rails server --help` for more startup options
    Running puma as a daemon...
    % tail log/puma.out
    === puma startup: 2021-07-17 10:03:37 +1200 ===