/*
|
* @copyright
|
* Copyright © Microsoft Open Technologies, Inc.
|
*
|
* All Rights Reserved
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http: *www.apache.org/licenses/LICENSE-2.0
|
*
|
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
* OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
* ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
|
* PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
|
*
|
* See the Apache License, Version 2.0 for the specific language
|
* governing permissions and limitations under the License.
|
*/
|
'use strict';
|
|
var _ = require('underscore');
|
var uuid = require('uuid'); // want to replace with this in the future: https://gist.github.com/jed/982883
|
|
|
|
var LEVEL_STRING_MAP = {
|
0 : 'ERROR:',
|
1 : 'WARNING:',
|
2 : 'INFO:',
|
3 : 'VERBOSE:'
|
};
|
|
/**
|
* Methods for controling global logging options for ADAL
|
* @namespace
|
*/
|
var Logging = {
|
|
/**
|
* @callback LoggingCallback
|
* @memberOf Logging
|
* @param {Logging.LOGGING_LEVEL} level The level of this log entry.
|
* @param {string} message The text content of the log entry.
|
* @param {Error} [error] An Error object if this is an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
|
*/
|
|
/**
|
* @typedef LoggingOptions
|
* @memberOf Logging
|
* @property {LoggingCallback} [log] The function to call when ADAL generates a log entry.
|
* @property {Logging.LOGGING_LEVEL} [level] The maximum level of log entries to generate.
|
*/
|
|
/**
|
* Describes the available logging levels.
|
* @enum
|
* @type {Number}
|
*/
|
LOGGING_LEVEL : {
|
ERROR : 0,
|
WARN : 1,
|
INFO : 2,
|
VERBOSE : 3
|
},
|
|
/**
|
* Sets global logging options for ADAL.
|
* @param {LoggingOptions} options
|
*/
|
setLoggingOptions : function(options) {
|
if (!options) {
|
options = {};
|
}
|
|
if (options.log) {
|
if (!_.isFunction(options.log)) {
|
throw new Error('setLogOptions expects the log key in the options parameter to be a function');
|
}
|
} else {
|
// if no log function was passed set it to a default no op function.
|
options.log = function() {};
|
}
|
|
if (options.level) {
|
var level = options.level;
|
if (level < 0 || level > 3) {
|
throw new Error('setLogOptions expects the level key to be in the range 0 to 3 inclusive');
|
}
|
} else {
|
options.level = this.LOGGING_LEVEL.ERROR;
|
}
|
|
if (options.loggingWithPII != true) {
|
options.loggingWithPII = false;
|
}
|
|
this.LogOptions = options;
|
},
|
|
/**
|
* Get's the current global logging options.
|
* @return {LoggingOptions}
|
*/
|
getLoggingOptions : function() {
|
return this.LogOptions;
|
},
|
|
/**
|
* Stores the current global logging options.
|
* @private
|
* @type {LoggingOptions}
|
*/
|
LogOptions : {
|
log : function() {},
|
level : 0,
|
loggingWithPII: false
|
}
|
};
|
|
/**
|
* An internal logging object.
|
* @class
|
* @private
|
* @param {string} componentName The name of the component that created this instance. This name will be
|
* prepended to the beginning of all log entries generated by this instance.
|
*/
|
function Logger(componentName, logContext) {
|
if (!logContext) {
|
throw new Error('Logger: logContext is a required parameter');
|
}
|
this._componentName = componentName;
|
this._logContext = logContext;
|
}
|
|
Object.defineProperty(Logger.prototype, 'context', {
|
get: function () {
|
return this._logContext;
|
}
|
});
|
|
/**
|
* Generates a log entry
|
* @param {Logging.LOGGING_LEVEL} level The level of this log entry
|
* @param {string|function} message A message string, or a function that returns a message string, to log.
|
* @param {Error} [error] If this is a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry then the caller
|
* should pass an error object in this parameter.
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.log = function (level, message, error, containsPII) {
|
if (containsPII == true && !Logging.LogOptions.loggingWithPII) {
|
return;
|
}
|
|
if (level <= Logging.LogOptions.level) {
|
if (_.isFunction(message)) {
|
message = message();
|
}
|
|
var correlationId = this._logContext.correlationId || '<no correlation id>';
|
var timeStamp = new Date().toUTCString();
|
|
var formattedMessage = timeStamp + ':' + correlationId + ' - ' + this._componentName + ': ' + LEVEL_STRING_MAP[level] + ' ' + message;
|
if (error) {
|
formattedMessage += '\nStack:\n' + error.stack;
|
}
|
Logging.LogOptions.log(level, formattedMessage, error);
|
}
|
};
|
|
/**
|
* Generate an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
|
* @param {string} message A message to log
|
* @param {Error} error The Error object associated with this log entry
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.error = function (message, error, containsPII) {
|
this.log(Logging.LOGGING_LEVEL.ERROR, message, error, containsPII);
|
};
|
|
/**
|
* Generate an {@link Logging.LOGGING_LEVEL.WARN|WARN} level log entry.
|
* @param {string} message A message to log
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.warn = function (message, containsPII) {
|
this.log(Logging.LOGGING_LEVEL.WARN, message, null, containsPII);
|
};
|
|
/**
|
* Generate an {@link Logging.LOGGING_LEVEL.INFO|INFO} level log entry.
|
* @param {string} message A message to log
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.info = function (message, containsPII) {
|
this.log(Logging.LOGGING_LEVEL.INFO, message, null, containsPII);
|
};
|
|
/**
|
* Generate an {@link Logging.LOGGING_LEVEL.VERBOSE|VERBOSE} level log entry.
|
* @param {string} message A message to log
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.verbose = function (message, containsPII) {
|
this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null, containsPII);
|
};
|
|
/**
|
* Generate a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry, as well as an
|
* Error object to go with it. This is a convenience method for throwing logged errors.
|
* @param {string} message A message to log
|
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
|
*/
|
Logger.prototype.createError = function(message, containsPII) {
|
var err = new Error(message);
|
this.error(message, err, containsPII);
|
return err;
|
};
|
|
/**
|
* Creates a new log context based on the correlationId passed in. If no correlationId is passed in
|
* then one is generated, by the function uuid.v4()
|
* @private
|
*/
|
function createLogContext(correlationId) {
|
var id = correlationId || uuid.v4();
|
return { correlationId : id };
|
}
|
|
var exports = {
|
Logging : Logging,
|
Logger : Logger,
|
createLogContext : createLogContext
|
};
|
|
module.exports = exports;
|