admin.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. use dokuwiki\Logger;
  3. /**
  4. * DokuWiki Plugin logviewer (Admin Component)
  5. *
  6. * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
  7. * @author Andreas Gohr <andi@splitbrain.org>
  8. */
  9. class admin_plugin_logviewer extends DokuWiki_Admin_Plugin
  10. {
  11. const MAX_READ_SIZE = 1048576; // 1 MB
  12. protected $facilities;
  13. protected $facility;
  14. protected $date;
  15. /** @inheritDoc */
  16. public function forAdminOnly()
  17. {
  18. return true;
  19. }
  20. /** @inheritDoc */
  21. public function handle()
  22. {
  23. global $INPUT;
  24. $this->facilities = $this->getFacilities();
  25. $this->facility = $INPUT->str('facility');
  26. if (!in_array($this->facility, $this->facilities)) {
  27. $this->facility = $this->facilities[0];
  28. }
  29. $this->date = $INPUT->str('date');
  30. if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $this->date)) {
  31. $this->date = gmdate('Y-m-d');
  32. }
  33. }
  34. /** @inheritDoc */
  35. public function html()
  36. {
  37. echo '<div id="plugin__logviewer">';
  38. echo $this->locale_xhtml('intro');
  39. $this->displayTabs();
  40. $this->displayLog();
  41. echo '</div>';
  42. }
  43. /**
  44. * Show the navigational tabs and date picker
  45. */
  46. protected function displayTabs()
  47. {
  48. global $ID;
  49. $form = new dokuwiki\Form\Form(['method' => 'GET']);
  50. $form->setHiddenField('do', 'admin');
  51. $form->setHiddenField('page', 'logviewer');
  52. $form->setHiddenField('facility', $this->facility);
  53. $form->addTextInput('date', $this->getLang('date'))
  54. ->attr('type', 'date')->val($this->date)->addClass('quickselect');
  55. $form->addButton('submit', '>')->attr('type', 'submit');
  56. echo $form->toHTML();
  57. echo '<ul class="tabs">';
  58. foreach ($this->facilities as $facility) {
  59. echo '<li>';
  60. if ($facility == $this->facility) {
  61. echo '<strong>' . hsc($facility) . '</strong>';
  62. } else {
  63. $link = wl($ID,
  64. ['do' => 'admin', 'page' => 'logviewer', 'date' => $this->date, 'facility' => $facility]);
  65. echo '<a href="' . $link . '">' . hsc($facility) . '</a>';
  66. }
  67. echo '</li>';
  68. }
  69. echo '</ul>';
  70. }
  71. /**
  72. * Read and output the logfile contents
  73. */
  74. protected function displayLog()
  75. {
  76. $logfile = Logger::getInstance($this->facility)->getLogfile($this->date);
  77. if (!file_exists($logfile)) {
  78. echo $this->locale_xhtml('nolog');
  79. return;
  80. }
  81. try {
  82. $lines = $this->getLogLines($logfile);
  83. $this->printLogLines($lines);
  84. } catch (Exception $e) {
  85. msg($e->getMessage(), -1);
  86. }
  87. }
  88. /**
  89. * Get the available logging facilities
  90. *
  91. * @return array
  92. */
  93. protected function getFacilities()
  94. {
  95. global $conf;
  96. // default facilities first
  97. $facilities = [
  98. Logger::LOG_ERROR,
  99. Logger::LOG_DEPRECATED,
  100. Logger::LOG_DEBUG,
  101. ];
  102. // add all other dirs
  103. $dirs = glob($conf['logdir'] . '/*', GLOB_ONLYDIR);
  104. foreach ($dirs as $dir) {
  105. $facilities[] = basename($dir);
  106. }
  107. $facilities = array_unique($facilities);
  108. return $facilities;
  109. }
  110. /**
  111. * Read the lines of the logfile and return them as array
  112. *
  113. * @param string $logfilePath
  114. * @return array
  115. * @throws Exception when reading fails
  116. */
  117. protected function getLogLines($logfilePath)
  118. {
  119. global $lang;
  120. $size = filesize($logfilePath);
  121. $fp = fopen($logfilePath, 'r');
  122. if (!$fp) throw new Exception($lang['log_file_failed_to_open']);
  123. try {
  124. if ($size < self::MAX_READ_SIZE) {
  125. $toread = $size;
  126. } else {
  127. $toread = self::MAX_READ_SIZE;
  128. fseek($fp, -$toread, SEEK_END);
  129. }
  130. $logData = fread($fp, $toread);
  131. if (!$logData) throw new Exception($lang['log_file_failed_to_read']);
  132. $lines = explode("\n", $logData);
  133. unset($logData); // free memory early
  134. if ($size >= self::MAX_READ_SIZE) {
  135. array_shift($lines); // Discard the first line
  136. while (!empty($lines) && (substr($lines[0], 0, 2) === ' ')) {
  137. array_shift($lines); // Discard indented lines
  138. }
  139. // A message to inform users that previous lines are skipped
  140. array_unshift($lines, "******\t" . "\t" . '[' . $lang['log_file_too_large'] . ']');
  141. }
  142. } finally {
  143. fclose($fp);
  144. }
  145. return $lines;
  146. }
  147. /**
  148. * Get an array of log lines and print them using appropriate styles
  149. *
  150. * @param array $lines
  151. */
  152. protected function printLogLines($lines)
  153. {
  154. $numberOfLines = count($lines);
  155. echo "<dl>";
  156. for ($i = 0; $i < $numberOfLines; $i++) {
  157. $line = $lines[$i];
  158. if (substr($line, 0, 2) === ' ') {
  159. // lines indented by two spaces are details, aggregate them
  160. echo '<dd>';
  161. while (substr($line, 0, 2) === ' ') {
  162. echo hsc(substr($line, 2)) . '<br />';
  163. $i++;
  164. $line = $lines[$i] ?? '';
  165. }
  166. echo '</dd>';
  167. $i -= 1; // rewind the counter
  168. } else {
  169. // other lines are actual log lines in three parts
  170. list($dt, $file, $msg) = sexplode("\t", $line, 3, '');
  171. echo '<dt>';
  172. echo '<span class="datetime">' . hsc($dt) . '</span>';
  173. echo '<span class="log">';
  174. echo '<span class="msg">' . hsc($msg) . '</span>';
  175. echo '<span class="file">' . hsc($file) . '</span>';
  176. echo '</span>';
  177. echo '</dt>';
  178. }
  179. }
  180. echo "</dl>";
  181. }
  182. }