Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Specification: the audit event model

This page is the technical summary of the audit trail introduced on 2026-10-02: event names, the record format, channels, files, checkpoints, archives, the database index, the classes, the settings and the extension…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/specifications/6.0/audit-event-model.md

On this page

Specification: the audit event model

This page is the technical summary of the audit trail introduced on 2026-10-02: event names, the record format, channels, files, checkpoints, archives, the database index, the classes, the settings and the extension points. Read it if you operate the audit trail, connect it to a log system, or record events from your own extension. The authoritative, much longer text is Audit; the user-level introduction is the audit trail.

In short

  • Every event has a dotted name, domain.subject.action[.detail], and lands in one of five channels.
  • Each channel is a hash chain of JSON lines, one file per channel and UTC day, under var/<site>/log/audit/.
  • ./console exp:audit verify proves a chain is intact; exit code 0 means intact.
  • Passwords, tokens and secrets are never recorded.

Example: follow and verify the log

Run in the installation root:

./console exp:audit status                       # the channels and their state
./console exp:audit tail --channel=access --lines=20
./console exp:audit verify --channel=content     # exit code 0 intact, 1 broken chain, 2 refused or error

The same commands run as php bin/php/audit.php <action>. Other actions: channels, show <event id>, checkpoint; tail also takes --name=access.*, --follow and --json, and verify takes --date=YYYY-MM-DD.

Data model

ElementDefinition
Event namedomain.subject.action[.detail], from a taxonomy registry of 135 names (expAuditTaxonomy). Can be switched on or off at any level (content.*, content.node.remove.*)
RecordA JSON object: actor, verb, object, target, result, before and after values, parent and child event ids, request id, session, job and run ids. Canonical JSON; carries the hash of the previous record of its channel
Channelcontent, access, system, commerce (also holds data.*), read. Routed by [AuditChannelSettings] Route[]: content.* to content, content.node.view to read, data.* to commerce; default channel system
FileOne JSON-lines file per channel and UTC day, var/<site>/log/audit/<channel>-<date>.jsonl; a new part past MaxFileSize. The first write of a new day appends system.audit.file.close to the previous file
CheckpointSigned head of each channel's chain (daily maintenance, exp:audit checkpoint)
ArchiveA compressed day with a manifest signed by HMAC (key id, link to the manifest before it). Formats: gzip, bzip2, xz, zstd, zip
IndexTables expaudit_event, expaudit_cursor, expaudit_file in the site database

expaudit_event holds one row per record, with the columns id, channel, seq, name, severity (0 to 7), time_ms, request_id, user, object, target, result, parent_id, depth, job_id, run_id, imported, pseudonymised, record, search_text.

Keys (installation id, signing key, pseudonym key) are generated on first use into settings/override.

Privacy defaults: addresses are truncated, sessions hashed, user agents shortened and query values removed. Passwords, tokens and secrets are never recorded.

Classes (kernel/classes/audit/)

ClassRole
expAuditRecord an event
expAuditBuffer, expAuditWriterOne append per channel at the end of the request, with a lock per channel so PHP-FPM, Velocity and commands never interleave
expAuditHookThe one guarded way kernel code records an event; builds the data only when the name is switched on
expAuditBridgeRecords existing ezpEvent events, mapped by [AuditBridgeSettings] Bridge[]
expAuditVerifierChecks the hash chains
expAuditKeys, expAuditConfig, expAuditPrivacy, expAuditReader, expAuditGuardKeys, settings, privacy rules, reading, access checks

Subdirectories: hook/, bridge/, sinks/, alerts/, archive/, format/, index/, console/.

Settings (settings/audit.ini)

BlockKeyDefaultScope
AuditSettingsAuditenabledinstallation; disabled raises an alert
AuditSettingsLogDirlog/auditinstallation
AuditSettingsOnWriteFailurecontinueinstallation
AuditSettingsRefuseExemptViews[]user/login, user/logoutinstallation
AuditEventSettingsEnabled[] / Disabled[]on: access.*, system.*, selected content.*, commerce.*, data.*; off: access.session.regenerate, access.session.expireinstallation
AuditChannelSettingsChannels[], Route[], DefaultChannelthe five channels; systeminstallation
AuditChannel_<name>LiveDays, ArchiveDays, MaxFileSize, ArchiveFormat90, 730, 64M, gzip (read: 30, 90, 256M, zstd)per channel
AuditChannel_<name>Sinks[]access and system use the syslog sinkper channel

Other blocks of the same file: [AuditRecordSettings], [AuditPrivacySettings], [AuditBufferSettings], [AuditChainSettings], [AuditKeySettings], [AuditReadSettings], [AuditSinkSettings], [AuditAlertSettings]; sink blocks [AuditSink_<name>] (syslog, webhook, mail); alert rule blocks [AlertRule_<name>] (for example [AlertRule_brute_force]); recipient groups [AlertRecipients_<name>].

Read a value with:

./console exp:ini get audit.ini/AuditChannel_read/LiveDays --allow-root-user

Expected output: 30, unless an override changes it.

Extension points

PointHow
Taxonomy branch[AuditEventSettings] Branches[<name>]=<class implementing expAuditTaxonomyBranch>. An extension registers its own event names; the RAD survey counts them as auditbranches
SinkA class implementing expAuditSink
Alert ruleA class implementing expAuditAlertRule (threshold, match, schedule)
Archive format[AuditArchiveSettings] FormatHandlers[]. Each handler reports what it needs; the registry falls back to gzip

The RAD survey (Setup > RAD, setup/rad) counts the four audit registries.

Interfaces

InterfaceDetails
Console./console exp:audit <action>; exit codes 0 intact, 1 broken chain, 2 refused or error
Admin viewsaudit/dashboard, audit/console, audit/event, charts, alerts, export, archives, settings, audit/recent
Policiesaudit/read (limitation Channel), audit/manage
Template fetch functionsevents, event, count, chain_status, can_read (empty without audit/read)
Template operatoraudit_label
Response headerEvery web response carries X-Exp-Request-Id; each record the request wrote stores the same id
Cronjob partcronjobs/audit.php (class Exponential\Cronjob\Kernel\Audit), in its own group and in frequent
Remote servicesThe read-only expaudit domain of expservices

Create the tables on an existing installation

php update/common/scripts/6.0/createaudittables.php

It works on every engine, Oracle and MongoDB included. It leaves existing tables alone and indexes the files written so far.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x