skip to Main Content

I’m working on a WordPress site that has a bunch of plugins installed. They are filling up the error-log with garbage and deprecation notices.

I’m looking for a way, where I can filter/sort what is inside the error.log file, so I can find the errors/notices generated by my code.

Project structure

wp-content
|- plugins
   |- admin-columns-pro        // I want to ignore errors from here
   |- yoast                    // I want to ignore errors from here
   |- my-plugin-foo            // I want to see errors from here
   |- my-plugin-bar            // I want to see errors from here
|- themes
   |- my-custom-theme          // I want to see errors from here
debug.log                      // This is the file where WordPress writes errors and warnings

I assume this has to be some PHP or bash-fix that is needed here, since I don’t know of any WordPress-functions to do this.

Let’s say that I, in my wp-content/themes/my-custom-theme/functions.php did something like this:

$a_var = null;
$stupid_error = $a_var[5];

Then it would give me an "Trying to access array offset on value of type null" in the error log.
But that is burried in all the deprecation notices from the admin-columns-pro and yoast-plugin.

Ideally, there would be a way to tell WordPress or the server something like this:

Error generated by everything within these paths here:

  • /wp-content/plugins/admin-columns-pro
  • /wp-content/plugins/yoast

Should go into wp-content/vendor-debug.log
Everything else should go into wp-content/debug.log

Example debug.log

[25-Apr-2023 21:01:33 UTC] PHP Deprecated:  Constant FILTER_SANITIZE_STRING is deprecated in /var/www/wp-content/plugins/admin-columns-pro/classes/Migrate/Export/Request.php on line 41
[25-Apr-2023 21:01:33 UTC] PHP Stack trace:
[25-Apr-2023 21:01:33 UTC] PHP   1. {main}() /var/www/wp-admin/index.php:0
[25-Apr-2023 21:01:33 UTC] PHP   2. require_once() /var/www/wp-admin/index.php:10
[25-Apr-2023 21:01:33 UTC] PHP   3. do_action($hook_name = 'admin_init') /var/www/wp-admin/admin.php:175
[25-Apr-2023 21:01:33 UTC] PHP   4. WP_Hook->do_action($args = [0 => '']) /var/www/wp-includes/plugin.php:517
[25-Apr-2023 21:01:33 UTC] PHP   5. WP_Hook->apply_filters($value = '', $args = [0 => '']) /var/www/wp-includes/class-wp-hook.php:332
[25-Apr-2023 21:01:33 UTC] PHP   6. ACPMigrateExportRequest->handle_request('') /var/www/wp-includes/class-wp-hook.php:308
[25-Apr-2023 21:01:33 UTC] PHP Deprecated:  Constant FILTER_SANITIZE_STRING is deprecated in /var/www/wp-content/plugins/admin-columns-pro/classes/Migrate/Import/Request.php on line 56
[25-Apr-2023 21:01:33 UTC] PHP Stack trace:
[25-Apr-2023 21:01:33 UTC] PHP   1. {main}() /var/www/wp-admin/index.php:0
[25-Apr-2023 21:01:33 UTC] PHP   2. require_once() /var/www/wp-admin/index.php:10
[25-Apr-2023 21:01:33 UTC] PHP   3. do_action($hook_name = 'admin_init') /var/www/wp-admin/admin.php:175
[25-Apr-2023 21:01:33 UTC] PHP   4. WP_Hook->do_action($args = [0 => '']) /var/www/wp-includes/plugin.php:517
[25-Apr-2023 21:01:33 UTC] PHP   5. WP_Hook->apply_filters($value = '', $args = [0 => '']) /var/www/wp-includes/class-wp-hook.php:332
[25-Apr-2023 21:01:33 UTC] PHP   6. ACPMigrateImportRequest->handle_request('') /var/www/wp-includes/class-wp-hook.php:308
[25-Apr-2023 21:01:33 UTC] PHP   7. ACPMigrateImportRequest->is_request() /var/www/wp-content/plugins/admin-columns-pro/classes/Migrate/Import/Request.php:83
[25-Apr-2023 21:01:33 UTC] PHP Fatal Error: Trying to access array offset on value of type null
[25-Apr-2023 21:01:33 UTC] PHP Stack trace:
[25-Apr-2023 21:01:33 UTC] PHP   1. Blah
[25-Apr-2023 21:01:33 UTC] PHP   2. Blah blah
[25-Apr-2023 21:01:33 UTC] PHP   3. Blah blah blah
[25-Apr-2023 21:01:33 UTC] PHP Deprecated:  Constant FILTER_SANITIZE_STRING is deprecated in /var/www/wp-content/plugins/wp-smushit/core/external/free-dashboard/module.php on line 248
[25-Apr-2023 21:01:33 UTC] PHP Stack trace:
[25-Apr-2023 21:01:33 UTC] PHP   1. {main}() /var/www/wp-admin/index.php:0
[25-Apr-2023 21:01:33 UTC] PHP   2. require_once() /var/www/wp-admin/index.php:137
[25-Apr-2023 21:01:33 UTC] PHP   3. do_action($hook_name = 'all_admin_notices') /var/www/wp-admin/admin-header.php:311
[25-Apr-2023 21:01:33 UTC] PHP   4. WP_Hook->do_action($args = [0 => '']) /var/www/wp-includes/plugin.php:517
[25-Apr-2023 21:01:33 UTC] PHP   5. WP_Hook->apply_filters($value = '', $args = [0 => '']) /var/www/wp-includes/class-wp-hook.php:332
[25-Apr-2023 21:01:33 UTC] PHP   6. WPMU_Free_Notice->all_admin_notices('') /var/www/wp-includes/class-wp-hook.php:308
[25-Apr-2023 21:01:33 UTC] PHP   7. WPMU_Free_Notice->choose_message() /var/www/wp-content/plugins/wp-smushit/core/external/free-dashboard/module.php:220

Solution attempt 1: A bash-script

I considered if it was possible to have a bash-script that I could run, that would generate filtered-error.log, that only contained errors/warnings from the error.log that I wanted to see. So from above example, if would filter everything except:

[25-Apr-2023 21:01:33 UTC] PHP Fatal Error: Trying to access array offset on value of type null
[25-Apr-2023 21:01:33 UTC] PHP Stack trace:
[25-Apr-2023 21:01:33 UTC] PHP   1. Blah
[25-Apr-2023 21:01:33 UTC] PHP   2. Blah blah
[25-Apr-2023 21:01:33 UTC] PHP   3. Blah blah blah

Solution attempt 2: Override the error_log-function

It feels like a pretty bad idea. But if I did it, then I could potentially check the stack trace and get a path from there or something. It feels pretty bad, though.

Solution attempt 3: Setup Graylog or another logging tool

That would be ideal, but it’s not something that can easily be done.

2

Answers


  1. You can redirect logging based on $errfile in a custom error handler.

    set_error_handler(function ($errno, $errstr, $errfile) {
      $root = '/var/www/';
      $vendorPaths = ['wp-content/plugins/admin-columns-pro/', 'wp-content/plugins/yoast/'];
      $log = 'wp-content/debug.log';
      foreach ($vendorPaths as $path) {
        if (str_starts_with($errfile, $root.$path)) {
          $log = 'wp-content/vendor-debug.log';
          break;
        }
      }
      ini_set('error_log', $root.$log);
      return false;
    });
    

    It is however not possible to redirect it back, so any subsequent manual error_log() call will use the log file previously set in the error handler.

    Login or Signup to reply.
  2. It’s quite usual that logfiles contain more messages than currently required.

    The most suitable solution depends on the way you want to read the logfiles, but finally filtering to fit the current purpose is the path:

    1. Eliminate only all "PHP Deprecated" messages:
    grep -v "]sPHPsDeprecated:" debug.log
    

    It’s a quick filter, but will show other messages that are not part of the "Fatal Error + Stack track", also.

    1. Another fast version allows to just show messages that fit the positive pattern:
    grep -E "]sPHPs(Fatal Error:|Stack trace:|  [0-9]*.s)" debug.log
    

    Also quite quick; the caveat is that this solution does not verify that before the numbered lines has been a "Stack trace:" key-line. So it’s possibile that some other PHP messages with a nubered list item might be included. But they should be obvious as they usually won’t fit in the desired numbered list.

    1. To get it more sophisticated only showing the desired entries, you could change to awk.

    You could do it by a one-liner:

    awk '{ if (/] PHP Fatal Error:/) { print; t = 0 } else { if (/] PHP Stack trace:/) { t = 1; print } else { if (/] PHP   [0-9]+. /) { print; } else { t = 0 } } } }' debug.log
    

    but probably you prefer to have this as a script file:

    File: MyDebugMessages

    #!/usr/bin/awk -f
    { 
        if (/] PHP Fatal Error:/) { 
            t = 0 
            print
        } else { 
            if (/] PHP Stack trace:/) { 
                t = 1
                print
            } else {
                if (/] PHP   [0-9]+. /) {
                    print;
                } else { 
                    t = 0 
                } 
            } 
        }
    }
    

    just store it and make it executable:

    chmod +x MyDebugMessages
    
    # Send output to file:
    MyDebugMessages debug.log > debug-filtered.log
    
    # Just display:
    MyDebugMessages debug.log
    
    # See output appear live in the ssh remote shell:
    MyDebugMessages debug.log | tail -f
    

    The awk script assumes that the Stack trace output is in one block, but not polluted by other log messages.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search