[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/logviewer/ -> admin.php (source)

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