Skip to main content

Logging in WordPress and WP-CLI

In this lesson you will enable the PHP error log for WP-CLI runs, update your cron configuration to log all scheduled tasks, create a WP-CLI command log for audit, and secure your debug.log from external access.

Logging plays such a big role in diagnosing problems with your WordPress site, and it can be extremely frustrating when you're unable to quickly find the logs you're looking for, especially when they don't exist.

So far we have Nginx access and error logs, as well as the PHP pool error and slow logs configured in our per-site logs directory. However, our per-site PHP configuration is only for the PHP-FPM pool, meaning it's only applied to HTTP traffic.

WP-CLI error logs

Our CLI configuration is still a global one, and that's the configuration used for any WP-CLI commands too. Any errors, including ones occurring in WP-Cron runs, will only be output to the current stderr without being logged anywhere.

We can address this by creating a per-site configuration for PHP CLI. Unfortunately, there is no built-in per-directory php.ini support in PHP. However, we can overcome this by using WP-CLI's require configuration, and address the problem with some PHP code.

First, let's create our new PHP script which we'll include with every run of WP-CLI. I'll place mine in /config/misc/wp-cli-logging.php:

<?php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
    return;
}

\WP_CLI::add_hook( 'before_wp_load', function() {
    ini_set( 'log_errors', '1' );
    ini_set( 'error_log', dirname( ABSPATH ) . '/logs/php-errors.log' );
} );

Here we ensure that we're running in a WP_CLI context, then use the WP-CLI hooks system to run a function on its before_wp_load event, which is very early in the bootstrap process but late enough that the target WordPress configuration file has been read, and the ABSPATH constant has been defined. We use this to set the error_log path to the same php-errors.log file where our PHP-FPM pool configuration is set to log errors.

Next we'll need to update our WP-CLI YAML configuration, to make sure this new file is loaded every time the CLI is invoked. This can be done in our existing /config/misc/wp-cli.yml file, which now looks like this:

disabled_commands:
  - db drop
  - db reset
  - site empty

require:
  - /config/misc/wp-cli-logging.php

Now, triggering an error in a WP-CLI command will lead to that error being logged to our corresponding php-errors.log file. You can test this by intentionally causing a fatal error, and watching the log file:

cd /sites/uncached.org/public_html
wp eval "undefined();"
tail -n20 ../logs/php-errors.log

Note that errors happening without a proper WordPress context will still only be shown on screen. Cron runs, however, occur in a valid WordPress context, so any errors during a background task will be logged to the correct file.

WordPress Cron logs

In addition to logging PHP errors, I highly recommend logging the WordPress cron in general. That way you'll always have a reference of what ran when and why, even if it didn't produce any errors.

I recommend using the ts utility for this, which adds timestamps to output. This is part of the moreutils package in Ubuntu and other Debian-based distributions:

sudo apt install moreutils
echo hello | ts

Let's now update our system cron configuration file, and have the WP-Cron runner output the results to a log file with timestamps. My system cron configuration is in /config/misc/crontab:

* * * * * www-data flock -n /sites/uncached.org/wp-cron.lock wp --path=/sites/uncached.org/public_html cron event run --due-now 2>&1 | ts >> /sites/uncached.org/logs/cron.log

As mentioned in an earlier lesson, this has to be a one-liner, but here is the command that runs, split into multiple lines for readability:

flock -n /sites/uncached.org/wp-cron.lock \
    wp --path=/sites/uncached.org/public_html \
    cron event run --due-now 2>&1 \
    | ts >> /sites/uncached.org/logs/cron.log

We use the same locking technique as before, however this time we redirect stderr to stdout using 2>&1, pipe the output to the timestamp utility ts, and finally append it to the relevant cron.log file.

WordPress cron log

Check your cron.log file in a few minutes to make sure it's being written to. Since we are redirecting stderr to stdout, any PHP errors during that run will also be written to this log file, in addition to the site's php-errors.log.

WordPress debug.log

WordPress has a WP_DEBUG_LOG constant to turn on debug logging, and by default it will attempt to set the log location to wp-content/debug.log. With our existing setup this is not possible because we are using a php_admin_value directive in our PHP pool configuration. This directive sets a configuration value and prevents anything (including WP_DEBUG_LOG) from overriding it.

This article is for premium members only. One-time payment of $96 unlocks lifetime access to all existing and future content on wpshell.com, and many other perks.