Changeset 19610

Show
Ignore:
Timestamp:
12/08/08 12:30:11 (7 months ago)
Author:
bergie
Message:

Implement error actions for logging or sending email on error pages, fixes #305

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/ragnaroek/midcom/midcom.core/errors.php

    r19606 r19610  
    2121    /** 
    2222     * Catch an Exception and show it as a HTTP error 
     23     * 
     24     * @see midcom_application::generate_error() 
     25     * @see midcom_exception_handler::show() 
    2326     */ 
    2427    public static function handle_exception(Exception $e) 
    2528    { 
    26         $this->show(MIDCOM_ERRCRIT, $e->getMessage()); 
     29        $_MIDCOM->generate_error(MIDCOM_ERRCRIT, $e->getMessage()); 
    2730        // This will exit 
    2831    } 
     
    6972        debug_print_r('Debugging Stacktrace:', $GLOBALS['midcom_debugger']->_prefixes); 
    7073        debug_print_function_stack('XDebug Stacktrace:'); 
     74 
     75        // Send error to special log or recipient as per in configuration. 
     76        $this->send($httpcode, $message); 
    7177 
    7278        if (headers_sent()) 
     
    159165</address> 
    160166<?php 
    161         if (MIDCOM_XDEBUG) 
    162         { 
    163             echo "<pre>\n"; 
    164             $stack = xdebug_get_function_stack(); 
    165             $stacktrace = ''; 
    166             foreach ($stack as $number => $frame) 
    167             { 
    168                 $stacktrace .= $number + 1; 
    169                 $stacktrace .= ": {$frame['file']}:{$frame['line']} "; 
    170                 if (array_key_exists('class', $frame)) 
    171                 { 
    172                     $stacktrace .= "{$frame['class']}::{$frame['function']}"; 
    173                 } 
    174                 else if (array_key_exists('function', $frame)) 
    175                 { 
    176                     $stacktrace .= $frame['function']; 
    177                 } 
    178                 else 
    179                 { 
    180                     $stacktrace .= 'require, include or eval'; 
    181                 } 
    182                 $stacktrace .= "\n"; 
    183             } 
    184             echo "Stacktrace:\n{$stacktrace}</pre>\n"; 
    185         } 
     167$stacktrace = $this->get_function_stack(); 
     168if (!empty($stacktrace)) 
     169
     170    echo "<pre>{$stacktrace}</pre>\n"; 
     171
    186172?> 
    187173</body> 
     
    191177        debug_add("Error Page output finished, exiting now", MIDCOM_LOG_DEBUG); 
    192178        debug_pop(); 
    193         $this->cache->content->no_cache(); 
    194         $this->finish(); 
     179        $_MIDCOM->cache->content->no_cache(); 
     180        $_MIDCOM->finish(); 
    195181        exit(); 
    196182    } 
     183 
     184    /** 
     185     * Send error for processing. 
     186     * 
     187     * If the given error code has an action configured for it, that action will be 
     188     * performed. This means that system administrators can request email notifications 
     189     * of 500 "Internal Errors" and a special log of 404 "Not Founds". 
     190     * 
     191     * @param int $httpcode        The error code to send. 
     192     * @param string $message    The message to print. 
     193     */ 
     194    private function send($httpcode, $message) 
     195    { 
     196        if (   !isset($GLOBALS['midcom_config']['error_actions'][$httpcode]) 
     197            || !is_array($GLOBALS['midcom_config']['error_actions'][$httpcode]) 
     198            || !isset($GLOBALS['midcom_config']['error_actions'][$httpcode]['action'])) 
     199        { 
     200            // No action specified for this error code, skip 
     201            return; 
     202        } 
     203 
     204        // Prepare the message 
     205        $msg = "{$_SERVER['REQUEST_METHOD']} request to {$_SERVER['REQUEST_URI']}: "; 
     206        $msg .= "{$httpcode} {$message}\n"; 
     207        if (isset($_SERVER['HTTP_REFERER'])) 
     208        { 
     209            $msg .= "(Referrer: {$_SERVER['HTTP_REFERER']})"; 
     210        } 
     211         
     212        // Send as email handler 
     213        if ($GLOBALS['midcom_config']['error_actions'][$httpcode]['action'] == 'email') 
     214        { 
     215            if (   !isset($GLOBALS['midcom_config']['error_actions'][$httpcode]['email']) 
     216                || empty($GLOBALS['midcom_config']['error_actions'][$httpcode]['email'])) 
     217            { 
     218                // No recipient specified, skip 
     219                return; 
     220            } 
     221             
     222            if (!$_MIDCOM->componentloader->is_installed('org.openpsa.mail')) 
     223            { 
     224                debug_push_class(__CLASS__, __FUNCTION__); 
     225                debug_add("Email sending library org.openpsa.mail, used for error notifications is not installed", MIDCOM_LOG_WARN); 
     226                debug_pop(); 
     227                return; 
     228            } 
     229 
     230            $_MIDCOM->load_library('org.openpsa.mail'); 
     231 
     232            $mail = new org_openpsa_mail(); 
     233            $mail->to = $GLOBALS['midcom_config']['error_actions'][$httpcode]['email']; 
     234            $mail->from = "\"MidCOM error notifier\" <webmaster@{$_SERVER['SERVER_NAME']}>"; 
     235            $mail->subject = "[{$_SERVER['SERVER_NAME']}] {$msg}"; 
     236            $mail->body = "{$_SERVER['SERVER_NAME']}:\n{$msg}"; 
     237             
     238            $stacktrace = $this->get_function_stack(); 
     239 
     240            if (empty($stacktrace)) 
     241            { 
     242                // No Xdebug, rely on MidCOM debugger stack 
     243                foreach ($GLOBALS['midcom_debugger']->_prefixes as $prefix) 
     244                { 
     245                    $stacktrace .= "{$prefix}\n"; 
     246                } 
     247            } 
     248 
     249            $mail->body .= "\n{$stacktrace}"; 
     250 
     251            if (!$mail->send()) 
     252            { 
     253                debug_push_class(__CLASS__, __FUNCTION__); 
     254                debug_add("failed to send error notification email to {$mail->to}, reason: " . $mail->get_error_message(), MIDCOM_LOG_WARN); 
     255                debug_pop(); 
     256            } 
     257             
     258            return; 
     259        } 
     260 
     261        // Append to log file handler 
     262        if ($GLOBALS['midcom_config']['error_actions'][$httpcode]['action'] == 'log') 
     263        { 
     264            if (   !isset($GLOBALS['midcom_config']['error_actions'][$httpcode]['filename']) 
     265                || empty($GLOBALS['midcom_config']['error_actions'][$httpcode]['filename'])) 
     266            { 
     267                // No log file specified, skip 
     268                return; 
     269            } 
     270             
     271            if (   !is_writable($GLOBALS['midcom_config']['error_actions'][$httpcode]['filename']) 
     272                && !is_writable(dirname($GLOBALS['midcom_config']['error_actions'][$httpcode]['filename']))) 
     273            { 
     274                debug_push_class(__CLASS__, __FUNCTION__); 
     275                debug_add("Error logging file {$GLOBALS['midcom_config']['error_actions'][$httpcode]['filename']} is not writable", MIDCOM_LOG_WARN); 
     276                debug_pop(); 
     277                return; 
     278            } 
     279             
     280            // Add the line to the error-specific log 
     281            $logger = new midcom_debug($GLOBALS['midcom_config']['error_actions'][$httpcode]['filename']); 
     282            $logger->setLoglevel(MIDCOM_LOG_INFO); 
     283            $logger->log($msg, MIDCOM_LOG_INFO); 
     284 
     285            return; 
     286        } 
     287    } 
     288     
     289    private function get_function_stack() 
     290    { 
     291        $stacktrace = ''; 
     292        if (!MIDCOM_XDEBUG) 
     293        { 
     294            return $stacktrace; 
     295        } 
     296         
     297        $stack = xdebug_get_function_stack(); 
     298        $stacktrace .= "Stacktrace:\n"; 
     299        foreach ($stack as $number => $frame) 
     300        { 
     301            $stacktrace .= $number + 1; 
     302            $stacktrace .= ": {$frame['file']}:{$frame['line']} "; 
     303            if (array_key_exists('class', $frame)) 
     304            { 
     305                $stacktrace .= "{$frame['class']}::{$frame['function']}"; 
     306            } 
     307            else if (array_key_exists('function', $frame)) 
     308            { 
     309                $stacktrace .= $frame['function']; 
     310            } 
     311            else 
     312            { 
     313                $stacktrace .= 'require, include or eval'; 
     314            } 
     315            $stacktrace .= "\n"; 
     316        } 
     317        return $stacktrace; 
     318    } 
    197319} 
    198320 
     321// Register the error and Exception handlers 
    199322set_error_handler(array('midcom_exception_handler', 'handle_error'), E_ALL & ~E_NOTICE | E_WARNING); 
    200323set_exception_handler(array('midcom_exception_handler', 'handle_exception')); 
  • branches/ragnaroek/midcom/midcom.core/midcom/config/midcom_config.php

    r19107 r19610  
    189189 *   the logging system. See the URL method log of midcom_application for details. Turned off 
    190190 *   by default for security reasons. 
     191 * - <b>array error_actions:</b> Actions to run when a specific error code is produced. This can 
     192 *   be used for saving logs about 404 errors from broken links, or sending an error 500 to 
     193 *   webmaster for analysis. 
     194 * 
     195 *   Configuration example: 
     196 * 
     197 * <code> 
     198 * $GLOBALS['midcom_config_default']['error_actions'] = array 
     199 * ( 
     200 *     500 => array 
     201 *     ( 
     202 *         'action' => 'email', 
     203 *         'email' => 'webmaster@example.net', 
     204 *     ), 
     205 *     404 => array 
     206 *     ( 
     207 *         'action' => 'log', 
     208 *         'filename' => '/var/log/broken_links.log', 
     209 *     ), 
     210 * ); 
     211 * </code> 
    191212 * 
    192213 * <b>MidCOM Core configuration</b> 
     
    424445$GLOBALS['midcom_config_default']['display_php_errors'] = true; 
    425446$GLOBALS['midcom_config_default']['enable_error_handler'] = true; 
     447$GLOBALS['midcom_config_default']['error_actions'] = array(); 
    426448 
    427449// Core configuration 
  • branches/ragnaroek/midcom/midcom.core/midcom/debug.php

    r17266 r19610  
    8686        $this->_enabled = true; 
    8787        $this->_loglevel = $GLOBALS['midcom_config']['log_level']; 
    88         $this->_loglevels = array ( 
     88        $this->_loglevels = array 
     89        ( 
    8990            MIDCOM_LOG_DEBUG => "debug", 
    9091            MIDCOM_LOG_INFO  => "info", 
  • branches/ragnaroek/midcom/org.openpsa.mail/backend/mail/smtp.php

    r18204 r19610  
    6262        $merged = $mailclass->merge_address_headers(); 
    6363        //debug_add("address_headers_merged:\n===\n{$merged}\n===\nheaders:\n===\n" . org_openpsa_helpers::sprint_r($mailclass->headers) . "===\n"); 
     64 
    6465        $mailRet = $mail->send($merged, $mailclass->headers, $mailclass->body); 
    6566        //This gives *huge* log in case of error since the full org_openpsa_mail object is included in the PEAR error as well 
    6667        //debug_add("mail->send returned\n===\n" . org_openpsa_helpers::sprint_r($mailRet) . "===\n"); 
     68 
    6769        if ($mailRet === true) 
    6870        {