首先安裝hyperf composer create-project hyperf/hyperf-skeleton
需要修改的檔案如下所示
hyperf-skeleton
├── app
│ ├── Controller
│ │ ├── AbstractController.php
│ │ └── IndexController.php // 增加丟擲錯誤的程式碼 throw new Exception("hello error!");
│ ├── Exception
│ │ └── Handler
│ │ │ └── AppExceptionHandler.php // 使用daily通道寫入日誌
│ ├── Helper
│ │ └── RotatingFileHandler.php // 複製monolog的RotatingFileHandler並且修改支援hyperf
├── config
│ ├── autoload
│ │ ├── logger.php // 增加daily通道日誌配置
├── runtime
│ └── logs
│ ├── daily-2020-07-12.log // 執行出來的效果
│ ├── daily-2020-07-13.log
│ ├── daily-2020-07-14.log
│ └── hyperf.log
增加丟擲異常
// 所在檔案:app/Controller/IndexController.php
class IndexController extends AbstractController
{
/**
* @var ContainerInterface
*/
protected $container;
public function index()
{
throw new Exception("hello error!"); //增加了這一行程式碼
$user = $this->request->input('user', 'Hyperf');
$method = $this->request->getMethod();
return [
'method' => $method,
'message' => "Hello {$user}.",
];
}
}
複製monolog的RotatingFileHandler.php並且修改支援hyperf
// 所在檔案:app/Helper/RotatingFileHandler.php
<?php declare(strict_types=1);
namespace App\Helper;
use InvalidArgumentException;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Handler\StreamHandler;
class RotatingFileHandler extends StreamHandler
{
... // 此處省略
protected function write(array $record): void
{
// on the first record written, if the log is new, we should rotate (once per day)
if (null === $this->mustRotate) {
$this->mustRotate = !file_exists($this->url);
}
if ($this->nextRotation <= $record['datetime']) {
$this->mustRotate = true;
$this->close();
}
// 增加以下四行程式碼
if($this->url != $this->getTimedFilename()){
$this->url = $this->getTimedFilename();
$this->stream = null;
}
parent::write($record);
}
... // 此處忽略
}
增加daily通道日誌配置
// 所在檔案:config/autoload/logger.php
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'handler' => [
'class' => Monolog\Handler\StreamHandler::class,
'constructor' => [
'stream' => BASE_PATH . '/runtime/logs/hyperf.log',
'level' => Monolog\Logger::DEBUG,
],
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [
'format' => null,
'dateFormat' => 'Y-m-d H:i:s',
'allowInlineLineBreaks' => true,
],
],
],
// 增加daily日誌通道
'daily' => [
'handler' => [
'class' => App\Helper\RotatingFileHandler::class,
'constructor' => [
'filename' => BASE_PATH . '/runtime/logs/daily.log',
'maxFiles' => 14, //最多顯示最近的15個檔案
],
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [
'format' => null,
'dateFormat' => 'Y-m-d H:i:s',
'allowInlineLineBreaks' => true,
],
],
],
];
使用daily通道寫入日誌
<?php declare(strict_types=1);
namespace App\Exception\Handler;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use Hyperf\Logger\LoggerFactory;
use Psr\Container\ContainerInterface;
class AppExceptionHandler extends ExceptionHandler
{
/**
* @var StdoutLoggerInterface
*/
protected $logger;
/**
* @var ContainerInterface
*/
protected $container;
public function __construct(StdoutLoggerInterface $logger, ContainerInterface $container)
{
$this->logger = $logger;
$this->container = $container;
}
public function handle(Throwable $throwable, ResponseInterface $response)
{
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$this->logger->error($throwable->getTraceAsString());
// 從容器獲取到日誌物件
$log = $this->container->get(LoggerFactory::class)->get('debug', 'daily'); // 關鍵程式碼
$log->info(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$log->info($throwable->getTraceAsString());
return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
}
public function isValid(Throwable $throwable): bool
{
return true;
}
}
效果圖
本作品採用《CC 協議》,轉載必須註明作者和本文連結