Log and data retention
This page is for the system administrators and compliance staff of a host. It lists, for every log and record an
Exponential site keeps, the default retention, the setting that changes it, and what enforces it. Use it to write the
retention section of a plan description, or to answer a customer whose privacy notice states a period. Settings are
changed in overrides (settings/override/<file>.ini.append.php); clear the INI cache afterwards.
Note
Which periods are right is a legal and business decision of the host and the customer, not of the software. This page is not legal advice (Compliance and GDPR).
Contents
- At a glance
- Kernel logs
- Request, security and CSP logs
- Velocity's logs
- The audit trail
- Mail consent and suppression
- Content and sessions
- What the host owns
- Checklist
At a glance
| Data | Default retention | Setting | Enforced by |
|---|---|---|---|
error.log, warning.log, notice.log, debug.log, storage.log ... | 3 archives, rotated at 2 MB; no age limit | site.ini [FileSettings] LogFileRotateCount, LogFileMaxSize, LogFileMaxAge (0) | the writer; exp:logs --prune; cronjob part logs |
404.log | 5 archives, 10 MB, pruned after 30 days | logviewer.ini [RotationSettings] key 404 | cronjob part logs, exp:logs |
security.log | 5 archives, 10 MB, pruned after 90 days | key security | the same |
csp.log | 5 archives, 10 MB, pruned after 30 days | key csp | the same |
| Velocity access and error logs | rotated by date | velocity.ini [LogSettings] | the engine |
Audit, channels content, access, system, commerce | 90 days live, 730 days archived | audit.ini [AuditChannel_<channel>] LiveDays, ArchiveDays | cronjob part audit (daily) |
Audit, channel read (off by default) | 30 days live, 90 archived | [AuditChannel_read] | the same |
| Audit index | 730 days; pseudonymised after 90 | [AuditIndexSettings] KeepDays; [AuditPrivacySettings] PseudonymiseAfterDays | the same |
| Mail consent log of people who are gone | 1095 days | mailpreferences.ini [ConsentSettings] RetentionDays | cronjob part mailpreferences |
| Pending mail confirmations | 7 days | [ConsentSettings] PendingDays | the same |
| Suppression list | kept (0) | [SuppressionSettings] RetentionDays | the same, when above 0 |
| Trash | purged whole when the cronjob runs (empty value) | content.ini [TrashSettings] KeepItemsForDays | cronjobs/trashpurge.php, when scheduled |
| Finished content jobs | 30 days | content.ini [ContentJobSettings] KeepDays | cronjob part contentjobs |
| Sessions | SessionTimeout 31104000 s (360 days) | site.ini [Session] | PHP's session GC; bin/php/ezsessiongc.php on demand |
Kernel logs
When a log outgrows LogFileMaxSize (2 MB), the next write rotates it and the archives beyond LogFileRotateCount (3)
are removed. LogFileMaxAge (0, no limit) adds an age limit that a prune applies; LogFileCompress=enabled
compresses archives from .2 on (Log rotation). Per log, by its key:
# settings/override/logviewer.ini.append.php
[RotationSettings]
Keep[error]=10
MaxAgeDays[error]=90
Compress[error]=enabledOn demand, or nightly as the site's user:
./console exp:logs --prune --dry-run
./console exp:logs --apply --prune
# crontab: 15 3 * * * cd /var/www/vhosts/<domain>/<installation> && php runcronjobs.php -q logsThe cronjob part logs is in no default group, so it runs only when scheduled. If the system's logrotate manages
var/log instead, set LogFileRotateCount=0 so the kernel does not rotate as well. Each change made by the part is
recorded in the audit trail.
Request, security and CSP logs
These ship with their own limits in logviewer.ini [RotationSettings] (keys 404, security, csp: MaxSize
10485760, Keep 5, Compress enabled, MaxAgeDays 30, 90 and 30). To keep security.log longer
(Request logs):
# settings/override/logviewer.ini.append.php
[RotationSettings]
Keep[security]=10
MaxAgeDays[security]=365Velocity's logs
Velocity writes <siteaccess>-access.log and <siteaccess>-error.log below var/vc/qbix/log/ ([LogSettings] Dir),
in Apache's combined format, with modes 0640 and 0750. Rotation puts the date before the extension
(site-access.2026-09-24.log) (8.3.12 Logs). The repository
documents no age limit for these dated files; remove old ones with your own scheduled job, at the period your plan
states.
The audit trail
Per channel in [AuditChannel_<channel>]: LiveDays (uncompressed) and ArchiveDays (kept as archives). The shipped
channel blocks set both values, so set them per channel, not in [AuditRotationSettings]
(4.3 Retention):
# settings/override/audit.ini.append.php: one year of archives instead of two
[AuditChannel_content]
ArchiveDays=365
[AuditChannel_access]
ArchiveDays=365
[AuditChannel_system]
ArchiveDays=365
[AuditChannel_commerce]
ArchiveDays=365- Removal is automatic, daily, and each removal is itself recorded.
- Retention never removes a signing key:
exp:audit purgenames the keys retained archives still need. Keep everySigningKey[]as long as the archives it signed. - Long retention (for example ten years on write-once storage) is the compliance configuration; minimal retention with hashed fields is the strict-privacy configuration.
- Records forwarded by a sink are kept by the receiving system under its own rules.
Mail consent and suppression
The cronjob part mailpreferences (group infrequent) removes the consent log rows of people who are gone once they
are older than RetentionDays (1095 days: the account's lifetime plus three years), removes confirmations that waited
longer than PendingDays (7), and, when [SuppressionSettings] RetentionDays is above 0, old suppression entries
(9. Retention and the cronjob).
./console exp:mail:consent cleanup --dry-run
php runcronjobs.php mailpreferencesKeep in mind that removing a suppression entry lets optional mail reach that address again if the person had switched it on before.
Content and sessions
- Trash:
[TrashSettings] KeepItemsForDaysempty or0means thetrashpurgecronjob (cronjobs/trashpurge.php) purges the whole trash, as before; a number keeps items that many days (up to 36500).bin/php/trashpurge.phptakes--trashed-days=<days>. - Content jobs: finished jobs are removed after
[ContentJobSettings] KeepDays=30(0keeps them). - Sessions:
SessionTimeout(31104000 seconds, 360 days) setssession.gc_maxlifetimewith PHP's own session handler;bin/php/ezsessiongc.phpremoves expired sessions as defined bySessionTimeouton demand. - Versions and drafts of content follow the content settings of the site; they are content, and their retention is the customer's editorial decision.
What the host owns
- Backups hold everything above, including logs and personal data, for as long as the backup is kept. Decide backup retention together with these periods (Backup schedules and retention).
- Web server, PHP-FPM, panel and mail server logs are outside Exponential; their retention is the host's configuration.
- Central log platforms and SIEMs that receive audit sinks or log copies keep them under their own rules.
- Exported files (audit exports, consent CSVs, data-subject exports in
var/tmp/) should be deleted when the request they answer is done.
Checklist
- To do: The retention of each row of the table above decided and written into the plan description.
- To do: Cronjob groups
frequentandinfrequentrunning; thelogspart scheduled if age limits are wanted. - To do:
LogFileMaxAgeor per-logMaxAgeDaysset where the plan states a period for kernel logs. - To do: Velocity's dated log files removed by a scheduled job at the stated period.
- To do: Audit
ArchiveDaysper channel agreed with the customer; signing keys kept as long as archives. - To do: Backup retention aligned with the log and data periods.
- To do: Exported personal data deleted after use.
Related pages
- Security for hosts: overview
- Compliance and GDPR
- Log viewer and rotation
- Audit trail
- Log rotation and pruning
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.