Debug.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. /**
  4. * TODO: debug to file based on session_id (/tmp/se-debug-{$date("Y-m-d")}-{$login}_{$ip}_{$session_id}.log)
  5. * TODO: function if loggind enabled, then save to file and print in default page
  6. * - DBG::log(string $msg or Exception $e)
  7. * TODO: better wfs log by fingerprint (User::getLogin() + IP + UserAgent)
  8. */
  9. class Route_Debug extends RouteBase {
  10. public function handleAuth() {
  11. if (!User::logged()) {
  12. throw new HttpException('Unauthorized', 401);
  13. }
  14. if (!User::hasAccess('dbg')) {// User::get('ADM_ADMIN_LEVEL') == 0
  15. throw new HttpException('Unauthorized - required dbg access', 401);
  16. }
  17. }
  18. public function defaultAction() {
  19. session_write_close();
  20. $this->defaultView();
  21. }
  22. public function defaultView($flashMsg = '') {
  23. UI::gora();
  24. UI::menu();
  25. try {
  26. echo UI::h('h1', [], [
  27. "Debug ",
  28. UI::h('small', [], "(" . (DBG::isActive() ? "włączony" : "wyłączony") . ") "),
  29. UI::hButtonPost((DBG::isActive()) ? "Wyłącz debug" : "Włącz debug", [
  30. 'class' => "btn-success btn-xs",
  31. 'data' => [
  32. '_route' => 'Debug',
  33. '_task' => DBG::isActive() ? 'deactivateDebug' : 'activateDebug'
  34. ]
  35. ])
  36. ]);
  37. echo $flashMsg;
  38. // DBG::nicePrint($_SERVER, '$_SERVER');
  39. // DBG::nicePrint([
  40. // 'date' => date("Y-m-d"),
  41. // 'login' => User::getLogin(),
  42. // 'ip' => Request::getUserIp(),
  43. // 'session_id' => session_id()
  44. // ], 'dbg');
  45. UI::table([
  46. 'caption' => "Log Files " . UI::h('a', [
  47. 'href' => "index.php?_route=Debug&_task=viewLatestUserLog",
  48. 'class' => "btn btn-xs btn-primary"
  49. ], "pokaż ostatni") . " " . UI::hButtonPost("Remove all log files", [
  50. 'class' => "btn-danger btn-xs",
  51. 'data' => [
  52. '_route' => 'Debug',
  53. '_task' => 'rmAllLogFiles'
  54. ]
  55. ]) . " " . UI::hButtonPost("Remove old log files", [
  56. 'class' => "btn-warning btn-xs",
  57. 'data' => [
  58. '_route' => 'Debug',
  59. '_task' => 'rmOldLogFiles'
  60. ]
  61. ]),
  62. 'cols' => [
  63. '#',
  64. 'file',
  65. 'user',
  66. 'request date',
  67. 'ip',
  68. 'rm',
  69. ],
  70. 'rows' => array_map(
  71. function ($logFile) {
  72. // /tmp/se-debug-2017-01-25-plabudda-192.168.61.206-4qqrd0.log
  73. try {
  74. if ('/tmp/se-debug-' != substr($logFile, 0, strlen('/tmp/se-debug-'))) throw new Exception("Wrong log file name '{$logFile}'");
  75. if ('.log' != substr($logFile, -4)) throw new Exception("Wrong log file name extension '{$logFile}'");
  76. $logName = substr($logFile, strlen('/tmp/se-debug-'), -4);
  77. list($logYear, $logMonth, $logDay, $logUser, $logIP, $logSessId, $logReqDate) = explode('-', $logName);
  78. return [
  79. '#' => UI::h('a', [
  80. 'href' => "index.php?_route=Debug&_task=viewLog&name={$logName}"
  81. ], "Pokaż"),
  82. 'request date' => ($logReqDate) ? date("Y-m-d H:i:s", $logReqDate) : '',// 1485775975
  83. 'file' => $logFile,
  84. 'user' => $logUser,
  85. 'ip' => $logIP,
  86. 'rm' => UI::hButtonPost("Usuń", [
  87. 'class' => 'btn-default btn-xs',
  88. 'data' => [
  89. '_route' => 'Debug',
  90. '_task' => 'rmLogFile',
  91. 'logName' => $logName
  92. ]
  93. ]),
  94. ];
  95. } catch (Exception $e) {
  96. return [
  97. '#' => '',
  98. 'file' => $e->getMessage(),
  99. ];
  100. }
  101. }
  102. , glob("/tmp/se-debug-*.log", GLOB_NOSORT)
  103. )
  104. ]);
  105. echo UI::hButtonPost("Test dbg with sleep", [
  106. 'class' => "btn-warning btn-xs",
  107. 'data' => [
  108. '_route' => 'Debug',
  109. '_task' => 'testDebugWithSleep'
  110. ]
  111. ]);
  112. } catch (Exception $e) {
  113. UI::alert('danger', $e->getMessage());
  114. DBG::log($e);
  115. }
  116. UI::dol();
  117. }
  118. public function viewLatestUserLogAction() {
  119. session_write_close();
  120. UI::gora();
  121. // UI::menu();
  122. echo UI::h('div', ['class'=>'container'], [
  123. UI::h('a', ['href'=>'index.php?_route=DEBUG'], "wróć")
  124. ]);
  125. try {
  126. $filerUser = V::get('user', '', $_REQUEST);// TODO: show another user debug
  127. $logName = V::get('name', '', $_REQUEST);
  128. if (!$logName) {
  129. $today = date("Y-m-d");
  130. $cmd = "ls -1rt /tmp/se-debug-{$today}-*.log | tail -5";
  131. V::exec($cmd, $out, $ret);
  132. if (empty($out)) {
  133. UI::alert('warning', "No logs today. Searching previous...");
  134. $cmd = "ls -1rt /tmp/se-debug-*.log | tail -5";
  135. V::exec($cmd, $out, $ret);
  136. if (empty($out)) throw new Exception("Log files not found");
  137. }
  138. echo UI::h('div', ['class'=>"alert alert-info"], [
  139. "Last log files",
  140. " (return code: {$ret})",
  141. "<br>cmd: <code>{$cmd}</code>",
  142. UI::h('pre', [], implode("\n", $out))
  143. ]);
  144. $logName = end($out);// /tmp/se-debug-2017-01-30-plabudda-192.168.61.206-4qqrd0-1485775975.log
  145. {
  146. if ('/tmp/se-debug-' != substr($logName, 0, strlen('/tmp/se-debug-'))) throw new Exception("Wrong log name prefix");
  147. if ('.log' != substr($logName, -1 * strlen('.log'))) throw new Exception("Wrong log name suffix");
  148. $logName = substr($logName, strlen('/tmp/se-debug-'), -1 * strlen('.log'));
  149. }
  150. }
  151. $this->printLogFileView($logName);
  152. } catch (Exception $e) {
  153. UI::alert('danger', $e->getMessage());
  154. }
  155. UI::dol();
  156. }
  157. public function viewLogAction() {
  158. session_write_close();
  159. UI::gora();
  160. // UI::menu();
  161. echo UI::h('div', ['class'=>'container'], [
  162. UI::h('a', ['href'=>'index.php?_route=DEBUG'], "wróć")
  163. ]);
  164. try {
  165. $logName = V::get('name', '', $_REQUEST);
  166. $this->printLogFileView($logName);
  167. } catch (Exception $e) {
  168. UI::alert('danger', $e->getMessage());
  169. }
  170. UI::dol();
  171. }
  172. public function printLogFileView($logName) {
  173. if (empty($logName)) throw new Exception("Missing name");
  174. $logName = $this->validateParamLogName($logName);
  175. $logPath = "/tmp/se-debug-{$logName}.log";
  176. if (!file_exists($logPath)) throw new Exception("Log file not exists");
  177. $content = file_get_contents($logPath);
  178. UI::table([
  179. 'cols' => [
  180. 'date',
  181. 'type',
  182. 'msg',
  183. 'log',
  184. 'trace',
  185. ],
  186. 'cols_help' => [
  187. 'trace' => "Cick to show trace"
  188. ],
  189. 'rows' => array_map(
  190. function ($line) {
  191. if (empty($line)) return [];
  192. $dbg = @json_decode($line, $assoc = true);
  193. if (null == $dbg && 0 !== json_last_error()) {
  194. return [
  195. 'type' => 'decode json error',
  196. 'msg' => "Error Processing Request - Parse json error: " . json_last_error()
  197. ];
  198. }
  199. return [
  200. 'date' => '<nobr>' . $dbg['date'] . '</nobr>',
  201. 'type' => $dbg['type'],
  202. 'msg' => $dbg['msg'],
  203. // 'log' => (!empty($dbg['log'])) ? json_encode($dbg['log']) : '',
  204. 'log' => UI::h('div', [
  205. 'title' => htmlspecialchars(var_export($dbg['log'], true)),
  206. 'onClick' => "return p5DBG__showLogTrace(this, event)",
  207. 'style' => "cursor:pointer"
  208. ], substr(htmlspecialchars(json_encode($dbg['log'])), 0, 100) . ' ...'
  209. ),
  210. 'trace' => UI::h('div', [
  211. 'title' => htmlspecialchars($dbg['trace']),
  212. 'onClick' => "return p5DBG__showLogTrace(this, event)",
  213. 'style' => "cursor:pointer"
  214. ], ('Exception' == $dbg['type'])
  215. ? "Code: {$dbg['log']['code']}, File: {$dbg['log']['file']}"
  216. : '...'
  217. ),
  218. ];
  219. },
  220. explode("\n", $content)
  221. ),
  222. ]);
  223. echo UI::h('script', [], "
  224. function p5DBG__showLogTrace(n, e) {
  225. if (!e) return false;
  226. if (e.target && 'PRE' == e.target.tagName) return false;
  227. if (n.lastChild.tagName == 'PRE') {
  228. if ('none' == n.lastChild.style.display) {
  229. n.lastChild.style.display = 'block'
  230. } else {
  231. n.lastChild.style.display = 'none'
  232. }
  233. } else {
  234. var pre = document.createElement('pre')
  235. pre.appendChild( document.createTextNode(n.title) )
  236. n.appendChild(pre)
  237. }
  238. }
  239. ");
  240. }
  241. public function activateDebugAction() {
  242. DBG::activate();
  243. $this->defaultView();
  244. }
  245. public function deactivateDebugAction() {
  246. DBG::deactivate();
  247. $this->defaultView();
  248. }
  249. public function testDebugWithSleepAction() {
  250. session_write_close();
  251. UI::gora();
  252. flush();
  253. for ($i = 0; $i < 10; $i++) {
  254. echo "TEST {$i}<br>";
  255. DBG::log("TEST {$i}");
  256. flush();
  257. sleep(2);
  258. }
  259. echo "DONE";
  260. DBG::log("DONE");
  261. UI::dol();
  262. }
  263. public function validateParamLogName($logName) {
  264. if (empty($logName)) throw new Exception("Missing log file name");
  265. if (!preg_match('/^[\-\.a-zA-Z0-9]+$/', $logName)) throw new Exception("Wrong log file name format");
  266. return $logName;
  267. }
  268. public function rmAllLogFilesAction() {
  269. session_write_close();
  270. try {
  271. $today = date("Y-m-d");
  272. $cmd = "rm -v /tmp/se-debug-*.log 2>&1";
  273. V::exec($cmd, $out, $ret);
  274. $this->defaultView(UI::h('div', ['class'=>"alert alert-success alert-dismissible"], [
  275. '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>',
  276. (0 === $ret) ? "All Log Files Removed" : "Error?",
  277. " (return code: {$ret})",
  278. "<br>cmd: <code>{$cmd}</code>",
  279. UI::h('pre', [], implode("\n", $out))
  280. ]));
  281. } catch (AlertSuccessException $e) {
  282. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  283. } catch (AlertWarningException $e) {
  284. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  285. } catch (Exception $e) {
  286. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  287. }
  288. }
  289. public function rmOldLogFilesAction() {
  290. session_write_close();
  291. try {
  292. $today = date("Y-m-d");
  293. $cmd = "ls -1 /tmp/se-debug-*.log | grep -v '/tmp/se-debug-{$today}-' | xargs rm -v 2>&1";
  294. V::exec($cmd, $out, $ret);
  295. $this->defaultView(UI::h('div', ['class'=>"alert alert-success alert-dismissible"], [
  296. '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>',
  297. (0 === $ret) ? "Old Log Files Removed" : "Error?",
  298. " (return code: {$ret})",
  299. "<br>cmd: <code>{$cmd}</code>",
  300. UI::h('pre', [], implode("\n", $out))
  301. ]));
  302. } catch (AlertSuccessException $e) {
  303. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  304. } catch (AlertWarningException $e) {
  305. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  306. } catch (Exception $e) {
  307. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  308. }
  309. }
  310. public function rmLogFileAction() {
  311. session_write_close();
  312. try {
  313. $logName = $this->validateParamLogName(V::get('logName', '', $_REQUEST));
  314. $logPath = "/tmp/se-debug-{$logName}.log";
  315. if (!file_exists($logPath)) throw new AlertWarningException("Log file not exists");
  316. unlink($logPath);
  317. throw new AlertSuccessException("File Removed");
  318. } catch (AlertSuccessException $e) {
  319. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  320. } catch (AlertWarningException $e) {
  321. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  322. } catch (Exception $e) {
  323. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  324. }
  325. }
  326. }