1. Create Plugin for ProductRepositoryInterface
In example also creates additional logger to write exception to separate file
app/code/Acme/StackExchange/etc/di.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Create Virtual Logger -->
<virtualType name="Acme\StackExchange\Model\VirtualLoggerHandler" type="Magento\Framework\Logger\Handler\Base">
<arguments>
<argument name="fileName" xsi:type="string">/var/log/acme_stackexchange.log</argument>
</arguments>
</virtualType>
<virtualType name="Acme\StackExchange\Model\VirtualLogger" type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">Acme\StackExchange\Model\VirtualLoggerHandler</item>
</argument>
</arguments>
</virtualType>
<!-- Register Plugin -->
<type name="Magento\Catalog\Api\ProductRepositoryInterface">
<plugin name="Acme_StackExchange_Plugin_Catalog_Model_ProductRepositoryPlugin"
type="Acme\StackExchange\Plugin\Catalog\Model\ProductRepositoryPlugin" sortOrder="10"/>
</type>
<!-- Pass Virtual Logger to Plugin -->
<type name="Acme\StackExchange\Plugin\Catalog\Model\ProductRepositoryPlugin">
<arguments>
<argument name="logger" xsi:type="object">Acme\StackExchange\Model\VirtualLogger</argument>
</arguments>
</type>
</config>
2. Create a Plugin
app/code/Acme/StackExchange/Plugin/Catalog/Model/ProductRepositoryPlugin.php
<?php
declare(strict_types=1);
namespace Acme\StackExchange\Plugin\Catalog\Model;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Exception\CouldNotSaveException;
use Psr\Log\LoggerInterface;
class ProductRepositoryPlugin
{
protected LoggerInterface $logger;
public function __construct(
LoggerInterface $logger
) {
$this->logger = $logger;
}
public function aroundSave(
ProductRepositoryInterface $subject,
callable $proceed,
ProductInterface $product,
$saveOptions = false
): ProductInterface {
try {
return $proceed($product, $saveOptions);
} catch (CouldNotSaveException $e) {
if ($e->getPrevious()) {
$this->logger->critical($e->getPrevious());
}
throw $e;
}
}
}