parent
b384c11837
commit
157e0d8dd0
@ -1,3 +1,3 @@
|
|||||||
# XXX
|
# PhpExtendedMonolog
|
||||||
|
|
||||||
XXX
|
Some extensions for [Monolog](https://github.com/Seldaek/monolog)
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace jrosset\ExtendedMonolog;
|
||||||
|
|
||||||
|
use jrosset\ExceptionHelper\ExceptionHelper;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A logger with method for managing exception directly
|
||||||
|
*/
|
||||||
|
class ExceptionLogger extends Logger implements ExceptionLoggerInterface {
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function exception (int $level, Throwable $exception, array $context = []): void {
|
||||||
|
$this->addRecord(
|
||||||
|
$level,
|
||||||
|
ExceptionHelper::toString($exception, false),
|
||||||
|
array_merge(
|
||||||
|
[
|
||||||
|
'exception' => $exception,
|
||||||
|
],
|
||||||
|
$context
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace jrosset\ExtendedMonolog;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe a logger interface with method for managing exception directly
|
||||||
|
*/
|
||||||
|
interface ExceptionLoggerInterface extends LoggerInterface {
|
||||||
|
/**
|
||||||
|
* Adds a log record about an exception
|
||||||
|
*
|
||||||
|
* @param int $level The logging level (a Monolog or RFC 5424 level)
|
||||||
|
* @param Throwable $exception The exception
|
||||||
|
* @param array $context The log context
|
||||||
|
*/
|
||||||
|
public function exception (int $level, Throwable $exception, array $context = []): void;
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace jrosset\ExtendedMonolog;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DirectoryIterator;
|
||||||
|
use jrosset\LastErrorException\LastErrorException;
|
||||||
|
use Monolog\Handler\StreamHandler;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use RuntimeException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler for storing log in a directory: one file per day, with an auto-clean mechanism
|
||||||
|
*
|
||||||
|
* The default formatter is {@see LogFileFormatter}
|
||||||
|
*/
|
||||||
|
class LogDirectoryHandler extends StreamHandler {
|
||||||
|
/**
|
||||||
|
* Initialization
|
||||||
|
*
|
||||||
|
* @param string $dirPath The log directory path
|
||||||
|
* @param int $historyNumberOfDays The maximum number of history files to keep (in number of days)
|
||||||
|
*
|
||||||
|
* @throws Throwable If an error occurs
|
||||||
|
*/
|
||||||
|
public function __construct (string $dirPath, int $historyNumberOfDays = 30) {
|
||||||
|
$dirPath = realpath($dirPath) . DIRECTORY_SEPARATOR;
|
||||||
|
$this->normalizeDirectory($dirPath, $historyNumberOfDays);
|
||||||
|
|
||||||
|
parent::__construct(
|
||||||
|
$dirPath . date('Y-m-d') . '.log',
|
||||||
|
Logger::WARNING
|
||||||
|
);
|
||||||
|
$this->setFormatter(new LogFileFormatter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a directory: create if missing and clear old files
|
||||||
|
*
|
||||||
|
* @param string $dirPath The directory path
|
||||||
|
* @param int $historyNumberOfDays The maximum number of history files to keep (in number of days)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws Throwable If an error occurs
|
||||||
|
*/
|
||||||
|
private function normalizeDirectory (string $dirPath, int $historyNumberOfDays = 30): void {
|
||||||
|
if (!file_exists($dirPath) || !is_dir($dirPath)) {
|
||||||
|
error_clear_last();
|
||||||
|
if (!mkdir($dirPath, 0755, true)) {
|
||||||
|
throw new RuntimeException('Failed to create log directory: ' . $dirPath, 0, LastErrorException::createFromLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dateLimit = (new DateTimeImmutable('now'))->sub(new DateInterval('P' . $historyNumberOfDays . 'D'));
|
||||||
|
|
||||||
|
$iterator = new DirectoryIterator($dirPath);
|
||||||
|
foreach ($iterator as $fileInfo) {
|
||||||
|
if ($fileInfo->isDot() || mb_substr($fileInfo->getFilename(), 0, 1) === '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!$fileInfo->isFile()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match('/^(?<date>\\d{4}-\\d{2}-\\d{2})(?:[_-].*)?\.log$/i', $fileInfo->getFilename(), $match) !== 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date = DateTimeImmutable::createFromFormat('Y-m-d', $match['date']);
|
||||||
|
if ($date >= $dateLimit) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink($fileInfo->getPathname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace jrosset\ExtendedMonolog;
|
||||||
|
|
||||||
|
use Monolog\Formatter\LineFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A formater for log files
|
||||||
|
*/
|
||||||
|
class LogFileFormatter extends LineFormatter {
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function __construct () {
|
||||||
|
parent::__construct(
|
||||||
|
'[%datetime%] %level_name% : %message%' . PHP_EOL . '%context%' . PHP_EOL . '%extra%',
|
||||||
|
'H:i:s',
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function format (array $record): string {
|
||||||
|
return preg_replace('/((?<!\\\\)\\\\[rn])+$/', PHP_EOL, parent::format($record));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue