Skip to main content
A driver is the component responsible for the final step in the audit pipeline: taking a fully-assembled LogEntry DTO and persisting or dispatching it somewhere. ModelScribe ships with three built-in drivers, each implementing the DriverInterface contract, so they are all interchangeable and composable. The active driver is resolved at runtime by the DriverManager singleton, which caches each resolved instance for the lifetime of the request.

Built-in Drivers

The database driver inserts a row into a database table for each audit event. It is the default driver and the most feature-rich, supporting multi-table routing, multiple DB connections, and configurable retention policies.

Store Resolution

When log() is called, the driver calls its internal resolveStore() method with the entry’s logName. Resolution follows this order:
  1. Named store match. If a key under drivers.database.stores matches the logName, the driver uses that store’s tables (or table) and optional connection.
  2. Global fallback. If no named store matches, the driver writes to the default table on the default connection.
A single named store can target multiple tables via the tables key — the entry is inserted into each table in the list. This is useful for writing the same audit record into both a partitioned archive table and a recent-events table.

Configuration

Retention Policies

The database driver supports three retention modes, configured under retention.type:Pruning is triggered by the model-scribe:prune Artisan command or by calling ModelScribe::prune() from a scheduled job.

Configuring the Default Driver

Set the default key to the name of the driver you want used for all models that do not specify their own:
You can also set it via the MODEL_SCRIBE_DRIVER environment variable without touching the config file, which is useful for switching drivers per environment.

Overriding the Driver Per Model

A model can opt into a different driver by setting the $auditDriver property in the HasAuditLog trait:
When $auditDriver is null (the default), the global default driver from config is used.

Custom Drivers

If the three built-in drivers do not cover your requirements — for example, you want to ship audit events to Elasticsearch, a message queue, or a webhook — you can register a custom driver using DriverManager::extend().

1. Implement DriverInterface

Your driver must implement the two-method DriverInterface contract:

2. Register via extend()

Call extend() on the DriverManager inside a service provider’s boot() method. The closure receives the driver’s config array and the DriverManager instance, and must return a DriverInterface implementation:

3. Add the Driver Config Block

Add a matching entry under drivers in config/model-scribe.php:
The driver key inside the config block tells the DriverManager which registered creator to invoke when building this named driver instance. You can then set 'default' => 'elasticsearch' or use protected ?string $auditDriver = 'elasticsearch' on individual models.