# Collecter des erreurs avec ErrorBuilder, les journaliser avec ERROR() et tenir une piste d'audit avec AUDIT()

> Répondez avec plusieurs erreurs à la fois grâce à ErrorBuilder, la réponse SUCCESS(), la façon dont ERROR() enregistre les échecs et dont AUDIT() ajoute à un fichier journal qui a fait quoi.

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

- **`ErrorBuilder`** collecte des erreurs. `push(message, [path], [index])` en ajoute une (`path` est le champ auquel elle appartient), `push(404)` ajoute le texte d'un code d'état et fixe l'état de la réponse, `length` les compte, `output()` les renvoie sous forme d'un tableau de `{ error, path, index }` et `toString()` assemble les messages. `$.invalid(builder)` répond avec ce tableau et l'état du builder (400 sauf si un code d'état a été ajouté).
- **`SUCCESS(value)`** renvoie l'objet d'une opération réussie : `{ success: true, value: value }`.
- **`ERROR(name)`** renvoie un callback pour les API en `function(err)` : quand il reçoit une erreur, il l'enregistre sous `name`, et il ne fait rien si l'erreur est vide. `ERROR()` est le même callback sans nom. Une erreur enregistrée est affichée dans la console, comptée dans `F.stats.error`, et les dix dernières sont conservées dans `F.errors` sous la forme `{ error, name, date }`.
- **`AUDIT($, message, type)`** ajoute une ligne JSON à `logs/audit.log` avec qui et où (`ip`, `ua`, `url` et l'utilisateur s'il y en a un), le `message`, le `type`, les `params`, `query` et `model` de la requête dans `data`, le nom de l'application dans `app` et l'heure dans `dtcreated`. `AUDIT('name', $, message, type)` écrit plutôt dans `logs/name.log`.

```js controllers/reports.js
exports.install = function() {
	ROUTE('GET /builder/', builder);
	ROUTE('GET /builder404/', builder404);
	ROUTE('GET /success/', success);
	ROUTE('GET /error/', error);
	ROUTE('GET /audit/', audit);
	ROUTE('GET /audit-read/{name}/', auditread);
};

function builder($) {
	const errors = new ErrorBuilder();
	errors.push('Name is required', 'name');
	errors.push('Age is too low', 'age', 2);
	$.invalid(errors);
}

function builder404($) {
	const errors = new ErrorBuilder();
	errors.push(404);
	$.invalid(errors);
}

function success($) {
	$.json(SUCCESS('saved'));
}

function error($) {
	const before = F.stats.error;
	ERROR('mypart')('Something broke');
	ERROR('mypart')(null);
	ERROR()('Without a name');
	$.json({ counted: F.stats.error - before, last: F.errors.slice(-2).map(n => ({ error: n.error, name: n.name || null, date: n.date instanceof Date || typeof n.date === 'string' })) });
}

function audit($) {
	AUDIT($, 'Opened the report', 'info');
	AUDIT('security', $, 'Checked the access');
	$.json({ ok: true });
}

function auditread($) {
	setTimeout(function() {
		const lines = require('fs').readFileSync(PATH.logs($.params.name + '.log'), 'utf8').trim().split('\n');
		$.json(lines.map(n => JSON.parse(n)));
	}, 300);
}
```
