PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/documentation/08-logging.markdown

https://github.com/caomania/propelorm.github.com
Markdown | 434 lines | 343 code | 91 blank | 0 comment | 0 complexity | 0c108fabd0456f72a0d06c759c82e2c4 MD5 | raw file
  1. ---
  2. layout: documentation
  3. title: Logging And Debugging
  4. ---
  5. # Logging And Debugging #
  6. Propel provides tools to monitor and debug your model. Whether you need to check the SQL code of slow queries, or to look for error messages previously thrown, Propel is your best friend for finding and fixing problems.
  7. ## Propel Logs ##
  8. Propel uses the logging facility configured in `runtime-conf.xml` to record errors, warnings, and debug information.
  9. By default Propel will attempt to use the Log framework that is distributed with PEAR. If you are not familiar with it, check its [online documentation](http://www.indelible.org/php/Log/guide.html). It is also easy to configure Propel to use your own logging framework -- or none at all.
  10. ### Logger Configuration ###
  11. The Propel log handler is configured in the `<log>` section of your project's `runtime-conf.xml` file. Here is the accepted format for this section with the default values that Propel uses:
  12. {% highlight xml %}
  13. <?xml version="1.0" encoding="ISO-8859-1"?>
  14. <config>
  15. <log>
  16. <type>file</type>
  17. <name>./propel.log</name>
  18. <ident>propel</ident>
  19. <level>7</level> <!-- PEAR_LOG_DEBUG -->
  20. <conf></conf>
  21. </log>
  22. <propel>
  23. ...
  24. </propel>
  25. </config>
  26. {% endhighlight %}
  27. Using these parameters, Propel creates a `file` Log handler in the background, and keeps it for later use:
  28. {% highlight php %}
  29. <?php
  30. Propel::$logger = Log::singleton($type = 'file', $name = './propel.log', $ident = 'propel', $conf = array(), $level = PEAR_LOG_DEBUG);
  31. {% endhighlight %}
  32. The meaning of each of the `<log>` nested elements may vary, depending on which log handler you are using. Most common accepted logger types are `file`, `console`, `syslog`, `display`, `error_log`, `firebug`, and `sqlite`. Refer to the [PEAR::Log](http://www.indelible.org/php/Log/guide.html#standard-log-handlers) documentation for more details on log handlers configuration and options.
  33. Note that the `<level>` tag needs to correspond to the integer represented by one of the `PEAR_LOG_*` constants:
  34. |Constant |Value |Description
  35. |-------------------|-------|-------------------------
  36. |PEAR_LOG_EMERG |0 |System is unusable
  37. |PEAR_LOG_ALERT |1 |Immediate action required
  38. |PEAR_LOG_CRIT |2 |Critical conditions
  39. |PEAR_LOG_ERR |3 |Error conditions
  40. |PEAR_LOG_WARNING |4 |Warning conditions
  41. |PEAR_LOG_NOTICE |5 |Normal but significant
  42. |PEAR_LOG_INFO |6 |Informational
  43. |PEAR_LOG_DEBUG |7 |Debug-level messages
  44. ### Logging Messages ###
  45. Use the static `Propel::log()` method to log a message using the configured log handler:
  46. {% highlight php %}
  47. <?php
  48. $myObj = new MyObj();
  49. $myObj->setName('foo');
  50. Propel::log('uh-oh, something went wrong with ' . $myObj->getName(), Propel::LOG_ERROR);
  51. {% endhighlight %}
  52. You can log your own messages from the generated model objects by using their `log()` method, inherited from `BaseObject`:
  53. {% highlight php %}
  54. <?php
  55. $myObj = new MyObj();
  56. $myObj->log('uh-oh, something went wrong', Propel::LOG_ERROR);
  57. {% endhighlight %}
  58. The log messages will show up in the log handler defined in `runtime-conf.xml` (`propel.log` file by default) as follows:
  59. {% highlight text %}
  60. Oct 04 00:00:18 [error] uh-oh, something went wrong with foo
  61. Oct 04 00:00:18 [error] MyObj: uh-oh, something went wrong
  62. {% endhighlight %}
  63. >**Tip**<br />All serious errors coming from the Propel core do not only issue a log message, they are also thrown as `PropelException`.
  64. ### Using An Alternative PEAR Log Handler ###
  65. In many cases you may wish to integrate Propel's logging facility with the rest of your web application. In `runtime-conf.xml`, you can customize a different PEAR logger. Here are a few examples:
  66. _Example 1:_ Using `display` handler (for output to HTML)
  67. {% highlight xml %}
  68. <log>
  69. <type>display</type>
  70. <level>6</level> <!-- PEAR_LOG_INFO -->
  71. </log>
  72. {% endhighlight %}
  73. _Example 2:_ Using `syslog` handler
  74. {% highlight xml %}
  75. <log>
  76. <type>syslog</type>
  77. <name>8</name> <!-- LOG_USER -->
  78. <ident>propel</ident>
  79. <level>6</level>
  80. </log>
  81. {% endhighlight %}
  82. ### Using A Custom Logger ###
  83. If you omit the `<log>` section of your `runtime-conf.xml`, then Propel will not setup _any_ logging for you. In this case, you can set a custom logging facility and pass it to Propel at runtime.
  84. Here's an example of how you could configure your own logger and then set Propel to use it:
  85. {% highlight php %}
  86. <?php
  87. require_once 'MyLogger.php';
  88. $logger = new MyLogger();
  89. require_once 'propel/Propel.php';
  90. Propel::setLogger($logger);
  91. Propel::init('/path/to/runtime-conf.php');
  92. {% endhighlight %}
  93. Your custom logger could be any object that implements a basic logger interface. Check the `BasicLogger` interface provided with the Propel runtime to see the methods that a logger must implement in order to be compatible with Propel. You do not actually have to implement this interface, but all the specified methods must be present in your container.
  94. Let's see an example of a simple log container suitable for use with Propel:
  95. {% highlight php %}
  96. <?php
  97. class MyLogger implements BasicLogger
  98. {
  99. public function emergency($m)
  100. {
  101. $this->log($m, Propel::LOG_EMERG);
  102. }
  103. public function alert($m)
  104. {
  105. $this->log($m, Propel::LOG_ALERT);
  106. }
  107. public function crit($m)
  108. {
  109. $this->log($m, Propel::LOG_CRIT);
  110. }
  111. public function err($m)
  112. {
  113. $this->log($m, Propel::LOG_ERR);
  114. }
  115. public function warning($m)
  116. {
  117. $this->log($m, Propel::LOG_WARNING);
  118. }
  119. public function notice($m)
  120. {
  121. $this->log($m, Propel::LOG_NOTICE);
  122. }
  123. public function info($m)
  124. {
  125. $this->log($m, Propel::LOG_INFO);
  126. }
  127. public function debug($m)
  128. {
  129. $this->log($m, Propel::LOG_DEBUG);
  130. }
  131. public function log($message, $priority)
  132. {
  133. $color = $this->priorityToColor($priority);
  134. echo '<p style="color: ' . $color . '">$message</p>';
  135. }
  136. private function priorityToColor($priority)
  137. {
  138. switch($priority) {
  139. case Propel::LOG_EMERG:
  140. case Propel::LOG_ALERT:
  141. case Propel::LOG_CRIT:
  142. case Propel::LOG_ERR:
  143. return 'red';
  144. break;
  145. case Propel::LOG_WARNING:
  146. return 'orange';
  147. break;
  148. case Propel::LOG_NOTICE:
  149. return 'green';
  150. break;
  151. case Propel::LOG_INFO:
  152. return 'blue';
  153. break;
  154. case Propel::LOG_DEBUG:
  155. return 'grey';
  156. break;
  157. }
  158. }
  159. }
  160. {% endhighlight %}
  161. >**Tip**<br />There is also a bundled `MojaviLogAdapter` class which allows you to use a Mojavi logger with Propel.
  162. ## Debugging Database Activity ##
  163. By default, Propel uses `PropelPDO` for database connections. This class, which extends PHP's `PDO`, offers a debug mode to keep track of all the database activity, including all the executed queries.
  164. ### Enabling The Debug Mode ###
  165. The debug mode is disabled by default, but you can enable it at runtime as follows:
  166. {% highlight php %}
  167. <?php
  168. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  169. $con->useDebug(true);
  170. {% endhighlight %}
  171. You can also disable the debug mode at runtime, by calling `PropelPDO::useDebug(false)`. Using this method, you can choose to enable the debug mode for only one particular query, or for all queries.
  172. Alternatively, you can ask Propel to always enable the debug mode for a particular connection by using the `DebugPDO` class instead of the default `PropelPDO` class. This is accomplished in the `runtime-conf.xml` file, in the `<classname>` tag of a given datasource connection (see the [runtime configuration reference]() for more details).
  173. {% highlight xml %}
  174. <?xml version="1.0"?>
  175. <config>
  176. <propel>
  177. <datasources default="bookstore">
  178. <datasource id="bookstore">
  179. <adapter>sqlite</adapter>
  180. <connection>
  181. <!-- the classname that Propel should instantiate, must be PropelPDO subclass -->
  182. <classname>DebugPDO</classname>
  183. {% endhighlight %}
  184. >**Tip**<br />You can use your own connection class there, but make sure that it extends `PropelPDO` and not only `PDO`. Propel requires certain fixes to PDO API that are provided by `PropelPDO`.
  185. ### Counting Queries ###
  186. In debug mode, `PropelPDO` keeps track of the number of queries that are executed. Use `PropelPDO::getQueryCount()` to retrieve this number:
  187. {% highlight php %}
  188. <?php
  189. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  190. $myObjs = MyObjPeer::doSelect(new Criteria(), $con);
  191. echo $con->getQueryCount(); // 1
  192. {% endhighlight %}
  193. Tip: You cannot use persistent connections if you want the query count to work. Actually, the debug mode in general requires that you don't use persistent connections in order for it to correctly log bound values and count executed statements.
  194. ### Retrieving The Latest Executed Query ###
  195. For debugging purposes, you may need the SQL code of the latest executed query. It is available at runtime in debug mode using `PropelPDO::getLastExecutedQuery()`, as follows:
  196. {% highlight php %}
  197. <?php
  198. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  199. $myObjs = MyObjPeer::doSelect(new Criteria(), $con);
  200. echo $con->getLastExecutedQuery(); // 'SELECT * FROM my_obj';
  201. {% endhighlight %}
  202. Tip: You can also get a decent SQL representation of the criteria being used in a SELECT query by using the `Criteria->toString()` method.
  203. Propel also keeps track of the queries executed directly on the connection object, and displays the bound values correctly.
  204. {% highlight php %}
  205. <?php
  206. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  207. $stmt = $con->prepare('SELECT * FROM my_obj WHERE name = :p1');
  208. $stmt->bindValue(':p1', 'foo');
  209. $stmt->execute();
  210. echo $con->getLastExecutedQuery(); // 'SELECT * FROM my_obj where name = "foo"';
  211. {% endhighlight %}
  212. >**Tip**<br />The debug mode is intended for development use only. Do not use it in production environment, it logs too much information for a production server, and adds a small overhead to the database queries.
  213. ## Full Query Logging ##
  214. The combination of the debug mode and a logging facility provides a powerful debugging tool named _full query logging_. If you have properly configured a log handler, enabling the debug mode (or using `DebugPDO`) automatically logs the executed queries into Propel's default log file:
  215. {% highlight text %}
  216. Oct 04 00:00:18 propel-bookstore [debug] INSERT INTO publisher (`ID`,`NAME`) VALUES (NULL,'William Morrow')
  217. Oct 04 00:00:18 propel-bookstore [debug] INSERT INTO author (`ID`,`FIRST_NAME`,`LAST_NAME`) VALUES (NULL,'J.K.','Rowling')
  218. Oct 04 00:00:18 propel-bookstore [debug] INSERT INTO book (`ID`,`TITLE`,`ISBN`,`PRICE`,`PUBLISHER_ID`,`AUTHOR_ID`) VALUES (NULL,'Harry Potter and the Order of the Phoenix','043935806X',10.99,53,58)
  219. Oct 04 00:00:18 propel-bookstore [debug] INSERT INTO review (`ID`,`REVIEWED_BY`,`REVIEW_DATE`,`RECOMMENDED`,`BOOK_ID`) VALUES (NULL,'Washington Post','2009-10-04',1,52)
  220. ...
  221. Oct 04 00:00:18 propel-bookstore [debug] SELECT bookstore_employee_account.EMPLOYEE_ID, bookstore_employee_account.LOGIN FROM `bookstore_employee_account` WHERE bookstore_employee_account.EMPLOYEE_ID=25
  222. {% endhighlight %}
  223. By default, Propel logs all SQL queries, together with the date of the query and the name of the connection.
  224. ### Setting The Data To Log ###
  225. The full query logging feature can be configured either in the `runtime-conf.xml` configuration file, or using the runtime configuration API.
  226. In `runtime-conf.xml`, tweak the feature by adding a `<debugpdo>` tag under `<propel>`:
  227. {% highlight xml %}
  228. <?xml version="1.0"?>
  229. <config>
  230. <log>
  231. ...
  232. </log>
  233. <propel>
  234. <datasources default="bookstore">
  235. ...
  236. </datasources>
  237. <debugpdo>
  238. <logging>
  239. <details>
  240. <method>
  241. <enabled>true</enabled>
  242. </method>
  243. <time>
  244. <enabled>true</enabled>
  245. </time>
  246. <mem>
  247. <enabled>true</enabled>
  248. </mem>
  249. </details>
  250. </logging>
  251. </debugpdo>
  252. </propel>
  253. </config>
  254. {% endhighlight %}
  255. To accomplish the same configuration as above at runtime, change the settings in your main include file, after `Propel::init()`, as follows:
  256. {% highlight php %}
  257. <?php
  258. $config = Propel::getConfiguration(PropelConfiguration::TYPE_OBJECT);
  259. $config->setParameter('debugpdo.logging.details.method.enabled', true);
  260. $config->setParameter('debugpdo.logging.details.time.enabled', true);
  261. $config->setParameter('debugpdo.logging.details.mem.enabled', true);
  262. {% endhighlight %}
  263. Let's see a few of the provided parameters.
  264. ### Logging More Connection Messages ###
  265. `PropelPDO` can log queries, but also connection events (open and close), and transaction events (begin, commit and rollback). Since Propel can emulate nested transactions, you may need to know when an actual `COMMIT` or `ROLLBACK` is issued.
  266. To extend which methods of `PropelPDO` do log messages in debug mode, customize the `'debugpdo.logging.methods'` parameter, as follows:
  267. {% highlight php %}
  268. <?php
  269. $allMethods = array(
  270. 'PropelPDO::__construct', // logs connection opening
  271. 'PropelPDO::__destruct', // logs connection close
  272. 'PropelPDO::exec', // logs a query
  273. 'PropelPDO::query', // logs a query
  274. 'PropelPDO::prepare', // logs the preparation of a statement
  275. 'PropelPDO::beginTransaction', // logs a transaction begin
  276. 'PropelPDO::commit', // logs a transaction commit
  277. 'PropelPDO::rollBack', // logs a transaction rollBack (watch out for the capital 'B')
  278. 'DebugPDOStatement::execute', // logs a query from a prepared statement
  279. 'DebugPDOStatement::bindValue' // logs the value and type for each bind
  280. );
  281. $config = Propel::getConfiguration(PropelConfiguration::TYPE_OBJECT);
  282. $config->setParameter('debugpdo.logging.methods', $allMethods, false);
  283. {% endhighlight %}
  284. By default, only the messages coming from `PropelPDO::exec`, `PropelPDO::query`, and `DebugPDOStatement::execute` are logged.
  285. ### Logging Execution Time And Memory ###
  286. In debug mode, Propel counts the time and memory necessary for each database query. This very valuable data can be added to the log messages on demand, by adding the following configuration:
  287. {% highlight php %}
  288. <?php
  289. $config = Propel::getConfiguration(PropelConfiguration::TYPE_OBJECT);
  290. $config->setParameter('debugpdo.logging.details.time.enabled', true);
  291. $config->setParameter('debugpdo.logging.details.mem.enabled', true);
  292. {% endhighlight %}
  293. Enabling the options shown above, you get log output along the lines of:
  294. {% highlight text %}
  295. Feb 23 16:41:04 Propel [debug] time: 0.000 sec | mem: 1.4 MB | SET NAMES 'utf8'
  296. Feb 23 16:41:04 Propel [debug] time: 0.002 sec | mem: 1.6 MB | SELECT COUNT(tags.NAME) FROM tags WHERE tags.IMAGEID = 12
  297. Feb 23 16:41:04 Propel [debug] time: 0.012 sec | mem: 2.4 MB | SELECT tags.NAME, image.FILENAME FROM tags LEFT JOIN image ON tags.IMAGEID = image.ID WHERE image.ID = 12
  298. {% endhighlight %}
  299. The order in which the logging details are enabled is significant, since it determines the order in which they will appear in the log file.
  300. ### Complete List Of Logging Options ###
  301. The following settings can be customized at runtime or in the configuration file:
  302. |Parameter |Default |Meaning
  303. |-----------------------------------------------|-----------|---------------------------------------------------------------------------------
  304. |`debugpdo.logging.innerglue` |":" |String to use for combining the title of a detail and its value
  305. |`debugpdo.logging.outerglue` |"&#124;" |String to use for combining details together on a log line
  306. |`debugpdo.logging.realmemoryusage` |`false` |Parameter to [memory_get_usage()](http://www.php.net/manual/en/function.memory-get-usage.php) and [memory_get_peak_usage()](http://www.php.net/manual/en/function.memory-get-peak-usage.php) calls
  307. |`debugpdo.logging.methods` |`array` |An array of method names (`Class::method`) to be included in method call logging
  308. |`debugpdo.logging.details.slow.enabled` |`false` |Enables flagging of slow method calls
  309. |`debugpdo.logging.details.slow.threshold` |`0.1` |Method calls taking more seconds than this threshold are considered slow
  310. |`debugpdo.logging.details.time.enabled` |`false` |Enables logging of method execution times
  311. |`debugpdo.logging.details.time.precision` |`3` |Determines the precision of the execution time logging
  312. |`debugpdo.logging.details.time.pad` |`10` |How much horizontal space to reserve for the execution time on a log line
  313. |`debugpdo.logging.details.mem.enabled` |`false` |Enables logging of the instantaneous PHP memory consumption
  314. |`debugpdo.logging.details.mem.precision` |`1` |Determines the precision of the memory consumption logging
  315. |`debugpdo.logging.details.mem.pad` |`9` |How much horizontal space to reserve for the memory consumption on a log line
  316. |`debugpdo.logging.details.memdelta.enabled` |`false` |Enables logging differences in memory consumption before and after the method call
  317. |`debugpdo.logging.details.memdelta.precision` |`1` |Determines the precision of the memory difference logging
  318. |`debugpdo.logging.details.memdelta.pad` |`10` |How much horizontal space to reserve for the memory difference on a log line
  319. |`debugpdo.logging.details.mempeak.enabled` |`false` |Enables logging the peak memory consumption thus far by the currently executing PHP script
  320. |`debugpdo.logging.details.mempeak.precision` |`1` |Determines the precision of the memory peak logging
  321. |`debugpdo.logging.details.mempeak.pad` |`9` |How much horizontal space to reserve for the memory peak on a log line
  322. |`debugpdo.logging.details.querycount.enabled` |`false` |Enables logging of the number of queries performed by the DebugPDO instance thus far
  323. |`debugpdo.logging.details.querycount.pad` |`2` |How much horizontal space to reserve for the query count on a log line
  324. |`debugpdo.logging.details.method.enabled` |`false` |Enables logging of the name of the method call
  325. |`debugpdo.logging.details.method.pad` |`28` |How much horizontal space to reserve for the method name on a log line
  326. ### Changing the Log Level ###
  327. By default the connection log messages are logged at the `Propel::LOG_DEBUG` level. This can be changed by calling the `setLogLevel()` method on the connection object:
  328. {% highlight php %}
  329. <?php
  330. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  331. $con->setLogLevel(Propel::LOG_INFO);
  332. {% endhighlight %}
  333. Now all queries and bind param values will be logged at the INFO level.
  334. ### Configuring a Different Full Query Logger ###
  335. By default the `PropelPDO` connection logs queries and binds param values using the `Propel::log()` static method. As explained above, this method uses the log storage configured by the `<log>` tag in the `runtime-conf.xml` file.
  336. If you would like the queries to be logged using a different logger (e.g. to a different file, or with different ident, etc.), you can set a logger explicitly on the connection at runtime, using `Propel::setLogger()`:
  337. {% highlight php %}
  338. <?php
  339. $con = Propel::getConnection(MyObjPeer::DATABASE_NAME);
  340. $logger = Log::factory('syslog', LOG_LOCAL0, 'propel', array(), PEAR_LOG_INFO);
  341. $con->setLogger($logger);
  342. {% endhighlight %}
  343. This will not affect the general Propel logging, but only the full query logging. That way you can log the Propel error and warnings in one file, and the SQL queries in another file.