PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/bors/debug.php

https://bitbucket.org/Balancer/bors-core
PHP | 411 lines | 316 code | 87 blank | 8 comment | 64 complexity | ce9463ff1b2e741eafa4df27d48832dd MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. class bors_debug
  3. {
  4. static function syslog($type, $message = NULL, $trace = true, $args = array())
  5. {
  6. static $out_idx = 0;
  7. if(!($out_dir = config('debug_hidden_log_dir')))
  8. return;
  9. bors_debug::timing_start('hidden_log');
  10. if(!$message)
  11. {
  12. $message = $type;
  13. $type = 'info/common';
  14. }
  15. if(preg_match('/error/', $type))
  16. bors::log()->error($message, $type, $trace, $args);
  17. if(preg_match('/^(error|warning|notice|info|debug)-(.+)$/', $type, $m))
  18. {
  19. $type = $m[1].'s/'.date('Ymd-His-'.sprintf('%03d', $out_idx++)).'-'.$m[2];
  20. }
  21. if($trace && empty($args['dont_show_user']) && class_exists('bors_class_loader', false) && function_exists('bors'))
  22. $user = bors()->user();
  23. else
  24. $user = NULL;
  25. if(popval($args, 'notime'))
  26. $out = '';
  27. else
  28. $out = strftime('%Y-%m-%d %H:%M:%S: ');
  29. $out .= $message . "\n";
  30. if($trace !== false)
  31. {
  32. require_once(BORS_CORE.'/inc/locales.php');
  33. if($trace === true)
  34. $trace_out = bors_debug::trace(0, false);
  35. elseif($trace >= 1)
  36. $trace_out = bors_debug::trace(0, false, $trace);
  37. else
  38. $trace_out = '';
  39. if(!empty($_GET))
  40. $data = "_GET=".print_r($_GET, true)."\n";
  41. else
  42. $data = "";
  43. if(!empty($_POST))
  44. $data .= "_POST=".print_r($_POST, true)."\n";
  45. $out .= "\tmain_url: ".@$GLOBALS['main_uri']."\n";
  46. foreach(['HTTP_HOST', 'REQUEST_URI', 'QUERY_STRING', 'HTTP_REFERER', 'REMOTE_ADDR', 'HTTP_USER_AGENT', 'HTTP_ACCEPT', 'REQUEST_METHOD'] as $name)
  47. if(!empty($_SERVER[$name]))
  48. $out .= "\t{$name}: ".$_SERVER[$name]."\n";
  49. if(!empty($GLOBALS['stat']['start_microtime']))
  50. $out .= "\twork time: ".(microtime(true) - $GLOBALS['stat']['start_microtime'])." us\n";
  51. $out .= (@$user ? "\tuser: ".dc($user->title()) . ' [' .bors()->user_id()."]\n": '')
  52. . $data
  53. . $trace_out
  54. . "\n-------------------------------------------------------------------\n\n";
  55. }
  56. if(!empty($args['append']))
  57. $out .= "\n".$args['append'];
  58. $file = "{$out_dir}/{$type}.log";
  59. if(!is_dir($dir = dirname($file)))
  60. {
  61. mkpath($dir);
  62. @chmod($dir, 0777);
  63. }
  64. @file_put_contents($file, $out, FILE_APPEND);
  65. @chmod($file, 0666);
  66. bors_debug::timing_stop('hidden_log');
  67. }
  68. static function exception_log($log, $message, Exception $e)
  69. {
  70. bors_debug::syslog($log, $message.':'.$e->getMessage()
  71. ."\n----------------------\nTrace:\n".bors_lib_exception::catch_trace($e)
  72. ."\n----------------------\n");
  73. }
  74. static function sepalog($type, $message = NULL, $params = array())
  75. {
  76. $dir = config('debug_hidden_log_dir').'/errors';
  77. if(!is_dir($dir))
  78. {
  79. @mkdir($dir);
  80. @chmod($dir, 0777);
  81. }
  82. if(!file_exists($dir))
  83. return;
  84. $trace = defval($params, 'trace');
  85. $args['append'] = "stack:\n==============\n".bors_debug::trace(0, false);
  86. bors_debug::syslog('errors/'.date('c').'-'.$type, $message."\n\ntrace=$trace", -1, $args);
  87. }
  88. static function log($category, $message = NULL, $level = 'info', $trace = true)
  89. {
  90. static $enter = false;
  91. if($enter)
  92. return;
  93. $enter = true;
  94. bors_new('bors_debug_log', array(
  95. 'create_time' => time(),
  96. 'title' => $message,
  97. 'category' => $category,
  98. 'level' => $level,
  99. 'trace' => serialize(array_slice(debug_backtrace(), 0, 100)),
  100. 'owner_id' => bors()->user_id(),
  101. 'request_uri' => bors()->request()->url(),
  102. 'get_vars' => json_encode(@$_GET),
  103. 'referer' => bors()->request()->referer(),
  104. 'remote_addr' => @$_SERVER['REMOTE_ADDR'],
  105. 'server_data' => strlen(serialize($_SERVER)),
  106. ));
  107. $enter = false;
  108. }
  109. static function timing_start($section)
  110. {
  111. global $bors_debug_timing;
  112. if(empty($bors_debug_timing[$section]))
  113. $bors_debug_timing[$section] = array('start' => NULL, 'calls'=>0, 'total'=>0, 'mem_total' => 0);
  114. $current = &$bors_debug_timing[$section];
  115. if($current['start'])
  116. {
  117. //TODO: need best method
  118. // bors_debug::syslog('__debug_error', ec("Вторичный вызов незавершённой функции debug_timing_start('$section')."));
  119. return;
  120. }
  121. $current['start'] = microtime(true);
  122. $current['mem'] = memory_get_usage();
  123. }
  124. static function timing_stop($section)
  125. {
  126. global $bors_debug_timing;
  127. $current = &$bors_debug_timing[$section];
  128. if(empty($current['start']))
  129. {
  130. // bors_debug::syslog('__debug_error', ec("Вызов неактивированной функции bors_debug::timing_stop('$section')."));
  131. return;
  132. }
  133. $mem = memory_get_usage() - $current['mem'];
  134. $time = microtime(true) - $current['start'];
  135. $current['start'] = NULL;
  136. $current['mem'] = NULL;
  137. $current['calls']++;
  138. $current['total'] += $time;
  139. $current['mem_total'] += $mem;
  140. }
  141. static function trace($skip = 0, $html = NULL, $level = -1, $traceArr = NULL)
  142. {
  143. $MAXSTRLEN = 1000;
  144. if(is_null($html))
  145. $html = 0 && !bors_debug::in_console();
  146. if($html)
  147. $s = '<pre align="left">';
  148. else
  149. $s = '';
  150. if(is_null($traceArr))
  151. $traceArr = debug_backtrace();
  152. for($i = 1; $i <= $skip; $i++)
  153. array_shift($traceArr);
  154. if(is_numeric($level) && $level > 0)
  155. $traceArr = array_slice($traceArr, 0, $level);
  156. // if(is_numeric($level) && $level < 0)
  157. // $traceArr = array_slice($traceArr, -$level);
  158. $tabs = 0; //sizeof($traceArr)-1;
  159. for($pos=0, $stop=sizeof($traceArr); $pos<$stop; $pos++)
  160. {
  161. $arr = $traceArr[$stop-$pos-1];
  162. $indent = '';
  163. for ($i=0; $i < $tabs; $i++)
  164. $indent .= $html ? '&nbsp;' : ' ';
  165. $Line = (isset($arr['line'])? $arr['line'] : "unknown");
  166. $File = (isset($arr['file'])? $arr['file'] : "unknown");
  167. $s .= "\n$indent";
  168. $tabs++;
  169. if($html)
  170. $s .= '<span style="font-family:monospace;size:9pt;padding:0;margin:0">';
  171. if(isset($arr['class']))
  172. $s .= $arr['class'].'.';
  173. $args = array();
  174. if(!empty($arr['args']))
  175. {
  176. foreach($arr['args'] as $v)
  177. {
  178. if (is_null($v)) $args[] = 'null';
  179. else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
  180. else if (is_object($v)) $args[] = 'Object:'.get_class($v);
  181. else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
  182. else
  183. {
  184. $v = (string) @$v;
  185. $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
  186. if (strlen($v) > $MAXSTRLEN) $str .= '...';
  187. $args[] = "\"".$str."\"";
  188. }
  189. }
  190. }
  191. if($html)
  192. $s .= "<b>{$arr['function']}</b>";
  193. else
  194. $s .= $arr['function'];
  195. $targs = implode(', ',$args);
  196. if($html)
  197. {
  198. $targs = preg_replace('/(".+?")/', '<font color="green">$1</font>', $targs);
  199. $targs = preg_replace('/(true|false)/', '<font color="brown">$1</font>', $targs);
  200. $s .= '<font color="#999">(</font>'.$targs.'<font color="#999">)</font>';
  201. }
  202. else
  203. $s .= '('.$targs.')';
  204. if($html)
  205. $s .= '</span>';
  206. $s .= "\n";
  207. if($html)
  208. $s .= "$indent<span style=\"font-size:8pt;margin:0;padding:0;color:#ccc\">{$File}:{$Line}</span>";
  209. else
  210. $s .= "[{$File}:{$Line}]";
  211. }
  212. if($html)
  213. $s .= '</pre>';
  214. return $s;
  215. }
  216. static function execute_trace($message)
  217. {
  218. if(!config('debug.execute_trace'))
  219. return;
  220. static $timestamp;
  221. static $mem;
  222. $now = microtime(true);
  223. $time = sprintf("%2.3f", $now - $GLOBALS['stat']['start_microtime']);
  224. if($timestamp)
  225. {
  226. $delta = sprintf("%1.3f", $now - $timestamp);
  227. $delta_mem = memory_get_usage() - $mem;
  228. $mem = memory_get_usage();
  229. }
  230. else
  231. {
  232. bors_debug::syslog('execute_trace', "--------------------------------------------------", false);
  233. $delta = sprintf("%1.3f", $now - $GLOBALS['stat']['start_microtime']);
  234. $mem = memory_get_usage();
  235. $delta_mem = $mem;
  236. }
  237. bors_debug::syslog('execute_trace', "+$delta = $time ["
  238. .($delta_mem > 0 ? '+' : '')
  239. .sprintf('%1.2f', $delta_mem/1048576).'Mb = '
  240. .sprintf('%1.2f', $mem/1048576)."Mb]: $message", false);
  241. $timestamp = $now;
  242. }
  243. static function warning($message)
  244. {
  245. }
  246. //TODO: убрать аналог из bors_global
  247. static function memory_usage() { return round(memory_get_usage()/1048576)."/".round(memory_get_peak_usage()/1048576)."MB"; }
  248. static function memory_usage_ping()
  249. {
  250. static $prev_usage = 0, $prev_peak_usage = 0;
  251. static $mb = 1048576;
  252. $cur_usage = memory_get_usage();
  253. $cur_peak_usage = memory_get_peak_usage();
  254. $usage_delta = round(($cur_usage - $prev_usage) / $mb, 2);
  255. if($usage_delta > 0)
  256. $usage_delta = "+$usage_delta";
  257. $peak_usage_delta = round(($cur_peak_usage - $prev_peak_usage) / $mb, 2);
  258. if($peak_usage_delta > 0)
  259. $peak_usage_delta = "+$peak_usage_delta";
  260. $report = round($cur_usage/$mb, 2)."({$usage_delta})/".round($cur_peak_usage/$mb, 2)."({$peak_usage_delta}) MB";
  261. $prev_usage = $cur_usage;
  262. $prev_peak_usage = $cur_peak_usage;
  263. return $report;
  264. }
  265. // Если показываем отладочную инфу, то описываем её в конец выводимой страницы комментарием.
  266. static function append_info(&$res, $app=NULL)
  267. {
  268. if(!config('debug.timing') || !is_string($res) || !preg_match('!</body>!i', $res))
  269. return;
  270. $deb = "<!--\n=== debug-info ===\n"
  271. ."BORS_CORE = ".BORS_CORE."\n"
  272. ."log dir = ".config('debug_hidden_log_dir')."\n"
  273. ."log created = ".date('r')."\n";
  274. if($app)
  275. $object = $app;
  276. else
  277. $object = bors()->main_object();
  278. if($object)
  279. {
  280. foreach(explode(' ', 'class_name class_file template body_template') as $var)
  281. if($val = @$object->get($var))
  282. $deb .= "$var = $val\n";
  283. if($cs = $object->cache_static())
  284. $deb .= "cache static expire = ". date('r', time()+$cs)."\n";
  285. }
  286. if(config('is_developer'))
  287. {
  288. $deb .= "\n=== config ===\n"
  289. . "cache_database = ".config('cache_database')."\n";
  290. }
  291. require_once BORS_CORE.'/inc/functions/debug/vars_info.php';
  292. require_once BORS_CORE.'/inc/functions/debug/count.php';
  293. require_once BORS_CORE.'/inc/functions/debug/count_info_all.php';
  294. require_once BORS_CORE.'/inc/functions/debug/timing_info_all.php';
  295. if($deb_vars = debug_vars_info())
  296. {
  297. $deb .= "\n=== debug vars: ===\n";
  298. $deb .= $deb_vars;
  299. }
  300. $deb .= "\n=== debug counting: ===\n";
  301. $deb .= debug_count_info_all();
  302. // Общее время работы
  303. $time = microtime(true) - $GLOBALS['stat']['start_microtime'];
  304. $deb .= "\n=== debug timing: ===\n";
  305. $deb .= debug_timing_info_all();
  306. $deb .= "Total time: $time sec.\n";
  307. $deb .= "-->\n";
  308. if(config('is_developer'))
  309. bors_debug::syslog('debug/timing', $deb, false);
  310. $res = str_ireplace('</body>', $deb.'</body>', $res);
  311. }
  312. static function exec_time()
  313. {
  314. return microtime(true) - $GLOBALS['stat']['start_microtime'];
  315. }
  316. static function count_inc($category, $inc = 1)
  317. {
  318. if(empty($GLOBALS['bors_debug_counts']))
  319. $GLOBALS['bors_debug_counts'] = [];
  320. if(empty($GLOBALS['bors_debug_counts'][$category]))
  321. $GLOBALS['bors_debug_counts'][$category] = 0;
  322. $GLOBALS['bors_debug_counts'][$category] += $inc;
  323. }
  324. }