Utilizing the Template Debugger in ExpressionEngine Add-ons
I like debugging. It's weird, I know. Say what you want but I like hunting down bugs and squashing them flat. (The natural exception, of course, is debugging Internet Explorer issues.) Today I want to share a tiny bit of code that can help you and your add-on users in debugging templates.
ExpressionEngine comes with a nifty tool called the Template Debugger. I mentioned it briefly in a previous article. Each time a page loads a template or more, this tool monitors what happens. It breaks down many parts of the page load showing when tags are encountered and parsed. A timestamp is included with each logged item which also allows you to spot bottlenecks in your page load.
Example of the first few lines of output from our main blog page:
(0.000024) - Begin Template Processing - (0.000252) URI: blog (0.000269) Path.php Template: / (0.000285) Retrieving Template (0.000295) Parsing Template URI (0.001176) Template Group Found: blog (0.001242) Retrieving Template from Database: blog/index (0.002050) Template Found (0.002255) Template Type: webpage (0.002279) Parsing Site Variables
You can enable this feature by going to Admin → System Preferences → Output and Debugging. Switch “Display Template Debugging” to “Yes.” Alternatively, you can turn this on in your config file with the following code:
$config['template_debugging'] = 'y';
In addition to spotting bottlenecks in a page load, you can also find out things like parameters not getting passed correctly, catch parse order issues or even find out if you've misspelled something if you look hard enough.
Helping Your Users
As an add-on developer you can show your users what your add-on is doing by utilizing a very simple function in the template class. It is ridiculously simple to use and only take a single parameter. To show this, make sure you have access to EE's “super object.” You probably already did this, but just in case: Add the following code to your add-ons class constructor:
public function __construct()
{
$this->EE =& get_instance();
}
With the EE super object at your disposal, you can utilize the template logging function. Check out how simple it is:
$this->EE->TMPL->log_item('This gets logged to the debugger');
That was simple! So let's see how this adds up into a real EE plugin.
Sample Plugin
First we need a home for our add-on. It will be a tiny plugin, but this technique is possible within plugins, modules and even certain extension hooks. Let's just call this add-on “Log Me.” Create a folder called log_me located in system/expressionengine/third_party. Now create a file called pi.log_me.php in that folder. Time to write the code. Or in this case, you can just copy and paste. Here's the code:
<?php
$plugin_info = array(
'pi_name' => 'Log Me',
'pi_version' => '1.0.0',
'pi_author' => 'Erik Reagan',
'pi_author_url' => 'http://focuslabllc.com',
'pi_description' => 'Sample template logging',
'pi_usage' => ''
);
class Log_me {
public $return_data = "";
// Support for pre 2.1.3 builds
public function Log_me() { $this->__construct(); }
/**
* Constructor
*
* Default function when a plugin doesn't have
* a third parameter in the tag
*/
public function __construct()
{
$this->EE =& get_instance();
$this->EE->TMPL->log_item('See! This was easy!');
$this->return_data = 'Done.';
}
// End function __construct()
}
// End class Log_me
/* End of file pi.log_me.php */
/* Location: ./system/expressionengine/third_party/log_me/pi.log_me.php */
Now we need a template where we can use this plugin. I'm just going to create a bare template located in my main template group called log_me. The contents of the template will just be our plugin's tag.
{exp:log_me}
With that, we can test our template and plugin. Load your new template and you should see the message, “Done.” If that's what you see then let's continue. If you don't see that then take a few steps back and see if you have a typo somewhere.
If you haven't already done so, turn on Template Debugging as described above. Then reload the page in your browser. Scrolling down about half way you should see our plugin begin to be parsed. You should see something like this in your log:
(0.070490) - Beginning Tag Processing -
(0.070515) Parsing Tags in Template
(0.070548) Tag: {exp:log_me}
(0.070600) No Closing Tag
(0.070634) Processing Tags
(0.070680) Plugin Tag: Log_me/log_me
(0.070691) Including Files for Plugins and Modules
(0.071051) Files for Plugins and Modules All Included
(0.071102) Beginning Final Tag Data Processing
(0.071115) Calling Class/Method: Log_me/log_me
(0.071227) -> Class Called: Log_me
(0.071240) See! This was easy!
(0.071254) -> Method Called: log_me
(0.071312) -> Data Returned
(0.071349) - End Tag Processing -
(0.071386) - End Template Processing -
About ¾ of the way down you'll see our logged item. Now that we know it works let's play around with it a little.
You may have noticed that some text is bold and some is not. The template debugging parser looks for a colon at which point it closes a strong HTML tag. That means we can do something like “Our Plugin: This is a statement.”
You can also indent your statements with non-breaking spaces. The parses honors white space the way pre-formatted text does. Let's take a look at both of these in action. Update the logged text to the following:
$this->EE->TMPL->log_item(' Log Me: See! This was easy!');
Viewing that on our page shows an updated template debugger. Take a look:
(0.013890) -> Class Called: Log_me (0.013902) Log Me: See! This was easy! (0.013916) -> Method Called: log_me
Now we know we can control the bold and regular text, along with white space indentation. It's also important to note that HTML tags don't render in this parser. The tags all get converted to entities.
One thing that we have found useful in our add-on development is to create a helper function for template logging. We like indenting and prefixing statements automatically so we wrote a small function to help with that. Here's what we use:
/**
* Write items to template debugging log
*
* @param string String to log
* @param int Tab indention
* @access private
* @return void
*/
private function _log_item($string = FALSE, $indent = 1)
{
if ($string)
{
$tab = str_repeat(' ', 7 * $indent);
$this->EE->TMPL->log_item($tab . '- ' . $string);
}
}
// End function _log_item()
This short function enables us to quickly log items at a specified indention level making the viewing of debug lines easier for more complex tag processing. To use it we just need to update our __construct() method accordingly. To give the indention a test let's add a second log item as well.
$this->_log_item('Log Me: See! This was easy!');
$this->_log_item('Look, ma! I\'m indented.', 2);
This should produce something like the following:
(0.025955) -> Class Called: Log_me (0.025971) - Log Me: See! This was easy! (0.025980) - Look, ma! I'm indented. (0.025994) -> Method Called: log_me (0.026040) -> Data Returned
You can obviously tweak the function to style it as you see fit. I like prefixing lines with a dash but you may not. You may also prefer a smaller or larger white space indention. The point is to find something that you like and that is helpful to your users.
Here is the final code for your reference (also available as a Gist here).
How do you plan to or how do you currently use this technique? I'm sure some of you have written add-ons before, or are working on your first now. In the comments below let's talk about how we can use this tool.
Aaron Waldon on June 16th, 2011 10:33 pm
Template logging can be very useful. I use it generously in CE Image for logging errors so that template developers can easily see what is causing the problem if something in the plugin isn’t working as they expect it to.
It is especially nice because it keeps the debug messages “safe,” as the template debugger will only show up if it is enabled, and the user is logged in with a Super Admin account. That way, you don’t have to worry as much about showing server paths and other typically sensitive debug data.
For development purposes, I tend to lean on Firebug coupled with FirePHP too. It is really quick to use and easy to setup. Just rename
FirePHP.class.phptofirePHP.php, drop it into your/system/expressionengine/librariesdirectory and call it like a native EE class:Which will then show up nicely in your browser’s Firebug console. It is great for logging arrays too without having to mess with
print_r().Good post Erik!
John D Wells on June 17th, 2011 3:42 am
Very clever, thanks for sharing Erik. And Aaron, that’s a great tip about FirePHP - I might just have to combine the two into a handy little in-house debug tool…
Cheers chaps
John
Natetronn on June 17th, 2011 12:11 pm
I like how you included “Support for pre 2.1.3 builds”, apparently this is something not all that important over at the EE docs for plugin development:
http://expressionengine.com/user_guide/development/plugins.html
Or am I missing something?
Erik Reagan on June 17th, 2011 12:18 pm
@Aaron
Cool stuff. I recall Leevi Graham talking about debugging add-ons with FirePHP but it’s been a while since I’ve heard anyone talk about it.
@Natetronn
You’re not missing anything. It’s a bug impacting ≤ 2.1.3 installs but doesn’t appear to be documented anywhere beyond the bug tracker and perhaps change log.
As an add-on developer you can do two things with this type of bug. Require that your add-on be installed in a post-2.1.3 release OR support the older users. In this case it’s very simple to support the bug so I do.
Iain Urquhart on June 20th, 2011 5:11 pm
Great write up Erik, thank you.
I remember trying to use the log_item method some time ago in an early beta of EE2 and quickly gave up because of errors, probably from me doing something stoopid.
You’ve shown (very well) how simple it can be to use, and the obvious benefits it brings to the debugging process, bravo!
Bryant on July 25th, 2011 10:57 pm
Chromephp is another firephp type debugger, but obviously for us chrome oriented devs :) ... Very similar install process
Aaron Waldon on July 25th, 2011 11:03 pm
@Bryant I have heard of Chromephp, but I have not used it yet. There are some Chrome extensions that allow you to see your FirePHP debug output as well; I use one called “Webug.”
Rene on January 24th, 2012 4:37 pm
Great article
Chris on February 3rd, 2012 1:05 pm
Thanks for the help!