Making WordPress.org

Changeset 8287


Ignore:
Timestamp:
02/20/2019 01:06:00 AM (7 years ago)
Author:
coreymckrill
Message:

WordCamp: More improvements to error handling/logging

  • Rename 0-slack.php to 0-error-handling.php, since that file's only purpose is to load the Slack library for error handling purposes anyway.
  • Move all of the error handling stuff from wcorg-misc.php to 0-error-handling.php. There's enough of it to warrant a separate file, and this way it all gets loaded before the rest of the mu-plugins so it can potentially catch errors there as well.
  • Run the custom error handler and shutdown function in other environments besides production, as long as the SANDBOX_SLACK_USERNAME constant is defined. This way the errors will be sent to the sandbox owner's Slack account, rather than the log channel.
  • In the shutdown function, only send the error to Slack if it is one of the types of errors that can't be handled in the custom error handler.
  • Modify the layout and contents of error messages sent to Slack to make them easier to parse when skimming through backscroll.
Location:
sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins
Files:
1 added
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/wcorg-misc.php

    r8267 r8287  
    443443add_filter( 'map_meta_cap', 'wcorg_central_modify_export_caps', 10, 2 );
    444444
    445 define( 'ERROR_RATE_LIMITING_DIR', '/tmp/error_limiting' );
    446 
    447 /**
    448  * Check and create filesystem dirs to manage rate limiting in error handling.
    449  * For legacy bugs we are doing rate limiting via filesystem. We would be investigating to see if we can instead use memcache to rate limit sometime in the future.
    450  *
    451  * @return bool Return true if file permissions etc are present
    452  */
    453 function init_error_handling() {
    454         if ( ! file_exists( ERROR_RATE_LIMITING_DIR ) ) {
    455                 mkdir( ERROR_RATE_LIMITING_DIR );
    456         }
    457 
    458         return is_dir( ERROR_RATE_LIMITING_DIR ) && is_writeable( ERROR_RATE_LIMITING_DIR );
    459 }
    460 
    461 /**
    462  * Error handler to send errors to slack. Always return false.
    463  */
    464 function send_error_to_slack( $err_no, $err_msg, $file, $line ) {
    465         if ( ! init_error_handling() ) {
    466                 return false;
    467         }
    468 
    469         // Checks to see if the error-throwing expression is prepended with the @ control operator.
    470         // See https://secure.php.net/manual/en/function.set-error-handler.php
    471         if ( 0 === error_reporting() ) {
    472                 error_clear_last();
    473 
    474                 return false;
    475         }
    476 
    477         $error_safelist = [
    478                 E_ERROR,
    479                 E_USER_ERROR,
    480                 E_CORE_ERROR,
    481                 E_COMPILE_ERROR,
    482                 E_PARSE,
    483                 E_NOTICE,
    484                 E_DEPRECATED,
    485                 E_WARNING,
    486         ];
    487 
    488         if ( ! in_array( $err_no, $error_safelist ) ) {
    489                 return false;
    490         }
    491 
    492         // Always use constants in the keys here to avoid path disclosure.
    493         $error_ignorelist = [
    494                 // See https://core.trac.wordpress.org/ticket/29204
    495                 ABSPATH . 'wp-includes/SimplePie/Registry.php:215' => 'Non-static method WP_Feed_Cache::create() should not be called statically',
    496         ];
    497 
    498         if ( isset( $error_ignorelist[ "$file:$line" ] ) && false !== strpos( $err_msg, $error_ignorelist[ "$file:$line" ] ) ) {
    499                 return false;
    500         }
    501 
    502         // Max file length for ubuntu system is 255.
    503         $err_key = substr( base64_encode("$file-$line-$err_no" ), -254 );
    504 
    505         $error_file = ERROR_RATE_LIMITING_DIR . "/$err_key";
    506 
    507         $text = '';
    508 
    509         $data = array(
    510                 'last_reported_at' => time(),
    511                 'error_count'      => 0, // since last reported.
    512         );
    513 
    514         if ( ! file_exists( $error_file ) ) {
    515                 $text = 'Error occured. ';
    516                 file_put_contents( $error_file, wp_json_encode( $data ) );
    517         } else {
    518                 $data                 = json_decode( file_get_contents( $error_file ), true );
    519                 $data['error_count'] += 1;
    520                 $time_elasped         = time() - $data['last_reported_at'];
    521 
    522                 if ( $time_elasped > 600 ) {
    523                         $text                     = "Still happening. Happened ${data['error_count']} time(s) since last reported. ";
    524                         $data['last_reported_at'] = time();
    525                         $data['error_count']      = 0;
    526 
    527                         file_put_contents( $error_file, wp_json_encode( $data ) );
    528                 } else {
    529                         file_put_contents( $error_file, wp_json_encode( $data ) );
    530                         return false;
    531                 }
    532         }
    533 
    534         $domain    = get_site_url();
    535         $page_slug = esc_html( trim( $_SERVER['REQUEST_URI'], '/' ) );
    536         $text      = $text . "Message : \"$err_msg\" occurred on \"$file:$line\" \n Domain: $domain \n Page: $page_slug \n Error type: $err_no";
    537 
    538         $message = array(
    539                 'fallback'    => $text,
    540                 'color'       => '#ff0000',
    541                 'pretext'     => "Error on \"$file:$line\" ",
    542                 'author_name' => $domain,
    543                 'text'        => $text,
    544         );
    545 
    546         $send = new \Dotorg\Slack\Send( SLACK_ERROR_REPORT_URL );
    547         $send->add_attachment( $message );
    548 
    549         $send->send( WORDCAMP_LOGS_SLACK_CHANNEL );
    550 
    551         return false;
    552 }
    553 
    554 /**
    555  * Shutdown handler which forwards errors to slack.
    556  */
    557 function send_fatal_to_slack() {
    558         $error = error_get_last();
    559         if ( ! $error ) {
    560                 return;
    561         }
    562 
    563         return send_error_to_slack( $error['type'], $error['message'], $error['file'], $error['line'] );
    564 }
    565 
    566 if ( 'production' === WORDCAMP_ENVIRONMENT ) {
    567         register_shutdown_function( 'send_fatal_to_slack' );
    568         set_error_handler( 'send_error_to_slack', E_ERROR );
    569 }
    570 
    571 /**
    572  * Function `send_error_to_slack` above also creates a bunch of files in /tmp/error_limiting folder in order to rate limit the notification.
    573  * This function will be used as a cron to clear these error_limiting files periodically.
    574  */
    575 function handle_clear_error_rate_limiting_files() {
    576         if ( ! init_error_handling() ) {
    577                 return;
    578         }
    579 
    580         foreach ( new DirectoryIterator( ERROR_RATE_LIMITING_DIR ) as $file_info ) {
    581                 if ( ! $file_info->isDot() ) {
    582                         unlink( $file_info->getPathname() );
    583                 }
    584         }
    585 
    586 }
    587 
    588 add_action( 'clear_error_rate_limiting_files', 'handle_clear_error_rate_limiting_files' );
    589 
    590 if ( ! wp_next_scheduled( 'clear_error_rate_limiting_files' ) ) {
    591         wp_schedule_event( time(), 'daily', 'clear_error_rate_limiting_files' );
    592 }
    593 
    594445/**
    595446 * Allow individual site administrators to activate and deactivate optional plugins.
Note: See TracChangeset for help on using the changeset viewer.