node-logitio
Version:
NodeJS plugin to integrate with logit.io logging system
406 lines (354 loc) • 14.8 kB
JavaScript
var PersistedArray = require('./persistedArray');
var Request = require('./request');
var LOGIT_URI = 'https://api.logit.io/node/v1';
/**
* @class Logit
* Provides an interface to log applications messages from a Cordova app to a Logit.io endpoint
*/
var Logit = function() {
/**
* Determines the importance of the message.
* Maps name to value.
* @type {Object}
*/
this.LOG_PRIORITIES = {
EMERGENCY : 0,
ERROR : 1,
WARN : 2,
INFO : 3,
LOG : 4,
DEBUG : 5,
TRACE : 6,
VERBOSE : 7
};
/**
* Whether plugin has been initialised with the init() method
* @type {Boolean}
*/
this.initialised = false;
/**
* Flag indicating when sending of message queue has been paused using pauseSending() method
* @type {Boolean}
*/
this.pausedSending = false;
/**
* A value corresponding to an entry in this.LOG_PRIORITIES which filters log messages if the priority value is greater than the verbosity value.
* Defaults to this.LOG_PRIORITIES.VERBOSE.
* @type {Integer}
*/
this.verbosity = 7;
/**
* Maximum size of queued messages in local storage, after which messages at the start of the queue will get dropped as new messages are added.
* Defaults to 2000.
* @type {Integer}
*/
this.maxQueueSize = 2000;
/**
* Interval in ms at which to send messages queued in local storage. Defaults to 200ms.
* @type {Integer}
*/
this.sendInterval = 200;
/**
* URI of Logit endpoint to POST to
* @type {String}
*/
this.uri = LOGIT_URI;
/**
* API used to access logit endpoint
* @type {String}
*/
this.apiKey = undefined;
/**
* Configuration options
* @type {Object}
*/
this.options = {};
/**
* Persistent message queue
* @type {PersistedArray}
*/
this.queue = [];
/**
* Flag indicating if queued messages are currently being sent.
* @type {Boolean}
*/
this.sending = false;
/**
* Flag indicating if queueing/sending of messages te remote endpoint should be disabled. Defaults to false.
* @type {Boolean}
*/
this.disableSending = false;
/**************
* Public API *
**************/
/**
* Initialises plugin for use. Must be called before logging functions are called.
* @param {String} uri - URI of Logit.io endpoint.
* @param {String} apiKey - your Logit.io API Key, which grants you app access to the endpoint.
* @param {Object} options - optional parameters, with the following key names:
* <ul>
* <li>{Function} onSuccess - callback function to execute on successfully sending a message to Logit.io endpoint.</li>
* <li>{Function} onError - callback function to execute on error when sending a message to Logit.io endpoint.</li>
* <li>{Object} defaultDimensions - JSON object describing default dimensions to send with every message.</li>
* <li>{Boolean} logToConsole - if true, messages will be logged using window.console methods. Defaults to false.</li>
* <li>{Integer} verbosity - a value corresponding to an entry in this.LOG_PRIORITIES which filters log messages if the priority value is greater than the verbosity value.
* Defaults to this.LOG_PRIORITIES.VERBOSE. </li>
* <li>{Integer} maxQueueSize - maxiumum number of messages to store in the persistent queue.
* Once this value is reached, adding a message to the end of the queue will cause the first message at the start of the queue to be dropped.
* Defaults to 2000. </li>
* <li>{Integer} sendInterval - Interval in ms at which to send messages queued in local storage. Defaults to 200ms.</li>
* <li>{Boolean} disableSending - if true, sending of messages to remote Logit endpoint is disabled and messages are not added to send queue.
* This is useful for development phases when it's useful to use the plugin to log to the console but not to the remote endpoint. Defaults to false.</li>
* </ul>
*
*/
this.init = function(apiKey, options) {
if (!apiKey) {
console.warn('API key for Logit endpoint must be specified as second parameter when calling window.logit.init()');
return;
}
this.apiKey = apiKey;
this.options = options || {};
// Set verbosity
if( this.options.verbosity ) this.verbosity = this.options.verbosity;
if(this.options.sendInterval) this.sendInterval = this.options.sendInterval;
if(typeof(this.options.disableSending) != 'undefined') this.disableSending = this.options.disableSending;
this.queue = new PersistedArray('logit_queue');
this.initialised = true;
checkAndSend.call(this);
};
/**
* Pauses sending of queued messages when online.
* Note: if the number of queued messages reaches the configured maxQueueSize while sending is paused,
* each time a new message is added to the queue, the first message will be lost.
*/
this.pauseSending = function(){
this.pausedSending = true;
};
/**
* Resumes sending of queued messages when online.
*/
this.resumeSending = function(){
if(this.pausedSending){
this.pausedSending = false;
checkAndSend.call(this);
}
};
/**
* Sets the current verbosity for logit messages.
*
* @param {Mixed} verbosity - new verbosity value to set, either as an integer value of 0 to 7,
* of as the string name of the corresponding priority (case-insensitive), e.g. "error"
*/
this.setVerbosity = function(verbosity){
if(typeof(verbosity) == 'string' && typeof(this.LOG_PRIORITIES[verbosity.toUpperCase()]) != 'undefined'){
verbosity = this.LOG_PRIORITIES[verbosity.toUpperCase()];
}
if(typeof(verbosity) != 'number' || verbosity < this.LOG_PRIORITIES.EMERGENCY || verbosity > this.LOG_PRIORITIES.VERBOSE){
throw new Error('verbosity value must be an integer between '+this.LOG_PRIORITIES.EMERGENCY+' and '+this.LOG_PRIORITIES.VERBOSE);
}
if(this.verbosity == verbosity) return;
this.info('Set logit verbosity', {
previous: this.getPriorityName(this.verbosity).toLowerCase(),
current: this.getPriorityName(verbosity).toLowerCase()
},{
force: true
});
this.verbosity = verbosity;
};
/**
* Returns the current verbosity for logit messages.
* @return {Integer} the current log verbosity
*/
this.getVerbosity = function(){
return this.verbosity;
};
/**
* Returns the string name of a log priority given the priority value.
* Returns null if a matching name is not found.
* @param {Integer} priority - numerical priority value to find name for.
* @return {String} log priority name
*/
this.getPriorityName = function(priority){
var k, name = null;
for (k in this.LOG_PRIORITIES){
if(this.LOG_PRIORITIES[k] == priority){
name = k;
break;
}
}
return name;
};
/**
* Sends a message with emergency priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.emergency = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.EMERGENCY, message, dimensions, opts);
};
/**
* Sends a message with error priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.error = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.ERROR, message, dimensions, opts);
};
/**
* Sends a message with warning priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.warn = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.WARN, message, dimensions, opts);
};
/**
* Sends a message with info priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.info = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.INFO, message, dimensions, opts);
};
/**
* Sends a message with log priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.log = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.LOG, message, dimensions, opts);
};
/**
* Sends a message with debug priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.debug = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.DEBUG, message, dimensions, opts);
};
/**
* Sends a message with trace priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.trace = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.TRACE, message, dimensions, opts);
};
/**
* Sends a message with verbose priority.
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.verbose = function(message, dimensions, opts) {
this.createMessage(this.LOG_PRIORITIES.VERBOSE, message, dimensions, opts);
};
/**
* Sends a message with specified priority.
* @param {Integer} priority - a message priority as defined in LOG_PRIORITIES
* @param {String} message - the message to send
* @param {Object} dimensions - a list of custom dimensions in key/value form
* @param {Object} opts - (optional) additional options:
* <ul>
* <li>{Boolean} force - if true, the message will be sent even if the priority is greater than the current verbosity.</li>
* </ul>
*/
this.createMessage = function (priority, message, dimensions, opts) {
if (!this.initialised) {
console.warn('Logit.io plugin not initialised\n\nCall window.logit.init() first.');
return;
}
opts = opts || {};
if(priority > this.verbosity && !opts.force) return;
dimensions = dimensions || {};
if (this.options.defaultDimensions) {
for (var k in this.options.defaultDimensions) {
dimensions[k] = this.options.defaultDimensions[k];
}
}
var pkg = {
timestamp : new Date().toISOString(),
message : message,
level : this.getPriorityName(priority).toLowerCase(),
properties : dimensions
};
if(!this.disableSending){
if(this.queue.length == this.maxQueueSize){
this.queue.unshift(); //remove first item
this.warn('Logit message queue message size exceeded', null, { force: true });
}
this.queue.add( pkg );
checkAndSend.call(this);
}
if (this.options.logToConsole) {
var consoleFn;
if (priority <= 1) {
consoleFn = console.error;
} else if (priority == 2) {
consoleFn = console.warn;
} else if (priority == 3) {
consoleFn = console.info;
} else if (priority == 5) {
consoleFn = console.debug;
} else {
consoleFn = console.log;
}
var msg = pkg.message;
var t = pkg.timestamp;
var details = JSON.stringify(pkg.dimensions);
consoleFn.call(console, this.getPriorityName(priority) + ': ' + t + ' - ' + msg + '; ' + details);
}
};
/*************
* Internals *
*************/
this._intervalSend = function(){
if(!this.queue.isEmpty() && !this.pausedSending) {
this.sending = true;
var message = this.queue.unshift(); // take the first message off the queue
var request = new Request(this.uri, this.apiKey, this.options.onSuccess || function(){}, this.options.onError || function(){});
request.send(message);
setTimeout(this._intervalSend.bind(this), this.sendInterval);
}else{
this.sending = false;
}
};
function checkAndSend() {
if (!this.disableSending && this.queue && !this.sending) {
this._intervalSend();
}
}
};
module.exports = new Logit();