例外処理のベストプラクティス
例外モデルをコンテキストとして使用してexception.log ファイルに例外が書き込まれない場合、New Relicまたはその他のPSR-3 モノログ互換ログストレージで例外が認識されず、正しく分析されません。 例外の一部のみをログに記録する(または間違ったファイルにログに記録する)と、例外が見落とされたときに本番環境でバグが発生します。
例外処理の修正
次のチェックリストは、正しい例外処理を示す例を示しています。
例外ログへの書き込み
次のパターンを使用して例外ログに書き込みます。追加のアクションに関係なく、書き込まない説得力のある理由がない限り。
try {
$this->productRepository->getById($sku);
} catch (Exception $e) {
$this->logger->critical($e);
}
このアプローチは、PSR-3 コンテキスト標準に従って、ログメッセージに$e->getMessageを、コンテキストに$e オブジェクトを自動的に保存します。 これは\Magento\Framework\Logger\Monolog::addRecordで行われます。
ミュート信号
目的の操作フローの一部である例外をログに記録しないことで、信号をミュートします。 例外が発生した場合にフォローアップアクションは必要ないため、発生したときにログを記録して分析する必要はありません。 シグナルをミュートする理由と、それが意図的であることを示すコメントを追加します。 phpcs:ignoreと組み合わせる。
try {
$this->productRepository->deleteById($sku);
} catch (NoSuchEntityException $e) { // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatch
// Product already removed
}
ダウングレードの例外
PSR-3 コンテキスト標準に従って、例外をダウングレードします。
try {
$this->productRepository->getById($sku);
} catch (Exception $e) {
$this->logger->debug($e->getMessage(), ['exception' => $e]);
}
ログが常に最初に表示されます
ベストプラクティスとして、ログは常にコード内で最初に発生し、ログに書き込む前に別の例外または致命的なエラーがスローされるケースを防ぎます。
try {
$this->productRepository->getById($sku);
} catch (Exception $e) {
$this->logger->critical($e);
$this->alternativeProcedure();
}
ログメッセージと例外トレース全体
PSR-3 コンテキスト標準に従って、メッセージと例外トレース全体を記録します。
try {
$this->productRepository->getById($sku);
} catch (Exception $e) {
$this->logger->critical($e->getMessage(), ['exception' => $e, 'trace' => $e->getTrace()]);
}
誤った例外処理
次の例は、誤った例外処理を示しています。
ログを記録する前の
ロジック
ログを記録する前にロジックを実行すると、別の例外または致命的なエラーが発生する可能性があります。これにより、例外がログに記録されなくなり、正しい例に置き換える必要があります。
try {
$this->productRepository->deleteById($sku);
} catch (NoSuchEntityException $e) {
$this->alternativeProcedure();
$this->logger->critical($e);
}
空のcatch
空のcatch ブロックは、意図しないミュートの兆候である可能性があり、正しい例に置き換える必要があります。
try {
$this->productRepository->deleteById($sku);
} catch (NoSuchEntityException $e) {
}
二重定位
検出されたローカライズされた例外がまだ翻訳されていない場合は、例外が最初にスローされた場所で問題を解決します。
try {
$this->productRepository->getById($sku);
} catch (LocalizedException $e) {
throw new LocalizedException(__($e->getMessage()));
}
ログメッセージとトレースを異なるログファイルに記録する
次のコードは、例外のスタックトレースを文字列としてログファイルに誤って記録します。
try {
$this->productRepository->getById($sku);
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
$this->logger->debug($e->getTraceAsString());
}
この方法では、PSR-3に準拠していないメッセージに改行が発生します。 スタックトレースを含む例外は、メッセージコンテキストの一部として、New Relicまたはその他のPSR-3 モノログ互換ログストレージにメッセージと共に正しく保存できるようにする必要があります。
この問題を修正するには、例外ログに書き込むまたは ダウングレード例外に示す正しい例に従ってコードを置き換えます。
コンテキストのない
ダウングレードの例外
例外はエラーにダウングレードされ、オブジェクトを渡すことができず、文字列のみが渡されないため、getMessage()が返されます。 これにより、トレースが失われ、例外ログへの書き込みまたは ダウングレード例外に示す正しい例に置き換える必要があります。
try {
$this->productRepository->getById($sku);
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
}
例外ログにメッセージのみを記録します
オブジェクト $eを渡す代わりに、$e->getMessage()のみが渡されます。 これにより、トレースが失われ、例外ログへの書き込みまたは ダウングレード例外に示す正しい例に置き換える必要があります。
try {
$this->productRepository->getById($sku);
} catch (\Exception $e) {
$this->logger->critical($e->getMessage());
}
// phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatchがありません
phpcs:ignore行を省略すると、PHPCSで警告がトリガーされ、CIを渡してはなりません。 これは、 ミュート信号に示す正しい例に置き換える必要があります。
try {
$this->productRepository->deleteById($sku);
} catch (NoSuchEntityException $e) {
// Product already removed
}