log.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * @copyright
  3. * Copyright © Microsoft Open Technologies, Inc.
  4. *
  5. * All Rights Reserved
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http: *www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
  14. * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
  15. * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
  16. * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
  17. *
  18. * See the Apache License, Version 2.0 for the specific language
  19. * governing permissions and limitations under the License.
  20. */
  21. 'use strict';
  22. var _ = require('underscore');
  23. var uuid = require('uuid'); // want to replace with this in the future: https://gist.github.com/jed/982883
  24. var LEVEL_STRING_MAP = {
  25. 0 : 'ERROR:',
  26. 1 : 'WARNING:',
  27. 2 : 'INFO:',
  28. 3 : 'VERBOSE:'
  29. };
  30. /**
  31. * Methods for controling global logging options for ADAL
  32. * @namespace
  33. */
  34. var Logging = {
  35. /**
  36. * @callback LoggingCallback
  37. * @memberOf Logging
  38. * @param {Logging.LOGGING_LEVEL} level The level of this log entry.
  39. * @param {string} message The text content of the log entry.
  40. * @param {Error} [error] An Error object if this is an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
  41. */
  42. /**
  43. * @typedef LoggingOptions
  44. * @memberOf Logging
  45. * @property {LoggingCallback} [log] The function to call when ADAL generates a log entry.
  46. * @property {Logging.LOGGING_LEVEL} [level] The maximum level of log entries to generate.
  47. */
  48. /**
  49. * Describes the available logging levels.
  50. * @enum
  51. * @type {Number}
  52. */
  53. LOGGING_LEVEL : {
  54. ERROR : 0,
  55. WARN : 1,
  56. INFO : 2,
  57. VERBOSE : 3
  58. },
  59. /**
  60. * Sets global logging options for ADAL.
  61. * @param {LoggingOptions} options
  62. */
  63. setLoggingOptions : function(options) {
  64. if (!options) {
  65. options = {};
  66. }
  67. if (options.log) {
  68. if (!_.isFunction(options.log)) {
  69. throw new Error('setLogOptions expects the log key in the options parameter to be a function');
  70. }
  71. } else {
  72. // if no log function was passed set it to a default no op function.
  73. options.log = function() {};
  74. }
  75. if (options.level) {
  76. var level = options.level;
  77. if (level < 0 || level > 3) {
  78. throw new Error('setLogOptions expects the level key to be in the range 0 to 3 inclusive');
  79. }
  80. } else {
  81. options.level = this.LOGGING_LEVEL.ERROR;
  82. }
  83. if (options.loggingWithPII != true) {
  84. options.loggingWithPII = false;
  85. }
  86. this.LogOptions = options;
  87. },
  88. /**
  89. * Get's the current global logging options.
  90. * @return {LoggingOptions}
  91. */
  92. getLoggingOptions : function() {
  93. return this.LogOptions;
  94. },
  95. /**
  96. * Stores the current global logging options.
  97. * @private
  98. * @type {LoggingOptions}
  99. */
  100. LogOptions : {
  101. log : function() {},
  102. level : 0,
  103. loggingWithPII: false
  104. }
  105. };
  106. /**
  107. * An internal logging object.
  108. * @class
  109. * @private
  110. * @param {string} componentName The name of the component that created this instance. This name will be
  111. * prepended to the beginning of all log entries generated by this instance.
  112. */
  113. function Logger(componentName, logContext) {
  114. if (!logContext) {
  115. throw new Error('Logger: logContext is a required parameter');
  116. }
  117. this._componentName = componentName;
  118. this._logContext = logContext;
  119. }
  120. Object.defineProperty(Logger.prototype, 'context', {
  121. get: function () {
  122. return this._logContext;
  123. }
  124. });
  125. /**
  126. * Generates a log entry
  127. * @param {Logging.LOGGING_LEVEL} level The level of this log entry
  128. * @param {string|function} message A message string, or a function that returns a message string, to log.
  129. * @param {Error} [error] If this is a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry then the caller
  130. * should pass an error object in this parameter.
  131. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  132. */
  133. Logger.prototype.log = function (level, message, error, containsPII) {
  134. if (containsPII == true && !Logging.LogOptions.loggingWithPII) {
  135. return;
  136. }
  137. if (level <= Logging.LogOptions.level) {
  138. if (_.isFunction(message)) {
  139. message = message();
  140. }
  141. var correlationId = this._logContext.correlationId || '<no correlation id>';
  142. var timeStamp = new Date().toUTCString();
  143. var formattedMessage = timeStamp + ':' + correlationId + ' - ' + this._componentName + ': ' + LEVEL_STRING_MAP[level] + ' ' + message;
  144. if (error) {
  145. formattedMessage += '\nStack:\n' + error.stack;
  146. }
  147. Logging.LogOptions.log(level, formattedMessage, error);
  148. }
  149. };
  150. /**
  151. * Generate an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
  152. * @param {string} message A message to log
  153. * @param {Error} error The Error object associated with this log entry
  154. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  155. */
  156. Logger.prototype.error = function (message, error, containsPII) {
  157. this.log(Logging.LOGGING_LEVEL.ERROR, message, error, containsPII);
  158. };
  159. /**
  160. * Generate an {@link Logging.LOGGING_LEVEL.WARN|WARN} level log entry.
  161. * @param {string} message A message to log
  162. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  163. */
  164. Logger.prototype.warn = function (message, containsPII) {
  165. this.log(Logging.LOGGING_LEVEL.WARN, message, null, containsPII);
  166. };
  167. /**
  168. * Generate an {@link Logging.LOGGING_LEVEL.INFO|INFO} level log entry.
  169. * @param {string} message A message to log
  170. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  171. */
  172. Logger.prototype.info = function (message, containsPII) {
  173. this.log(Logging.LOGGING_LEVEL.INFO, message, null, containsPII);
  174. };
  175. /**
  176. * Generate an {@link Logging.LOGGING_LEVEL.VERBOSE|VERBOSE} level log entry.
  177. * @param {string} message A message to log
  178. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  179. */
  180. Logger.prototype.verbose = function (message, containsPII) {
  181. this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null, containsPII);
  182. };
  183. /**
  184. * Generate a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry, as well as an
  185. * Error object to go with it. This is a convenience method for throwing logged errors.
  186. * @param {string} message A message to log
  187. * @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
  188. */
  189. Logger.prototype.createError = function(message, containsPII) {
  190. var err = new Error(message);
  191. this.error(message, err, containsPII);
  192. return err;
  193. };
  194. /**
  195. * Creates a new log context based on the correlationId passed in. If no correlationId is passed in
  196. * then one is generated, by the function uuid.v4()
  197. * @private
  198. */
  199. function createLogContext(correlationId) {
  200. var id = correlationId || uuid.v4();
  201. return { correlationId : id };
  202. }
  203. var exports = {
  204. Logging : Logging,
  205. Logger : Logger,
  206. createLogContext : createLogContext
  207. };
  208. module.exports = exports;