profiler.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php namespace Laravel\Profiling;
  2. use Laravel\View;
  3. use Laravel\File;
  4. use Laravel\Event;
  5. use Laravel\Config;
  6. use Laravel\Request;
  7. use Laravel\Database;
  8. class Profiler {
  9. /**
  10. * An array of the recorded Profiler data.
  11. *
  12. * @var array
  13. */
  14. protected static $data = array('queries' => array(), 'logs' => array(), 'timers' => array());
  15. /**
  16. * Get the rendered contents of the Profiler.
  17. *
  18. * @param Response $response
  19. * @return string
  20. */
  21. public static function render($response)
  22. {
  23. // We only want to send the profiler toolbar if the request is not an AJAX
  24. // request, as sending it on AJAX requests could mess up JSON driven API
  25. // type applications, so we will not send anything in those scenarios.
  26. if ( ! Request::ajax() and Config::get('application.profiler') )
  27. {
  28. static::$data['memory'] = get_file_size(memory_get_usage(true));
  29. static::$data['memory_peak'] = get_file_size(memory_get_peak_usage(true));
  30. static::$data['time'] = number_format((microtime(true) - LARAVEL_START) * 1000, 2);
  31. foreach ( static::$data['timers'] as &$timer)
  32. {
  33. $timer['running_time'] = number_format((microtime(true) - $timer['start'] ) * 1000, 2);
  34. }
  35. return render('path: '.__DIR__.'/template'.BLADE_EXT, static::$data);
  36. }
  37. }
  38. /**
  39. * Allow a callback to be timed.
  40. *
  41. * @param closure $func
  42. * @param string $name
  43. * @return void
  44. */
  45. public static function time( $func, $name = 'default_func_timer' )
  46. {
  47. // First measure the runtime of the func
  48. $start = microtime(true);
  49. $func();
  50. $end = microtime(true);
  51. // Check to see if a timer by that name exists
  52. if (isset(static::$data['timers'][$name]))
  53. {
  54. $name = $name.uniqid();
  55. }
  56. // Push the time into the timers array for display
  57. static::$data['timers'][$name]['start'] = $start;
  58. static::$data['timers'][$name]['end'] = $end;
  59. static::$data['timers'][$name]['time'] = number_format(($end - $start) * 1000, 2);
  60. }
  61. /**
  62. * Start, or add a tick to a timer.
  63. *
  64. * @param string $name
  65. * @return void
  66. */
  67. public static function tick($name = 'default_timer', $callback = null)
  68. {
  69. $name = trim($name);
  70. if (empty($name)) $name = 'default_timer';
  71. // Is this a brand new tick?
  72. if (isset(static::$data['timers'][$name]))
  73. {
  74. $current_timer = static::$data['timers'][$name];
  75. $ticks = count($current_timer['ticks']);
  76. // Initialize the new time for the tick
  77. $new_tick = array();
  78. $mt = microtime(true);
  79. $new_tick['raw_time'] = $mt - $current_timer['start'];
  80. $new_tick['time'] = number_format(($mt - $current_timer['start']) * 1000, 2);
  81. // Use either the start time or the last tick for the diff
  82. if ($ticks > 0)
  83. {
  84. $last_tick = $current_timer['ticks'][$ticks- 1]['raw_time'];
  85. $new_tick['diff'] = number_format(($new_tick['raw_time'] - $last_tick) * 1000, 2);
  86. }
  87. else
  88. {
  89. $new_tick['diff'] = $new_tick['time'];
  90. }
  91. // Add the new tick to the stack of them
  92. static::$data['timers'][$name]['ticks'][] = $new_tick;
  93. }
  94. else
  95. {
  96. // Initialize a start time on the first tick
  97. static::$data['timers'][$name]['start'] = microtime(true);
  98. static::$data['timers'][$name]['ticks'] = array();
  99. }
  100. // Run the callback for this tick if it's specified
  101. if ( ! is_null($callback) and is_callable($callback))
  102. {
  103. // After we've ticked, call the callback function
  104. call_user_func_array($callback, array(
  105. static::$data['timers'][$name]
  106. ));
  107. }
  108. }
  109. /**
  110. * Add a log entry to the log entries array.
  111. *
  112. * @param string $type
  113. * @param string $message
  114. * @return void
  115. */
  116. public static function log($type, $message)
  117. {
  118. static::$data['logs'][] = array($type, $message);
  119. }
  120. /**
  121. * Add a performed SQL query to the Profiler.
  122. *
  123. * @param string $sql
  124. * @param array $bindings
  125. * @param float $time
  126. * @return void
  127. */
  128. public static function query($sql, $bindings, $time)
  129. {
  130. foreach ($bindings as $binding)
  131. {
  132. $binding = Database::escape($binding);
  133. $sql = preg_replace('/\?/', $binding, $sql, 1);
  134. $sql = htmlspecialchars($sql, ENT_QUOTES, 'UTF-8', false);
  135. }
  136. static::$data['queries'][] = array($sql, $time);
  137. }
  138. /**
  139. * Attach the Profiler's event listeners.
  140. *
  141. * @return void
  142. */
  143. public static function attach()
  144. {
  145. // First we'll attach to the query and log events. These allow us to catch
  146. // all of the SQL queries and log messages that come through Laravel,
  147. // and we will pass them onto the Profiler for simple storage.
  148. Event::listen('laravel.log', function($type, $message)
  149. {
  150. Profiler::log($type, $message);
  151. });
  152. Event::listen('laravel.query', function($sql, $bindings, $time)
  153. {
  154. Profiler::query($sql, $bindings, $time);
  155. });
  156. // We'll attach the profiler to the "done" event so that we can easily
  157. // attach the profiler output to the end of the output sent to the
  158. // browser. This will display the profiler's nice toolbar.
  159. Event::listen('laravel.done', function($response)
  160. {
  161. echo Profiler::render($response);
  162. });
  163. }
  164. }