central logging mechanism

This introduces a logger mechanism and a new data/log directory. This is
a first proof of concept. It's built on top of the new global error
handling mechanism

Things to discuss:

* should we adopt PSR-3 somehow? if yes, how and should plugins be able
  to drop-in other psr3 loggers?
* how to configure which facilities shall be logged?
* should we implement a log deletion feature?
* is the log format sensible?
* should we implement a log viewer admin plugin?
* should logging trigger events (it should maybe replace the
  deprecation event)
This commit is contained in:
Andreas Gohr 2020-08-13 13:25:46 +02:00
parent 51c1fbb36b
commit 0ecde6ce23
6 changed files with 126 additions and 35 deletions

View File

@ -5,6 +5,7 @@ namespace dokuwiki\Debug;
use Doku_Event;
use dokuwiki\Extension\EventHandler;
use dokuwiki\Logger;
class DebugHelper
{
@ -160,7 +161,7 @@ class DebugHelper
if ($event->data['alternative']) {
$msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
}
dbglog($msg);
Logger::getInstance(Logger::LOG_DEPRECATED)->log($msg);
}
$event->advise_after();
}

View File

@ -36,7 +36,7 @@ class ErrorHandler
$msg = 'An unforeseen error has occured. This is most likely a bug somewhere.';
if ($plugin) $msg .= ' It might be a problem in the ' . $plugin . ' plugin.';
$logged = self::logException($e)
? 'More info has been written to the DokuWiki _error.log'
? 'More info has been written to the DokuWiki error log.'
: $e->getFile() . ':' . $e->getLine();
echo <<<EOT
@ -64,7 +64,7 @@ EOT;
public static function showExceptionMsg($e, $intro = 'Error!')
{
$msg = hsc($intro) . '<br />' . hsc(get_class($e) . ': ' . $e->getMessage());
if (self::logException($e)) $msg .= '<br />More info is available in the _error.log';
if (self::logException($e)) $msg .= '<br />More info is available in the error log.';
msg($msg, -1);
}
@ -100,16 +100,12 @@ EOT;
*/
public static function logException($e)
{
global $conf;
$log = join("\t", [
gmdate('c'),
get_class($e),
$e->getFile() . '(' . $e->getLine() . ')',
$e->getMessage(),
]) . "\n";
$log .= $e->getTraceAsString() . "\n";
return io_saveFile($conf['cachedir'] . '/_error.log', $log, true);
return Logger::getInstance()->log(
get_class($e) . ': ' . $e->getMessage(),
$e->getTraceAsString(),
$e->getFile(),
$e->getLine()
);
}
/**

View File

@ -3,6 +3,8 @@
namespace dokuwiki\Extension;
use dokuwiki\Logger;
/**
* The Action plugin event
*/
@ -71,7 +73,8 @@ class Event
if ($EVENT_HANDLER !== null) {
$EVENT_HANDLER->process_event($this, 'BEFORE');
} else {
dbglog($this->name . ':BEFORE event triggered before event system was initialized');
Logger::getInstance(Logger::LOG_DEBUG)
->log($this->name . ':BEFORE event triggered before event system was initialized');
}
return (!$enablePreventDefault || $this->runDefault);
@ -92,7 +95,8 @@ class Event
if ($EVENT_HANDLER !== null) {
$EVENT_HANDLER->process_event($this, 'AFTER');
} else {
dbglog($this->name . ':AFTER event triggered before event system was initialized');
Logger::getInstance(Logger::LOG_DEBUG)->
log($this->name . ':AFTER event triggered before event system was initialized');
}
}

87
inc/Logger.php Normal file
View File

@ -0,0 +1,87 @@
<?php
namespace dokuwiki;
class Logger
{
const LOG_ERROR = 'error';
const LOG_DEPRECATED = 'deprecated';
const LOG_DEBUG = 'debug';
/** @var Logger[] */
static protected $instances;
/** @var string what kind of log is this */
protected $facility;
/**
* Logger constructor.
*
* @param string $facility The type of log
*/
protected function __construct($facility)
{
$this->facility = $facility;
}
/**
* Return a Logger instance for the given facility
*
* @param string $facility The type of log
* @return Logger
*/
static public function getInstance($facility = self::LOG_ERROR)
{
if (self::$instances[$facility] === null) {
self::$instances[$facility] = new Logger($facility);
}
return self::$instances[$facility];
}
/**
* Log a message to the facility log
*
* @param string $message The log message
* @param mixed $details Any details that should be added to the log entry
* @param string $file A source filename if this is related to a source position
* @param int $line A line number for the above file
* @return bool
*/
public function log($message, $details = null, $file = '', $line = 0)
{
// details are logged indented
if ($details && !is_string($details)) {
$details = json_encode($details, JSON_PRETTY_PRINT);
$details = explode("\n", $details);
$loglines = array_map(function ($line) {
return ' ' . $line;
}, $details);
} elseif ($details) {
$loglines = [$details];
} else {
$loglines = [];
}
$logline = gmdate('c') . "\t" . $message;
if ($file) {
$logline .= "\t$file";
if ($line) $logline .= "($line)";
}
array_unshift($loglines, $logline);
return $this->writeLogLines($loglines);
}
/**
* Write the given lines to today's facility log
*
* @param string[] $lines the raw lines to append to the log
* @return bool true if the log was written
*/
protected function writeLogLines($lines)
{
global $conf;
$logfile = $conf['logdir'] . '/' . $this->facility . '/' . gmdate('Y-m-d') . '.log';
return io_saveFile($logfile, join("\n", $lines) . "\n", true);
}
}

View File

@ -424,14 +424,13 @@ function dbg($msg,$hidden=false){
* Print info to a log file
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @deprecated 2020-08-13
* @param string $msg
* @param string $header
*/
function dbglog($msg,$header=''){
global $conf;
/* @var Input $INPUT */
global $INPUT;
dbg_deprecated('\\dokuwiki\\Logger');
// The debug log isn't automatically cleaned thus only write it when
// debugging has been enabled by the user.
@ -440,14 +439,15 @@ function dbglog($msg,$header=''){
$msg = print_r($msg,true);
}
if($header) $msg = "$header\n$msg";
$file = $conf['cachedir'].'/debug.log';
$fh = fopen($file,'a');
if($fh){
fwrite($fh,date('H:i:s ').$INPUT->server->str('REMOTE_ADDR').': '.$msg."\n");
fclose($fh);
// was the msg as single line string? use it as header
if($header === '' && strpos($msg, "\n") === false) {
$header = $msg;
$msg = '';
}
\dokuwiki\Logger::getInstance(\dokuwiki\Logger::LOG_DEBUG)->log(
$header, $msg
);
}
/**

View File

@ -269,16 +269,19 @@ function init_session() {
function init_paths(){
global $conf;
$paths = array('datadir' => 'pages',
'olddir' => 'attic',
'mediadir' => 'media',
'mediaolddir' => 'media_attic',
'metadir' => 'meta',
'mediametadir' => 'media_meta',
'cachedir' => 'cache',
'indexdir' => 'index',
'lockdir' => 'locks',
'tmpdir' => 'tmp');
$paths = [
'datadir' => 'pages',
'olddir' => 'attic',
'mediadir' => 'media',
'mediaolddir' => 'media_attic',
'metadir' => 'meta',
'mediametadir' => 'media_meta',
'cachedir' => 'cache',
'indexdir' => 'index',
'lockdir' => 'locks',
'tmpdir' => 'tmp',
'logdir' => 'log',
];
foreach($paths as $c => $p) {
$path = empty($conf[$c]) ? $conf['savedir'].'/'.$p : $conf[$c];