ForgeTotal.js 5
en

Total.js 5

Collect errors with ErrorBuilder, log them with ERROR() and keep an audit trail with AUDIT()

Total.js 5 · total5@0.0.19 errorsloggingaudit Executed against Total.js 5
  • ErrorBuilder collects errors. push(message, [path], [index]) adds one (path is the field it belongs to), push(404) adds the text of a status code and sets the status of the answer, length counts them, output() returns them as an array of { error, path, index } and toString() joins the messages. $.invalid(builder) answers with that array and the status of the builder (400 unless a status code was pushed).
  • SUCCESS(value) returns the object for a successful operation: { success: true, value: value }.
  • ERROR(name) returns a callback for function(err) APIs: when it receives an error it records it under name, and it does nothing when the error is empty. ERROR() is the same callback without a name. A recorded error is printed to the console, counted in F.stats.error, and the last ten are kept in F.errors as { error, name, date }.
  • AUDIT($, message, type) appends one JSON line to logs/audit.log with who and where (ip, ua, url, and the user when there is one), the message, the type, the params, query and model of the request in data, the name of the application in app and the time in dtcreated. AUDIT('name', $, message, type) writes to logs/name.log instead.
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);
}