Debug.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. 'data' => [
  88. '_route' => 'Debug',
  89. '_task' => 'rmLogFile',
  90. 'logName' => $logName
  91. ]
  92. ]),
  93. ];
  94. } catch (Exception $e) {
  95. return [
  96. '#' => '',
  97. 'file' => $e->getMessage(),
  98. ];
  99. }
  100. }
  101. , glob("/tmp/se-debug-*.log", GLOB_NOSORT)
  102. )
  103. ]);
  104. echo UI::hButtonPost("Test dbg with sleep", [
  105. 'class' => "btn-warning btn-xs",
  106. 'data' => [
  107. '_route' => 'Debug',
  108. '_task' => 'testDebugWithSleep'
  109. ]
  110. ]);
  111. } catch (Exception $e) {
  112. UI::alert('danger', $e->getMessage());
  113. DBG::log($e);
  114. }
  115. UI::dol();
  116. }
  117. public function viewLatestUserLogAction() {
  118. session_write_close();
  119. UI::gora();
  120. // UI::menu();
  121. echo UI::h('div', ['class'=>'container'], [
  122. UI::h('a', ['href'=>'index.php?_route=DEBUG'], "wróć")
  123. ]);
  124. try {
  125. $filerUser = V::get('user', '', $_REQUEST);// TODO: show another user debug
  126. $logName = V::get('name', '', $_REQUEST);
  127. if (!$logName) {
  128. $today = date("Y-m-d");
  129. $cmd = "ls -1rt /tmp/se-debug-{$today}-*.log | tail -5";
  130. V::exec($cmd, $out, $ret);
  131. if (empty($out)) {
  132. UI::alert('warning', "No logs today. Searching previous...");
  133. $cmd = "ls -1rt /tmp/se-debug-*.log | tail -5";
  134. V::exec($cmd, $out, $ret);
  135. if (empty($out)) throw new Exception("Log files not found");
  136. }
  137. echo UI::h('div', ['class'=>"alert alert-info"], [
  138. "Last log files",
  139. " (return code: {$ret})",
  140. "<br>cmd: <code>{$cmd}</code>",
  141. UI::h('pre', [], implode("\n", $out))
  142. ]);
  143. $logName = end($out);// /tmp/se-debug-2017-01-30-plabudda-192.168.61.206-4qqrd0-1485775975.log
  144. {
  145. if ('/tmp/se-debug-' != substr($logName, 0, strlen('/tmp/se-debug-'))) throw new Exception("Wrong log name prefix");
  146. if ('.log' != substr($logName, -1 * strlen('.log'))) throw new Exception("Wrong log name suffix");
  147. $logName = substr($logName, strlen('/tmp/se-debug-'), -1 * strlen('.log'));
  148. }
  149. }
  150. $this->printLogFileView($logName);
  151. } catch (Exception $e) {
  152. UI::alert('danger', $e->getMessage());
  153. }
  154. UI::dol();
  155. }
  156. public function viewLogAction() {
  157. session_write_close();
  158. UI::gora();
  159. // UI::menu();
  160. echo UI::h('div', ['class'=>'container'], [
  161. UI::h('a', ['href'=>'index.php?_route=DEBUG'], "wróć")
  162. ]);
  163. try {
  164. $logName = V::get('name', '', $_REQUEST);
  165. $this->printLogFileView($logName);
  166. } catch (Exception $e) {
  167. UI::alert('danger', $e->getMessage());
  168. }
  169. UI::dol();
  170. }
  171. public function printLogFileView($logName) {
  172. if (empty($logName)) throw new Exception("Missing name");
  173. $logName = $this->validateParamLogName($logName);
  174. $logPath = "/tmp/se-debug-{$logName}.log";
  175. if (!file_exists($logPath)) throw new Exception("Log file not exists");
  176. $content = file_get_contents($logPath);
  177. UI::table([
  178. 'cols' => [
  179. 'date',
  180. 'type',
  181. 'msg',
  182. 'log',
  183. 'trace',
  184. ],
  185. 'cols_help' => [
  186. 'trace' => "Cick to show trace"
  187. ],
  188. 'rows' => array_map(
  189. function ($line) {
  190. if (empty($line)) return [];
  191. $dbg = @json_decode($line, $assoc = true);
  192. if (null == $dbg && 0 !== json_last_error()) {
  193. return [
  194. 'type' => 'decode json error',
  195. 'msg' => "Error Processing Request - Parse json error: " . json_last_error()
  196. ];
  197. }
  198. return [
  199. 'date' => '<nobr>' . $dbg['date'] . '</nobr>',
  200. 'type' => $dbg['type'],
  201. 'msg' => $dbg['msg'],
  202. // 'log' => (!empty($dbg['log'])) ? json_encode($dbg['log']) : '',
  203. 'log' => UI::h('div', [
  204. 'title' => htmlspecialchars(var_export($dbg['log'], true)),
  205. 'onClick' => "return p5DBG__showLogTrace(this, event)",
  206. 'style' => "cursor:pointer"
  207. ], substr(htmlspecialchars(json_encode($dbg['log'])), 0, 100) . ' ...'
  208. ),
  209. 'trace' => UI::h('div', [
  210. 'title' => htmlspecialchars($dbg['trace']),
  211. 'onClick' => "return p5DBG__showLogTrace(this, event)",
  212. 'style' => "cursor:pointer"
  213. ], ('Exception' == $dbg['type'])
  214. ? "Code: {$dbg['log']['code']}, File: {$dbg['log']['file']}"
  215. : '...'
  216. ),
  217. ];
  218. },
  219. explode("\n", $content)
  220. ),
  221. ]);
  222. echo UI::h('script', [], "
  223. function p5DBG__showLogTrace(n, e) {
  224. if (!e) return false;
  225. if (e.target && 'PRE' == e.target.tagName) return false;
  226. if (n.lastChild.tagName == 'PRE') {
  227. if ('none' == n.lastChild.style.display) {
  228. n.lastChild.style.display = 'block'
  229. } else {
  230. n.lastChild.style.display = 'none'
  231. }
  232. } else {
  233. var pre = document.createElement('pre')
  234. pre.appendChild( document.createTextNode(n.title) )
  235. n.appendChild(pre)
  236. }
  237. }
  238. ");
  239. }
  240. public function activateDebugAction() {
  241. DBG::activate();
  242. $this->defaultView();
  243. }
  244. public function deactivateDebugAction() {
  245. DBG::deactivate();
  246. $this->defaultView();
  247. }
  248. public function testDebugWithSleepAction() {
  249. session_write_close();
  250. UI::gora();
  251. flush();
  252. for ($i = 0; $i < 10; $i++) {
  253. echo "TEST {$i}<br>";
  254. DBG::log("TEST {$i}");
  255. flush();
  256. sleep(2);
  257. }
  258. echo "DONE";
  259. DBG::log("DONE");
  260. UI::dol();
  261. }
  262. public function validateParamLogName($logName) {
  263. if (empty($logName)) throw new Exception("Missing log file name");
  264. if (!preg_match('/^[\-\.a-zA-Z0-9]+$/', $logName)) throw new Exception("Wrong log file name format");
  265. return $logName;
  266. }
  267. public function rmAllLogFilesAction() {
  268. session_write_close();
  269. try {
  270. $today = date("Y-m-d");
  271. $cmd = "rm -v /tmp/se-debug-*.log 2>&1";
  272. V::exec($cmd, $out, $ret);
  273. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], [
  274. (0 === $ret) ? "All Log Files Removed" : "Error?",
  275. " (return code: {$ret})",
  276. "<br>cmd: <code>{$cmd}</code>",
  277. UI::h('pre', [], implode("\n", $out))
  278. ]));
  279. } catch (AlertSuccessException $e) {
  280. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  281. } catch (AlertWarningException $e) {
  282. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  283. } catch (Exception $e) {
  284. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  285. }
  286. }
  287. public function rmOldLogFilesAction() {
  288. session_write_close();
  289. try {
  290. $today = date("Y-m-d");
  291. $cmd = "ls -1 /tmp/se-debug-*.log | grep -v '/tmp/se-debug-{$today}-' | xargs rm -v 2>&1";
  292. V::exec($cmd, $out, $ret);
  293. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], [
  294. (0 === $ret) ? "Old Log Files Removed" : "Error?",
  295. " (return code: {$ret})",
  296. "<br>cmd: <code>{$cmd}</code>",
  297. UI::h('pre', [], implode("\n", $out))
  298. ]));
  299. } catch (AlertSuccessException $e) {
  300. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  301. } catch (AlertWarningException $e) {
  302. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  303. } catch (Exception $e) {
  304. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  305. }
  306. }
  307. public function rmLogFileAction() {
  308. session_write_close();
  309. try {
  310. $logName = $this->validateParamLogName(V::get('logName', '', $_REQUEST));
  311. $logPath = "/tmp/se-debug-{$logName}.log";
  312. if (!file_exists($logPath)) throw new AlertWarningException("Log file not exists");
  313. unlink($logPath);
  314. throw new AlertSuccessException("File Removed");
  315. } catch (AlertSuccessException $e) {
  316. $this->defaultView(UI::h('div', ['class'=>"alert alert-success"], $e->getMessage()));
  317. } catch (AlertWarningException $e) {
  318. $this->defaultView(UI::h('div', ['class'=>"alert alert-warning"], $e->getMessage()));
  319. } catch (Exception $e) {
  320. $this->defaultView(UI::h('div', ['class'=>"alert alert-danger"], $e->getMessage()));
  321. }
  322. }
  323. }