Jump to content

Debugging tips


adrian
 Share

Recommended Posts

I thought I'd start this thread so we could all share our favorite debugging techniques. The idea for this came from this post by Soma: http://processwire.com/talk/topic/4416-delete-user-when-page-is-deleted/?p=43320 and some of the followups with other suggestions.

Here's one that I find really useful. It allows you to output content to the browser's console from PHP. It sends content from PHP through javasacript's console.log();

Not as powerful as FirePHP etc, but simple and easy to use.

Put this function somewhere that it will be available to all your template files.

function debug ($data) {
    echo "<script>\r\n//<![CDATA[\r\nif(!console){var console={log:function(){}}}";
    $output    =    explode("\n", print_r($data, true));
    foreach ($output as $line) {
        if (trim($line)) {
            $line    =    addslashes($line);
            echo "console.log(\"{$line}\");";
        }
    }
    echo "\r\n//]]>\r\n</script>";
} 

Then you can simply put these anywhere in your templates:

debug('test');
debug($variable);
debug($array);

This keeps your page content clear of debug messages and is easier then looking in log files, like if you were to use error_log()

What are your favorite techniques?

  • Like 12
Link to comment
Share on other sites

When I need a quick info of assigned values I use a better readable version of var_dump:

<?php 

/**
  * Original script from Stefan Eickhoff, 05.12.2002
  * URL: http://aktuell.de.selfhtml.org/artikel/php/variablen/
  *
  * @shortdesc output a better vardump. $outputMode: 1=Browser; 2=Commandline-Window; 3=StringVar; 4=file;
  *
  **/
function my_var_dump($v, $outputMode=2, $filename='') {

	// Ausgabe von var_dump ueber Output-Buffer in Variable einlesen
	ob_start();
	var_dump($v);
	$content = ob_get_contents();
	ob_end_clean();

	// maximale Einrueckung ermitteln
	$m = 0;
	preg_match_all('#^(.*)=>#mU', $content, $stack);
	$lines = $stack[1];
	$indents = array_map('strlen', $lines);
	if($indents) $m = max($indents) + 1;

	// Ausgabe von var_dump() an maximaler Einrueckung ausrichten
	$content = preg_replace('#^(.*)=>\\n\s+(\S)#eUm', '"\\1" .str_repeat(" ", $m - strlen("\\1")>1 ? $m - strlen("\\1") : 1). "\\2"', $content);

	// bei Array-Strukturen oeffnende Klammer { in neue Zeile
	$content = preg_replace('#^((\s*).*){$#m', "\\1\n\\2{", $content);

	// pre tags entfernen
	$content = str_replace(array('<pre>','</pre>'),'',$content);

	switch($outputMode) {
		case 1:
			// Output to Browser-Window
			echo '<pre style=" margin: 10px 10px 10px; padding: 10px 10px 10px 10px; background-color:#F2F2F2; color:#000; border: 1px solid #333; font-family: Lucida Console, Courier, monospace; font-size : 12px; overflow: visible;">'.$content.'</pre>';
			break;
		case 2:
			// Output to Commandline-Window or to Browser as hidden comment
			echo isset($_SERVER['HTTP_HOST']) ? "\n<!--\n".$content."\n-->\n" : $content."\n";
			break;
		case 3:
			// Output into a StringVar
			return '<pre style=" margin: 10px 10px 10px; padding: 10px 10px 10px 10px; background-color:#F2F2F2; color:#000; border: 1px solid #333; font-family: Lucida Console, Courier, monospace; font-size : 12px; overflow: visible;">'.$content.'</pre>';
			break;
		case 4:
			// Output into a file, if a valid filename is given and we have write access to it
			//return $this->string2file(str_replace(array('>','"','
'), array('>','"',''), strip_tags($content)), $filename, true);
			break;
	}
}
  • Like 3
Link to comment
Share on other sites

  • 1 year later...

I know this thread is old, but with the new Log viewer that Ryan just set up, I have started putting the following just before the body close tag (in main.inc or foot.inc or wherever needed so it is on all pages):

if($user->isSuperuser()) echo '<iframe width="100%" height="200px" src="'.$config->urls->admin.'/setup/logs/view/debug/?modal=1"></iframe>';

Then whenever I need to log a variable or output of a function etc, I use the following in my template file:

$log->save('debug', $problem_variable);

If you need to output an array, json_encode is quite a nice solution:

$log->save('debug', json_encode($array));

This will give you (as superuser) a panel showing the "debug" log output (which shows latest entries at the top) at the bottom of your site - very handy :)

  • Like 16
Link to comment
Share on other sites

  • 10 months later...

This is a helper class to using debug log.

require_once 'Debug.php';

Debug::init();
Debug::log($myVar);
Debug::log($myArray);
<?php
/**
* Helps with the debugging log
*/
class Debug {

	protected static $name = 'debug';

	public static function init() {
		if(!file_exists(self::filename())) {
			self::log('Debug File Init');
		}
	}

	public static function log($param) {
		if (is_array($param)) {
			$param = json_encode($param);
		}

		wire('log')->save(self::$name, $param);
	}

	public static function filename() {
		return wire('log')->getFilename(self::$name);
	}

	public static function name() {
		return self::$name;
	}
}
  • Like 4
Link to comment
Share on other sites

  • 5 weeks later...

I have further refined this class. For instructions, you can read the comments in the code, or this:

 
<?php namespace ProcessWire;
/**
 * Flog.php: Can be used to inspect variables for debugging purposes.
 *
 * Example usage:
 * - If NOT running ProcessWire 3.x or higher, remove namespace ProcessWire;
 * - Create a directory called lib in your /site directory and put Flog.php into it.
 * - Insert this line into config.php: require_once(dirname(__FILE__).'/lib/Flog.php');
 * - In the case of frontend debugging, start the rendering of the output
 *   by calling Flog::init() before your code does anything else (for example
 *   it could be the first line in your _init.php).
 *
 * - example log entry for PHP 5.5.x and below: Flog::log($page->children(), 0, 'kids', __FILE__, __LINE__);
 * - example log entry for PHP 5.6.x and above: Flog::log($page->children(), 2, 'kids', __FILE__, __LINE__);
 *
 * TIP: Use a shortcut to insert this code snippet into your code: Flog::log($var, 0, '', __FILE__, __LINE__);
 *      then edit the first three parameters accordingly. Read all the other notes below for more information.
 *
 */
class Flog {

    protected static $name = 'flog'; // name of the log file
    protected static $firstSave = true; // no variables have been logged so far?

    /**
     * Initializes the class. Call it once before you start calling Flog::log()
     * The log file can be found in /site/assets/logs/flog.txt (assuming $name = 'flog')
     *
     */
    public static function init() {
        if(!file_exists(self::filename())) {
            self::log('f-log debug file created...');
        }
        @ini_set('error_log', self::filename()); // so that the same file is used for runtime errors as well
    }

    /**
     * Call Flog::log($my_variable) to log a variable.
     *
     * NOTE: the Wire class customizes the output of print_r (__debugInfo) when running on PHP 5.6+, so the $print_r
     * parameter can be used to output objects this way.
     *
     * @param mixed $var Any variable or expression to be logged.
     * @param 0|1|2 $print_r 0: print_r is not used, 1: print_r's output in one line, 2: formatted print_r output.
     * @param string $info Any string that helps identify the output, such as a variable name.
     * @param string $file Should be __FILE__ to identify the caller.
     * @param string $line Should be __LINE__ to identify the caller's line.
     *
     */
    public static function log($var, $print_r = 0, $info = '', $file = '', $line = '' ) {
        $type = '';
        $pretty = false;
        $php56plus = version_compare(PHP_VERSION, '5.6.0') >= 0;

        if (gettype($var) != "object") {
            $type = "[".gettype($var)."]";
        } else {
            $print_r >= 1 && $php56plus ? $type ='' : $type = "[".get_class($var)."]";
        }

        if (is_array($var)) {
            $var = json_encode($var);
        } elseif ($print_r >= 1 && is_object($var) && $php56plus) {
           if ($print_r == 1) {
               $var = print_r($var, true);
               // reformat whitespaces:
               $var = preg_replace('/\s+/s', ' ', $var);
               $var = str_replace(" => ", '=>', $var);
           } else {
               $pretty = true;
           }
        }

        if (self::$firstSave) {
            self::$firstSave = false;
            wire('log')->save(self::$name, "________________________ Flog.php _______________________");
        }
        if ($file) {
            $file = basename($file, '.php');
        }

        if ($pretty) {
            error_log(print_r($var,true)); // works in PHP 5.6.x and higher
        } else {
            wire('log')->save(self::$name, "$file $line $info $type $var");
        }
    }

    public static function filename() {
        return wire('log')->getFilename(self::$name);
    }

    public static function name() {
        return self::$name;
    }
}
 
  • Like 1
Link to comment
Share on other sites

  • 1 month later...
  • 2 months later...

I have put Tracy Debugger on my list of things to look over soon. In the meantime I just use Xdebug usually. Depends on what I'm doing. I got burnt big time the other day by throwing a quickie echo statement in a piece of code which in turn messed up an Ajax call which in turn screwed up the Admin Page tree. LoL. So I took a very simple wrapper class I wrote to help with debugging. It's a simple wrapper for the FirePhp class. I took it and created a quick and dirty PW module out of it. So everything goes to the Firebug console in Firefox. The code is just taking the array passed to it and doing var_exports on each element in the array. It can also be used to call Firebug's trace function. Nothing fancy, crude,  I know.  I reinvented the wheel there but it didn't take very long to do. I had the code already more or less. I think it would have taken longer to uses someone else's and get familiar with it.

Sample code for using it:

$module = $wire->modules->get("FirePhpBC");

$t1=55.12;

$module->fireLog(array('Joe',$t1));

$module->trace("i`m here.");

And lastly, more preaching to the choir with this wiki article https://en.wikipedia.org/wiki/Defensive_programming

'Defensive programming' I think it is part science, part gut feel. I think the same holds true for debugging.  I think you can get a little obsessive with defensive coding and waste a lot of time checking for ghosts. The article mentions this also. Like everything else, it only helps if you put it to practice. Obviously .. better code... fewer bugs. :) And another thing I try to avoid is writing large chunks of code without testing and I also try to modularize and reuse..'Separation of Concerns' :)

. Again.. preaching to the choir. Anyway.. enough .. I'm trying to keep my posts to a reasonable limit. lol. Have a good one..

  • Like 1
Link to comment
Share on other sites

So I took a very simple wrapper class I wrote to help with debugging. It's a simple wrapper for the FirePhp class. I took it and created a quick and dirty PW module out of it. ....

Aah, did we intend to post a link to the module maybe? :-)

  • Like 2
Link to comment
Share on other sites

 So I took a very simple wrapper class I wrote to help with debugging. It's a simple wrapper for the FirePhp class. I took it and created a quick and dirty PW module out of it. So everything goes to the Firebug console in Firefox. 

Sounds good, but just so you know, Tracy can also log errors and dump variables to the console in both Firefox and Chrome. And on that note, there is also soma's Chrome PHP Logger: http://modules.processwire.com/modules/chrome-php-logger/

  • Like 2
Link to comment
Share on other sites

Hahaha.. good one! I'll move it up on the list then :)

Sounds good, but just so you know, Tracy can also log errors and dump variables to the console in both Firefox and Chrome. And on that note, there is also soma's Chrome PHP Logger: http://modules.processwire.com/modules/chrome-php-logger/


Thanks Adrian! Appreciate the tip. Have a good one.

Aah, did we intend to post a link to the module maybe? :-)


Hi. Word has it you'do be much happier with the Tracy debugger, but sure if you'd like the code I'll write something up and get it to you. Thanks.

  • Like 1
Link to comment
Share on other sites

Aah, did we intend to post a link to the module maybe? :-)

Hi kongondo,

 Very important update : This module will not work in Processwire 3.0. Main reason being there is no 'namespace Processwire;' in the source., sorry. The module DOES work on 2.7.2. but no dice on 3.0.18. I just happened to update my dev site to 3.0.18 this morning and in the course of doing so, I hit this problem because of the lack of a PW namespace in the module. After adding it, still getting an error on one of the methods that uses Reflectionclass. I am going to try to sort this out. When it's done, I'll let you know. Thanks.

 ===============================================================================================================

update part 2 : I have the module working in PW 3.0.18 now. This has been a learning experience on namespaces. A few problems came up fixing the module, that I resolved, I need to go back and test a bit before I post anything here. This link helped explain what the problem was with trying to instantiate a Reflectionclass object : <http://php.net/manual/en/language.namespaces.fallback.php> The fix was to prefix the classname with a backslash.  So changing this line within the FirePhp class : $reflectionClass = new ReflectionClass($class); to this : $reflectionClass = new \ReflectionClass($class);, solved that problem. I want to look into this further. 

Once I'm comfortable with the fixes, I will update the zip I created. Thanks.

update part 3: The dropbox link for updated version https://www.dropbox.com/s/wdhxy1ke1z4rm25/firebugMod_V2.zip?dl=0

================================================================================================================

Original post before the fun began:

Here's the dropbox link to the zip file I put together. - https://www.dropbox.com/home?preview=firebugMod.7z

 I'm on Windows. I created the zip with 7-zip. I hope that doesn't pose a problem. If it does, let me know please.

I did try to make the code a little more presentable. PSR compliant? Probably not but close? lol :)

The zip includes a few things other than the module itself, which I thought my be helpful.

1) There's a read me file of course. It explains how to set up the module. I'm sure you don't need help I wrote it up anyway :)

2). There's some uber simple examples of calls to the module which I think hit every available function in the module. The module does NOT provide

calls for every available feature of Firebug or Firephp, but I do think I included code for the most used functions. 

 3). There's some example screen prints of the output on the Firefox console.

4) and Last but not Least, there's the Firebug and FirePhp library files which the module pulls in of course. I saved you the trouble of

downloading them yourself. I believe they are the most recent versions. I'm on Firefox 46.0.1. I have Firebug 2.0.16  and Firephp 0.7.4.1-signed.1-signed.

I'm not super techy when it comes to Firefox add ons. My concern is how the code with behave if you're not on the same versions.

I guess we'll see. I am hoping there won't be issues.

 I think that is it. Thanks for the interest and have a good one.

  • Like 1
Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...