Logs are your first line of defense when something goes wrong in production. But in a default Magento 2 installation, the logging setup is often either too noisy — filled with warnings that don't matter — or too quiet, missing the errors that actually need attention. Getting logging right is a force multiplier for your whole operations workflow.
This guide covers how Magento 2 logging works under the hood, what you should configure, what to ignore, and how to build a lean, actionable logging setup.
How Magento 2 Logging Works
Magento uses Monolog as its logging library. Log channels are defined as virtual types in di.xml, and each module can register its own logger instance. By default, most logging goes to var/log/system.log and var/log/exception.log, but individual modules write to their own files:
-
var/log/system.log— general system messages -
var/log/exception.log— PHP exceptions caught by Magento -
var/log/debug.log— debug-level messages (should be disabled in production) -
var/log/cron.log— cron job execution -
var/log/payment.log— payment-related activity -
var/log/shipping.log— shipping carrier requests and responses
Each of these can grow very large, very fast on a busy store.
Step 1: Disable Debug Logging in Production
This one is critical. Magento's debug mode logs an enormous amount of data — request parameters, SQL queries, observer calls — and it should never be enabled in production.
Check your current setting:
php bin/magento config:show dev/debug/debug_logging
Disable it:
php bin/magento config:set dev/debug/debug_logging 0
php bin/magento cache:flush
Also check var/log/debug.log — if it exists and is growing, that's your culprit. On a high-traffic store this file can reach several GB within hours.
Step 2: Implement Log Rotation
Magento does not rotate logs automatically. Without rotation, log files will grow indefinitely until your disk fills up — and that will take your store down.
Use logrotate on Linux. Create /etc/logrotate.d/magento:
/var/www/html/var/log/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 664 www-data www-data
sharedscripts
postrotate
/usr/bin/find /var/www/html/var/log -name "*.log" -mtime +14 -delete
endscript
}
Adjust the path and user to match your setup. This keeps 14 days of compressed logs and removes anything older.
You can also clean old logs via Magento's built-in cron task. Check app/etc/crontab.xml — the log_clean job runs and cleans database logs (customer log, quote log), but not file-based logs in var/log/. That's still your responsibility.
Step 3: Fix Third-Party Module Log Spam
A very common problem: a third-party module logs aggressively at WARNING or INFO level for things that aren't actually problems. These entries flood your logs and make it hard to spot real issues.
To identify noisy modules, look at what's filling your system.log:
grep -oP 'main\.\w+' var/log/system.log | sort | uniq -c | sort -rn | head -20
Or check by log level:
grep -c 'WARNING' var/log/system.log
grep -c 'ERROR' var/log/system.log
grep -c 'CRITICAL' var/log/system.log
If WARNING vastly outnumbers ERROR and CRITICAL, you have log spam. Track it to the source:
grep 'WARNING' var/log/system.log | grep -oP 'in .*\.php' | sort | uniq -c | sort -rn | head -10
Once identified, you have two options:
-
Raise the minimum log level for that module's handler in
di.xml - Open a support ticket with the extension vendor — this is their bug, not yours
Step 4: Set Minimum Log Level Per Handler
You can configure the minimum severity level for Magento's default log handlers via di.xml. Add this to your module or app/etc/di.xml:
<type name="Magento\Framework\Logger\Handler\System">
<arguments>
<argument name="fileName" xsi:type="string">/var/log/system.log</argument>
<argument name="loggerType" xsi:type="number">400</argument>
</arguments>
</type>
The loggerType corresponds to Monolog levels:
-
100= DEBUG -
200= INFO -
250= NOTICE -
300= WARNING -
400= ERROR -
500= CRITICAL
Setting 400 (ERROR) means WARNING and below will be ignored. This is a reasonable production default for system.log.
Step 5: Write Better Custom Logs
If you're developing a custom module, follow these guidelines to write logs that are actually useful:
Use the right level:
$this->logger->debug('Processing item', ['id' => $itemId]); // dev only
$this->logger->info('Order exported', ['order' => $orderId]); // informational
$this->logger->warning('Fallback used', ['reason' => $msg]); // worth noting
$this->logger->error('Export failed', ['exception' => $e]); // needs attention
$this->logger->critical('Payment gateway down', [...]); // wake someone up
Always include context:
// Bad
$this->logger->error('Failed to process order');
// Good
$this->logger->error('Failed to process order', [
'order_id' => $order->getIncrementId(),
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
Context arrays are serialized to JSON in the log line, making them searchable and parseable by log aggregators.
Use a dedicated log channel for your module:
<!-- di.xml -->
<virtualType name="MyModule\Logger\Handler" type="Magento\Framework\Logger\Handler\Base">
<arguments>
<argument name="fileName" xsi:type="string">/var/log/mymodule.log</argument>
</arguments>
</virtualType>
<virtualType name="MyModule\Logger\Logger" type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="name" xsi:type="string">mymodule</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">MyModule\Logger\Handler</item>
</argument>
</arguments>
</virtualType>
This keeps your logs isolated from Magento core logs and makes debugging much faster.
Step 6: Monitor Critical Logs
Logging is only useful if someone reads the logs. In production, set up alerting:
-
Simple option: Use a cron job that runs
grep -c CRITICAL var/log/system.logand sends an alert if the count increases - Better option: Ship logs to a centralized service like Papertrail, Logtail, Datadog, or Elasticsearch + Kibana
- Best option: Use structured JSON logging so your log aggregator can parse fields properly
For JSON logging in Magento, you can replace the default formatter:
<type name="Magento\Framework\Logger\Handler\System">
<arguments>
<argument name="formatter" xsi:type="object">Monolog\Formatter\JsonFormatter</argument>
</arguments>
</type>
JSON logs are harder to read manually but much easier to query, filter, and alert on.
Step 7: Don't Log Sensitive Data
This sounds obvious but it happens — especially with payment modules. Never log:
- Credit card numbers or CVV codes
- Full customer passwords or tokens
- API keys or secrets
- Full HTTP request bodies from payment endpoints
If you need to log payment-related activity for debugging, log only order IDs, masked card data (last 4 digits), and response codes. Many PCI DSS compliance failures originate in log files.
Quick Wins Checklist
- [ ]
dev/debug/debug_logging= 0 in production - [ ]
logrotateconfigured forvar/log/*.log - [ ]
var/log/debug.logdoesn't exist or is empty - [ ] System log filtered to ERROR level minimum
- [ ] Third-party log spam identified and addressed
- [ ] Critical log monitoring / alerting in place
- [ ] No sensitive data in any log file
Conclusion
Good logging discipline makes the difference between a 5-minute incident response and a 5-hour debugging session. On Magento 2, the defaults are not production-ready — you need to actively configure log levels, implement rotation, suppress noise, and make sure critical errors reach the right people.
Invest 30 minutes into your logging setup now and you'll save hours when something inevitably goes wrong.
Top comments (0)