Debug.php 14 KB

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