8.3 KiB
post_title |
---|
Logging in WooCommerce |
WooCommerce has its own robust system for logging, which can be used for debugging during development, catching errors on production, or even sending notifications when specific events occur. By default, WooCommerce uses this logger to record errors, warnings, and other notices that may be useful for troubleshooting problems with a store. Many extensions for WooCommerce also make use of the logger for similar purposes.
Viewing logs
Depending on the log handler(s) used, you can view the entries created by the logger by going to WooCommerce > Status > Logs.
Log levels
Logs have eight different severity levels:
emergency
alert
critical
error
warning
notice
info
debug
Aside from giving a site owner context as to how important a log entry is, these levels also allow logs to be filtered by the handler. If you only want log entries to be recorded for error
severity and higher, you can set the threshold in the WC_LOG_THRESHOLD
constant by adding something like this to your wp-config.php
file:
define( 'WC_LOG_THRESHOLD', 'error' );
Note that this threshold will apply to all logs, regardless of which log handler is in use. The WC_Log_Handler_Email
class, for example, has its own threshold setting, but it is secondary to the global threshold.
Log handlers
In WooCommerce, a log handler is a PHP class that takes the raw log data and transforms it into a log entry that can be stored or dispatched. WooCommerce ships with three different log handler classes:
WC_Log_Handler_File
: The default handler. Records log entries to files. The files are stored inwp-content/uploads/wc-logs
, but this can be changed by defining theWC_LOG_DIR
constant in yourwp-config.php
file with a custom path. Log files can be up to 5 MB in size, after which the log file will rotate.WC_Log_Handler_DB
: Records log entries to the database. Entries are stored in the{$wpdb->prefix}woocommerce_log
table.WC_Log_Handler_Email
: Sends log entries as email messages. Emails are sent to the site admin email address. This handler has some limitations.
Changing or adding handlers
To switch from the default file log handler to the database handler, you can add an entry like this to your wp-config.php
file:
define( 'WC_LOG_HANDLER', 'WC_Log_Handler_DB' );
In some cases, you may want to have more than one log handler, and/or you might want to modify the settings of a handler. For example, you may want to have most logs saved to files, but log entries that are classified as emergency or critical errors also sent to an email address. For this, you can use the woocommerce_register_log_handlers
filter hook to create an array of log handler class instances that you want to use. Some handler class constructors have optional parameters that you can use when instantiating the class to change their default behavior.
Example:
function my_wc_log_handlers( $handlers ) {
$size_limit = 10 * 1024 * 1024; // Make the file size limit 10 MB instead of 5.
$handlers[] = new WC_Log_Handler_File( $size_limit );
$recipients = array( 'wayne@example.com', 'garth@example.com' ); // Send logs to multiple recipients.
$threshold = 'critical'; // Only send emails for logs of this level and higher.
$handlers[] = new WC_Log_Handler_Email( $recipients, $threshold );
return $handlers;
}
add_filter( 'woocommerce_register_log_handlers', 'my_wc_log_handlers' );
Creating a custom handler
You may want to create your own log handler class in order to send logs somewhere else, such as a Slack channel or perhaps an InfluxDB instance. Your class must extend the WC_Log_Handler
abstract class and implement the WC_Log_Handler_Interface
interface. The WC_Log_Handler_Email
handler class provides a good example of how to set it up.
Adding logs
Logs are added via methods in the WC_Logger
class. The class instance is accessed by using the wc_get_logger()
function. The basic method for adding a log entry is WC_Logger::log( $level, $message, $context )
. There are also shortcut methods for each log severity level, for example WC_Logger::warning( $message, $context )
. Here is an example from the codebase:
$logger = wc_get_logger();
$logger->warning(
sprintf(
'ComparisonOperation "%s" option value "%s" is not an array, defaulting to empty array.',
$rule->operation,
$rule->option_name
),
array(
'option_value' => $option_value,
'rule' => $rule,
)
);
Log sources
Each log entry can include a source
value, which is intended to provide context about where in the codebase the log was generated, and can be used to filter log entries. A source value can be added to a log by including it in the context
parameter like so:
$logger->info( 'Time for lunch', array( 'source' => 'your_stomach' ) );
Each log handler uses the source information a bit differently.
WC_Log_Handler_File
: The source becomes the prefix of the log filename. Thus, log entries with different sources will be stored in different log files. If no source value is given, the handler defaults tolog
as the source.WC_Log_Handler_DB
: The source value is stored in thesource
column in the log database table. When viewing the list table of logs, you can choose a source value from a dropdown as a filter, and only view logs with that source. If no source value is given, the handler uses a stacktrace to determine the name of the file where the log was triggered, and that filename becomes the source.WC_Log_Handler_Email
: This log handler does not use source information.
Clearing old logs
When WooCommerce is first installed, it sets up a scheduled event to delete logs older than 30 days that runs daily. You can change the log retention period using the woocommerce_logger_days_to_retain_logs
filter hook:
add_filter( 'woocommerce_logger_days_to_retain_logs', function() { return 90; } );
Turning off noisy logs
If there is a particular log that is recurring frequently and clogging up your log files, you should probably figure out why it keeps getting triggered and resolve the issue. However, if that's not possible, you can add a filter to ignore that particular log while still allowing other logs to get through:
function my_ignored_logs( $message, $level, $context, $handler ) {
if ( false !== strpos( $message, 'Look, a squirrel!' ) ) {
return null;
}
return $message;
}
add_filter( 'woocommerce_logger_log_message', 'my_ignored_logs', 10, 4 );
Debugging with the logger
Sometimes during debugging you need to find out if the runtime reaches a certain line in the code, or you need to see what value a variable contains, and it's not possible to directly observe what's happening with a var_dump
call or a breakpoint. In these cases you can log the information you need with a one-liner like this:
wc_get_logger()->debug( 'Made it to the conditional!', array( 'source', 'debug-20230825' ) );
On the occasion where you need to know what a non-scalar variable (array, object) contains, you may be tempted to put it in the $context
parameter alongside your source
value. However, only the database log handler even stores the contents of $context
, and none of the handlers display it anywhere. Instead, consider outputting it in the $message
parameter using something like wc_print_r
:
wc_get_logger()->debug(
wc_print_r( $my_special_array ),
array( 'source', 'debug-20230825' )
);