Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 360ef75549ca944b89b8a24fe074068168bea5df @StevenLooman committed Sep 5, 2012
4 .gitignore
@@ -0,0 +1,4 @@
+*.swp
+.sonar/
+coverage/
+node_modules/
5 .npmignore
@@ -0,0 +1,5 @@
+node_modules/
+run_sonar.hs
+sonar-runner.properties
+coverage
+.sonar
4 .travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
25 LICENSE
@@ -0,0 +1,25 @@
+Copyright 2011 Steven Looman. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY STEVEN LOOMAN ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STEVEN LOOMAN OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of Steven Looman.
3 README.md
@@ -0,0 +1,3 @@
+Blammo
+======
+Blammo - the Log-ger for NodeJS!
33 blammo.xml
@@ -0,0 +1,33 @@
+<configuration>
+ <appender name="console" type="console_appender">
+ <encoder type="dummy_encoder"/>
+ <layout type="pattern_layout">%timestamp|%pid|%logger|%level|%message</layout>
+ </appender>
+
+ <appender name="file_pattern" type="file_appender">
+ <encoder type="dummy_encoder"/>
+ <layout type="pattern_layout">%timestamp|%pid|%logger|%level|%message</layout>
+
+ <config>
+ <filename>/tmp/blammo.log</filename>
+ </config>
+ </appender>
+
+ <appender name="file_json" type="file_appender">
+ <encoder type="dummy_encoder"/>
+ <layout type="json_layout" />
+
+ <config>
+ <filename>/tmp/blammo.json</filename>
+ </config>
+ </appender>
+
+ <logger name="logger1">
+ <appender-ref ref="console" />
+ </logger>
+
+ <root level="warn">
+ <appender-ref ref="file_pattern" />
+ <appender-ref ref="file_json" />
+ </root>
+</configuration>
14 example.js
@@ -0,0 +1,14 @@
+var blammo = require('./');
+
+function main() {
+ var logger1 = blammo.LoggerFactory.getLogger('logger1');
+ var logger2 = blammo.LoggerFactory.getLogger('logger2');
+
+ logger1.debug('test debug message');
+ logger2.debug('test debug message');
+
+ logger1.error('test error message');
+ logger2.error('test error message');
+}
+
+main();
6 index.js
@@ -0,0 +1,6 @@
+/**
+ * Export lib/
+ *
+ */
+
+module.exports = require('./lib');
43 lib/appender.js
@@ -0,0 +1,43 @@
+var FilterReply = require('./filter_reply');
+
+
+function Appender() {
+}
+
+
+Appender.prototype.addFilter = function(filter) {
+ this.filters.push(filter);
+};
+
+Appender.prototype.shouldAppend = function(le) {
+ var i;
+ var filter, reply;
+ for (i = 0; i < this.filters.length; ++i) {
+ filter = this.filters[i];
+ reply = filter.decide(le);
+
+ if (reply === FilterReply.ACCEPT) {
+ return true;
+ } else if (reply === FilterReply.DENY) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+Appender.prototype.doAppend = function(le) {
+ if (!this.shouldAppend(le)) {
+ return;
+ }
+
+ this.append(le);
+};
+
+
+Appender.prototype.getName = function() {
+ return this.name;
+};
+
+
+module.exports = Appender;
213 lib/configuration_reader.js
@@ -0,0 +1,213 @@
+var fs = require('fs');
+var DOMParser = require('xmldom').DOMParser;
+
+var LoggerFactory = require('./logger_factory');
+var Logger = require('./logger');
+var Levels = require('./levels');
+
+
+var knownAppenders = {
+ 'console_appender' : require('./console_appender'),
+ 'file_appender' : require('./file_appender'),
+ 'rolling_file_appender': require('./rolling_file_appender')
+};
+
+var knownEncoders = {
+ 'dummy_encoder': require('./dummy_encoder')
+};
+
+var knownLayouts = {
+ 'pattern_layout': require('./pattern_layout'),
+ 'json_layout' : require('./json_layout')
+};
+
+var knownFilters = {
+ 'level_filter' : require('./level_filter'),
+ 'threshold_filter': require('./threshold_filter')
+};
+
+
+/**
+ * Read the confugration file and construct the Appenders/Loggers
+ */
+function readConfiguration(filename) {
+ var xml = fs.readFileSync(filename).toString();
+ var doc = new DOMParser().parseFromString(xml);
+ var root = doc.firstChild;
+
+ return parseConfiguration(root);
+}
+
+
+function getChildrenByTagName(node, name) {
+ var children = [];
+
+ var i;
+ var child;
+ for (i = 0; i < node.childNodes.length; ++i) {
+ child = node.childNodes.item(i);
+ if (child.tagName === name) {
+ children.push(child);
+ }
+ }
+
+ return children;
+}
+
+function getChildByTagName(node, name) {
+ var i;
+ var child;
+ for (i = 0; i < node.childNodes.length; ++i) {
+ child = node.childNodes.item(i);
+ if (child.tagName === name) {
+ return child;
+ }
+ }
+}
+
+
+function parseConfiguration(node) {
+ var appenderNodes = getChildrenByTagName(node, 'appender');
+ var appenders = parseAppenders(appenderNodes);
+
+ var loggerNodes = getChildrenByTagName(node, 'logger');
+ var loggers = parseLoggers(loggerNodes, appenders);
+
+ var rootNode = getChildByTagName(node, 'root');
+ var root = parseRoot(rootNode, appenders);
+
+ return root;
+}
+
+
+function parseAppenders(appenderNodes) {
+ var appenders = {};
+
+ appenderNodes.forEach(function(appenderNode) {
+ appender = parseAppender(appenderNode);
+ appenders[appender.name] = appender;
+ });
+
+ return appenders;
+}
+
+function parseAppender(node) {
+ var name = node.getAttribute('name');
+ var type = node.getAttribute('type');
+
+ var encoderNode = getChildByTagName(node, 'encoder');
+ var encoder = parseEncoder(encoderNode);
+
+ var layoutNode = getChildByTagName(node, 'layout');
+ var layout = parseLayout(layoutNode);
+
+ var filtersNode = getChildByTagName(node, 'filters');
+ var filters = parseFilters(filtersNode);
+
+ var configNode = getChildByTagName(node, 'config');
+ var config = {};
+ if (configNode) {
+ config = parseAppenderConfig(configNode);
+ }
+
+ return new knownAppenders[type](name, encoder, layout, config);
+}
+
+function parseEncoder(node) {
+ var type = node.getAttribute('type');
+
+ return new knownEncoders[type]();
+}
+
+function parseLayout(node) {
+ var type = node.getAttribute('type');
+ var pattern = node.textContent;
+
+ return new knownLayouts[type](pattern);
+}
+
+function parseFilters(node) {
+ if (!node) {
+ return [];
+ }
+
+ var filterNodes = getChildrenByTagName(node, 'filter');
+
+ var filters = [];
+ filterNodes.forEach(function(filterNode) {
+ var filter = parseFilter(filterNode);
+ filters.append(filter);
+ });
+
+ return filters;
+}
+
+function parseFilter(node) {
+ var type = node.getAttribute('type');
+ var param = node.textContent;
+
+ return new knownFilters[type](param);
+}
+
+function parseAppenderConfig(node) {
+ var config = {};
+
+ var i, child, key, value;
+ for (i = 0; i < node.childNodes.length; ++i) {
+ child = node.childNodes.item(i);
+
+ key = child.tagName;
+ value = child.textContent;
+
+ if (key) {
+ config[key] = value;
+ }
+ }
+
+ return config;
+}
+
+
+function parseLoggers(loggerNodes, appenders) {
+ loggerNodes.forEach(function(loggerNode) {
+ parseLogger(loggerNode, appenders);
+ });
+}
+
+function parseLogger(node, appenders) {
+ var name = node.getAttribute('name');
+ var logger = LoggerFactory.getLogger(name);
+
+ return parseLogger2(logger, node, appenders);
+}
+
+function parseRoot(node, appenders) {
+ var root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+
+ return parseLogger2(root, node, appenders);
+}
+
+function parseLogger2(logger, node, appenders) {
+ var levelString = (node.getAttribute('level') || 'debug').toUpperCase();
+ var level = Levels[levelString];
+ logger.setLevel(level);
+
+ var appenderRefs = getChildrenByTagName(node, 'appender-ref');
+ appenderRefs.forEach(function(appenderRefNode) {
+ var ref = appenderRefNode.getAttribute('ref');
+ var appender = appenders[ref];
+ logger.addAppender(appender);
+ });
+
+ return logger;
+}
+
+
+function doRead() {
+ var configFile = process.env.BLAMMO_CONFIG || 'blammo.xml';
+ if (fs.existsSync(configFile)) {
+ readConfiguration(configFile);
+ }
+}
+
+doRead();
31 lib/console_appender.js
@@ -0,0 +1,31 @@
+var util = require('util');
+
+var Appender = require('./appender');
+
+
+/**
+ * Build a ConsoleAppender
+ *
+ * Appends to the console
+ */
+function ConsoleAppender(name, encoder, layout) {
+ this.name = name;
+ this.encoder = encoder;
+ this.layout = layout;
+
+ this.filters = [];
+}
+
+
+util.inherits(ConsoleAppender, Appender);
+
+
+ConsoleAppender.prototype.append = function(e) {
+ var str = this.layout.doLayout(e);
+ var encodedStr = this.encoder.doEncode(str);
+
+ console.log(encodedStr);
+};
+
+
+module.exports = ConsoleAppender;
19 lib/dummy_encoder.js
@@ -0,0 +1,19 @@
+/**
+ * Build a dummy encoder
+ *
+ * Does nothing
+ */
+function DummyEncoder() {
+}
+
+
+DummyEncoder.prototype.doEncode = function(str) {
+ return this.encode(str);
+};
+
+DummyEncoder.prototype.encode = function(str) {
+ return str;
+};
+
+
+module.exports = DummyEncoder;
33 lib/file_appender.js
@@ -0,0 +1,33 @@
+var util = require('util');
+var fs = require('fs');
+
+var Appender = require('./appender');
+
+
+/**
+ * Build a FileAppender
+ *
+ * Appends to the configured filename
+ */
+function FileAppender(name, encoder, layout, config) {
+ this.name = name;
+ this.encoder = encoder;
+ this.layout = layout;
+ this.filename = config.filename;
+
+ this.filters = [];
+}
+
+
+util.inherits(FileAppender, Appender);
+
+
+FileAppender.prototype.append = function(e) {
+ var str = this.layout.doLayout(e);
+ var encodedStr = this.encoder.doEncode(str) + '\n';
+
+ fs.appendFileSync(this.filename, encodedStr);
+};
+
+
+module.exports = FileAppender;
8 lib/filter_reply.js
@@ -0,0 +1,8 @@
+var FilterReply = {
+ ACCEPT : 1,
+ NEUTRAL : 0,
+ DENY : -1
+};
+
+
+module.exports = FilterReply;
20 lib/index.js
@@ -0,0 +1,20 @@
+module.exports.LoggerFactory = require('./logger_factory');
+module.exports.Levels = require('./levels');
+module.exports.Logger = require('./logger');
+module.exports.LoggingEvent = require('./logging_event');
+
+module.exports.Appender = require('./appender');
+module.exports.ConsoleAppender = require('./console_appender');
+module.exports.FileAppender = require('./file_appender');
+module.exports.RollingFileAppender = require('./rolling_file_appender');
+
+module.exports.DummyEncoder = require('./dummy_encoder');
+
+module.exports.PatternLayout = require('./pattern_layout');
+module.exports.JsonLayout = require('./json_layout');
+
+module.exports.FilterReply = require('./filter_reply');
+module.exports.LevelFilter = require('./level_filter');
+module.exports.ThresholdFilter = require('./threshold_filter');
+
+require('./configuration_reader');
22 lib/json_layout.js
@@ -0,0 +1,22 @@
+/**
+ * JSON layout
+ */
+function JsonLayout() {
+}
+
+
+/**
+ * Copy the 'visible' parts of the LoggingEvent and stringify it
+ */
+JsonLayout.prototype.doLayout = function(le) {
+ var o = {
+ timestamp: le.timestamp,
+ logger: le.logger,
+ level: le.level,
+ message: le.message
+ };
+ return JSON.stringify(o);
+};
+
+
+module.exports = JsonLayout;
24 lib/level_filter.js
@@ -0,0 +1,24 @@
+var FilterReply = require('./filter_reply');
+var Levels = require('./levels');
+
+
+/**
+ * Build a Level Filter
+ *
+ * ACCEPTs any log message which is of the configured level
+ */
+function LevelFilter(level) {
+ this.level = level;
+}
+
+
+LevelFilter.prototype.decide = function(le) {
+ if (this.level === le.levelValue) {
+ return FilterReply.ACCEPT;
+ }
+
+ return FilterReply.NEUTRAL;
+};
+
+
+module.exports = LevelFilter;
25 lib/levels.js
@@ -0,0 +1,25 @@
+var LogLevels = {
+ 0 : 'ALL',
+ ALL : 0,
+
+ 10 : 'TRACE',
+ TRACE : 10,
+
+ 20 : 'DEBUG',
+ DEBUG : 20,
+
+ 30 : 'INFO',
+ INFO : 30,
+
+ 40 : 'WARN',
+ WARN : 40,
+
+ 50 : 'ERROR',
+ ERROR : 50,
+
+ 60 : 'OFF',
+ OFF : 60
+};
+
+
+module.exports = LogLevels;
154 lib/logger.js
@@ -0,0 +1,154 @@
+var LoggingEvent = require('./logging_event');
+var Levels = require('./levels');
+
+
+/**
+ * Construct a new logger
+ */
+function Logger(name, parent) {
+ this.name = name;
+ this.parent = parent;
+
+ this.appenders = [];
+ this.additive = true;
+}
+
+
+Logger.ROOT_LOGGER_NAME = 'ROOT';
+
+
+/**
+ * Set the new effective level for this Logger
+ */
+Logger.prototype.setLevel = function(level) {
+ this.level = level;
+};
+
+/**
+ * Get the effective level for this logger
+ */
+Logger.prototype.getLevel = function() {
+ if (this.level === undefined) {
+ return this.parent.getLevel();
+ }
+
+ return this.level;
+};
+
+
+/**
+ * Add an Appender to this Logger
+ */
+Logger.prototype.addAppender = function(appender) {
+ this.appenders.push(appender);
+};
+
+/**
+ * Detach a (single) Appender from this Logger
+ */
+Logger.prototype.detachAppender = function(appender) {
+ var index = this.appenders.indexOf(appender);
+ if (index !== -1) {
+ this.appenders.splice(index, 1);
+ }
+};
+
+/**
+ * Get an Appender by name
+ */
+Logger.prototype.getAppender = function(name) {
+ var namedAppenders = this.getNamedAppenders();
+ return namedAppenders[name];
+};
+
+/**
+ * Get the appenders for this Logger
+ */
+Logger.prototype.getAppenders = function() {
+ var namedAppenders = this.getNamedAppenders();
+ var appenders = [];
+
+ var name, appender;
+ for (name in namedAppenders) {
+ if (namedAppenders.hasOwnProperty(name)) {
+ appender = namedAppenders[name];
+ appenders.push(appender);
+ }
+ }
+
+ return appenders;
+};
+
+/**
+ * Get the appenders by name for this Logger
+ */
+Logger.prototype.getNamedAppenders = function() {
+ var appenders = {};
+
+ var p = this;
+ var f = function(appender) {
+ appenders[appender.name] = appender;
+ };
+ while (p) {
+ p.appenders.forEach(f);
+
+ if (p.additive) {
+ p = p.parent;
+ } else {
+ break;
+ }
+ }
+
+ return appenders;
+};
+
+
+Logger.prototype.log = function(level, message) {
+ if (this.getLevel() > level) {
+ return;
+ }
+
+ var le = new LoggingEvent(this.name, level, message);
+
+ this.getAppenders().forEach(function(appender) {
+ appender.doAppend(le);
+ });
+};
+
+/**
+ * Log a TRACE message
+ */
+Logger.prototype.trace = function() {
+ this.log(Levels.TRACE, arguments);
+};
+
+/**
+ * Log a DEBUG message
+ */
+Logger.prototype.debug = function() {
+ this.log(Levels.DEBUG, arguments);
+};
+
+/*
+ * Log a INFO message
+ */
+Logger.prototype.info = function() {
+ this.log(Levels.INFO, arguments);
+};
+
+/**
+ * Log a WARN message
+ */
+Logger.prototype.warn = function() {
+ this.log(Levels.WARN, arguments);
+};
+
+/**
+ * Log a ERROR message
+ */
+Logger.prototype.error = function() {
+ this.log(Levels.ERROR, arguments);
+};
+
+
+module.exports = Logger;
52 lib/logger_factory.js
@@ -0,0 +1,52 @@
+var Logger = require('./logger');
+
+
+function LoggerFactory() {
+ throw new Error("No instances thank you");
+}
+
+
+var loggers = {};
+
+
+/**
+ * Get a logger by its name
+ *
+ * If the logger does not exist, create it
+ */
+LoggerFactory.getLogger = function(name) {
+ if (!loggers[name]) {
+ // find parent
+ var parent = LoggerFactory.getParent(name);
+
+ // duplicate parent, or duplicate root if no parent found
+ var logger = new Logger(name);
+ loggers[name] = logger;
+ logger.parent = parent;
+ }
+
+ return loggers[name];
+};
+
+
+/**
+ * Get the first parent/ancestor from a logger by its name
+ *
+ * Name of the loggers should be in the form of: ancestor.parent.logger...
+ */
+LoggerFactory.getParent = function(name) {
+ var elements = name.split('.');
+
+ var i;
+ for (i = 1; i < elements.length; ++i) {
+ var parentName = elements.slice(0, -i).join('.');
+ if (loggers[parentName]) {
+ return loggers[parentName];
+ }
+ }
+
+ return loggers[Logger.ROOT_LOGGER_NAME];
+};
+
+
+module.exports = LoggerFactory;
36 lib/logging_event.js
@@ -0,0 +1,36 @@
+var Logger = require('./logger');
+var Levels = require('./levels');
+var utils = require('./utils');
+
+
+/**
+ * Build a LoggingEvent
+ *
+ * Timestamp is added from current dat in the form of YYYY-MM-DD hh:mm:ss.ms
+ */
+function LoggingEvent(logger, level, message) {
+ this.logger = logger;
+ this.levelValue = level;
+ this.message = Array.prototype.slice.call(message).join(''); // XXX: HACKetyhack
+
+ this._timestamp = new Date();
+ this.timestamp = LoggingEvent.buildTimestampString(this._timestamp);
+ this.pid = process.pid;
+
+ this.level = Levels[level];
+}
+
+
+
+LoggingEvent.buildTimestampString = function(timestamp) {
+ var str = '';
+
+ str += timestamp.getFullYear() + '-' + utils.fill(timestamp.getMonth() + 1, 2, '0') + '-' + utils.fill(timestamp.getDate(), 2, '0');
+ str += ' ';
+ str += utils.fill(timestamp.getHours(), 2, '0') + ':' + utils.fill(timestamp.getMinutes(), 2, '0') + ':' + utils.fill(timestamp.getSeconds(), 2, '0') + '.' + utils.fill(timestamp.getMilliseconds(), 3, '0');
+
+ return str;
+};
+
+
+module.exports = LoggingEvent;
33 lib/pattern_layout.js
@@ -0,0 +1,33 @@
+/**
+ * Build the Pattern Layout
+ *
+ * Possible tokens for the layout:
+ * - %timestamp
+ * - %logger
+ * - %level
+ * - %message
+ */
+function PatternLayout(pattern) {
+ this.layout = this.buildLayoutFunction(pattern);
+}
+
+
+/**
+ * Build the layout function
+ */
+PatternLayout.prototype.buildLayoutFunction = function(pattern) {
+ var getToken = function(match, name, offset) {
+ return '" + le[\'' + name + '\'] + "';
+ };
+
+ var js = 'return "' + pattern.replace(/%(\w+)/g, getToken) + '";';
+ return new Function('le', js);
+};
+
+
+PatternLayout.prototype.doLayout = function(le) {
+ return this.layout(le);
+};
+
+
+module.exports = PatternLayout;
32 lib/rolling_file_appender.js
@@ -0,0 +1,32 @@
+var util = require('util');
+var fs = require('fs');
+
+var Appender = require('./appender');
+var utils = require('./utils');
+
+
+function RollingFileAppender(name, encoder, layout, config) {
+ this.name = name;
+ this.encoder = encoder;
+ this.layout = layout;
+ this.filename = config.filename;
+
+ this.filters = [];
+}
+
+
+util.inherits(RollingFileAppender, Appender);
+
+
+RollingFileAppender.prototype.append = function(e) {
+ var str = this.layout.doLayout(e);
+ var encodedStr = this.encoder.doEncode(str) + '\n';
+
+ var dateSuffix = e._timestamp.getFullYear() + '-' + utils.fill(e._timestamp.getMonth() + 1, 2, '0') + '-' + utils.fill(e._timestamp.getDate(), 2, '0');
+ var filename = this.filename + '_' + dateSuffix;
+
+ fs.appendFileSync(filename, encodedStr);
+};
+
+
+module.exports = RollingFileAppender;
24 lib/threshold_filter.js
@@ -0,0 +1,24 @@
+var FilterReply = require('./filter_reply');
+var Levels = require('./levels');
+
+
+/**
+ * Build a Threshold Filter
+ *
+ * DENYs all mesasges which are above the configured level
+ */
+function ThresholdFilter(level) {
+ this.level = level;
+}
+
+
+ThresholdFilter.prototype.decide = function(le) {
+ if (this.level > le.levelValue) {
+ return FilterReply.DENY;
+ }
+
+ return FilterReply.NEUTRAL;
+};
+
+
+module.exports = ThresholdFilter;
13 lib/utils.js
@@ -0,0 +1,13 @@
+module.exports.fill = function(val, width, filler) {
+ if (!filler) {
+ filler = ' ';
+ }
+
+ width -= val.toString().length;
+
+ if (width > 0) {
+ return new Array(width + (/\./.test(val) ? 2 : 1)).join(filler) + val;
+ }
+
+ return val.toString();
+};
36 package.json
@@ -0,0 +1,36 @@
+{
+ "name": "blammo",
+ "description": "Blammo! Logger for NodeJS - built after LogBack for Java",
+ "version": "0.4.0",
+ "author": "Steven Looman <steven.looman@gmail.com>",
+ "keywords": [ "logger", "logging", "log" ],
+ "licenses" : [
+ {
+ "type": "2-clause BSD",
+ "url": "https://raw.github.com/StevenLooman/blammo/master/LICENSE"
+ }
+ ],
+
+ "dependencies": {
+ "xmldom": "0.1.11"
+ },
+ "devDependencies": {
+ "mocha": "1.2.2",
+ "mocha-lcov-reporter": "0.0.1"
+ },
+ "directories": {
+ "lib": "./lib",
+ "test": "./test"
+ },
+ "main": "index.js",
+ "engines": {
+ "node": ">= 0.6.0"
+ },
+ "scripts": {
+ "test": "mocha test/*"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/StevenLooman/blammo.git"
+ }
+}
18 run_sonar.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+rm -rf coverage
+rm -rf lib-cov
+
+mkdir coverage
+
+echo Running mocha
+node-jscoverage lib lib-cov
+mv lib lib-orig
+mv lib-cov lib
+mocha -R mocha-lcov-reporter > coverage/coverage.lcov
+mocha -R xunit > coverage/TEST-all.xml
+rm -rf lib
+mv lib-orig lib
+
+echo Running sonar-runner
+sonar-runner
22 sonar-project.properties
@@ -0,0 +1,22 @@
+# project metadata (required)
+sonar.projectKey=js.blammo
+sonar.projectName=Blammo
+sonar.projectVersion=0.4.0
+
+# path to source directories (required)
+sources=lib
+
+# path to test source directories (optional)
+tests=test
+
+# The value of the property must be the key of the language.
+sonar.language=js
+
+# Advanced parameters
+sonar.javascript.jstestdriver.reportsfolder=coverage
+sonar.javascript.jstestdriver.coveragefile=coverage.lcov
+sonar.dynamicAnalysis=reuseReports
+
+# SCM plugin
+sonar.scm.enabled=true
+sonar.scm.url=scm:git:git://github.com/StevenLooman/blammo.git
25 test/level_filter.js
@@ -0,0 +1,25 @@
+var blammo = require('..');
+var assert = require('assert');
+
+
+describe('LevelFilter', function() {
+ describe('#decide()', function() {
+ it('should reply neutral when the log level is not equal to the set level', function() {
+ var filter = new blammo.LevelFilter(blammo.Levels.TRACE);
+ var le = new blammo.LoggingEvent('test', blammo.Levels.DEBUG, 'dummy message');
+
+ var r = filter.decide(le);
+
+ assert.equal(r, blammo.FilterReply.NEUTRAL);
+ });
+
+ it('should reply accept when the log level is equal to the set level', function() {
+ var filter = new blammo.LevelFilter(blammo.Levels.WARN);
+ var le = new blammo.LoggingEvent('test', blammo.Levels.WARN, 'dummy message');
+
+ var r = filter.decide(le);
+
+ assert.equal(r, blammo.FilterReply.ACCEPT);
+ });
+ });
+});
188 test/logger.js
@@ -0,0 +1,188 @@
+var blammo = require('..');
+var assert = require('assert');
+
+var TestAppender = require('./test_appender');
+
+
+describe('Logger', function() {
+ describe('#trace()', function() {
+ it('should log when the level is low enough', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.TRACE);
+
+ logger.trace('test message');
+
+ assert.ok(appender.events.length === 1);
+ });
+
+ it('should not log when the level is too high', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.OFF);
+
+ logger.trace('test message');
+
+ assert.ok(appender.events.length === 0);
+ });
+ });
+
+ describe('#debug()', function() {
+ it('should log when the level is low enough', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.DEBUG);
+
+ logger.debug('test message');
+
+ assert.ok(appender.events.length === 1);
+ });
+
+ it('should not log when the level is too high', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.OFF);
+
+ logger.debug('test message');
+
+ assert.ok(appender.events.length === 0);
+ });
+ });
+
+ describe('#info()', function() {
+ it('should log when the level is low enough', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.INFO);
+
+ logger.info('test message');
+
+ assert.ok(appender.events.length === 1);
+ });
+
+ it('should not log when the level is too high', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.OFF);
+
+ logger.info('test message');
+
+ assert.ok(appender.events.length === 0);
+ });
+ });
+
+ describe('#warn()', function() {
+ it('should log when the level is low enough', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.WARN);
+
+ logger.warn('test message');
+
+ assert.ok(appender.events.length === 1);
+ });
+
+ it('should not log when the level is too high', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.OFF);
+
+ logger.warn('test message');
+
+ assert.ok(appender.events.length === 0);
+ });
+ });
+
+ describe('#error()', function() {
+ it('should log when the level is low enough', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.ERROR);
+
+ logger.error('test message');
+
+ assert.ok(appender.events.length === 1);
+ });
+
+ it('should not log when the level is too high', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender();
+ logger.addAppender(appender);
+ logger.setLevel(blammo.Levels.OFF);
+
+ logger.error('test message');
+
+ assert.ok(appender.events.length === 0);
+ });
+ });
+
+ describe('#getAppender()', function() {
+ it('should get an added appender by name', function() {
+ var logger = new blammo.Logger('test');
+ var appender = new TestAppender('test');
+ logger.addAppender(appender);
+
+ var r = logger.getAppender('test');
+ assert.equal(r.name, appender.name);
+ });
+ });
+
+ describe('log level inheritance', function() {
+ it('should inherit the parents level if no level is set (effective level)', function() {
+ var logger1 = new blammo.Logger('a');
+ logger1.setLevel(blammo.Levels.WARN);
+ var logger2 = new blammo.Logger('a.b');
+ logger2.parent = logger1;
+
+ assert.equal(logger2.getLevel(), blammo.Levels.WARN);
+ });
+
+ it('should use its own level if it is set', function() {
+ var logger1 = new blammo.Logger('a');
+ logger1.setLevel(blammo.Levels.WARN);
+ var logger2 = new blammo.Logger('a.b');
+ logger2.parent = logger1;
+ logger2.setLevel(blammo.Levels.ERROR);
+
+ assert.equal(logger2.getLevel(), blammo.Levels.ERROR);
+ });
+ });
+
+
+ describe('appender additivity', function() {
+ it('should include its parents appenders', function() {
+ var appender = new TestAppender('test_appender');
+ var logger1 = new blammo.Logger('a');
+ logger1.setLevel(blammo.Levels.DEBUG);
+ logger1.addAppender(appender);
+ var logger2 = new blammo.Logger('a.b');
+ logger2.parent = logger1;
+
+ var appenders = logger2.getAppenders();
+ assert.ok(appenders.length === 1);
+ });
+
+ it('should not include its parents appenders when the logger is not additive', function() {
+ var appender = new TestAppender('test_appender');
+ var logger1 = new blammo.Logger('a');
+ logger1.setLevel(blammo.Levels.DEBUG);
+ logger1.addAppender(appender);
+ var logger2 = new blammo.Logger('a.b');
+ logger2.parent = logger1;
+ logger2.additive = false;
+
+ var appenders = logger2.getAppenders();
+ assert.ok(appenders.length === 0);
+ });
+ });
+});
+
57 test/pattern_layout.js
@@ -0,0 +1,57 @@
+var blammo = require('..');
+var assert = require('assert');
+
+var TestAppender = require('./test_appender');
+
+
+describe('PatternLayout', function() {
+ describe('doLayout()', function() {
+ it('should layout an acceptable layout', function() {
+ var layout = new blammo.PatternLayout('%timestamp|%logger|%level|%message');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.ok(result.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\|blammo\|TRACE\|test message/));
+ });
+
+ it('should layout timestamp', function() {
+ var layout = new blammo.PatternLayout('%timestamp');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.ok(result.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}/));
+ });
+
+ it('should layout pid', function() {
+ var layout = new blammo.PatternLayout('%pid');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.ok(result.match(/\d+/));
+ });
+
+ it('should layout level', function() {
+ var layout = new blammo.PatternLayout('%level');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.equal(result, 'TRACE');
+ });
+
+ it('should layout messages', function() {
+ var layout = new blammo.PatternLayout('%message');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.equal(result, 'test message');
+ });
+
+ it('should layout logger', function() {
+ var layout = new blammo.PatternLayout('%logger');
+ var le = new blammo.LoggingEvent('blammo', blammo.Levels.TRACE, 'test message');
+
+ var result = layout.doLayout(le);
+ assert.equal(result, 'blammo');
+ });
+ });
+});
22 test/test_appender.js
@@ -0,0 +1,22 @@
+function TestAppender(name) {
+ if (name) {
+ this.name = name;
+ } else {
+ this.name = 'TestAppender';
+ }
+
+ this.events = [];
+}
+
+
+TestAppender.prototype.getName = function() {
+ return this.name;
+};
+
+
+TestAppender.prototype.doAppend = function(e) {
+ this.events.push(e);
+};
+
+
+module.exports = TestAppender;
25 test/threshold_filter.js
@@ -0,0 +1,25 @@
+var blammo = require('..');
+var assert = require('assert');
+
+
+describe('ThresholdFilter', function() {
+ describe('#decide()', function() {
+ it('should reply neutral when the log level is high enough', function() {
+ var filter = new blammo.ThresholdFilter(blammo.Levels.TRACE);
+ var le = new blammo.LoggingEvent('test', blammo.Levels.DEBUG, 'dummy message');
+
+ var r = filter.decide(le);
+
+ assert.equal(r, blammo.FilterReply.NEUTRAL);
+ });
+
+ it('should reply deny when the log level is too low', function() {
+ var filter = new blammo.ThresholdFilter(blammo.Levels.WARN);
+ var le = new blammo.LoggingEvent('test', blammo.Levels.DEBUG, 'dummy message');
+
+ var r = filter.decide(le);
+
+ assert.equal(r, blammo.FilterReply.DENY);
+ });
+ });
+});

0 comments on commit 360ef75

Please sign in to comment.
Something went wrong with that request. Please try again.