Logger

rainmikko 26.01.06 11:20

Helppokäytöinen logittaja vaikkapa debuggaamiseen. Yhdistin tähän myös Ezkun ErrorHandlerin (http://mureakuha.com/koodikirjasto/823) hanskaamaan virheilmotukset luettavampaan muotoon lokiin.

 Tekstiversio  Arvo: 3 (5 ääntä)  Äänestä: +  -
-- Logger.php --
<?php
/**
 * Logger is easy and usefull logging tool.
 *
 * @author Mikko Rainio 2006
 * @package Logger
 */



////////////////////
//Logger parameters
/**
 * Defines debugmode
 */

define("LOG_DEBUG_ENABLED", true);

/**
 * Absolute path to log directory.
 */

define("LOG_DIR_PATH","/path/to/logfolder");

/**
 * Log filename
 */

define("LOG_FILENAME","debug.log");

/**
 * Use custom error handler. Works in >= PHP 4.3.0
 */

define("LOG_USE_CUSTOM_ERROR_HANDLER",true);

/**
 * Set the maximum size that the output file is allowed to reach
 * before being rolled over to backup files.
 *
 * <p>You can specify the value with the suffixes "KB", "MB" or "GB"
 * so that the integer is interpreted being expressed respectively
 * in kilobytes, megabytes or gigabytes. For example, the value "10KB"
 * will be interpreted as 10240.</p>
 * <p>The default maximum file size is 5MB.</p>
 *
 * <p>Note that <var>LOG_MAX_FILE_SIZE</var> cannot exceed <b>2 GB</b>.</p>
 */

define("LOG_MAX_FILE_SIZE","5MB");

/**
 * Date format
 */

define("LOG_DATE_FORMAT","Y-m-d H:i:s");

// End: Logging parameters
//////////////////////////

//verify log folder existence
//if it does not exist, create it
if(LOG_DIR_PATH != '' && !is_dir(LOG_DIR_PATH)){
    if(mkdir(LOG_DIR_PATH)===FALSE){
        die( "Could not create log dir: ".LOG_DIR_PATH );
    }
}

// Use our own error handler?
// Using class method in error handler works since PHP 4.3.0 
if(LOG_USE_CUSTOM_ERROR_HANDLER && PHP_VERSION >= '4.3.0')
    set_error_handler(array(new Log(),'ErrorHandler'));

/**
 * Class Log. Handles logging to logfile. All class methods can be used as
 * static method.
 *
 * <p>Usefull also for logging variables at debugtime.</p>
 * <p>For example:
 * <code>
 * $arr = array("one","two","three");
 * Log::debug("Log array values",__FILE__,__LINE__);
 * Log::debug($arr);
 * </code></p>
 * <p>Output:
 * <pre>
 * 2006-01-25 16:21:21 DEBUG /path/to/filename.php(21): Log array values
 * 2006-01-25 16:21:21 DEBUG : Array ( [0] => one [1] => two [2] => three )
 * </pre></p>
 *
 * @author Mikko Rainio 2006
 * @version 1.1
 * @package Logger
 * @static  All methods can be used as static
 */

class Log {
   
    /**
     * Writes DEBUG-level message to log file.
     * For example:<code>Log::debug("Message",__FILE__,__LINE__);</code>
     *
     * @uses LOG_DEBUG_ENABLED
     * @param String $logMsg    Log row
     * @param String $file      Optional. Filename where something happens
     * @param String $line      Optional. Line number
     */

    function debug($logMsg,$file='',$line='') {
        if(LOG_DEBUG_ENABLED) {
            Log::logRow($logMsg,'DEBUG',$file,$line);
        }
    }
   
    /**
     * Writes WARNING-level message to log file.
     * For example:<code>Log::warn("Message",__FILE__,__LINE__);</code>
     *
     * @param String $logMsg    Log row
     * @param String $file      Optional. Filename where something happens
     * @param String $line      Optional. Line number
     */

    function warn($logMsg,$file='',$line='') {
        Log::logRow($logMsg,'WARNING',$file,$line);
    }
   
    /**
     * Writes ERROR-level message to log file.
     * For example:<code>Log::error("Message",__FILE__,__LINE__);</code>
     *
     * @param String $logMsg    Log row
     * @param String $file      Optional. Filename where something happens
     * @param String $line      Optional. Line number
     */

    function error($logMsg,$file='',$line='') {
        Log::logRow($logMsg,'ERROR',$file,$line);
    }
   
    /**
     * Writes INFO-level message to log file.
     * For example:<code>Log::info("Message",__FILE__,__LINE__);</code>
     *
     * @param String $logMsg    Log row
     * @param String $file      Optional. Filename where something happens
     * @param String $line      Optional. Line number
     */

    function info($logMsg,$file='',$line='') {
        Log::logRow($logMsg,'INFO',$file,$line);
    }
   
    /**
     * Return formatted actual date.
     *
     * @uses LOG_DATE_FORMAT
     * @param   String $pattern Optional. Date pattern. Default is 'Y-m-d H:i:s'
     * @return  String          Actual date.
     */

    function get_formatted_date($pattern = ''){
        if($pattern == '')
            $pattern = LOG_DATE_FORMAT;
        return date($pattern);
    }
   
    /**
     * Converts $arg to string. Can handle objects, arrays, multidimensional
     * arrays etc...
     *
     * @access private
     * @param mixed     $arg    Convertable input
     * @return String           Converted string
     */

    function msgToString($arg) {
        $retMsg = '';
        if(is_array($arg)) {
            $retMsg .= " Array (";
            foreach($arg as $key => $value) {
                $retMsg .= " [".$key.'] => '.Log::msgToString($value)." ";
            }
            $retMsg .= ")";
        }
        elseif( is_object($arg) ) {
            $retMsg .= get_class($arg)." Object (";
            $vars = get_object_vars($arg);
            foreach($vars as $key => $value) {
                $retMsg .= " [".$key.'] => '.Log::msgToString($value)." ";
            }
            $retMsg .= ")";
        }
        elseif( is_bool($arg) ) {
            $retMsg .= ($arg)? 'true': 'false';
        }
        elseif( $arg == NULL ) {
            $retMsg .= 'NULL';
        }
        else {
            $retMsg .= "$arg"
        }
        return $retMsg;
    }
   
    /**
     * Error handler, providing rigorous backtrace information.
     *
     * @author  Ezku
     * @link    http://mureakuha.com/koodikirjasto/823
     * @param   int     error type
     * @param   string  error message
     * @param   string  file name
     * @param   string  line number
     */

    function ErrorHandler ($error_type, $error_message, $file, $line) {
        $strReturn = "";
        static $error_types = array (
                1       => 'E_ERROR',           2       => 'E_WARNING',
                4       => 'E_PARSE',           8       => 'E_NOTICE',
                16      => 'E_CORE_ERROR',      32      => 'E_CORE_WARNING',
                64      => 'E_COMPILE_ERROR',   128     => 'E_COMPILE_WARNING',
                256     => 'E_USER_ERROR',      512     => 'E_USER_WARNING',
                1024    => 'E_USER_NOTICE',     2047    => 'E_ALL',
                2048    => 'E_STRICT'
            );
           
        // Check error type against error reporting level. @ is always ignored.
        if (($error_type != 0) && ($error_type & ini_get('error_reporting'))){
   
            $strReturn .= Log::get_formatted_date().' '.$error_types[$error_type].
                            ' '.$file.'('.$line.'): '.$error_message."\n";
           
            $backtrace = debug_backtrace();
            // First is always ErrorHandler, skip it
            array_shift($backtrace);
            $i = -1;
            foreach ($backtrace as $trace) {
                $args = array();
                if (isset($trace['args'])) {
                    foreach ($trace['args'] as $a) {
                        switch (gettype($a)) {
                            case 'integer':
                            case 'double':
                                $args[] = $a;
                                break;
                            case 'string':
                                $args[] = "\"$a\"";
                                break;
                            case 'array':
                                $args[] = 'Array('.count($a).')';
                                break;
                            case 'object':
                                $args[] = 'Object('.get_class($a).')';
                                break;
                            case 'resource':
                                $args[] = 'Resource('.strstr($a, '#').')';
                                break;
                            case 'boolean':
                                $args[] = $a ? 'True' : 'False';
                                break;
                            case 'NULL':
                                $args[] = 'NULL';
                                break;
                            default:
                                $args[] = 'UNKNOWN';
                        }
                    }
                }
                if( true)
                {
                    $strReturn .= "\t".'#'.++$i.' '.$trace['file'].'('.$trace['line'].'): '.
                                (isset($trace['class']) ? $trace['class'].$trace['type'] : '').
                                $trace['function'].'('.implode(', ',$args).')'."\n";
                }
            }
           
            Log::writeLog($strReturn);
            if($error_types[$error_type] == 'E_ERROR' ||
                $error_types[$error_type] == 'E_USER_ERROR' ||
                $error_types[$error_type] == 'E_USER_NOTICE')
                exit
        }
    }
       
    /**
     * Empty constructor. Needed only in set_error_handler()-function above.
     *
     * @access private
     */

    function Log(){}
       
    /**
     * Constructs the log row.
     *
     * @access private
     * @param String $logMsg    Log row
     * @param String $level     Message log-level ('INFO','DEBUG','WARNING','ERROR')
     * @param String $file      Optional. Filename where something happens
     * @param String $line      Optional. Line number
     */

    function logRow($logMsg,$level,$file='',$line=''){
        $logRow = Log::get_formatted_date().' '.$level.' ';
        if($file != '') {
            $logRow .= $file;
            if($line != '')
                $logRow .= '('.$line.')';
        }
        $logRow .= ': '.Log::msgToString($logMsg)."\n";
        Log::writeLog($logRow);

    }//end function
   
    /**
     * Recieves the string and writes it in to log file.
     *
     * @access private
     * @uses LOG_DIR_PATH
     * @uses LOG_FILENAME
     * @param String $logString     Log row
     */

    function writeLog($logString){
        $logFile=(LOG_DIR_PATH != '')? LOG_DIR_PATH . "/" . LOG_FILENAME : LOG_FILENAME;   
       
        //write to log file
        $fp=fopen($logFile,"a");
        if(fwrite($fp,$logString)===FALSE){
            die("Could not write to LOG file: ".$logFile);
        }
        fclose($fp);
       
        if(filesize($logFile) >= Log::getMaxFileSizeInBytes()) {
                        $bakFile = ((LOG_DIR_PATH == '')? '': LOG_DIR_PATH.'/') . date("YmdHis") . ".log.bak";
            rename( $logFile, $bakFile );
        }
    }//end function
   
    /**
     * Converts property <var>LOG_MAX_FILE_SIZE</var> to bytes.
     *
     * @access private
     * @uses LOG_MAX_FILE_SIZE
     * @return integer LOG_MAX_FILE_SIZE in bytes
     */

    function getMaxFileSizeInBytes()
    {
        $value = LOG_MAX_FILE_SIZE;
        $maxFileSize = null;
        $numpart = substr($value,0, strlen($value) -2);
        $suffix  = strtoupper(substr($value, -2));

        switch ($suffix) {
            case 'KB': $maxFileSize = (int)((int)$numpart * 1024); break;
            case 'MB': $maxFileSize = (int)((int)$numpart * 1024 * 1024); break;
            case 'GB': $maxFileSize = (int)((int)$numpart * 1024 * 1024 * 1024); break;
            default:
                if (is_numeric($value)) {
                    $maxFileSize = (int)$value;
                }
        }
       
        if ($maxFileSize === null) {
            // if something fails, return default value (5242880 = 5MB)
            return 5242880;
        } else {
            return abs($maxFileSize);
        }
    }
}
?>

-- test.php --

<?php

require_once('Logger.php');

Log::debug("debug-viesti",__FILE__,__LINE__);
Log::info("info-viesti",__FILE__,__LINE__);
Log::warn("warning-viesti",__FILE__,__LINE__);
Log::error("error-viesti",__FILE__,__LINE__);

$arr = array("one","two","three");
Log::debug("Laitetaan taulukko lokiin",__FILE__,__LINE__);
Log::debug($arr);
// Lokiin tulostuu:
// 2006-01-25 16:21:21 DEBUG /path/to/filename.php(21): Laitetaan taulukko lokiin
// 2006-01-25 16:21:21 DEBUG : Array ( [0] => one [1] => two [2] => three )

//Lähetetään virhe omalle virheenkäsittelijälle
trigger_error("Nostetaan trigger_error() -functiolla E_USER_NOTICE -tasoinen virhe");

echo "Tätä ei pitäisi näkyä :)";

?>

rainmikko 11:24 26.1.06 
Onko jotakin mitä en ole ottanut huomioon lokittajan toiminnassa? :)
rainmikko 12:19 2.2.06 
Pari bugikorjausta ja turhat vakiot pois.
rainmikko 08:42 3.2.06 
Eikö löydy kommentoitavaa? :)
Veikko91 12:53 4.2.06 
En saa toimiin Mbnetissä!

http://koti.mbnet.fi/veikko91/rekkaa.htm
Virus 04:20 5.2.06 
Muutappa pääte .php:ksi.