--- /dev/null
+{
+ "rules": {
+ "indent": [
+ 2,
+ 2
+ ],
+ "quotes": [
+ 2,
+ "single"
+ ],
+ "linebreak-style": [
+ 2,
+ "unix"
+ ],
+ "semi": [
+ 2,
+ "always"
+ ],
+ "no-trailing-spaces": [
+ 2,
+ {
+ "skipBlankLines": false
+ }
+ ],
+ "eqeqeq": [
+ 2,
+ "allow-null"
+ ],
+ "consistent-return": 2,
+ "curly": 2,
+ "dot-location": [2, "property"],
+ "guard-for-in": 2,
+ "no-extra-bind": 2
+ },
+ "env": {
+ "es6": true,
+ "node": true,
+ "browser": true
+ },
+ "extends": "eslint:recommended"
+}
--- /dev/null
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
+node_modules
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+# JSDoc
+doc
-2015-01-21 Ben Beltran <ben@nsovocal.com>
-
- Version 1.1.3
-
- * lib/loggers/file.js: Makes the log work in append mode instead of
- overwrite mode.
-
-2015-01-09 Sergio de la Garza <sergio@delagarza.io>
-
- Version 1.1.2
-
- * lib/cobalt.js (dependencies): Require colors fix the log output when
- using the tocken formatter.
-
-
-2015-01-09 Ben Beltran <ben@nsovocal.com>
-
- Version 1.1.1
-
- * lib/loggers/file.js: Writes raw log if no formatter is present.
-
- * lib/cobalt.js: Logging null now converts it to the string "null";
+2016-01-22 Ruben Beltran Del Rio <ben@nsovocal.com>
Version 1.1.0
- * lib/loggers/file.js: Includes the new file logger.
+ * lib/cologne.js (buildLog): Add a new parameter called meta that expects an
+ object, it will be used to extend the log.
- * lib/formatters/simple.js (format): Simple formatter outputs date and
- loglevel.
+ * lib/cologne/log_utilities.js: Add the getLevelAnsi method that will
+ return an ANSI keyword depending on the log level sent.
- * lib/cobalt.js: Includes the file logger and simple formatter.
+ * lib/cologne/formatter/simple (format): Now uses getLevelAnsi, this means
+ that info and debug get colors (they used to be defualt.) info is blue,
+ debug is green.
- * lib/formatters/token.js: Extends with options on
- initialization, including a new option isoDate that will make the
- date an ISOString.
+ * lib/cologne/formatter/token (format): Adds support for the {{_ansi:_level}}
+ token that uses getLevelAnsi to generate color depending on the level.
- * README.md: Updates documentation to consider the new options, formatter
- and logger.
+ * README.md: Adds references to all new features
-
-2014-03-20 Ben Beltran <ben@nsovocal.com>
+2016-01-21 Ruben Beltran Del Rio <ben@nsovocal.com>
Version 1.0.0
- * lib/cobalt.js (buildLog): Logging a logObject will now use the calling
- method's severity instead of the logObject severity. so calling `#error`
- will always provide severity level 3.
-
- * package.json: Updates neon dependency to 2.0, adds tellurium as
- dev-dependency.
-
- * /test: Adds VERY basic tests before tellurium is integrated.
+ * all: initial release.
-# Cobalt #
+# Cologne
-Cobalt is a simple logger multiplexer that works with a JSON based format.
-You can instantiate it with a set of loggers or add them later
-(see API reference below). When logging anything, Cobalt will attempt to
-generate an Object that conforms to the Cobalt Log Format Definition
-(if required) and passes it to every logger it has by calling their `log`
-method.
+![https://david-dm.org/rbdr/cologne.svg][dependencies-shield]
+![https://circleci.com/gh/rbdr/cologne.svg?style=shield][circle-ci-shield]
-Example of instantiating a cobalt logger:
+Cologne is a logger multiplexer that works mainly with a JSON format. It
+can be instantiated with several loggers, or they can be changed after
+the fact.
+
+## Usage
+
+Install from npm or add to your package.json:
-In node:
```
-require('cobalt-log');
+$ npm install cologne
```
-In the browser just require the files. Then:
+Create an instance:
-```
-this.logger = new Cobalt.Console({
- from : "Breezi Client",
- loggers : [ new Cobalt.Logger.JsConsole({
- formatter : Cobalt.Formatter.Token,
- formatterOpts : {
- formatString : "{{_from}}: {{message}}",
- ansiColor : true
- }
- })]
+```javascript
+require('cologne');
+
+let co = new Cologne({
+ from: "Special Worker Logger",
+ loggers: [
+ new Cologne.Logger.Console({
+ formatter: new Cologne.Formatter.Token({
+ formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
+ })
+ })
+ ]
});
```
-This code will create an instance with a JsConsole logger that uses the
-Token formatter (See loggers and formatters below).
+This example would create a cologne instance with a console logger that
+uses a Token formatter. (More on loggers and formatters below.);
-Cobalt works in a browser or inside node, so feel free to use cobalt all
-over! (Also, see the socket logger below for info on connecting cobalt
-loggers)
+## Do I need anything special?
-## Quick API Reference ##
+Node 4.0+
-* **addLogger(logger)**: Adds a logger to the cobalt instance.
-* **removeLogger(logger)**: Removes a logger from the cobalt instance.
-* **buildLog(item, level=7)**: Generates a cobalt log object as if you had
- logged item (it will do this automatically when you log anything)
-* **extendLog(object)**: Creates a dummy log object and extends it with
- object.
-* **buildSeparator**: Generates a cobalt log object that defines a separator
+## Quick API Reference
+
+* **addLogger(logger)**: Adds a logger to the cologne instance.
+* **removeLogger(logger)**: Removes a logger from the cologne instance.
+* **buildLog(item, level, [meta])**: Generates a cologne log object as if you had
+ logged an item (it will do this automatically when you log anything.)
+ level defaults to 6. You can optionally send it an object to extend
+ the object with.
* **log, info, notice, warn, error**: Generates a log object with the
appropriate severity level and sends it to all loggers.
-* **separator()**: Generates a separator log object and sends it to all
- loggers.
-* **space(lines)**: Logs an empty string `lines` times
-* **indent()**: Increases the indent level globally.
-* **indent(callback)**: Increases the indent level for anything logged
- from inside the callback.
-* **outdent()/outdent(callback)**: Same as indent, but decreases indent level.
-* **color()**: Changes the color globally. †
-* **color(callback)**: Changes the color for anything logged from inside the
- callback. †
-* **now()**: Returns the current time in microseconds, using performance.now()
- or process.hrtime() if available. If not, falls back to miliseconds.
-
-† Cobalt doesn't really care about formatting or colors, but it allows you
-to set the `_color` property in the generated object. In the end, it's up to
-the formatter to decide if it will use this property. However, this maintains
-the old cobalt API and gives you flexibility in how you color your logs.
-
-
-## Loggers ##
-
-Cobalt doesn't depend on any particular logger, and the loggers it expects
-to receive is any object that responds to the log method. However, since it
-would pass a JSON object instead of a string, this may result in unexpected
-behavior for loggers that don't expect it. To ease the use of Cobalt with
-existing loggers, cobalt includes a couple of loggers that you can use out
-of the box.
-
-
-### Cobalt.Logger.JsConsole ###
-
-This logger communicates the Javascript console present in web browsers or
-node with cobalt. It uses the logLevel to trigger the appropriate method
-(e.g. info vs warn vs error). You can also initialize it with a formatter,
-to convert the log object to a string:
-```
- new Cobalt.Logger.JsConsole({
- formatter : Cobalt.Formatter.Token,
- formatterOpts : {
- formatString : "[{{_timestamp}}] {{message}} (@{{_from}})"
- }
- })
-```
+## Loggers
-What this does is: it will trigger the method `format` on `formatter`
-passing the `logObject` and `formatterOpts`. This means that a formatter is
-any object that responds to `format(logObject, formatterOpts)`. It expects
-a string to be returned.
+Cologne loggers are any object that responds to the `#log()` method.
+This methoud should be able to receive any number of arguments and
+log them independently. Similar to how you can send multiple arguments
+to the JS console.
-### Cobalt.Logger.File ###
+`#log()` will receive any number of `Cologne Log Objects`. To see what
+this format includes, check further below.
-This logger communicates a file via a writable stream, and is intended
-only for node. Like the JSConsole logger, you can also initialize it with
-a formatter to convert the log object to a string:
+We include two loggers out of the box:
+* `Cologne.Logger.Console` logs to the JS console
+* `Cologne.Logger.File` appends to a file
+
+### Cologne.Logger.Console
+
+This logger communicates the Javascript console. It uses the log level
+to trigger the appropriate method, so `error` logs would go to stderr
+as expected when calling `console.error`.
+
+This logger can be sent a `formatter`, which is an object that responds
+to the `#format()` method: it should get a cologne log object and respond
+with a string.
+
+```javascript
+new Cologne.Logger.Console({
+ formatter : new Cologne.Formatter.Token({
+ formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
+ })
+});
```
- new Cobalt.Logger.File({
- formatter : Cobalt.Formatter.Token,
- formatterOpts : {
- formatString : "[{{_timestamp}}] {{message}} (@{{_from}})"
- }
- })
-```
-What this does is: it will trigger the method `format` on `formatter`
-passing the `logObject` and `formatterOpts`. This means that a formatter is
-any object that responds to `format(logObject, formatterOpts)`. It expects
-a string to be returned.
+### Cologne.Logger.File
+
+This logger opens a writable stream to a file, to which it will append
+everything. Like the Console logger it supports a `formatter` property
+that will respond to the `#format()` method.
+
+It MUST include a `file` property on initialization, otherwise it won't
+know where to write and you'll get an exception and be sad.
+
+```javascript
+new Cologne.Logger.File({
+ file: '/var/log/server_log.log',
+ formatter : new Cologne.Formatter.Token({
+ formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
+ })
+});
+```
-### Cobalt.Logger.Socket ###
+### More Loggers?
-This logger sends the log object to a socket using Socket.IO. It does not
-format the output. To catch the log from the recipient, you have to listen
-for the `log` event, and from there you can pass it to another Cobalt
-instance or do whatever you want with it.
+We're working on a socket logger. It's separate so you don't have to
+install the socket dependencies if you don't want to.
-### More Loggers? ###
+If you need to, you can roll your own. Check info on the interfaces
+below.
You can build your own logger easily for any method of transport you find
necessary (e.g. mail, database, twitter, etc). Any object that responds
-to `#log(logObject)` is a valid logger:
+to `#log()` is a valid logger:
```javascript
// A valid, very minimalistic logger
-var simpleLogger = {
- log : function (logObject) {
- console.log(logObject.message);
+let simpleLogger = {
+ log : function () {
+ for (let logObject of arguments) {
+ this._doSomeMagic(logObject);
+ }
+ },
+
+ _doSomeMagic : function (logObject) {
+ console.log(logObject + "... but magical!");
}
-}
+};
logger.addLogger(simpleLogger);
```
-## Formatters ##
-Cobalt itself makes no assumptions about the output of the logger and just
-passes the object to every logger it has. However, it is clear that loggers
-may want to manipulate this object. As shown in the JsConsole, a formatter
-should respond to the format method and receive a `logObject` and an
-`optsObject`. However, as this is not a core part of Cobalt, this is only a
-recommendation (as this is the way the included JsConsole/File loggers do it)
-and it is up to the logger on how to transform the object it receives.
+## Formatters
+
+Cologne doesn't need formatters to work, and in fact they're optional in
+the included workers. But if you would like to make your logs prettier,
+then you can use one of the included formatters or roll your own.
+
+Formatters are objects that respond to the `#format()` method. It will
+receive a single cologne log object (see fields it includes below), and
+it should return a string. That's all there is to it.
-### Cobalt.Formatter.Simple ###
+We include some formatters so you can get running real quicklike:
+
+* `Cologne.Formatter.Simple` a simple predefined formatter
+* `Cologne.Formatter.Token` a formatter that lets you define format
+ strings that it will use to build your final log.
+
+### Cologne.Formatter.Simple
This is the lazy formatter, it just outputs the string in the following
format:
```
-'[{{_timestamp}}][{{_logLevelString}}]{{_from}}: {{_message}}'
+'[{{_timestamp}}][{{_levelString}}]{{_from}}: {{message}}'
```
Where `_timestamp` is converted to ISO.
-Example output:
+#### Accepted Options
+
+* `colorize` <Boolean>: whether or not to add color. False by default.
+
+By default we don't colorize the output, but if you enable the flag this
+formatter will add a bit of color in the level string. Red for bad,
+yellow for warn, blue for info, and white for everything else.
+#### Usage
+
+```javascript
+new Cologne.Formatter.Simple({
+ colorize: true
+});
```
-cobalt.log("hello world");
-// -> [2015-01-09T16:02:23.102Z][INFO] Generic Cobalt Logger : hello world
+
+### Example Output
+
+```
+co.log("hello world");
+// -> [2016-01-21T05:50:36.505Z][INFO] Server Logger: hello world
```
-### Cobalt.Formatter.Token ###
+### Cologne.Formatter.Token
-The Token formatter is a more advanced, but still fairly simple
-formatter. It takes a `formatString` and interpolates the properties
-of the object. By default it transforms anything inside double curly
-braces `{{likeThis}}`, however you can set a custom `replaceRule`.
+The token formatter lets you build strings with simple tokens. When
+instantiating, you can specify a `formatString` to interpolate
+properties from the logObject. The default version looks for tokens
+inside double curly braces like `{{message}}` or `{{_level}}`. If
+you don't like it, you can specify your own.
-#### Accepted Options ####
+#### Accepted Options
-* `formatString` : The string used to replace. Defaults to `"{{message}}"`
-* `replaceRule` : The regex rule to use for replacement of tokens in the
+* `formatString` <String>: The string used to replace. Defaults to `"{{message}}"`
+* `replaceRule` <String>: The regex rule to use for replacement of tokens in the
formatString. Defaults to `/{{(.*?)}}/g`
-* `separatorLength` <Number> : How long to print separators. Defaults to 60.
* `isoDate` <Boolean> : Whether or not to convert `_timestamp` to ISO
- date. Defaults to true.
-* `separatorType` <String> : The string to use for the separator.
- Defaults to `"="`
-* `ansiColor` <Boolean> : Whether to use ANSI colors for output.
- Defaults to `false`. This options depends on `colors`
-
-#### Options ####
-
-* **formatString**: A string that defines the format of the output. It is a
- string with double curly braces denoting fields. For example:
- `"[{{_timestamp}}] {{message}} (@{{_from}})"` would attempt to extract the
- \_timestamp, message and \_from fields to create a string similar to this:
- `"[124896126491.123] Testing the logger (@Client Application)"`
- (defaults to `"{{message}}"`)
-* **ansiColor**: A boolean value, when `true` will output the string in ANSI
- color depending on the severity level (defaults to `false`)
-
-### More Formatters? ###
-
-As with loggers, cobalt itself does not worry about these things. However,
-if you wish to make a formatter that is exchangable with Token, you just
-need to create an object that responds to the`format(logObject, optionsObject)`
-method:
+ date. Defaults to true. Otherwise it'll use the raw timestamp.
+
+#### Usage
+
+```javascript
+new Cologne.Formatter.Token({
+ formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
+});
+```
+
+#### ANSI tokens
+
+If you want to add color to your logs, you can use the special \_ansi
+token. It has several options which you can call like `{{_ansi:red}}`
+and `{{_ansi:reset}}`. Here's a list of all the ansi stuff you can use:
+
+* `bold`: makes text bold
+* `italics`: makes text italics
+* `underline`: makes text underlined
+* `inverse`: inverts foreground and background
+* `strikethrough`: strikethrough text
+* `bold_off`, `italics_off`, `underline_off`, `inverse_off`, and
+ `strikethrough_off`: turn off the specified effect.
+* `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`,
+ and `default`: change the foreground color of your text.
+* `black_bg`, `red_bg`, `green_bg`, `yellow_bg`, `blue_bg`, `magenta_bg`,
+ `cyan_bg`, `white_bg`, and `default_bg`: change the background color of your
+ text.
+* `reset`: makes everything normal again.
+* `_level`: this is a special code that will set a color depending on
+ the level of the log: debug gets green, info and notice blue, warn is
+ yellow, and anything worse is red.
+
+### More Formatters?
+
+You can create your own formatters by creating an object that responds
+to the `#format()` method, knows how to handle cologne log objects and
+returns a string.
+
+Here's an example of a logger that surrounds a log with sparkles:
```javascript
-// A valid, very minimalistic formatter
var simpleFormatter = {
- format : function (logObject, options) {
- if (options.showDate) {
- return "[" + Date(logObject._timeStamp) + "] " + logObject.message
- } else {
- return logObject.message;
- }
+ format : function (logObject) {
+ return '✨' + logObject.message + '✨';
}
}
-logger.addLogger(new Cobalt.Logger.JsConsole({
- formatter: simpleFormatter,
- formatterOpts : {
- showDate : true
- }
+logger.addLogger(new Cologne.Logger.Console({
+ formatter: simpleFormatter
}));
```
-## The Cobalt Log Format ##
+## The Cologne Log Format
+
+The cologne log format is a JSON based log format, based on the cobalt
+log format, which is inturn based on Graylog's GELF. However, where GELF
+treats all internal fields without a prefix, and all user fields with a
+prefix we do it backwards so it's easier to extend the object with
+metadata from existing objects. Besides, we'll probably write the
+default keys automatically so you shouldn't have to do that extra work.
-The Cobalt Log (CoLog) format is a JSON based log format used with cobalt.
-It is partly inspired in Greylog's GELF format, but with very notorious
-differences. The CoLog requires a header with certain fields that allow
-cobalt and its pieces to handle it. All header fields are prefixed with
-an underscore. Other than those fields, you can put whatever you want in
-the object; It's up to the loggers to make sense of the structure and
-display it in a way that makes sense.
+You could try to build it on your own, but you can use `#buildLog()`
+to build it without logging.
-You can attempt to build this structure on your own, or let cobalt build it for
-you. Any object you pass for logging will be converted. However, if you
-build it on your own you have two options: The first one is use buildLog
-to create a log object for "item" as if you had logged "item" or you can
-use extendLog that will create a dummy log object and extends it with
-whatever object you pass to it.
+### Fields
-### Required Fields ###
+* **\_timestamp** : A timestamp in miliseconds with fractions of a second
+ in the floating point area.
+* **\_cologneLog** <String> : This is how we know if the log is already
+ formatted and ready to go. This field is a string containing the
+ version of cologne log format it's using. It's `1.0.0` right now.
+* **\_from**: The sender of the log (Defaults to Generic Cologne Logger)
+* **\_level**: The level of the log (Defaults to 6)
+* **\_levelString**: The string corresponding to the log level (e.g. 7 ->
+ debug, 3 -> error, 0 -> emerg)
-* **_version** : The version of cobalt this is designed to work with
-* **_timestamp** : A timestamp in microseconds.
-* **_cobaltLog** [true] : Cobalt will check for the \_cobaltLog to decide if
-transformation will happen or not.
+### A word on Log Levels
-### Optional Fields ###
+The log levels in cologne correspond to the syslog levels, and the
+levelStrings correspond to the priority keywords:
-* **\_from**: The sender of the log (Defaults to Generic Cobalt Logger)
-* **\_level**: The level of the log (Defaults to 7)
-* **\_levelString**: The string corresponding to the log level (e.g. 7 ->
- DEBUG, 3 -> ERROR, 0 -> CRIT)
-* **\_indentLevel**: The indent level of the log
-* **\_color**: The color of the log
-* **\_separator**: If true, indicates that this is a separator and holds no
- valuable information.
+* `0 -> emerg`
+* `1 -> alert`
+* `2 -> crit`
+* `3 -> error`
+* `4 -> warning`
+* `5 -> notice`
+* `6 -> info`
+* `7 -> debug`
+
+This is useful when deciding how to log. You could even have a logger
+filter out unnecessary levels (eg. If you have a reporting logger that
+only reports error or worse.)
+
+## Further Improvements
+
+* Improve the API for buildLog
+* More loggers & formatters (will not be distributed in core cologne)
+* Improve tests
+
+[dependencies-shield]: https://david-dm.org/rbdr/cologne.svg
+[circle-ci-shield]: https://circleci.com/gh/rbdr/cologne.svg?style=shield
+++ /dev/null
-{
- "name": "cobalt-log",
- "version": "1.1.0",
- "homepage": "https://github.com/rbdr/cobalt",
- "authors": [
- "Ben Beltran <ben@nsovocal.com>"
- ],
- "description": "Logger + multiplexer for JSON based logs",
- "main": "lib/cobalt.js",
- "keywords": [
- "log"
- ],
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components",
- "test",
- "tests"
- ],
- "dependencies": {
- "neon" : "*"
- }
-}
--- /dev/null
+{
+ "plugins": ["plugins/markdown"],
+ "opts": {
+ "destination": "doc",
+ "readme": "README.md",
+ "template": "node_modules/jsdoc-augmented-template",
+ "recurse": true
+ }
+}
+++ /dev/null
-// Load up dependencies
-if (typeof require === 'function') {
- require('neon');
- var colors = require('colors');
- var Microtime = require('microtime');
-}
-
-Cobalt = Module("Cobalt");
-Module(Cobalt, 'Logger')({});
-Module(Cobalt, 'Formatter')({});
-
-// Load up loggers + formatters
-if (typeof require === 'function') {
- // Formatters
- require('./formatters/token.js');
- require('./formatters/simple.js');
-
- // Loggers
- require('./loggers/console.js');
- require('./loggers/socket.js');
- require('./loggers/file.js');
-}
-
-Cobalt.now = function () {
- if (typeof performance !== 'undefined' && performance.timing) {
- return performance.timing.navigationStart + performance.now();
- }
-
- if (typeof Microtime !== 'undefined') {
- return Microtime.nowDouble() * 1000;
- }
-
- return Date.now();
-}
-
-// Stringify with circular dereference.
-Cobalt.stringify = function (object) {
- var cache = [], stringified;
- stringified = JSON.stringify(object, function (key, value) {
- if (typeof value === 'object' && value !== null) {
- if (cache.indexOf(value) !== -1) {
- return "[Circular]";
- }
- cache.push(value);
- }
- return value;
- });
- cache = null;
-
- return stringified;
-}
-
-Class(Cobalt, 'Console')({
- prototype : {
- from : "Generic Cobalt Logger",
- version : "0.1.0",
- currentIndent : 0,
- indentSize : 2,
- loggers : [],
- separatorLength : 120,
- currentColor : "black",
-
- // Initialize instance of cobalt console
- // and extend configuration.
- init : function (config) {
- var co = this,
- property;
-
- if (config) {
- for (property in config) {
- co[property] = config[property];
- }
- }
- },
-
- addLogger : function (logger) {
- this.loggers.push(logger);
- },
-
- removeLogger : function (logger) {
- var index;
-
- index = this.loggers.indexOf(logger);
- this.loggers.splice(index, 1);
- },
-
- // Builds a Cobalt Log Object
- buildLog : function (item, level) {
- var co = this, oldItem, logObject = {};
-
- if (typeof item === "undefined" || item === null || !item._cobaltLog) {
- logObject.message = item;
- logObject._cobaltLog = true;
- logObject._from = co.from;
- logObject._level = level || 6;
- logObject._levelString = co._levelString(logObject._level);
- logObject._version = co.version;
- logObject._timestamp = co.now();
- logObject._indentLevel = co.currentIndent;
- logObject._color = co.currentColor;
- logObject._separator = false;
- return logObject;
- }
-
- if (item._cobaltLog) {
- item._level = level || item._level || 6;
- item._levelString = co._levelString(item._level);
- }
-
- return item;
- },
-
- extendLog : function (extendingObject) {
- var co = this, logObject,
- property;
-
- logObject = co.buildLog(undefined, 6);
- extendingObject = extendingObject || {};
-
- for (property in extendingObject) {
- if (extendingObject.hasOwnProperty(property)) {
- logObject[property] = extendingObject[property];
- }
- }
-
- return logObject;
- },
-
- buildSeparator : function (type) {
- var co = this;
- return {
- _cobaltLog : true,
- _separator : true,
- _version : co.version,
- _timestamp : co.now(),
- _separatorType : type,
- _indentLevel : co.currentIndent,
- _color : co.currentColor
- }
- },
-
- _log : function (severity) {
- var co = this,
- logString,
- logObjectArray = [],
- i, j;
-
- for (i = 1; i < arguments.length; i++) {
- if (typeof arguments[i] === 'undefined') {
- logObjectArray.push(co.buildLog("undefined", severity));
- } else if (arguments[i] === null) {
- logObjectArray.push(co.buildLog("null", severity));
- } else {
- logObjectArray.push(co.buildLog(arguments[i], severity));
- }
- }
-
- for (j = 0; j < co.loggers.length; j++) {
- co.loggers[j].log.apply(co.loggers[j], logObjectArray);
- }
- },
-
- log : function () {
- this._log.apply(this, [6].concat(Array.prototype.slice.call(arguments)));
- },
-
- debug : function () {
- this._log.apply(this, [7].concat(Array.prototype.slice.call(arguments)));
- },
-
- info : function () {
- this._log.apply(this, [6].concat(Array.prototype.slice.call(arguments)));
- },
-
- notice : function () {
- this._log.apply(this, [5].concat(Array.prototype.slice.call(arguments)));
- },
-
- warn : function () {
- this._log.apply(this, [4].concat(Array.prototype.slice.call(arguments)));
- },
-
- error : function () {
- this._log.apply(this, [3].concat(Array.prototype.slice.call(arguments)));
- },
-
- dir : function () {
- },
-
- time : function () {
- },
-
- timeEnd : function () {
- },
-
- groupCollapsed : function () {
- },
-
- groupEnd : function () {
- },
-
- separator : function (type) {
- var co = this;
-
- co._log(7, co.buildSeparator(type));
- },
-
- space : function (lines) {
- var co = this,
- i;
-
- if (typeof lines === "undefined") {
- lines = 1;
- }
-
- for (i = 0; i < lines; i++) {
- co.log(' ');
- }
-
- return co;
- },
-
- indent : function (callback) {
- var co = this;
-
- if (typeof callback === "function") {
- co.currentIndent = co.currentIndent + co.indentSize;
- callback();
- co.currentIndent = co.currentIndent - co.indentSize;
- } else {
- co.currentIndent = co.currentIndent + co.indentSize;
- }
-
- return co;
- },
-
- outdent : function (callback) {
- var co = this;
-
- if (typeof callback === "function") {
- co.currentIndent = co.currentIndent - co.indentSize;
- if (co.currentIndent < 0) {
- co.currentIndent = 0;
- }
-
- callback();
-
- co.currentIndent = co.currentIndent + co.indentSize;
- } else {
- co.currentIndent = co.currentIndent - co.indentSize;
- if (co.currentIndent < 0) {
- co.currentIndent = 0;
- }
- }
-
- return co;
- },
-
- color : function (color, callback) {
- var co = this,
- oldColor = co.currentColor;
-
- if (typeof callback === "function") {
- co.currentColor = color;
- callback();
- co.currentColor = oldColor;
- } else {
- co.currentColor = color;
- }
-
- return co;
- },
-
- // Returns the current time in microseconds.
- now : function () {
- if (typeof performance !== 'undefined' && performance.timing) {
- return performance.timing.navigationStart + performance.now();
- }
-
- if (typeof Microtime !== 'undefined') {
- return Microtime.nowDouble() * 1000;
- }
-
- return Date.now();
- },
-
- _levelString : function (level) {
- switch(level) {
- case 0:
- return "PANIC";
- break;
- case 1:
- return "ALERT"
- break;
- case 2:
- return "CRIT"
- break;
- case 3:
- return "ERROR"
- break;
- case 4:
- return "WARN"
- break;
- case 5:
- return "NOTICE"
- break;
- case 6:
- return "INFO"
- break;
- case 7:
- return "DEBUG"
- break;
- }
- }
- }
-});
-
-if (Cobalt.Console.__objectSpy) {
- Cobalt.Console.__objectSpy.destroy();
-}
--- /dev/null
+'use strict';
+
+let LogUtilities = require('./cologne/log_utilities');
+
+/** TYPE DEFINITIONS **/
+
+/**
+ * Main interface for Cologne Loggers
+ *
+ * @memberof Cologne
+ * @interface ILogger
+ */
+
+/**
+ * Receives any number of cologne log objects and logs them.
+ *
+ * @memberof Cologne.ILogger
+ * @function
+ * @name log
+ * @returns {undefined}
+ */
+
+/**
+ * Main interface for Cologne Formatters
+ *
+ * @memberof Cologne
+ * @interface IFormatter
+ */
+
+/**
+ * Receives a cologne log object and returns a formatted string.
+ *
+ * @memberof Cologne.IFormatter
+ * @function
+ * @name format
+ * @param {Cologne.tCologneLog} logObject the log to be formatted
+ * @returns {string} the formatted log
+ */
+
+/**
+ * The main cologne log format.
+ *
+ * @memberof Cologne
+ * @typedef {object} tCologneLog
+ * @property {Number} _timestamp the timestamp in miliseconds with decimal
+ * numbers representing fractions of miliseconds
+ * @property {String} _cologneLog main identifier, encodes the version of the
+ * cologne log format being used.
+ * @property {String} _from the origin of the log message.
+ * @property {String} _level the severity level of the log, uses syslog
+ * priorities.
+ * @property {String} _levelString the severity level keyword of the log,
+ * uses syslog priority keywords.
+ */
+
+/**
+ * Cologne is a logger multiplexer that works mainly with a JSON format. It
+ * can be instantiated with several loggers, or they can be changed after
+ * the fact.
+ *
+ * ## Usage
+ *
+ * ```
+ * require('cologne');
+ *
+ * let co = new Cologne({
+ * from: "Special Worker Logger",
+ * loggers: [
+ * new Cologne.Logger.Console({
+ * formatter: new Cologne.Formatter.Token({
+ * formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
+ * })
+ * })
+ * ]
+ * });
+ * ```
+ *
+ * @class Cologne
+ */
+let Cologne = class Cologne {
+
+ constructor (config) {
+
+ /**
+ * The name of this logger, useful to distinguish between different
+ * loggers.
+ *
+ * @name from
+ * @instance
+ * @memberof Cologne
+ * @type String
+ * @default 'Generic Cologne Logger
+ */
+ this.from = 'Generic Cologne Logger';
+
+ /**
+ * The array containing all the loggers it will call to.
+ *
+ * @name loggers
+ * @instance
+ * @memberof Cologne
+ * @type Cologne.ILogger[]
+ * @default []
+ */
+ this.loggers = [];
+
+ Object.assign(this, config || {});
+ }
+
+ /**
+ * Adds a logger to the current instance.
+ *
+ * @function addLogger
+ * @instance
+ * @memberof Cologne
+ * @param {Cologne.ILogger} logger the logger to add
+ * @return {undefined}
+ */
+ addLogger (logger) {
+ this.loggers.push(logger);
+ }
+
+ /**
+ * Removes a logger from the current instance.
+ *
+ * @function removeLogger
+ * @instance
+ * @memberof Cologne
+ * @param {Cologne.ILogger} logger the logger to remove
+ * @return {Cologne.ILogger[]} the removed log, inside an array.
+ */
+ removeLogger (logger) {
+ let index;
+
+ index = this.loggers.indexOf(logger);
+ if (index >= 0) {
+ this.loggers.splice(index, 1);
+ }
+ }
+
+ /**
+ * Given an item, it builds a cologne log object. this is done
+ * automatically by the logger, though this is useful if you need
+ * to attach metadata before logging.
+ *
+ * @function buildLog
+ * @instance
+ * @memberof Cologne
+ * @param {*} item The item to log
+ * @return {Cologne.tCologneLog} a cologne log object
+ */
+ buildLog (item, level, meta) {
+ let logObject;
+
+ logObject = {};
+
+ if (typeof item === 'undefined' || item === null || !item._cologneLog) {
+ logObject.message = item;
+ logObject._cologneLog = this.constructor._version;
+ logObject._from = this.from;
+ logObject._level = level || 6;
+ logObject._levelString = this._levelString(logObject._level);
+ logObject._timestamp = LogUtilities.now();
+
+ if (meta && typeof meta === 'object') {
+ Object.assign(logObject, meta);
+ }
+
+ return logObject;
+ }
+
+ if (item._cologneLog) {
+ item._level = level || item._level || 6;
+ item._levelString = this._levelString(item._level);
+ }
+
+ return item;
+ }
+
+ /**
+ * Default log function. Sends arguments to loggers. If not specified in log
+ * object, it will set the severity to 6 - INFO.
+ *
+ * @function log
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ log () {
+ this._log.apply(this, [null].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ /**
+ * Logs with debug level
+ *
+ * @function debug
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ debug () {
+ this._log.apply(this, [7].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ /**
+ * Logs with info level
+ *
+ * @function info
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ info () {
+ this._log.apply(this, [6].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ /**
+ * Logs with notice level
+ *
+ * @function notice
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ notice () {
+ this._log.apply(this, [5].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ /**
+ * Logs with warn level
+ *
+ * @function warn
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ warn () {
+ this._log.apply(this, [4].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ /**
+ * Logs with error level
+ *
+ * @function error
+ * @instance
+ * @memberof Cologne
+ * @return {undefined}
+ */
+ error () {
+ this._log.apply(this, [3].concat(Array.prototype.slice.call(arguments)));
+ }
+
+ // Private method that builds all the logs and sends them to the loggers.
+ _log (severity) {
+ let remainingArguments, logObjectArray, log, logger;
+
+ remainingArguments = Array.prototype.slice.call(arguments, 1);
+ logObjectArray = [];
+
+ for (log of remainingArguments) {
+ if (typeof log === 'undefined') {
+ logObjectArray.push(this.buildLog('undefined', severity));
+ continue;
+ }
+
+ if (log === null) {
+ logObjectArray.push(this.buildLog('null', severity));
+ continue;
+ }
+
+ logObjectArray.push(this.buildLog(log, severity));
+ }
+
+ for (logger of this.loggers) {
+ logger.log.apply(logger, logObjectArray);
+ }
+ }
+
+ // Private utility method that will return the string for any given
+ // numerical severity level
+ _levelString (level) {
+ switch(level) {
+ case 0:
+ return 'emerg';
+ case 1:
+ return 'alert';
+ case 2:
+ return 'crit';
+ case 3:
+ return 'error';
+ case 4:
+ return 'warning';
+ case 5:
+ return 'notice';
+ case 6:
+ return 'info';
+ case 7:
+ return 'debug';
+ }
+ }
+};
+
+// Version of the Cologne Log Format used.
+Cologne._version = '1.0.0';
+
+/**
+ * Namespace that includes the built-in formatters.
+ *
+ * @namespace Formatter
+ * @memberof Cologne
+ */
+Cologne.Formatter = {};
+Cologne.Formatter.Simple = require('./cologne/formatter/simple');
+Cologne.Formatter.Token = require('./cologne/formatter/token');
+
+/**
+ * Namespace that includes the built-in loggers.
+ *
+ * @namespace Logger
+ * @memberof Cologne
+ */
+Cologne.Logger = {};
+Cologne.Logger.Console = require('./cologne/logger/console');
+Cologne.Logger.File = require('./cologne/logger/file');
+
+Cologne.LogUtilities = require('./cologne/log_utilities');
+
+module.exports = Cologne;
--- /dev/null
+'use strict';
+
+let LogUtilities = require('../log_utilities');
+
+/**
+ * Simple formatter. Outputs a predefined format:
+ * `[{{_timestamp}}][{{_levelString}}] {{_from}}: {{message}}`;
+ *
+ * @memberof Cologne.Formatter
+ * @implements Cologne.IFormatter
+ * @class Simple
+ */
+let SimpleFormatter = class SimpleFormatter {
+
+ constructor (config) {
+
+ /**
+ * Flag that tells us whether or not to use ANSI color. Defaults to
+ * false.
+ *
+ * @name colorize
+ * @instance
+ * @memberof Cologne.Formatter.Simple
+ * @type Boolean
+ * @default false
+ */
+ this.colorize = false;
+
+ Object.assign(this, config || {});
+ }
+
+ /**
+ * Main entry point, it will read the incoming log object and convert
+ * it to the output string.
+ *
+ * @function format
+ * @instance
+ * @memberof Cologne.Formatter.Simple
+ * @param {Cologne.tCologneLog} logObjet the log to format
+ * @return {String} the formatted object
+ */
+ format (logObject) {
+ let date, levelString;
+
+ date = new Date(logObject._timestamp);
+ date = date.toISOString();
+ levelString = this._colorize(logObject._levelString, logObject._level);
+
+ return `[${date}][${levelString}] ${logObject._from}: ${logObject.message}`;
+ }
+
+ _colorize (levelString, level) {
+ let escapeCode, color, reset;
+
+ if (!this.colorize) {
+ return levelString;
+ }
+
+ escapeCode = String.fromCharCode(27);
+ color = escapeCode + LogUtilities.getAnsiCode(LogUtilities.getLevelAnsi(level));
+ reset = escapeCode + LogUtilities.getAnsiCode('reset');
+
+ return color + levelString + reset;
+ }
+};
+
+module.exports = SimpleFormatter;
--- /dev/null
+'use strict';
+
+let LogUtilities = require('../log_utilities');
+
+/**
+ * Token formatter. Given a format string it will attempt to output
+ * a message.
+ *
+ * @memberof Cologne.Formatter
+ * @implements Cologne.IFormatter
+ * @class Token
+ */
+let TokenFormatter = class TokenFormatter {
+ constructor (config) {
+
+ /**
+ * The string to use as a template string. By default, any property
+ * inside double curly braces `{{likeThis}}` will be extracted from
+ * the object and replaced. If the object does not contain the
+ * property, it will leave it.
+ *
+ * @name formatString
+ * @instance
+ * @memberof Cologne.Formatter.Token
+ * @type String
+ * @default '{{message}}'
+ */
+ this.formatString = '{{message}}';
+
+ /**
+ * The regex rule to use to match the tokens.
+ *
+ * @name replaceRule
+ * @instance
+ * @memberof Cologne.Formatter.Token
+ * @type RegExp
+ * @default /{{(.*)}}/g
+ */
+ this.replaceRule = /{{(.*?)}}/g;
+
+ /**
+ * Flag that specifies whether or not to use an isoDate when using
+ * `_timestamp`. If false it will output the raw timestamp.
+ *
+ * @name isoDate
+ * @instance
+ * @memberof Cologne.Formatter.Token
+ * @type Boolean
+ * @default true
+ */
+ this.isoDate = true;
+
+ this._ansiRe = /_ansi:.+/;
+
+ Object.assign(this, config || {});
+ }
+
+ /**
+ * Main entry point, it will read the incoming log object and convert
+ * all the tokens to their corresponding representation, finally
+ * returning the string.
+ *
+ * @function format
+ * @instance
+ * @memberof Cologne.Formatter.Token
+ * @param {Cologne.tCologneLog} logObjet the log to format
+ * @return {String} the formatted object
+ */
+ format (logObject) {
+ let resultString, escapeCode;
+
+ escapeCode = String.fromCharCode(27);
+
+ resultString = this.formatString.replace(this.replaceRule, function (match, token) {
+ let date, ansiType;
+
+ if (token === '_timestamp' && this.isoDate) {
+ date = new Date(logObject._timestamp);
+ return date.toISOString();
+ }
+
+ if (token.match(this._ansiRe)) {
+ ansiType = token.split(':')[1];
+
+ // Smartish coloring
+ if (ansiType === '_level') {
+ return escapeCode + LogUtilities.getAnsiCode(LogUtilities.getLevelAnsi(logObject._level));
+ }
+
+ return escapeCode + LogUtilities.getAnsiCode(ansiType);
+ }
+
+ if (!logObject.hasOwnProperty(token)) {
+ return match;
+ }
+
+ return logObject[token];
+ }.bind(this));
+
+ return resultString;
+ }
+};
+
+module.exports = TokenFormatter;
--- /dev/null
+'use strict';
+
+let microtime = require('microtime');
+
+/**
+ * Container object for utilities used by loggers.
+ *
+ * @memberof Cologne
+ * @class LogUtilities
+ */
+let LogUtilities = {
+
+ /**
+ * Returns the current timestamp in miliseconds as a floating point that
+ * includes fractions (ie. microseconds)
+ *
+ * @function now
+ * @memberof Cologne.LogUtilities
+ * @return {Number} current time in miliseconds, including fractions.
+ */
+ now: function now() {
+ return microtime.nowDouble() * 1000;
+ },
+
+ /**
+ * Stringifies objects, avoiding circular references.
+ *
+ * @function stringify
+ * @memberof Cologne.LogUtilities
+ * @param {Object} object the object to stringify
+ * @return {String} the stringified object
+ */
+ stringify: function stringify(object) {
+ let cache;
+
+ cache = [];
+
+ return JSON.stringify(object, function (key, value) {
+ if (typeof value === 'object' && value !== null) {
+ if (cache.indexOf(value) !== -1) {
+ return this._circularString;
+ }
+
+ cache.push(value);
+ }
+
+ return value;
+ }.bind(this));
+ },
+
+ /**
+ * Given an ansi keyword, it will return the appropriate code.
+ *
+ * @function getAnsiCode
+ * @memberof Cologne.LogUtilities
+ * @param {String} ansiString the name of the desired code
+ * @return {String} the ansi code
+ */
+ getAnsiCode: function getAnsiCode(ansiString) {
+ switch(ansiString) {
+ case 'bold':
+ return '[1m';
+ case 'italics':
+ return '[3m';
+ case 'underline':
+ return '[4m';
+ case 'inverse':
+ return '[7m';
+ case 'strikethrough':
+ return '[9m';
+ case 'bold_off':
+ return '[22m';
+ case 'italics_off':
+ return '[23m';
+ case 'underline_off':
+ return '[24m';
+ case 'inverse_off':
+ return '[27m';
+ case 'strikethrough_off':
+ return '[29m';
+ case 'black':
+ return '[30m';
+ case 'red':
+ return '[31m';
+ case 'green':
+ return '[32m';
+ case 'yellow':
+ return '[33m';
+ case 'blue':
+ return '[34m';
+ case 'magenta':
+ return '[35m';
+ case 'cyan':
+ return '[36m';
+ case 'white':
+ return '[37m';
+ case 'default':
+ return '[39m';
+ case 'black_bg':
+ return '[40m';
+ case 'red_bg':
+ return '[41m';
+ case 'green_bg':
+ return '[42m';
+ case 'yellow_bg':
+ return '[43m';
+ case 'blue_bg':
+ return '[44m';
+ case 'magenta_bg':
+ return '[45m';
+ case 'cyan_bg':
+ return '[46m';
+ case 'white_bg':
+ return '[47m';
+ case 'default_bg':
+ return '[49m';
+ case 'reset': // for informative purpouses
+ default:
+ return '[0m';
+ }
+ },
+
+ /**
+ * Given a level, it will return the appropriate ansi keyword related
+ * to it.
+ *
+ * @function getLevelAnsi
+ * @memberof Cologne.LogUtilities
+ * @param {number} level the level of the log
+ * @return {String} the ansi keyword
+ */
+ getLevelAnsi: function getLevelAnsi(level) {
+ switch(level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ return 'red';
+ case 4:
+ return 'yellow';
+ case 5:
+ case 6:
+ return 'blue';
+ case 7:
+ return 'green';
+ default:
+ return 'default';
+ }
+ }
+};
+
+// String used as default circular reference.
+LogUtilities._circularString = '[Circular]';
+
+module.exports = LogUtilities;
--- /dev/null
+'use strict';
+
+let LogUtilities = require('../log_utilities');
+
+/**
+ * Logger for the javascript console.
+ *
+ * @memberof Cologne.Logger
+ * @implements Cologne.ILogger
+ * @class Console
+ */
+let ConsoleLogger = class ConsoleLogger {
+ constructor (config) {
+
+ /**
+ * The console it will write to, can be any object that looks
+ * and acts like a console, including other cologne objects.
+ *
+ * @name console
+ * @instance
+ * @memberof Cologne.Logger.Console
+ * @type Object
+ * @default global.console
+ */
+ this.console = console;
+
+ /**
+ * The formatter it will use to output the log. If not present it
+ * will output raw JSON
+ *
+ * @name formatter
+ * @instance
+ * @memberof Cologne.Logger.Console
+ * @type Cologne.IFormatter
+ * @default null
+ */
+ this.formatter = null;
+
+ Object.assign(this, config || {});
+ }
+
+
+ /**
+ * Main entry point, for each incoming argument it will attempt to
+ * format and send to the console.
+ *
+ * @function log
+ * @instance
+ * @memberof Cologne.Logger.Console
+ * @return {undefined}
+ */
+ log () {
+ let logObject, messages, severity;
+
+ messages = [];
+
+ for (logObject of arguments) {
+ messages.push(this._format(logObject));
+
+ if (!severity) {
+ severity = logObject._level;
+ }
+ }
+
+ switch(severity) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ this.console.error.apply(this.console, messages);
+ break;
+ case 4:
+ this.console.warn.apply(this.console, messages);
+ break;
+ case 5:
+ case 6:
+ this.console.info.apply(this.console, messages);
+ break;
+ case 7:
+ default:
+ this.console.log.apply(this.console, messages);
+ break;
+ }
+ }
+
+ _format (logObject) {
+ if (this.formatter) {
+ return this.formatter.format(logObject);
+ }
+
+ return LogUtilities.stringify(logObject);
+ }
+};
+
+module.exports = ConsoleLogger;
--- /dev/null
+'use strict';
+
+let fs = require('fs');
+
+let LogUtilities = require('../log_utilities');
+
+/**
+ * Logger for files.
+ *
+ * @memberof Cologne.Logger
+ * @implements Cologne.ILogger
+ * @class File
+ */
+let FileLogger = class FileLogger {
+ constructor (config) {
+
+ /**
+ * Path to the file it will write to, must be readable.
+ *
+ * @name file
+ * @instance
+ * @memberof Cologne.Logger.File
+ * @type string
+ * @default null
+ */
+ this.file = null;
+
+ /**
+ * The formatter it will use to output the log. If not present it
+ * will output raw JSON
+ *
+ * @name formatter
+ * @instance
+ * @memberof Cologne.Logger.File
+ * @type Cologne.IFormatter
+ * @default null
+ */
+ this.formatter = null;
+
+ Object.assign(this, config || {});
+
+ this._stream = fs.createWriteStream(this.file, {flags: 'a'});
+ }
+
+ /**
+ * Main entry point, for each incoming argument it will attempt to
+ * format and send to the stream to be written.
+ *
+ * @function log
+ * @instance
+ * @memberof Cologne.Logger.File
+ * @return {undefined}
+ */
+ log () {
+ let logObject;
+
+ for (logObject of arguments) {
+ this._stream.write(this.format(logObject) + '\n');
+ }
+ }
+
+ format (logObject) {
+ if (this.formatter) {
+ return this.formatter.format(logObject);
+ }
+
+ return LogUtilities.stringify(logObject);
+ }
+};
+
+module.exports = FileLogger;
+++ /dev/null
-var bindEvents = function (socket, logger) {
- socket.on('log', function (logArgs) {
- logger.log.apply(logger, logArgs);
- });
-}
-
-exports.bindEvents = bindEvents;
+++ /dev/null
-if (typeof require === 'function') {
- require('colors');
-}
-
-Module(Cobalt.Formatter, 'Ansi')({
- format : function (logObject, opts){
- var indent,
- message;
-
- indent = Array(logObject._indentLevel + 1).join(' ');
-
- message = indent + logObject.message;
-
- switch(logObject._level) {
- case 0:
- case 1:
- case 2:
- case 3:
- return message.red;
- case 4:
- return message.yellow;
- case 5:
- case 6:
- return message.blue;
- default:
- return message;
- }
- }
-});
+++ /dev/null
-Module(Cobalt.Formatter, 'Simple')({
- format : function (logObject, opts){
- var indent, date;
-
- indent = Array(logObject._indentLevel + 1).join(' ');
-
- date = new Date(logObject._timestamp);
-
- return indent + '[' + date.toISOString() + '][' + logObject._levelString + '] ' + logObject._from + ' : ' + logObject.message;
- }
-});
+++ /dev/null
-Module(Cobalt.Formatter, 'Token')({
- formatString : "{{message}}",
- replaceRule : /{{(.*?)}}/g,
- separatorLength : 60,
- isoDate : true,
- separatorType : "-",
- format : function (logObject, opts){
- var indent, indentSize,
- separatorLength, separatorType,
- output, property;
- indentSize = logObject._indentLevel || 0;
-
- // Extend opts
- if (opts) {
- for (property in opts) {
- if (opts.hasOwnProperty(property)) {
- this[property] = opts[property];
- }
- }
- }
-
- indent = Array(indentSize + 1).join(' ');
-
- if (logObject._separator) {
- separatorLength = logObject._separatorLength || this.separatorLength;
- separatorType = logObject._separatorType || this.separatorType;
- output = indent + Array(separatorLength - indentSize + 1).join(separatorType);
- } else {
- output = indent + this.parseFormatString(logObject, this.formatString);
- }
-
- if (this.ansiColor) {
- output = this.colorize(logObject._level, output);
- }
-
- return output;
- },
-
- parseFormatString : function (logObject, formatString) {
- var resultString = '';
- if (typeof formatString === 'undefined') {
- formatString = this.formatString;
- }
-
- resultString = formatString.replace(this.replaceRule, function(match, paren){
- var date;
- if (paren === "_timestamp" && this.isoDate) {
- date = new Date(logObject[paren]);
- return date.toISOString();
- }
- return logObject[paren] || "-";
- }.bind(this));
-
- return resultString;
- },
-
- colorize : function (level, message) {
- switch(level) {
- case 0:
- case 1:
- case 2:
- case 3:
- return message.red;
- case 4:
- return message.yellow;
- case 5:
- case 6:
- return message.blue;
- default:
- return message;
- }
- }
-});
+++ /dev/null
-Class(Cobalt.Logger, 'JsConsole')({
- prototype : {
- console : null,
- formatterOpts : {},
-
- init : function (config) {
- var logger = this,
- property;
-
- if (config) {
- for (property in config) {
- logger[property] = config[property];
- }
- }
-
- if (!logger.console) {
- logger.console = console;
- }
- },
-
- log : function () {
- var i, message = [], severity;
-
- for (i = 0; i < arguments.length; i++) {
- // We're not formatting objects for now.
-
- if (!arguments[i].__skipConsole && !arguments[i].message.__skipConsole) {
- if (typeof arguments[i].message === 'object') {
- message.push(arguments[i].message);
- } else {
- message.push(this.format(arguments[i]));
- }
- if (!severity) {
- severity = arguments[i]._level
- }
- }
- }
-
- switch (severity){
- case 0:
- case 1:
- case 2:
- case 3:
- this.console.error.apply(this.console, message);
- break;
- case 4:
- this.console.warn.apply(this.console, message);
- break;
- case 5:
- case 6:
- this.console.info.apply(this.console, message);
- break;
- case 7:
- default:
- this.console.log.apply(this.console, message);
- break;
- }
- },
-
- format : function (logObject) {
- // Usually what you want to do here is format. Preferably using
- // someone inside Cobalt.Formatter
- if (this.formatter) {
- return this.formatter.format(logObject, this.formatterOpts);
- }
-
- return logObject.message;
- }
- }
-});
+++ /dev/null
-var fs = require('fs');
-
-Class(Cobalt.Logger, 'File')({
- prototype : {
- file : null,
- formatterOpts : {},
-
- init : function (config) {
- if (config) {
- for (property in config) {
- this[property] = config[property];
- }
- }
-
- this._stream = fs.createWriteStream(this.file, {flags: 'a'});
- },
-
- log : function () {
- var i, message = [], severity;
-
- for (i = 0; i < arguments.length; i++) {
- // We're not formatting objects for now.
-
- if (!arguments[i].__skipConsole && !arguments[i].message.__skipConsole) {
- message.push(this.format(arguments[i]));
- if (!severity) {
- severity = arguments[i]._level
- }
- }
- }
-
- for (i = 0; i < message.length; i++) {
- this._stream.write(message[i] + '\n');
- }
- },
-
- format : function (logObject) {
- if (this.formatter) {
- if (typeof logObject.message === 'object') {
- return logObject.message;
- }
- return this.formatter.format(logObject, this.formatterOpts);
- }
-
- return Cobalt.stringify(logObject);
- }
- }
-});
+++ /dev/null
-if (typeof require === 'function') {
- var ioClient = require('socket.io-client');
-}
-
-Class(Cobalt.Logger, 'Socket')({
- prototype : {
- serverUrl : '/',
-
- init : function (config) {
- var logger = this;
-
- if (config) {
- for (property in config) {
- logger[property] = config[property];
- }
- }
-
- if (!logger.socketIo) {
- logger.socketIo = ioClient;
- }
-
- logger._socket = logger.socketIo.connect(logger.serverUrl);
- },
-
- log : function () {
- var i, messageArray = [];
-
- for (i = 0; i < arguments.length; i++) {
- messageArray.push(arguments[i]);
- }
-
- if (this._socket) {
- this._socket.emit('log', messageArray);
- }
- }
- }
-});
{
- "name": "cobalt-log",
- "description": "Logger + multiplexer for JSON based logs, based on Cobalt ruby gem by ktlacaelel (http://rubygems.org/gems/cobalt)",
+ "name": "cologne",
+ "description": "Logger + multiplexer for JSON based logs",
"author": {
"name": "Ben Beltran",
"email": "ben@nsovocal.com",
- "url": "http://nsovocal.com"
+ "url": "http://unlimited.pizza"
},
"repository": {
"type": "git",
- "url": "https://github.com/rbdr/cobalt.git"
+ "url": "https://github.com/rbdr/cologne.git"
},
- "contributors": [
- {
- "name": "Kazuyoshi Tlacaelel",
- "email": "kazu.dev@gmail.com",
- "url": "http://github.com/ktlacaelel"
- }
- ],
- "version": "1.1.3",
+ "version": "1.1.0",
"dependencies": {
- "colors": "^1.0.3",
- "emailjs": "^0.3.12",
- "microtime": "^1.2.0",
- "neon": "^2.0.0",
- "socket.io-client": "^1.2.1"
+ "microtime": "2.0.x"
},
"devDependencies": {
- "tellurium": "2.0.x"
+ "tap": "5.1.x",
+ "jsdoc-augmented-template": "rbdr/jsdoc-augmented-template"
},
"engines": {
- "node": ">= 0.8.0"
+ "node": ">= 4.0.0"
},
- "main": "./lib/cobalt.js"
+ "scripts": {
+ "test": "node_modules/tap/bin/run.js test/*.js test/**/*.js test/**/**/*.js",
+ "document": "jsdoc -c ./config/jsdoc.json lib"
+ },
+ "main": "./lib/cologne.js"
}
+++ /dev/null
-if (typeof require === "function") {
- require("cobalt-log");
-}
-
-var co = new Cobalt.Console({
- loggers : [
- new Cobalt.Logger.JsConsole({
- formatter : Cobalt.Formatter.Token,
- formatterOpts : {
- formatString : "[{{_level}}] {{message}} {{customParam}}"
- }
- })
- ]
-})
-
-// TODO: Do this whole thing with tellurium.
-
-co.log("Log - Normal");
-co.debug("Warn - Normal");
-co.info("Info - Normal");
-co.notice("Notice - Normal");
-co.warn("Warn - Normal");
-co.error("Error - Normal");
-
-var logObject = co.extendLog({
- message : "Extended Log Object",
- customParam : "<3"
-});
-
-co.log(logObject);
-co.debug(logObject);
-co.info(logObject);
-co.notice(logObject);
-co.warn(logObject);
-co.error(logObject);
+++ /dev/null
-<!DOCTYPE html>
-<html>
- <head>
- <title>Tellurium Test Runner</title>
-
- <!-- load neon dependency. These are node modules, I'm not sure this is a good way to load it -->
- <script src="../node_modules/neon/neon.js" type="text/javascript" charset="utf-8"></script>
-
- <!-- include cobalt -->
- <script src="../node_modules/cobalt-log/lib/cobalt.js" type="text/javascript" charset="utf-8"></script>
- <script src="../node_modules/cobalt-log/lib/loggers/console.js" type="text/javascript" charset="utf-8"></script>
- <script src="../node_modules/cobalt-log/lib/formatters/token.js" type="text/javascript" charset="utf-8"></script>
-
- <!-- include test files here... -->
- <script type="text/javascript" src="basic.js"></script>
-
- </head>
- <body>
- </body>
-</html>
--- /dev/null
+'use strict';
+
+let tap = require('tap');
+
+let Cologne = require('../lib/cologne');
+
+let dummyLogger = {
+ values : null,
+ log : function () {
+ let logObject;
+
+ this.values = [];
+
+ for (logObject of arguments) {
+ this.values.push(logObject);
+ }
+ }
+};
+
+// Prepare the test
+let dummyLoggerA, dummyLoggerB, dummyLoggerC,
+ co, params, builtLog, meta,
+ valueCheck, levelCheck;
+
+tap.plan(18);
+
+dummyLoggerA = Object.assign({}, dummyLogger);
+dummyLoggerB = Object.assign({}, dummyLogger);
+dummyLoggerC = Object.assign({}, dummyLogger);
+
+co = new Cologne({
+ loggers : [
+ dummyLoggerA,
+ dummyLoggerB
+ ]
+});
+
+meta = {
+ rainbows: true
+};
+
+params = ['example1', null, undefined, 1, {example: true}];
+
+/**
+ * TEST: #log()
+ */
+co.log.apply(co, params);
+
+// Calculate values
+valueCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (typeof current._cologneLog === 'string') {
+ previous++;
+ }
+ return previous;
+}, 0);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 6) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+// Now check the values
+
+tap.equal(dummyLoggerA.values.length, params.length,
+ '#log() should send every argument to the loggers');
+
+tap.similar(dummyLoggerA.values, dummyLoggerB.values,
+ '#log() should send the same arguments to all the loggers');
+
+tap.equal(valueCheck, params.length,
+ '#log() should send all objects in cologne log format');
+
+tap.equal(levelCheck, params.length,
+ '#log() should default to level 6');
+
+/**
+ * TEST: #debug()
+ */
+co.debug.apply(co, params);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 7) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, params.length,
+ '#debug() should set to level 7');
+
+/**
+ * TEST: #info()
+ */
+co.info.apply(co, params);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 6) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, params.length,
+ '#info() should set to level 6');
+
+/**
+ * TEST: #notice()
+ */
+co.notice.apply(co, params);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 5) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, params.length,
+ '#notice() should set to level 5');
+
+/**
+ * TEST: #warn()
+ */
+co.warn.apply(co, params);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 4) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, params.length,
+ '#warn() should set to level 4');
+
+/**
+ * TEST: #error()
+ */
+co.error.apply(co, params);
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 3) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, params.length,
+ '#error() should set to level 3');
+
+/**
+ * TEST: #buildLog()
+ */
+builtLog = co.buildLog('example');
+
+// With the default level
+tap.equal(typeof builtLog._cologneLog, 'string',
+ '#buildLog() should return a cologne log');
+tap.equal(builtLog._level, 6,
+ '#buildLog() should default to level 6');
+
+// Now with a specific value
+builtLog = co.buildLog('example', 1);
+
+tap.equal(builtLog._level, 1,
+ '#buildLog() should use the specified level');
+
+// Now with meta
+builtLog = co.buildLog('example', 1, meta);
+
+tap.equal(builtLog.rainbows, true,
+ '#buildLog() should extend the object with meta if available');
+
+/**
+ * TEST: #log() with builtLog.
+ */
+co.log(builtLog);
+
+levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
+ if (current._level === 1) {
+ previous++;
+ }
+ return previous;
+}, 0);
+
+tap.equal(levelCheck, 1,
+ '#log() calls using a pre-built cologne log should maintain the log level');
+
+
+/**
+ * TEST: #removeLogger()
+ */
+co.removeLogger(dummyLoggerC);
+
+tap.equal(co.loggers.length, 2,
+ '#removeLogger() should do nothing if it can\'t find a logger');
+
+co.log.apply(co, params);
+co.removeLogger(dummyLoggerB);
+co.log(1);
+
+tap.equal(co.loggers.length, 1,
+ '#removeLogger() should remove a logger');
+
+tap.notEqual(dummyLoggerB.values.length, dummyLoggerA.values.length,
+ '#removeLogger() should no longer affect removed logs');
+
+/**
+ * TEST: #addLogger()
+ */
+
+co.addLogger(dummyLoggerC);
+co.log.apply(co, params);
+
+tap.equal(dummyLoggerC.values.length, params.length,
+ '#addLogger() should add loggers after instance is live');
--- /dev/null
+'use strict';
+
+let tap = require('tap');
+
+let SimpleFormatter = require('../../../lib/cologne/formatter/simple');
+
+// Prepare the test
+let logObject, colorFormatter, plainFormatter, formattedString, isoDate;
+
+tap.plan(12);
+
+logObject = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 3,
+ _levelString: 'error',
+ message: 'testing stuff!'
+};
+isoDate = (new Date(logObject._timestamp)).toISOString();
+
+plainFormatter = new SimpleFormatter();
+colorFormatter = new SimpleFormatter({
+ colorize: true
+});
+
+/**
+ * TEST: #format() - plain
+ */
+
+formattedString = plainFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in plain mode');
+
+tap.ok(formattedString.match(logObject._from),
+ '#format() should include the from property in plain mode');
+
+tap.ok(formattedString.match(isoDate),
+ '#format() should include the timestamp property in iso format in plain mode');
+
+tap.ok(formattedString.match(logObject._levelString),
+ '#format() should include the level string property in plain mode');
+
+tap.ok(formattedString.match(logObject.message),
+ '#format() should include the message property in plain mode');
+
+/**
+ * TEST: #format() - colorized
+ */
+
+formattedString = colorFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in color mode');
+
+tap.ok(formattedString.match(logObject._from),
+ '#format() should include the from property in color mode');
+
+tap.ok(formattedString.match(isoDate),
+ '#format() should include the timestamp property in iso format in color mode');
+
+tap.ok(formattedString.match(logObject._levelString),
+ '#format() should include the level string property in color mode');
+
+tap.ok(formattedString.match(logObject.message),
+ '#format() should include the message property in color mode');
+
+tap.equal(formattedString.split(String.fromCharCode(27) + '[31m').length, 2,
+ '#format() should colorize the string');
+
+tap.equal(formattedString.split(String.fromCharCode(27) + '[0m').length, 2,
+ '#format() should colorize only a bit of the string');
--- /dev/null
+'use strict';
+
+let tap = require('tap');
+
+let TokenFormatter = require('../../../lib/cologne/formatter/token');
+
+// Prepare the test
+let logObject, defaultFormatter, customFormatter, ansiFormatter,
+ plainDateFormatter, customSearchFormatter, formattedString, isoDate;
+
+tap.plan(13);
+
+logObject = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 3,
+ _levelString: 'error',
+ message: 'testing stuff!'
+};
+isoDate = (new Date(logObject._timestamp)).toISOString();
+
+defaultFormatter = new TokenFormatter();
+customFormatter = new TokenFormatter({
+ formatString: '{{_level}} {{_cologneLog}} {{_timestamp}}'
+});
+ansiFormatter = new TokenFormatter({
+ formatString: 'string {{_ansi:red}}with color:{{_ansi:reset}} {{message}}'
+});
+plainDateFormatter = new TokenFormatter({
+ isoDate: false,
+ formatString: '{{_timestamp}}'
+});
+customSearchFormatter = new TokenFormatter({
+ formatString: '[[message]]',
+ replaceRule: /\[\[(.*?)\]\]/g
+});
+
+/**
+ * TEST: #format() - default
+ */
+
+formattedString = defaultFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in default mode');
+
+tap.equal(formattedString, logObject.message,
+ '#format() should include the message in default mode');
+
+/**
+ * TEST: #format() - custom
+ */
+
+formattedString = customFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in custom mode');
+
+tap.ok(formattedString.match(logObject._level),
+ '#format() with custom string should include the specified tokens (check 1)');
+
+tap.ok(formattedString.match(logObject._cologneLog),
+ '#format() with custom string should include the specified tokens (check 2)');
+
+tap.ok(formattedString.match(isoDate),
+ '#format() with iso date should include the timestamp as an iso date');
+
+/**
+ * TEST: #format() - ansi
+ */
+
+formattedString = ansiFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in ansi mode');
+
+tap.equal(formattedString.split(String.fromCharCode(27) + '[31m').length, 2,
+ '#format() with ansi tokens should colorize the string');
+
+tap.equal(formattedString.split(String.fromCharCode(27) + '[0m').length, 2,
+ '#format() with ansi reset should reset the string');
+
+
+/**
+ * TEST: #format() - plain date
+ */
+
+formattedString = plainDateFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in plain date mode');
+
+tap.equal(formattedString, logObject._timestamp.toString(),
+ '#format() with plain date should include the timestamp as-is');
+
+/**
+ * TEST: #format() - custom search
+ */
+
+formattedString = customSearchFormatter.format(logObject);
+
+tap.equal(typeof formattedString, 'string',
+ '#format() should output a string in custom search mode');
+
+tap.equal(formattedString, logObject.message,
+ '#format() with a custom search, should properly match the new tokens');
--- /dev/null
+'use strict';
+
+let tap = require('tap');
+
+let LogUtilities = require('../../lib/cologne/log_utilities');
+
+// Prepare the test
+let t1, t2, preciseTime, regularObject, circularObject,
+ regularStringify, cologneStringify, circularStringify;
+
+tap.plan(7);
+
+regularObject = {
+ a: 1,
+ b: {
+ c: 'true',
+ d: false
+ }
+};
+
+circularObject = {
+ a: 1,
+ b: {
+ c: 'true',
+ d: false
+ }
+};
+circularObject.b.circular = circularObject;
+
+/**
+ * TEST: ::now()
+ */
+t1 = Date.now();
+preciseTime = LogUtilities.now();
+t2 = Date.now();
+
+// This test is sloppy :(
+tap.ok(Math.abs(t1 - preciseTime) < 1,
+ '::now() should give a precise timestamp (before)');
+tap.ok(Math.abs(t2 - preciseTime) < 1,
+ '::now() should give a precise timestamp (after)');
+
+/**
+ * TEST: ::stringify()
+ */
+
+regularStringify = JSON.stringify(regularObject);
+cologneStringify = LogUtilities.stringify(regularObject);
+circularStringify = LogUtilities.stringify(circularObject);
+
+tap.equal(regularStringify, cologneStringify,
+ '::stringify() should behave like JSON.stringify for non-circular objects');
+tap.equal(typeof JSON.parse(circularStringify).b.circular, 'string',
+ '::stringify() should replace circular references with a string');
+
+/**
+ * TEST: ::getAnsiCode()
+ */
+
+// NOTE: This isn't even trying to be a complete test... Just testing
+// that we get other than reset if valid, and the same as reset for all
+// invalid ones. knowing that reset is [0m
+
+tap.equal(LogUtilities.getAnsiCode('reset'), '[0m',
+ '::getAnsiCode is sending the correct reset code');
+tap.equal(LogUtilities.getAnsiCode('someRandomString'), LogUtilities.getAnsiCode('reset'),
+ '::getAnsiCode() should give us a reset code if something weird is sent');
+tap.notEqual(LogUtilities.getAnsiCode('red'), LogUtilities.getAnsiCode('reset'),
+ '::getAnsiCode() should give us a non-reset code if it\'s something real');
--- /dev/null
+'use strict';
+
+let tap = require('tap');
+
+let ConsoleLogger = require('../../../lib/cologne/logger/console');
+
+// Prepare the test
+let dummyFormatter, dummyConsole, logObjectA, logObjectB, regularLogger,
+ overrideLogger, formattedLogger, params;
+
+dummyFormatter = {
+ values: [],
+ format: function (logObject) {
+ this.values.push(logObject);
+ return 'lol';
+ }
+};
+
+dummyConsole = {
+ values: {},
+ _log: function (type, args) {
+ this.values[type] = args;
+ },
+ log: function() {
+ this._log('log', Array.prototype.splice.call(arguments, [0]));
+ },
+ warn: function() {
+ this._log('warn', Array.prototype.splice.call(arguments, [0]));
+ },
+ error: function() {
+ this._log('error', Array.prototype.splice.call(arguments, [0]));
+ },
+ info: function() {
+ this._log('info', Array.prototype.splice.call(arguments, [0]));
+ }
+};
+
+logObjectA = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageOne'
+};
+
+logObjectB = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageTwo'
+};
+
+params = [logObjectA, logObjectB];
+
+regularLogger = new ConsoleLogger({});
+overrideLogger = new ConsoleLogger({
+ console: dummyConsole
+});
+formattedLogger = new ConsoleLogger({
+ console: dummyConsole,
+ formatter: dummyFormatter
+});
+
+/**
+ * TEST: #log() - regular
+ */
+
+tap.equal(regularLogger.console, global.console,
+ 'It should default to the global console');
+
+/**
+ * TEST: #log() - override
+ */
+
+logObjectA._level = 5;
+logObjectB._level = 6;
+overrideLogger.log.apply(overrideLogger, params); // should go to info
+
+logObjectA._level = 4;
+logObjectB._level = 4;
+overrideLogger.log.apply(overrideLogger, params); // should go to warn
+
+logObjectA._level = 1;
+logObjectB._level = 3;
+overrideLogger.log.apply(overrideLogger, params); // should go to error
+
+logObjectA._level = 7;
+logObjectB._level = 7;
+overrideLogger.log.apply(overrideLogger, params); // should go to log
+
+tap.equal(dummyConsole.values.log.length, params.length,
+ 'It should send debug messages to console\'s #log');
+tap.equal(dummyConsole.values.info.length, params.length,
+ 'It should send info and notice messages to console\'s #info');
+tap.equal(dummyConsole.values.warn.length, params.length,
+ 'It should send warn messages to console\'s #warn');
+tap.equal(dummyConsole.values.error.length, params.length,
+ 'It should send error messages to console\'s #error');
+
+/**
+ * TEST: #log() - with formatter
+ */
+
+formattedLogger.log.apply(formattedLogger, params); // should go to log
+
+tap.similar(dummyFormatter.values, params,
+ 'If available, it should send the objects to the formatter');
--- /dev/null
+'use strict';
+
+let fs = require('fs');
+
+let tap = require('tap');
+
+let FileLogger = require('../../../lib/cologne/logger/file');
+
+// Prepare the test
+let logObjectA, logObjectB, rawFile, formatterFile, rawLogger, formatterLogger,
+ params, dummyFormatter, formatterString;
+
+rawFile = './raw.log';
+formatterFile = './formatter.log';
+formatterString = 'example';
+
+logObjectA = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageOne'
+};
+
+logObjectB = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageTwo'
+};
+
+params = [logObjectA, logObjectB];
+
+
+dummyFormatter = {
+ values: [],
+ format: function (logObject) {
+ this.values.push(logObject);
+ return formatterString;
+ }
+};
+
+rawLogger = new FileLogger({
+ file: rawFile
+});
+formatterLogger = new FileLogger({
+ file: formatterFile,
+ formatter: dummyFormatter
+});
+
+/**
+ * TEST: #log() - regular
+ */
+
+rawLogger.log.apply(rawLogger, params);
+
+setTimeout(function () {
+ tap.test('raw file', function (t) {
+ fs.readFile(rawFile, {encoding: 'utf8'}, function (error, contents) {
+ let lines;
+
+ lines = contents.trim().split('\n');
+
+ tap.equal(lines.length, params.length,
+ 'it should send all params to the file');
+
+ tap.equal(JSON.stringify(logObjectA), lines[0],
+ 'it should log the raw json object');
+
+ fs.unlink(rawFile, function () {
+ t.end();
+ });
+ });
+ });
+}, 10); // allow for flush
+/**
+ * TEST: #log() - formatter
+ */
+
+formatterLogger.log.apply(formatterLogger, params);
+
+setTimeout(function () {
+ tap.test('formatted file', function (t) {
+ fs.readFile(formatterFile, {encoding: 'utf8'}, function (error, contents) {
+ let lines;
+
+ lines = contents.trim().split('\n');
+
+ tap.equal(lines.length, params.length,
+ 'it should send all params to the file');
+
+ tap.equal(formatterString, lines[0],
+ 'it should log the formatted object');
+
+ fs.unlink(formatterFile, function () {
+ t.end();
+ });
+ });
+ });
+}, 10);