http://joshfire.github.io/woodman/
ParisJS – le 29 janvier 2014
François Daoust / @tidoust
(logo by @mauriz)
Implémentation en C++
Une implémentation de log4j en JavaScript
# Pour les fans de npm
npm install woodman
# Si votre truc, c’est Bower
bower install woodman
# Si vous êtes plutôt brut de décoffrage
wget https://raw.github.com/joshfire/woodman/master/dist/woodman.js
// Démarrer Woodman avec une configuration de base
// (à faire une fois pour toutes au chargement de l’application)
woodman.load('console');
// Récupérer un logger pour le module ou le scope courant
// (par module/scope à identifier dans les logs)
var logger = woodman.getLogger('slides');
// Ecrire des messages
logger.log('Salut Woodman');
logger.info('Ceci n’est pas une pipe');
logger.warn('Résultat étonnant', { result: 42, operation: '6x7' });
logger.error('Oh non !', 'J’ai tout cassé !');
logger.log('Ceci est {} {}', 'une', 'substitution');
Et puis c’est tout.
woodman.load({
"loggers": [ … ], // What to log depending on provenance
"appenders": [ … ], // Where to log and how
"filters": [ … ] // Additional filters, if needed
});
woodman.load({
loggers: [{
root: true,
level: 'log',
appenders: [ 'theconsole' ]
}],
appenders: [{
name: 'theconsole',
type: 'Console',
appendStrings: false,
layout: {
type: 'PatternLayout',
pattern: '%date{yyyy-MM-dd HH:mm:ss} [%logger] %message%n'
}
}]
});
woodman.load({
loggers: [{
root: true,
level: 'warn',
appenders: [ 'theconsole' ]
}],
appenders: [ … ]
});
var logger = woodman.getLogger('slides');
logger.log('Un log filtré');
logger.info('Une info filtrée');
logger.warn('Une alerte affichée');
logger.error('Une erreur affichée');
woodman.load({
loggers: [
{ level: 'log', root: true, appenders: [ 'theconsole' ] },
{ level: 'off', name: 'slides' },
{ level: 'warn', name: 'slides.shout' }
],
appenders: [ … ]
});
var logger = woodman.getLogger('slides');
var sublogger = woodman.getLogger('slides.sub');
var shoutlogger = woodman.getLogger('slides.shout');
logger.warn('Cette alerte est filtrée');
sublogger.warn('Cette alerte d’un sous-module est filtrée');
shoutlogger.warn('Cette alerte du sous-module "shout" n’est pas filtrée');
woodman.load({
loggers: [{
level: 'log', root: true,
appenders: [ 'theconsole', 'remoteserver' ] }
],
appenders: [
{ name: 'theconsole', … },
{ name: 'remoteserver',
type: 'SocketAppender',
url: 'http://localhost:40031',
layout: {
type: 'PatternLayout',
pattern: '%date{ISO8601} [%level] %logger - %message'
}
}
]
});
(sous réserve d’avoir un serveur Socket.IO qui tourne !)
Les paramètres peuvent se combiner.
On peut s’y perdre…
mais la configuration change rarement.
Et surtout…
le code de l’application ne change pas !
Le précompilateur de Woodman supprime tout ou une partie des appels à Woodman présents dans du code javascript.
npm install woodman
node woodman/precompile/precompiler.js {JSFILE}
node woodman/precompile/precompiler.js {JSFOLDER} {OUTPUTFOLDER}
node woodman/precompile/precompiler.js {JSFILE} {OUTPUTFILE} --verbose
node woodman/precompile/precompiler.js {JSFILE} --keep warn,error
Usage: node precompiler.js [options] <input> [output]
Description:
Removes calls to Woodman from a JavaScript file or folder.
Parameters:
input Full path to the JS file or folder to update.
output Full path to the JS file or folder to create.
Precompiler outputs the result to the console otherwise.
Options:
-h, --help Outputs usage information.
-k, --keep <levels> Keeps specified trace levels in updated file(s).
Comma-separated values.
Possible values: "log", "info", "warn", "error".
Defaults to an empty list.
-v, --verbose Trace precompiler execution.
Un serveur HTTP traite plusieurs requêtes en parallèle.
Comment séparer les logs ?
Facile sous Apache, IIS via le local thread storage.
Equivalent sous Node.js ?
// Create two domains with an ID
var domain = require('domain');
var firstDomain = domain.create();
var secondDomain = domain.create();
firstDomain.id = 'first';
secondDomain.id = 'second';
// Some function to execute
var func = function () { … };
// Run function in both domains
firstDomain.run(func);
secondDomain.run(func);
%domain
dans Woodman
// Tell Woodman to log the message with the domain ID to the console.
var woodman = require('woodman');
var logger = woodman.getLogger();
woodman.load('console Got "%message" from %domain domain.%n');
// Async function that logs two messages using Woodman.
// The function does not know anything about its underlying domain.
var func = function () {
logger.log('sync message');
setTimeout(function () {
logger.log('async message');
}, 0);
};
%domain
dans Woodman
Got "sync message" from first domain.
Got "sync message" from second domain.
Got "async message" from first domain.
Got "async message" from second domain.
var connect = require('connect');
var domain = require('domain');
var woodman = require('woodman');
var logger = woodman.getLogger();
var requestID = 1;
var app = connect()
.use(function (req, res, next) {
// Code below extends connect-domain (MIT license)
// https://github.com/baryshev/connect-domain
var reqDomain = domain.create();
reqDomain.id = requestID++;
reqDomain.bind(res);
res.on('finish', function () {
reqDomain.dispose();
});
reqDomain.on('error', function (err) {
reqDomain.dispose();
next(err);
});
reqDomain.run(next);
})
.use(function (req, res) {
logger.log('start request processing');
setTimeout(function () {
logger.log('end request processing');
res.end('Hello, see console');
}, 2000);
})
.use(function (err, req, res, next) {
res.end(err.message);
});
woodman.load('console request %domain - %message%n');
app.listen(3000);
SyslogAppender
DBAppender
http://joshfire.github.io/woodman/talks/20140129-parisjs/
http://joshfire.github.io/woodman/