# Record action audit events with a native audit sink

> Observe the audit option and explicit $.audit() calls without contacting a logging service or writing sensitive input to an application log.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: en
Content-SHA256: b949a031d439b733931dd095add9923cac6304897ab4528084ca59651f89a176
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

An action can set `audit` to a text template. On successful completion, the framework sends an audit record to `DEF.onAudit(name, data, context)`. The automatic record uses the sink name `actions` and includes the action id. An action can also call `$.audit(message, type)` explicitly; this emits its own record and can carry a type such as `info`.

The example replaces the audit sink with an in-memory collector to inspect its contract. It records only the name, action id, message and type. The framework also prepares contextual data and serialized request data: a real sink needs an explicit policy for secrets, retention, access and failures. An audit event is not evidence that a business transaction committed; the action should call its success callback only after the intended write succeeds.

In this version the automatic audit event occurs after the successful action callback path. It does not automatically log validation failures or failed actions.

```js definitions/audit.js
MAIN.auditEvents = [];
DEF.onAudit = function(name, data) {
	MAIN.auditEvents.push({ sink: name || null, action: data.action, message: data.message || '', type: data.type || null });
};

NEWACTION('AuditExample|save', {
	input: '*name:String',
	audit: 'Saved the example',
	action: function($) {
		$.callback({ ok: true });
	}
});

NEWACTION('AuditExample|explicit', {
	action: function($) {
		$.audit('Explicit example event', 'info');
		$.success();
	}
});

NEWACTION('AuditExample|fail', {
	audit: 'This must not become a success event',
	action: function($) {
		$.invalid(409);
	}
});
```

```js controllers/audit.js
exports.install = function() {
	ROUTE('POST /save/ --> *AuditExample|save');
	ROUTE('POST /explicit/ --> *AuditExample|explicit');
	ROUTE('POST /fail/ --> *AuditExample|fail');
	ROUTE('GET /events/', function($) { $.json(MAIN.auditEvents); });
};
```
