Logging with source object name and function (updated) June 14, 2006
Posted by rossoft in CakePHP.trackback
When you log some info, get the caller filename:filenumber object_name->function_name like:
class TestsController{
function myaction()
{
$this->log('Some info here')
}
}
at error.log file :
06-06-07 10:12:09 [ /app/controllers/tests_controller.php:4 TestsController::myaction()] Error: Some info here
The code is from OT (MIT license)
You need to load this class before the original cake class. Copy to vendors/logs/logs.php. Then put in your bootstrap.php file: require_once ROOT. DS .’vendors’ . DS . ‘logs’ . DS . ‘logs.php’;
Now everywhere you can use some other functions like caller_path that returns the complete stack trace or $this->log('xxxx') that will show the caller filename:linenumber object_name->function_name()
<?php
/** * Extends log class. The log now shows the caller [Filename:linenumber ClassName->function()]
*
* @author RosSoft
* @version 0.3
* @license MIT
*
* @link http://sputnik.pl/dev/labs/fase/ Fase Framework
*/
/**
* Set to true if you want filename::linenumber at logs
*/
define('LOG_FILENAME',true);
/**
* Set to true if you want objectname->function() at logs
*/
define('LOG_OBJECTNAME',true);
/**
* Date format of the logs
*
* Spain Locale: 'd-m-y H:i:s'
* US Locale: 'y-m-y H:i:s'
*/
define('LOG_DATEFORMAT','d-m-y H:i:s');
/**
* Logs messages to text files.
*
* @package cake
* @subpackage cake.cake.libs
*/
class CakeLog
{
/**
* Writes given message to a log file in the logs directory.
* Puts the calling function name
*
* @param string $type Type of log, becomes part of the log's filename
* @param string $msg Message to log
* @param integer $skip Number of calls to skip for reaching the calling function. The default skips to the caller of Object->log
* @return boolean Success
*/
function write($type, $msg,$skip=3)
{
if (!class_exists('File'))
{
uses('file');
}
$filename=LOGS . $type . '.log';
$output=date(LOG_DATEFORMAT);
if (LOG_FILENAME || LOG_OBJECTNAME)
{
$output.=' [ ';
if (LOG_FILENAME)
{
$output.=caller_place($skip) . ' ';
}
if (LOG_OBJECTNAME)
{
$output.=caller_name($skip) . ' ';
}
$output.=']';
}
$output.=' ' . ucfirst($type) . ': ' . $msg . "\n\n";
$log=new File($filename);
return $log->append($output);
}
}
/**
* Debug calling file path
* @author Michal Tatarynowicz (Fase Framework)
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
function caller_file ($skip=1)
{
$trace = caller_backtrace($skip);
foreach ($trace as $step)
{
if (@$step['file']) return $step['file'];
}
return false;
}
/**
* Returns nicely formatted call stack
* @author Michal Tatarynowicz (Fase Framework)
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
function caller_backtrace ($skip=1) {
$trace = debug_backtrace();
$output = array();
for ($i=$skip;$i<count($trace);$i++)
{
$step=$trace[$i];
if (! empty($step['file']))
{
if (isset($step['object']) && is_object($step['object']))
{
$class = get_class($step['object']);
}
else
{
$class = @$step['class'];
}
$type = @$step['type'];
$funct = @$step['function'];
$output[] = array
(
'name' => $class? $class.$type.$funct.'()': $funct.'()',
'place' => str_replace(ROOT, '', $step['file']).':'.$step['line'],
'file' => $step['file'],
'class' => $class,
'type' => $type,
'funct' => $funct
);
}
else if (! empty ($step['class']))
{
$class = str_replace(' ', '_', ucwords(str_replace('_', ' ', @$step['class'])));
$funct = @$step['function'];
$output[] = array
(
'name'=> $class . '->' . $funct . '()',
'place'=>'',
'file'=>'',
'class'=>$class,
'type'=>'',
'funct'=>$funct,
);
}
}
return $output;
}
/**
* Returns caller function's full stack trace
* @author Michal Tatarynowicz (Fase Framework)
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
function caller_path ($skip=1)
{
$parsed = caller_backtrace($skip);
$output = array();
foreach ($parsed as $step)
{
list($name, $place) = array_values($step);
$output[] = $name . '::' . $place;
}
return join( ' > ', $output );
}
/**
* Returns calling method or function name
* @author Michal Tatarynowicz (Fase Framework)
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
function caller_name ($skip=1)
{
$step = caller_backtrace($skip);
return $step[0]['class'] . '->' . $step[1]['funct'] . '()';
}
/**
* Retuns caller function's filename and line number
* @author Michal Tatarynowicz (Fase Framework)
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
function caller_place ($skip=1)
{
$step = caller_backtrace($skip);
if ($step[0]['place'])
{
return $step[0]['place'];
}
else
{
return $step[0]['name'];
}
}
?>
Great, but I get an error.
I’m not sure about doing it in the right way.
When I add the vendors() call in the bootstrap I get
Fatal error: Call to undefined function: vendors() in …
Thanks
ok I load it with require_once (I was thinking that it work with vendor function)
require_once ROOT. DS .’vendors’ . DS . ‘logs’ . DS . ‘logs.php’;
Hey rossoft, I like that idea, you could open an RFC on trac for this in 2.0 ; ). Bye
thanks, done
[...] RosSoft » Logging with source object name and function A nifty error logging plugin (tags: cakephp plugin) [...]
Wow, this is really useful. I had wanted something like this for a while, but didn’t know that there was such a function as debug_backtrace in PHP. However, I put this into an existing project with a number of existing log() calls, and some of them were not displaying correctly (would show the caller function as “debug_traceback”). I modified the print statements to include line numbers, and this would also occasionally not work - printing the same class:function instead of file:line.
Anyway, I have rewritten the caller_traceback function, which fixes these for me. I will email this to you for your perusal.
Thanks Grant Cox, I’ve included Filename:linenumber (but your caller_traceback function doesn’t work in my case)
I prefer the version with no filename. Makes a more readable logs, IMO.
However it would be nice if you can configure the log format, something like log4j. And sure, make some system for rolling the log files on some criterias, for example dimensions, or date, and so on.
Some hints
[...] For Example: in my extension to CakeLog class, you can do: [...]
Great stuff, thanks for that. I had a minor problem loading the vendor file in bootstrap, turned out to simply be some strange quotes copied from this page - replaced with normal single quote and all worked fine. Thanks again!
straight guys ass raped
xrtest
Hi,
I am new to Cake php. I want to know how i can made missing controller,missing actions etc errors to be logged to error.log.
I have set define(’LOG_ERROR’, 2); in core.php and have provided 777 permissions to /tmp/logs folder.
In addition to this, i want that 404 errors should be logged in apache’s log file but its not happening currently. May be cakephp bypasses this.
Please guide me.
Thanks in advance,
Kashish