Root/
<?php /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* # ***** BEGIN LICENSE BLOCK ***** # This file is part of Plume Framework, a simple PHP Application Framework. # Copyright (C) 2001-2009 Loic d'Anterroches and contributors. # # Plume Framework is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # Plume Framework is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # ***** END LICENSE BLOCK ***** */ /** * High performance logging infrastructure. * * Logging while keeping a high performance in production is hard, it * is even harder if we want to track the point in the code where the * log information is generated, for example the file name and line * number. PHP offers the assert statement which, used in a not so * conventional way can get everything in a very efficient way. * * Note that the messages do not need to be strings. You can log * whatever you want. How the message is then stored in your logs is * up to the writer you are using. This can be for example a JSON * fragment. * * The removal of constraints on the log message simplify the log * system as you can push into it categories or extra informations. * * In the log stack, each log message is microtimed together with the * log level as integer. You can convert the integer to string at * write time. * */ class Pluf_Log { /** * The log stack. * * A logger function is just pushing the data in the log stack, * the writers are then called to write the data later. */ public static $stack = array (); /** * A simple storage to track stats. * * A good example is to store stats and at the end of the request, * push the info back in the log. You can for example store the * total time doing SQL or other things like that. */ public static $store = array (); /** * Different log levels. */ const ALL = 1; const DEBUG = 3; const INFO = 4; const PERF = 5; const EVENT = 6; const WARN = 7; const ERROR = 8; const FATAL = 9; const OFF = 10; /** * Used to reverse the log level to the string. */ public static $reverse = array (1 => 'ALL' , 3 => 'DEBUG' , 4 => 'INFO' , 5 => 'PERF' , 6 => 'EVENT' , 7 => 'WARN' , 8 => 'ERROR' , 9 => 'FATAL' ); /** * Current log level. * * By default, logging is not enabled. */ public static $level = 10; /** * Current message in the assert log. */ public static $assert_mess = null; /** * Current level of the message in the assert log. */ public static $assert_level = 10; /** * Log the information in the stack. * * Flush the information if needed. * * @param $level Level to log * @param $message Message to log */ private static function _log( $level , $message ) { if (self:: $level <= $level and self:: $level != 10) { self:: $stack [] = array (microtime(true), $level , $message ); if (!Pluf::f( 'log_delayed' , false)) { self:: flush (); } } } /** * Base assert logger. * * The assert logging is a two step process as one need to go * through the assertion callback. * * @param $level Level to log * @param $message Message to log * @return bool false */ private static function _alog( $level , $message ) { self:: $assert_level = $level ; self:: $assert_mess = $message ; return false; // This will trigger the assert handler. } /** * Log at the ALL level. * * @param $message Message to log */ public static function log( $message ) { self::_log(self::ALL, $message ); } /** * Log at the DEBUG level. * * @param $message Message to log */ public static function debug( $message ) { self::_log(self::DEBUG, $message ); } public static function info( $message ) { self::_log(self::INFO, $message ); } public static function perf( $message ) { self::_log(self::PERF, $message ); } public static function event( $message ) { self::_log(self::EVENT, $message ); } public static function warn( $message ) { self::_log(self::WARN, $message ); } public static function error( $message ) { self::_log(self::ERROR, $message ); } public static function fatal( $message ) { self::_log(self::FATAL, $message ); } /** * Assert log at the ALL level. * * @param $message Message to log */ public static function alog( $message ) { return self::_alog(self::ALL, $message ); } /** * Assert log at the DEBUG level. * * @param $message Message to log */ public static function adebug( $message ) { self::_alog(self::DEBUG, $message ); } public static function ainfo( $message ) { self::_alog(self::INFO, $message ); } public static function aperf( $message ) { self::_alog(self::PERF, $message ); } public static function aevent( $message ) { self::_alog(self::EVENT, $message ); } public static function awarn( $message ) { self::_alog(self::WARN, $message ); } public static function aerror( $message ) { self::_alog(self::ERROR, $message ); } public static function afatal( $message ) { self::_alog(self::FATAL, $message ); } /** * Flush the data to the writer. * * This reset the stack. */ public static function flush () { $writer = Pluf::f( 'log_handler' , 'Pluf_Log_File' ); call_user_func( array ( $writer , 'write' ), self:: $stack ); self:: $stack = array (); } /** * Signal handler to flush the log. * * The name of the signal and the parameters are not used. * * @param $signal Name of the signal * @param &$params Parameters */ public static function flushHandler( $signal , & $params ) { self:: flush (); } /** * Activation of the low impact logging. * * When called, it enabled the assertions for debugging. */ public static function activeAssert() { assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); assert_options(ASSERT_QUIET_EVAL, 1); assert_options(ASSERT_CALLBACK, 'Pluf_Log_assert' ); } /** * Increment a key in the store. * * It automatically creates the key as needed. * * @param $key Key to increment * @param $amount Amount to increase (1) */ public static function inc( $key , $amount =1) { if (!isset(Pluf_Log:: $store [ $key ])) { Pluf_Log:: $store [ $key ] = 0; } Pluf_Log:: $store [ $key ] += $amount ; } /** * Set a key in the store. * * @param $key Key to set * @param $value Value to set */ public static function set( $key , $value ) { Pluf_Log:: $store [ $key ] = $value ; } /** * Get a key from the store. * * @param $key Key to set * @param $value Default value (null) */ public static function get( $key , $value =null) { return (isset(Pluf_Log:: $store [ $key ])) ? Pluf_Log:: $store [ $key ] : $value ; } /** * Start the time to track. * * @param $key Tracker */ public static function stime( $key ) { Pluf_Log:: $store [ 'time_tracker_' . $key ] = microtime(true); } /** * End the time to track. * * @param $key Tracker * @param $total Tracker to store the total (null) * @return float Time for this track */ public static function etime( $key , $total =null) { $t = microtime(true) - Pluf_Log:: $store [ 'time_tracker_' . $key ]; if ( $total ) { Pluf_Log::inc( 'time_tracker_' . $total , $t ); } return $t ; } } /** * Assertion handler. * * @param $file Name of the file where the assert is called * @param $line Line number of the file where the assert is called * @param $code Code evaluated by the assert call */ function Pluf_Log_assert( $file , $line , $code ) { if (Pluf_Log:: $level <= Pluf_Log:: $assert_level and Pluf_Log:: $level != 10) { Pluf_Log:: $stack [] = array ( microtime(true), Pluf_Log:: $assert_level , Pluf_Log:: $assert_mess , $file , $line , $code ); if (!Pluf::f( 'log_delayed' , false)) { Pluf_Log:: flush (); } } Pluf_Log:: $assert_level = 6; Pluf_Log:: $assert_mess = null; } |