Introduction
Ledgerly provides a flexible export pipeline that allows audit entries to be transformed before they are written to an external destination.
Entry Transformers allow you to:
- redact or mask sensitive values
- remove internal metadata
- enrich entries with external context
- reshape payloads for ingestion systems
- normalize output for analytics pipelines
Transformers are applied during export and do not modify stored ledger entries.
When Should You Use a Transformer?
Transformers are typically used when:
- exporting audit logs to external systems
- preparing payloads for SIEM ingestion
- sanitizing sensitive information (PII)
- enforcing compliance policies
- adapting audit data for data warehouses
They are not intended for:
- modifying stored ledger entries
- influencing logging behavior
- altering metadata collection
Creating a Transformer
To create a transformer, implement the:
Ledgerly\Core\Contracts\EntryTransformer
interface.
Example
use Ledgerly\Core\Contracts\EntryTransformer;
class RemoveIpAddressTransformer
implements EntryTransformer
{
public function transform(array $entry): array
{
unset($entry['metadata']['ip']);
return $entry;
}
public function getConstructorArgs(): array
{
return [];
}
}
Applying a Transformer
Transformers may be applied at export time:
LedgerExporter::make()
->transformUsing(
new RemoveIpAddressTransformer
)
->usingDriver('file', [
'path' => storage_path('ledger.jsonl'),
])
->export();
Multiple transformers may be chained:
LedgerExporter::make()
->transformUsing(new RemoveIpAddressTransformer)
->transformUsing(new MaskEmailTransformer)
->export();
Transformers are executed in the order they are registered.
Making Transformers Queue-Safe
Queued exports require transformers to be reconstructible.
For this reason, all transformers must implement:
public function getConstructorArgs(): array;
Example:
class MaskFieldsTransformer
implements EntryTransformer
{
public function __construct(
protected array $fields
) {}
public function transform(array $entry): array
{
foreach ($this->fields as $field) {
data_set($entry, $field, '***');
}
return $entry;
}
public function getConstructorArgs(): array
{
return [
'fields' => $this->fields,
];
}
}
This allows Ledgerly to serialize and later reconstruct the transformer during queued export execution.
Automatically Applying Transformers
Transformers may be registered globally via an extension.
Implement:
Ledgerly\Core\Extension\RegistersLedgerlyExtensions
Example Extension
use Ledgerly\Core\Extension\ExtensionRegistry;
use Ledgerly\Core\Extension\RegistersLedgerlyExtensions;
class ComplianceExtension
implements RegistersLedgerlyExtensions
{
public function registerLedgerlyExtensions(
ExtensionRegistry $registry
): void {
$registry->transformer(
MaskFieldsTransformer::class
);
}
}
Registered transformers will automatically be applied to all exports.
Execution Order
Transformer execution order is:
LedgerEntryExport
↓
Extension Transformers
↓
Manually Registered Transformers
↓
Export Driver
This allows:
- global policies to apply automatically
- export-specific overrides to be layered on top
Best Practices
When writing transformers:
- avoid side-effects
- do not perform network calls
- keep transformations deterministic
- ensure constructor arguments are serializable
- treat entries as immutable
- prefer idempotent transformations
Transformers should operate only on the provided entry array and return a modified copy.
Next Steps
See:
- Exporting Guide
- Writing Export Drivers
- Metadata Resolvers
to further customize Ledgerly export behavior.