node.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * Module dependencies.
  3. */
  4. var tty = require('tty');
  5. var util = require('util');
  6. /**
  7. * This is the Node.js implementation of `debug()`.
  8. *
  9. * Expose `debug()` as the module.
  10. */
  11. exports = module.exports = require('./debug');
  12. exports.init = init;
  13. exports.log = log;
  14. exports.formatArgs = formatArgs;
  15. exports.save = save;
  16. exports.load = load;
  17. exports.useColors = useColors;
  18. /**
  19. * Colors.
  20. */
  21. exports.colors = [6, 2, 3, 4, 5, 1];
  22. /**
  23. * Build up the default `inspectOpts` object from the environment variables.
  24. *
  25. * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
  26. */
  27. exports.inspectOpts = Object.keys(process.env).filter(function (key) {
  28. return /^debug_/i.test(key);
  29. }).reduce(function (obj, key) {
  30. // camel-case
  31. var prop = key
  32. .substring(6)
  33. .toLowerCase()
  34. .replace(/_([a-z])/, function (_, k) { return k.toUpperCase() });
  35. // coerce string value into JS value
  36. var val = process.env[key];
  37. if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
  38. else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
  39. else if (val === 'null') val = null;
  40. else val = Number(val);
  41. obj[prop] = val;
  42. return obj;
  43. }, {});
  44. /**
  45. * The file descriptor to write the `debug()` calls to.
  46. * Set the `DEBUG_FD` env variable to override with another value. i.e.:
  47. *
  48. * $ DEBUG_FD=3 node script.js 3>debug.log
  49. */
  50. var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
  51. if (1 !== fd && 2 !== fd) {
  52. util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')()
  53. }
  54. var stream = 1 === fd ? process.stdout :
  55. 2 === fd ? process.stderr :
  56. createWritableStdioStream(fd);
  57. /**
  58. * Is stdout a TTY? Colored output is enabled when `true`.
  59. */
  60. function useColors() {
  61. return 'colors' in exports.inspectOpts
  62. ? Boolean(exports.inspectOpts.colors)
  63. : tty.isatty(fd);
  64. }
  65. /**
  66. * Map %o to `util.inspect()`, all on a single line.
  67. */
  68. exports.formatters.o = function(v) {
  69. this.inspectOpts.colors = this.useColors;
  70. return util.inspect(v, this.inspectOpts)
  71. .replace(/\s*\n\s*/g, ' ');
  72. };
  73. /**
  74. * Map %o to `util.inspect()`, allowing multiple lines if needed.
  75. */
  76. exports.formatters.O = function(v) {
  77. this.inspectOpts.colors = this.useColors;
  78. return util.inspect(v, this.inspectOpts);
  79. };
  80. /**
  81. * Adds ANSI color escape codes if enabled.
  82. *
  83. * @api public
  84. */
  85. function formatArgs(args) {
  86. var name = this.namespace;
  87. var useColors = this.useColors;
  88. if (useColors) {
  89. var c = this.color;
  90. var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';
  91. args[0] = prefix + args[0].split('\n').join('\n' + prefix);
  92. args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
  93. } else {
  94. args[0] = new Date().toUTCString()
  95. + ' ' + name + ' ' + args[0];
  96. }
  97. }
  98. /**
  99. * Invokes `util.format()` with the specified arguments and writes to `stream`.
  100. */
  101. function log() {
  102. return stream.write(util.format.apply(util, arguments) + '\n');
  103. }
  104. /**
  105. * Save `namespaces`.
  106. *
  107. * @param {String} namespaces
  108. * @api private
  109. */
  110. function save(namespaces) {
  111. if (null == namespaces) {
  112. // If you set a process.env field to null or undefined, it gets cast to the
  113. // string 'null' or 'undefined'. Just delete instead.
  114. delete process.env.DEBUG;
  115. } else {
  116. process.env.DEBUG = namespaces;
  117. }
  118. }
  119. /**
  120. * Load `namespaces`.
  121. *
  122. * @return {String} returns the previously persisted debug modes
  123. * @api private
  124. */
  125. function load() {
  126. return process.env.DEBUG;
  127. }
  128. /**
  129. * Copied from `node/src/node.js`.
  130. *
  131. * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
  132. * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
  133. */
  134. function createWritableStdioStream (fd) {
  135. var stream;
  136. var tty_wrap = process.binding('tty_wrap');
  137. // Note stream._type is used for test-module-load-list.js
  138. switch (tty_wrap.guessHandleType(fd)) {
  139. case 'TTY':
  140. stream = new tty.WriteStream(fd);
  141. stream._type = 'tty';
  142. // Hack to have stream not keep the event loop alive.
  143. // See https://github.com/joyent/node/issues/1726
  144. if (stream._handle && stream._handle.unref) {
  145. stream._handle.unref();
  146. }
  147. break;
  148. case 'FILE':
  149. var fs = require('fs');
  150. stream = new fs.SyncWriteStream(fd, { autoClose: false });
  151. stream._type = 'fs';
  152. break;
  153. case 'PIPE':
  154. case 'TCP':
  155. var net = require('net');
  156. stream = new net.Socket({
  157. fd: fd,
  158. readable: false,
  159. writable: true
  160. });
  161. // FIXME Should probably have an option in net.Socket to create a
  162. // stream from an existing fd which is writable only. But for now
  163. // we'll just add this hack and set the `readable` member to false.
  164. // Test: ./node test/fixtures/echo.js < /etc/passwd
  165. stream.readable = false;
  166. stream.read = null;
  167. stream._type = 'pipe';
  168. // FIXME Hack to have stream not keep the event loop alive.
  169. // See https://github.com/joyent/node/issues/1726
  170. if (stream._handle && stream._handle.unref) {
  171. stream._handle.unref();
  172. }
  173. break;
  174. default:
  175. // Probably an error on in uv_guess_handle()
  176. throw new Error('Implement me. Unknown stream file type!');
  177. }
  178. // For supporting legacy API we put the FD here.
  179. stream.fd = fd;
  180. stream._isStdio = true;
  181. return stream;
  182. }
  183. /**
  184. * Init logic for `debug` instances.
  185. *
  186. * Create a new `inspectOpts` object in case `useColors` is set
  187. * differently for a particular `debug` instance.
  188. */
  189. function init (debug) {
  190. debug.inspectOpts = util._extend({}, exports.inspectOpts);
  191. }
  192. /**
  193. * Enable namespaces listed in `process.env.DEBUG` initially.
  194. */
  195. exports.enable(load());