The Complete Guide To Magento Debugging
Integration of new solutions into different systems can become a headache without the knowledge of correct debugging. In case of Magento, such simple constructions as print_r() or var_dump() , var_export() don’t work. Because of heavyweight constructions, you need to investigate the new effective ways to find intermediate values or broken places. Fortunately, there are a lot of tools and methods designed to turn the debugging into a developer friendly process.
Table of contents
Xdebug
To make the debugging more handy, you need the improved development environment.
The major debugging methods
If you need to debug something on a remote system and has only SSH and tools of command line, you can use Zend_Debug class of Zend Framework. It contains a function, that works the same as var_dump. Zend_Debug::dump() is a static method, that returns information about an expression or prints it:
1 |
Zend_Debug::dump($var, $label = null, $echo = true) |
The $var argument is used to identify the variable or expression about which Zend-Debug method shows the information. The $label is a string prepended to the output. The argument is useful in a case of multiple variables on a given screen. The $echo is used to specify whether the method output is echoed or not. In general, the method plays a role of a wrapper for var_dump(), but extends its functionality a bit.
For the debugging on the environment working in the production mode, there are a few ways to hide the debug activity. First of all, you can restrict the output of debug info by your IP:
1 2 3 |
if ($_SERVER[‘REMOTE_ADDR’] == ‘69.69.69.69’) { Zend_Debug::dump($var, $label = null, $echo = true); } |
Mage::log() method is another solution, which is a little bit more intelligent. It requires the use of logging system for debugging. Mage::log() is declared here: app/Mage.php. The method inludes 4 parameters:
1 |
public static function log($message, $level = null, $file = '', $forceLog = false) |
The $message is used to specifies the string required to be outputted into a file. The $level defines one of eight log levels of a debug message:
1 2 3 4 5 6 7 8 |
const EMERG = 0; // Emergency: system is unusable const ALERT = 1; // Alert: action must be taken immediately const CRIT = 2; // Critical: critical conditions const ERR = 3; // Error: error conditions const WARN = 4; // Warning: warning conditions const NOTICE = 5; // Notice: normal but significant condition const INFO = 6; // Informational: informational messages const DEBUG = 7; // Debug: debug messages |
To threat your debug message as a “DEBUG level message“, you have to specify ‘0’ as a parameters value. You can use integer values from 0 to 7 or their equivalent constants (Zend_Log::CRIT, Zend_Log::DEBUG etc..). In the second case, the code will be more readable.
The $file contains a log file relative path. Magento uses the var/log directory to put logs there. To place the log file in this directory, you have to pass a filename as a parameter. In its turn, $forceLog allows you to use Mage::log in a case, when the logging is disabled from the configurations. If you are going to implement a non-regular instant debugging, you just have to pass $forceLog. The complete structure:
1 |
Mage::log(Zend_Debug::dump($product, null, false), null, ‘product_debug.log’, true); |
Zend_Debug::dump() is used for variable dumping. To disable output, you should pass the third parameter as false. As a result, debug method will return the string written into a log. The path of the log is ‘product_debug.log’, the placement of the file is ‘var/log/product_debug.log’.
It is also possible to use mageDebugBacktrace() function for the Magento debugging. By using it, you will be able to get files call stack. It is often used to see the order.
How to view the log
There is no need to refresh the screen to view the log. You just have to use command line tools. There is unix command line utility ‘tail’. From the Magento log folder, use -f via ‘tail’ as a parameter to open your log file:
1 2 |
cd var/log tail product_debug.log -f |
Now, you know how to see the changes in a real time.
Varien_Object is a parent class to the most of the Magento models and it has a useful debug method, required to get readable model’s data. Imagine the situation, when you need to get the current product’s data. You have to debug a product’s model:
1 2 |
$product = Mage::getModel('catalog/product')->load(12); Zend_Debug::dump($product->debug()) |
The difference between this solution and Zend_Debug::dump($product->getData()) is simple. In a case with getData() call, you get information about all data items of the object, and a list of the object’s properties, if some item is an object. In the same case with a debug() method, you get just object’s data.
Use the following construction to get class methods:
1 |
Zend_Debug::dump(get_class_methods(get_class($product))) |
As a result, you will be able to see a limited list of object’s methods. But at the same time, you won’t be able to see methods arguments.
For the blank pages of a live store. open index.php in a Magento root directory and go to the line with:
1 |
#ini_set('display_errors', 1); |
Use your IP to surround it:
1 2 3 |
if ($_SERVER[‘REMOTE_ADDR’] == ‘69.69.69.69’) { ini_set('display_errors', 1); } |
This will help you to find the error as fast as possible. Keep in mind, that Mage::setIsDeveloperMode(true) at this point can cause some additional troubles.
Template Path Hints
For the situation, when it is necessary to detect a *.phtml file from a remote server, you can use template hints:
- Go to Admin->System->Configuration.
- In the “Current Configuration Scope” choose the necessary site.
- Find the ‘Developer’ tab.
- Go to ‘Debug’ section and enable “Template Path Hints” and “Add Block Names to Hints”.
- Don’t save anything at this step.
- If you are not going to “improve” the design of site, restrict the option by the IP: find the “Developer Client Restrictions” section and put your IP there.
- Save the changes.
- If everything is Ok, you’ll see something like this example:
Before starting debugging, you should always check Admin->System->Configuration->Advanced to ensure that the output isn’t disabled.
How To Log Database Queries
There is a feature in the Varien library designed to log database queries to a file automagically. It provides a detailed information about Magento behind-the-scenes functionality and helps to debug different problems, such as slow-running queries and model-based performance issues.
To enable the feature, you have to open the lib/Varien/Db/Adapter/Pdo/Mysql.php file in your text editor. As a result, you’ll see the following class variables down around line 86:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/** * Write SQL debug data to file * * @var bool */ protected $_debug = false; /** * Minimum query duration time to be logged * * @var unknown_type */ protected $_logQueryTime = 0.05; /** * Log all queries (ignored minimum query duration time) * * @var bool */ protected $_logAllQueries = false; /** * Add to log call stack data (backtrace) * * @var bool */ protected $_logCallStack = false; /** * Path to SQL debug data log * * @var string */ protected $_debugFile = 'var/debug/sql.txt'; |
Where:
- “protected $_debug = false;” is the switch used to turn on or off SQL debugging. To enable the process, use “true”
- “protected $_logQueryTime = 0.05;” sets the minimum time to determine which queries should be logged. You can use this variable to find slow queries that impact the performance of store. Use “1.0” second instead of “0.05” to find really slow queries.
- “protected $_logAllQueries = false;” is used to dismiss the aforementioned variable and log everything. To enable this option, set it to “true”. As a result, you will get a general sense of the database operations.
- “protected $_logCallStack = false;” is used for debugging third-party modules. The option logs a backtrace of methods responsible for calling the query.
- “protected $_debugFile = ‘var/debug/sql.txt’;” sets the location of the debug file.
Before enabling this debugging feature, limit access your site. In order to achieve this, you have to edit the appropriate section of .htaccess file.
1 2 3 4 5 6 7 |
############################################ ## By default allow all access #Order allow,deny #Allow from all Order deny,allow Deny from all Allow from YOUR.IP.ADDR.ESS |
And don’t forget to turn off debugging after you troubleshooting is finished.
Varien Object Debugging
Unfortunately, PHP step debuggers aren’t as common as they should be. At the same time, Magento’s abstractions produce the situation where an object revisits the same places over and over again. There’s also the common problem of debugging. To make your life easier, you should be able to debug with Varien Object.
The other advices
Enable PHP Errors
To enable PHP errors, you can use both a more permanent solution and merely something more temporary.
Permanent solution
For Apache/mod_php
-
Go to document root’s .htaccess file.
-
Drop this at the top:
1 |
php_flag display_startup_errors on php_flag display_errors on php_flag html_errors on php_flag log_errors on php_value error_log /home/path/public_html/var/log/system.log |
For Nginx/FastCGI
-
Do the same In Nginx virtualhost configuration.
-
You can use location .php { directive, or fastcgi_params file (if you have a specified one).
-
Drop this at the top:
1 |
fastcgi_param PHP_VALUE display_startup_errors=on; fastcgi_param PHP_VALUE display_errors=on; fastcgi_param PHP_VALUE html_errors=on; fastcgi_param PHP_VALUE log_errors=on; fastcgi_param PHP_VALUE error_log=/home/path/public_html/var/log/system.log; |
Temporary/Universal solution
The solution works for every platform.
-
Go to document root.
-
Edit the Magento bootstrap index.php
-
Uncomment the following:
1 |
#ini_set('display_errors', 1); |
Enable Developer Mode
For errors strings like 2184267227721,there are also a few options.
Permanent solution
For Apache/mod_php
-
Go to document root .htaccess file.
-
Drop the following at the top:
1 |
SetEnv MAGE_IS_DEVELOPER_MODE true |
For Nginx/fastcgi
-
Do the same In Nginx virtualhost configuration.
-
You can use location .php { directive, or fastcgi_params file (if you have a specified one).
-
Drop this:
1 |
fastcgi_param MAGE_IS_DEVELOPER_MODE true; |
Temporary/Universal solution
-
Go to your document root.
-
Edit the Magento bootstrap index.php
-
make the if statement always true:
1 |
if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE']) || true) { Mage::setIsDeveloperMode(true); } |
- or make the if statement enabled for your specific IP:
1 |
if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE']) || $_SERVER['REMOTE_ADDR'] == 'my.ip.add.ress') { Mage::setIsDeveloperMode(true); } |
Check your permissions
Incorrect permissions always cause a lot of problems. Often, it is very difficult to find them.
The example. In the situation, when PHP can not write to the ./media directory and the JS combine is enabled, the system is unable to work with the media correctly and to produce the combined file and associated unique URI for it. A full server path to the media file is in source code of browser (/home/path/public_html/media/xxx).
The practice is secure only for the dedicated hosting. The security issues are common for shared hosting in case where the Apache process isn’t chroot’ed per user.
In the aforementioned example, the Apache user is apache, the SSH/FTP user is sonassi, and the group is apache
FTP/SSH user and the Apache group
FTP/SSH user should be a part of the Apache group. In the aforementioned example, it is apache, but it can also be www-data
1 |
usermod -a -G apache sonassi |
Add as many users as you have in FTP/SSH.
Original permissions
Make sure that all the permissions are correct and reset the original permissions.
1 |
chown -R sonassi:apache /home/path/public_html/ find /home/path/public_html/ -type d -exec chmod 775 {} \; find /home/path/public_html/ -type f -exec chmod 664 {} \; |
Permanent changes
ACLs and Sticky Bits
In Linux, ACLs allow to define specific rules. For instance, what permissions should be inherited upon creation by files. In their turn, sticky bits take care of group inheritance. At the same time, they don’t help with permissions, so we have to use ACLs.
Ensure, that your Kernel is compiled with ACL support, and enable the support on the active partition.
The partition can be /home, /var or something else.
1 |
mount -o remount,acl /home |
Set the ACL rules and group the sticky bits:
1 |
setfacl -d -m u::rwx,g::rwx,o::rx /home/path/public_html/ chmod g+s /home/path/public_html/ |
If your Kernel doesn’t have ACLs support, you can use umask to set the permissions for the default file. In index.php file change the umask line to umask(022);
Set umask 022 in either .bashrc or .bash_profile in the BASH environment for SSH. The principle for the FTP server is the same. Read the dedicated documentation for the additional information.
Revert theme to default
A new theme or a package can be both responsible for the issue. To solve the problem, you can go back to a vanilla theme.
To rename the offending directories Via SSH, use:
1 |
mv ./app/design/frontend/myBrokenTheme{,.tmp} mv ./skin/frontend/myBrokenTheme{,.tmp} |
Via FTP client, traverse your package and rename it to something like myCrashedTheme.tmp
If this resolves the problem, you should find the problematic part of the template. Enable directories gradually as you traverse down the file tree. and you will find the offending file at a certain point.
- Rename the layout directory to .tmp
- template directory – to .tmp
Then something fixes the issue, rename all files from the layout directory into .tmp. ls | xargs -I {} mv {} {}.tmp or rename ‘s/^/.tmp/’ * for SSH users. After this procedure, you have to enable each file 1 by 1 gradually until the problem is resolved.
If the issue is not resolved, base/default or enterprise/default directories can be contaminated. To fix this, you can use a known clean version. Download Magento clean build and replace the directories. Via SSH:
1 |
cd /home/path/public_html/ mkdir clean_mage cd clean_mage MAGENTO_VERSION=1.7.0.0 wget -O magento.tgz http://www.magentocommerce.com/downloads/assets/$MAGENTO_VERSION/magento-$MAGENTO_VERSION.tar.gz tar xvfz magento.tgz cd /home/path/public_html/app/design/frontend mv base{,.tmp} cp -par /home/path/public_html/clean_mage/magento/app/design/frontend/base . cd /home/path/public_html/skin/frontend mv base{,.tmp} cp -par /home/path/public_html/clean_mage/magento/skin/frontend/base . |
Diff the both directories to verify changes:
1 |
diff -r base base.tmp |
Disable local modules
In Magento, PHP include path uses the following order to load classes: Local > Community > Core
- Files from Local should be only loaded.
- The same about files from Community.
- If files can’t be found anywhere else, you should load them from the Core.
Don’t disable modules from the admin panel, do it at a file level. Edit the ./app/etc/modules/MyModule.xml file and set <active>false</active>.Keep in mind, that, these actions don’t prevent a class from loading. If any other class extends a given class in a module, it will be loaded in any case. In this situation, the best way to disable any extension is to rename the directory.
First of all, try to rename the directory via FTP. You can also use the following SSH command:
1 |
mv ./app/code/local{,.tmp} |
Then you should try to disable community:
1 |
mv ./app/code/community{,.tmp} |
If the issue is resolved, you should find out, what module causes the problem. Apply the same actions as with the example with the packages: enable modules one-by-one until the error re-occurs
- In the directory, rename the modules to .tmp. ls | xargs -I {} mv {} {}.tmp or rename ‘s/^/.tmp/’ * for SSH users.
- Remove .tmp from the file name of every module gradually to enable each module one-by-one.
If the issue is not resolved, there is a possibility, that the core is contaminated. The main Magento PHP core consists of ./app/code/core and ./lib. Rename the directories and copy them in a clean variant. Do this for a clean Magento version:
1 |
cd /home/path/public_html/app/code mv core{,.tmp} cp -par /home/path/public_html/clean_mage/magento/app/code/core |
If this doesn’t help, you should also replace lib directory
1 |
cd /home/path/public_html mv lib{,.tmp} cp -par /home/path/public_html/clean_mage/magento/lib |
It will turn your Magento store into its vanilla version with a modified database.
Callstack Debugging
Callstack is a useful debugging tool for Magento. Call it from anywhere and get the function call stack. As a result, you will be able to see where the current function was called from.