Admin Action Logs Archive

Published: May 17, 2017

Tags:

The Admin Actions Log a useful feature of both Magento 1 and 2 Enterprise Edition. For those who haven’t seen it before, it offers an audit history of all actions taken by users in the admin panel.

A screenshot showing the admin actions log

As with sales, invoices, credit memos and shipments, Magento Enterprise occasionally archives data recorded to the admin actions log. However, for some reason, the mechanics used for archiving admin actions are completely different from how sales data is handled.

Here I’ll show you how that process works…

Kicking Things Off

The process of kicking off admin actions log archiving is handled by a cron job. In Magento 1 you’ll find the following declaration in app/code/core/Enterprise/Logging/etc/config,xml

<crontab>
    <jobs>
        <enterprise_logging_rotate_logs>
            <schedule>
                <cron_expr>1 2 * * *</cron_expr>
            </schedule>
            <run>
                <model>enterprise_logging/observer::rotateLogs</model>
            </run>
        </enterprise_logging_rotate_logs>
    </jobs>
</crontab>

In Magento 2 you’ll find it in vendor/magento/module-logging/etc/crontab.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="default">
        <job name="magento_logging_rotate_logs" instance="Magento\Logging\Cron\RotateLogs" method="execute">
            <schedule>1 2 * * *</schedule>
        </job>
    </group>
</config>

The Window

In both Magento 1 and 2 the window to archive is managed by the system/rotation/lifetime configuration value. In Magento 2, we can see the following line in Magento\Logging\Cron\RotateLogs::execute

$this->eventFactory->create()->rotate(
    3600 * 24 * (int)$this->_coreConfig->getValue('system/rotation/lifetime', 'default')
);

In vendor/magento/module-logging/etc/config.xml we can see that the lifetime defaults to 60 days.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <system>
            <rotation translate="frequency">
                <lifetime>60</lifetime>
            </rotation>
        </system>
    </default>
</config>

How Admin Actions Are Archived

This is the most interesting thing. Magento handles archiving sales data by deleting records from the _grid tables, and creating new records in _archive tables in the database. However, for some reason, admin actions are archived by writing the data to a log file. The file is then saved to the file system and the records are deleted entirely from the database.

Show Me The Code

The process is the same in both Magento 1 and 2. In Magento 2. If we look at Magento\Logging\Model\ResourceModel\Event::rotate we’ll see the following at the bottom…

$path = $this->directory->getRelativePath($archive->getFilename());
$stream = $this->directory->openFile($path, 'w');
// dump all records before this log entry into a CSV-file
foreach ($rows as $row) {
    $stream->writeCsv($row);
}
$stream->close();

$connection->delete($this->getMainTable(), ['log_id <= ?' => $latestLogEntry]);

$rows refers to the data that will be archived (fetched previously based on $lifetime). As we can see, it is written to a CSV and then deleted.

Where’s The CSV?

Per Magento\Logging\Model\Archive::getBasePath(), we can see that the file will be placed in var/logging/archive

public function getBasePath()
{
    return $this->directory->getAbsolutePath('logging/archive');
}

But Why?

Great question. I have no idea why Magento chose to handle admin actions archiving this way. My best guess is that maybe the dev who built the feature, misinterpreted the task and thought, since the module being worked on is called Enterprise_Logging that the data was supposed to be written to a log file. Another potential reason is due to the fact that there is no _grid table for admin actions log.

Maybe there’s some better reason and this is actually intentional, though.

Conclusion

I hope that some of you found this post helpful. If you have any questions or comments, feel free to drop a note below, or, as always, you can reach me on Twitter as well.

Max Chadwick Hi, I'm Max!

I'm a software developer who mainly works in PHP, but loves dabbling in other languages like Go and Ruby. Technical topics that interest me are monitoring, security and performance. I'm also a stickler for good documentation and clear technical writing.

During the day I lead a team of developers and solve challenging technical problems at Something Digital where I mainly work with the Magento platform. I've also spoken at a number of events.

In my spare time I blog about tech, work on open source and participate in bug bounty programs.

If you'd like to get in contact, you can find me on Twitter and LinkedIn.