This section is meant as a quick introduction to the source code of Woodman, available in Woodman's GitHub repository. For all the gory details, check the code itself. It contains hopefully useful and readable comments that explain how the library operates in practice.
Woodman's GitHub repository is organized in folders:
dist/
folder contains Woodman distribution files, in other words the results building Woodman into a minified JavaScript file that contains all the code and exports Woodman for some JavaScript runtime environment.examples/
folder contains examples that you may try out in your Web browser or run in node.jslib/
folder contains the actual source code of Woodman.precompile/
folder contains the precompiler library and command-line interface.test/
folder contains unit tests.Gruntfile.js
file is a Grunt make file that runs the different instructions needed to build Woodman and update the dist/
folder accordingly.To start developing for Woodman, clone the repository and run npm install
to install the different libraries needed to build Woodman, precompile and/or run tests.
Woodman is defined as a series of AMD modules that get bundled together during build. The basic concepts presented earlier directly match the base classes that you will find in the lib/
folder:
appender.js
defines the base Appender
class.logevent.js
defines the base LogEvent
class.logger.js
defines the Logger
class.Other files define classes that follow the Apache Log4j architecture, for instance: loggercontext.js
, logmanager.js
, message.js
, or lifecycle.js
.
There is one entry point per distribution of Woodman, named woodman.js
or woodman-xx.js
. If you take a look at one of these files, you will see that these entry points merely return the static LogManager
class initialized with the different appenders, filters, and layouts that the distribution supports. In turn, the LogManager
class wraps a LoggerContext
instance that contains the gist of Woodman's configuration logic.
Said differently, when you issue a call to woodman.getLogger
, you will actually call LoggerContext.getLogger
.
Unit tests are written using Jasmine. To run the tests from the root folder of the repository:
node test/run.js
Unless something is wrong with the version of Woodman on which you run the tests, you should see a friendly green message that looks like xxx specs, 0 failures
.
The test runner may also generate JUnit XML test reports (one per spec), e.g. for integrating in Jenkins:
node test/run.js junit
The report files are written in the test-reports
folder.
Building Woodman essentially boils down to:
Woodman uses Grunt to automate these tasks. The grunt.js
file in the root folder of the repository contains the logic needed.
The precompile/precompile.js
file implements the logic of the precompiler. Internally, the precompiler uses Esprima to parse the incoming JavaScript into an Abstract Syntax Tree (AST). It then parses that tree to extract statements of interest and uses an adapted version of Falafel to update the original source code. Using Falafel makes it easy to update the code while preserving spaces, lines and comments. It also has the drawback that it is also easy to create invalid code.
Check the code of the precompiler for details. The precompilation updates the initial code in steps:
log
, info
, warn
, error
ex: logger.log('blah');
var logger = woodman.getLogger('foo');
woodman.load(config, function (err) { ... });
var woody = require('woodman');
ex: define(['woodman'], function (woodman) { ... });
define('woodman', ...);
The precompiler is rather slow. It has the merit that it exists and does the right thing most of the time. It is most certainly possible to improve performances here. If you're into AST trees, feel free to have a look at the code and suggest improvements!
The dist/
folder in Woodman's repository contains different builds of Woodman. These builds differ by the types of Appenders they support and by the way the library exports itself to the underlying JavaScript runtime environment. If you're desesperatly looking for a distribution that does not yet exist, check the Build a custom distribution section below and build the distribution of Woodman of your dreams!
The dist/woodman.js file is the main build of Woodman, designed to run everywhere. It is the one that you get when you install Woodman through an npm install
command. The distribution supports the Console
, File
, RollingFile
and Socket
appenders (although note the File
and RollingFile
appenders de facto cannot be used in a Web browser environment). The dist/woodman.js
file exports a global woodman
object if window
is defined, a node.js module if module.exports
is defined, and an AMD module if the define
function is defined. This should make it easy to use Woodman in a vast majority of JavaScript runtime environments.
However, if you're as picky as we are, you may not appreciate the fact that Woodman leaks to the global scope in that distribution when window
is defined. You may also run into situations where window
, define
or module.exports
exist but do not have their usual meaning. This is where the AMD module, node.js or Web browser distribution might be useful.
If you want to use Woodman in a project that uses AMD modules, use the dist/woodman-amd.js file. This distribution is the same as the main distribution but it only exports Woodman as an AMD module and thus never leaks to the global scope.
If you only need to use the Console
appender and would prefer Woodman to remain as small as possible, use the dist/woodman-console.js file. This distribution is the same as the main distribution but it drops support for the Socket
appender in particular that amounts for a bit less than 2/3 of the size of the main distribution. Resulting size is ~20Ko
(~10Ko
if compressed).
Similarly, if you want to use Woodman in a project that will only run in Web browsers, the dist/woodman-browser.js file contains all that you need. It exports a global woodman
object and does not contain the code of the File
Appender since it is useless in that context.
If you want to use Woodman in a project that uses AMD modules and only runs in Web browser, the dist/woodman-browser-amd.js file is a combinaison of the previous two distributions: it does not support the File
Appender and exports Woodman as an AMD module.
If you want to use Woodman in a node.js only project, the dist/woodman-node.js file is the same as the main distribution but it only exports Woodman as a node.js module.
IF you want to use Woodman in a node.js only project that uses AMD modules, the dist/woodman-node-amd.js file is the same as the node.js module but only exports Woodman as an AMD module.
The dist/woodman-disabled.js distribution is a tiny file (less than 1Kb) that contains a shim of Woodman that simply does nothing. You may want to use that distribution if you cannot or do not want to run Woodman's precompiler on your project for some reason but still would like to silence Woodman in a release version of the project without having to include a full release of Woodman in the mix. By definition, that shim does not support any Appender but equally will not complain if the configuration references types of Appender it does not know anything about.
Woodman is highly modularized with a view to making it easy to extend the library, in particular to create new types of appenders, layouts, or filters.
Appenders in Woodman should (although note that is not stricto senso required) derive from the base Appender
class in lib/appender.js
. To create a new type of appender:
lib/appenders
lib/appenders/consoleappender.js
to create a class that derives from the base Appender
class.doAppend
function.start
and stop
functions if needed.lib/woodman.js
and alike) to add a require
call that loads the code of your appender and a call to registerAppender
with the name that is to appear in the configuration to reference your appender.Layouts in Woodman should (although, once again, that is not stricto senso required) derive from the base Layout
class in lib/layout.js
. To create a new type of Layout:
lib/layouts
lib/layouts/patternlayout.js
to create a class that derives from the base Layout
class.toMessageString
function.lib/woodman.js
and alike) to add a require
call that loads the code of your layout and a call to registerLayout
with the name that is to appear in the configuration to reference your layout.Starting to get it? Good, because it is just about the same thing for Filters... Filters in Woodman should (although not required) derive from the base Filter
class in lib/filter.js
. To create a new type of Filter:
lib/filters
lib/filters/regexfilter.js
to create a class that derives from the base Filter
class.filter
function.lib/woodman.js
and alike) to add a require
call that loads the code of your filter and a call to registerFilter
with the name that is to appear in the configuration to reference your filter.By default, Woodman knows about the trace levels: log
, info
, warn
and error
. The order of these trace levels is significant, as loggers and appenders process log events that are at or below a given trace level. Woodman also handles the two specific values all
(which means any trace level) and off
(which means no trace level).
While these trace levels should be enough in most cases, you may also want to introduce additional levels, for instance a trace
or debug
level to trace even more things than the log
level or a fatal
level below the error
level.
To introduce these new log levels, simply add corresponding calls to registerLevel
in the entry point of the distribution you are using, for instance:
LogManager.registerLevel('trace', 'log');
LogManager.registerLevel('debug', 'trace');
LogManager.registerLevel('fatal');
Registering a level creates a trace function with the same name on all Logger instances. You may start to use that new trace function right away:
var logger = woodman.getLogger();
logger.debug('Logging a message at the "debug" level');
logger.fatal('Argh!');
Note that, if you only want to add new levels to use Woodman in a specific application, you may also directly issue calls such as woodman.registerLevel('fatal');
from anywhere in your code and use these trace levels afterwards. In other words, you do not need to re-build Woodman to add new trace levels.
Also note that the precompiler only knows about regular log levels for the time being and will not be able to remove calls made to additional trace functions.
If you want to create your own distribution of Woodman, run the following steps:
lib/woodman.js
main distribution entry point into a lib/woodman-xx.js
file.registerAppender
, registerLayout
, registerFilter
, registerLevel
as needed.requirejs
task with the name of your distribution in the Grunt file with the appropriate wrapping code.concat
task with the right banner and destination file.Did you find a bug? Do you have a new feature to suggest? Great! Use the issue tracking system on GitHub to report bugs or propose new features.
Do you feel like contributing to the code of Woodman? Even better! The best way forward would be to fork the repository, commit the changes in the forked version and send a pull request. Please note the MIT License.
Is documentation your thing? Awesome! Please get in touch through the issue tracking system on GitHub with suggestions to turn the documentation into a pleasant read. Translations welcome as well.