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