ARTICLE

Magento 2 Logging Explained: system.log, exception.log, debug.log, Custom Monolog Channels, and Log Rotation

Magento 2 Logging Explained: system.log, exception.log, debug.log, Custom Monolog Channels, and Log Rotation

Magento 2 logs through Monolog behind the PSR-3 LoggerInterface. By default it writes INFO and above to var/log/system.log, exceptions to var/log/exception.log, and DEBUG messages to var/log/debug.log only outside production mode. Database query logging and syslog are opt-in CLI switches, and Magento never rotates its own log files.

That last point is where most stores get into trouble. Logs that nobody reads grow until a disk fills, and logs that everybody reads are full of noise that hides the one line that matters. This guide covers what each file actually contains, how to turn the optional logs on and off, how to give a custom module its own channel without writing a new PHP class, and how to keep log volume under control on a busy Adobe Commerce or Magento Open Source store.

How Magento 2 logging is wired

Adobe’s custom logging overview states that Commerce complies with PSR-3 and uses Monolog by default, with Monolog set as the implementation of Psr\Log\LoggerInterface in the application’s di.xml. In practice that means three things for anyone writing or debugging code:

  1. Your classes should ask for Psr\Log\LoggerInterface in the constructor. Never pull a logger from the ObjectManager.
  2. What you get is Magento\Framework\Logger\Monolog, a Monolog logger (a “channel”) with a stack of handlers attached.
  3. Each handler decides whether a message is for it, based on level, and writes it somewhere. Magento’s own handlers live in Magento\Framework\Logger\Handler and extend Monolog’s stream handler.

Monolog’s model is simple. A channel has a name and an ordered list of handlers. A message travels down the list, and each handler either writes it and stops the bubble, or writes it and passes it on. Adobe’s documentation gives the classic example of debug output going to a file, higher levels going to a database, and critical messages going out by email. Magento ships the file part and leaves the rest to you.

What lands in each log file

The default handlers map to a small set of files under var/log/, plus two optional ones. Use the table below as a quick reference when someone pastes “the logs” into a ticket and you need to know where to look first.

File Written by When it is written What to look for
var/log/system.log Handler\System INFO and above, all modes Warnings from core and extensions, failed integrations, configuration problems
var/log/exception.log Handler\Exception Any log call that carries an exception in its context Full stack traces for errors the request or cron survived
var/log/debug.log Handler\Debug DEBUG level, default and developer mode only (unless enabled) Verbose diagnostics from core and modules
var/log/cron.log Cron channel Every cron run (since 2.3.1) Job start, finish and failure lines, separate from system.log
var/debug/db.log Query logger Only after dev:query-log:enable Every SQL statement, timing, bindings
var/report/ Error processor Uncaught errors that reach the error page The report number a shopper sees on “There has been an error processing your request”
OS syslog Syslog handler Only after --enable-syslog-logging=true Same messages, routed to the operating system log

A few details are worth knowing because they trip people up:

  • exception.log is not “errors only.” It receives any message whose context includes an exception object, at whatever level the caller chose. A module that catches an exception and logs it at notice with the exception attached still produces a stack trace in exception.log.
  • system.log is noisy by design. Third-party extensions often log routine information at INFO. On a store with dozens of modules, system.log can grow by hundreds of megabytes a week without anything being wrong.
  • var/report is a separate system. When a shopper sees an error page with a report ID, the matching file is in var/report/, not in exception.log. Check both.
  • cron.log was split out deliberately. Adobe’s logging configuration guide notes that the separate cron log arrived in 2.3.1 so cron output stops lengthening system.log. If you are chasing a cron problem, that is where to start. Our guide to Magento 2 cron groups and the cron_schedule backlog covers what those lines mean.

Turning debug, database and syslog logging on and off

All three optional logs are controlled from the CLI, and all three need a cache flush to take effect. These commands come straight from Adobe’s documentation.

Debug logging. Commerce writes debug.log in default and developer mode but not in production mode. To force it on in production while you investigate a problem:

bin/magento setup:config:set --enable-debug-logging=true
bin/magento cache:flush

Turn it off the same way with =false. Adobe notes that as of 2.3.1 the old bin/magento config:set dev/debug/debug_logging path no longer works for this, which is why older tutorials that use it appear to do nothing.

Database query logging. This writes every query, its execution time, its parameters and bindings to var/debug/db.log:

bin/magento dev:query-log:enable
bin/magento cache:flush

Disable it with dev:query-log:disable. Adobe warns that the file can grow quickly on high-traffic sites. On a production store, treat this as a five-minute tool: enable, reproduce the problem, disable, then read the file offline. Leaving it on during a sale is an easy way to fill a disk. If you need query-level insight on production for longer than that, an APM is the better tool, and our walkthrough on profiling a slow Magento 2 request with Blackfire, Xhprof and New Relic shows how to get there without logging every statement.

Syslog. Disabled by default. Enable with bin/magento setup:config:set --enable-syslog-logging=true and flush cache. Adobe notes the Admin setting for this was removed in 2.3.1, so the CLI is the only route.

One production gotcha: these setup:config:set switches write to app/etc/env.php. If your deployment pipeline regenerates env.php from a template, a flag you set by hand on the server will be overwritten on the next release. Put the flag in the template, or expect it to vanish.

Giving a module its own log file with a custom Monolog channel

Most custom modules should not write to system.log. When a payment integration or ERP sync misbehaves, you want its messages in one file, not interleaved with every extension on the store. You can do this entirely in di.xml using virtual types, with no new PHP classes.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <virtualType name="Vendor\ErpSync\Logger\Handler" type="Magento\Framework\Logger\Handler\Base">
        <arguments>
            <argument name="fileName" xsi:type="string">/var/log/erp_sync.log</argument>
        </arguments>
    </virtualType>

    <virtualType name="Vendor\ErpSync\Logger" type="Magento\Framework\Logger\Monolog">
        <arguments>
            <argument name="name" xsi:type="string">erp_sync</argument>
            <argument name="handlers" xsi:type="array">
                <item name="file" xsi:type="object">Vendor\ErpSync\Logger\Handler</item>
            </argument>
        </arguments>
    </virtualType>

    <type name="Vendor\ErpSync\Model\OrderExporter">
        <arguments>
            <argument name="logger" xsi:type="object">Vendor\ErpSync\Logger</argument>
        </arguments>
    </type>
</config>

What this does:

  • The first virtual type is a file handler pointed at var/log/erp_sync.log. The path is relative to the Magento root.
  • The second virtual type is a new Monolog channel named erp_sync that uses only that handler. The channel name appears in every line, which makes grepping across files reliable.
  • The type block injects the new channel into one class’s logger constructor argument. That class still type-hints Psr\Log\LoggerInterface, so it stays testable and portable.

Because the handlers array only contains your file handler, nothing from this channel reaches system.log. If you want errors to appear in both places, add Magento’s system handler as a second item. If you have never used virtual types, our explainer on Magento 2 virtual types in di.xml covers the syntax and when a virtual type beats a preference or a plugin.

After adding or changing di.xml, run setup:di:compile in production mode, or the old object graph keeps serving.

Writing log calls that stay useful

The file layout matters less than what goes into it. These rules keep custom-module logs readable.

Use PSR-3 placeholders and context, not string building. $this->logger->error('ERP export failed for order {increment_id}', ['increment_id' => $id, 'exception' => $e]); keeps the message stable for grepping and lets handlers format the context. String concatenation also runs even when the level is filtered out.

Pass the exception object under the exception key. That is what routes a stack trace to exception.log and keeps the message line short.

Pick levels on purpose.

  • debug: values you only need while developing or reproducing a bug.
  • info: normal business events worth an audit trail, such as “exported 412 orders.”
  • warning: something recovered but should not keep happening, such as a retry.
  • error: an operation failed and the merchant or a person needs to know.
  • critical and above: the store or a core flow is broken.

Never log inside a tight loop. A catalog import that logs one line per SKU produces a file nobody can read. Count successes and failures, log one summary, and log the first handful of failures in detail.

Keep personal and payment data out. Do not log full request or response bodies from payment, customer or address APIs. Log identifiers, status codes and timings. If you must log a payload while debugging, mask names, emails, addresses, tokens and card data before the call, and remove the line before the code ships. Logs get copied to laptops, tickets and third-party tools far more casually than databases do.

Log rotation and retention

Magento writes to its log files and never truncates them. Rotation is an operating system job, and the right answer depends on where you host.

Self-managed servers. Use logrotate with a file in /etc/logrotate.d/. A sensible starting point for var/log/*.log is daily rotation, compression, two to four weeks of history, and copytruncate so PHP-FPM workers holding the file open keep writing to the same handle. Test the config with logrotate -d before trusting it, and include var/debug/db.log in case someone forgets to disable query logging.

Adobe Commerce on cloud infrastructure. Adobe’s cloud log locations reference states that Pro Staging and Production application logs are archived daily, compressed and kept for 30 days by default, and retention can be raised to 365 days through a support ticket. It also notes that Pro Integration and Starter environments have no log rotation, so you need your own script and cron job there. Deploy and post-deploy logs are never rotated.

Where the files are on cloud. On Pro Staging and Production, platform logs live under /var/log/platform/<project-ID>/ (with _stg for staging), while application logs such as exception.log and system.log stay in the app’s var/log/. Adobe also notes that cron, deploy and post-deploy logs exist only on the first node, and other logs are node-specific, so check every node before deciding a message is missing.

Hosting Who rotates Default retention What you must add
Self-managed or VPS You, via logrotate None A logrotate config for var/log and var/debug
Adobe Commerce Cloud Pro Staging and Production Platform 30 days, compressed Nothing, unless you need longer retention
Adobe Commerce Cloud Pro Integration Nobody None Your own script and cron job
Adobe Commerce Cloud Starter Nobody None Your own script and cron job

When file logs stop being enough

Files on each web node are fine for a single server. Once a store runs several web nodes, separate cron and consumer servers, or a CDN in front, reading logs file by file stops working. Adobe’s guidance recommends centralized logging so logs are stored somewhere other than the application server, and names Logstash, Logplex and fluentd as example tools without endorsing one.

The practical path is to keep Magento writing local files, ship them with an agent to a central store, and alert on patterns: a spike in exception.log lines, any critical from the checkout or payment channels, or cron.log going quiet. That is a monitoring conversation more than a logging one, and our piece on Adobe Commerce observability, APM, logging and SLAs goes further into what to alert on.

A short triage routine

When a merchant says “something is broken,” work through the logs in the same order every time:

  1. Get the time and the URL of the failure. Without a time window, every log is too long to read.
  2. Check var/report/ if the shopper saw an error page with a report number.
  3. Check exception.log for stack traces in that window.
  4. Check system.log for warnings just before it, which often show the cause rather than the symptom.
  5. Check cron.log if the issue involves prices, stock, emails, indexes or anything that should have “happened by itself.”
  6. Check the module’s own channel if it has one. This is the payoff for setting up custom channels.
  7. Only then enable debug or query logging, reproduce once, and turn it straight back off.

How Bemeir handles logging on client stores

Bemeir is a Brooklyn Magento, Adobe Commerce and Hyva agency. As part of Magento development services, the logging checklist above applies to any build: per-module log channels for integrations, rotation that matches the hosting model, and a short runbook so the in-house team knows which file to open first. On Hyva development services projects, the server-side logging story is the same as Luma, since Hyva changes the frontend, not Magento’s logger. What changes is that frontend errors now come from Alpine.js components in the browser, which never reach var/log, so server logs should be paired with browser error tracking.

The same principles apply on the other platforms we build for, though the tools differ. A Shopify development project has no server log to rotate, while Shopware development also uses Monolog channels and benefits from the same discipline. BigCommerce development work pushes most logging into the apps and middleware you own. For log platforms, APM and error tracking, see the vendors listed among the Bemeir technology partners. You can read more about how the team works on the About Bemeir page.

FAQ

Where are the Magento 2 log files?

Under var/log/ in the Magento root: system.log, exception.log, debug.log (outside production mode, or when enabled) and cron.log. Query logging writes to var/debug/db.log when enabled, and error page reports go to var/report/. On Adobe Commerce Cloud Pro, platform logs are under /var/log/platform/<project-ID>/.

Why is debug.log empty in production mode?

Commerce only writes debug.log in default and developer mode. To enable it in production, run bin/magento setup:config:set --enable-debug-logging=true and flush cache. Since 2.3.1 the old config:set dev/debug/debug_logging command no longer controls this.

How do I create a custom log file in Magento 2?

Declare a virtual type of Magento\Framework\Logger\Handler\Base with a fileName argument, a virtual type of Magento\Framework\Logger\Monolog that uses that handler, and inject the new channel into your class’s logger argument in di.xml. No new PHP class is needed.

Does Magento rotate its own log files?

No. Magento appends to its logs indefinitely. Use logrotate on self-managed servers. Adobe Commerce Cloud Pro Staging and Production rotate and keep 30 days by default, while Pro Integration and Starter have no rotation and need your own script.

Is it safe to leave database query logging on?

Not on production. The db.log file records every query with bindings and can grow very quickly under traffic. Enable it, reproduce the issue, disable it, and analyze the file offline. Use an APM for ongoing query visibility.

Let us help you get started on a project with Magento 2 Logging Explained: system.log, exception.log, debug.log, Custom Monolog Channels, and Log Rotation and leverage our partnership to your fullest advantage. Fill out the contact form below to get started.

more articles about ecommerce

Read on the latest with Shopify, Magento, eCommerce topics and more.