node.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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])/g, 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. .split('\n').map(function(str) {
  72. return str.trim()
  73. }).join(' ');
  74. };
  75. /**
  76. * Map %o to `util.inspect()`, allowing multiple lines if needed.
  77. */
  78. exports.formatters.O = function(v) {
  79. this.inspectOpts.colors = this.useColors;
  80. return util.inspect(v, this.inspectOpts);
  81. };
  82. /**
  83. * Adds ANSI color escape codes if enabled.
  84. *
  85. * @api public
  86. */
  87. function formatArgs(args) {
  88. var name = this.namespace;
  89. var useColors = this.useColors;
  90. if (useColors) {
  91. var c = this.color;
  92. var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';
  93. args[0] = prefix + args[0].split('\n').join('\n' + prefix);
  94. args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
  95. } else {
  96. args[0] = new Date().toUTCString()
  97. + ' ' + name + ' ' + args[0];
  98. }
  99. }
  100. /**
  101. * Invokes `util.format()` with the specified arguments and writes to `stream`.
  102. */
  103. function log() {
  104. return stream.write(util.format.apply(util, arguments) + '\n');
  105. }
  106. /**
  107. * Save `namespaces`.
  108. *
  109. * @param {String} namespaces
  110. * @api private
  111. */
  112. function save(namespaces) {
  113. if (null == namespaces) {
  114. // If you set a process.env field to null or undefined, it gets cast to the
  115. // string 'null' or 'undefined'. Just delete instead.
  116. delete process.env.DEBUG;
  117. } else {
  118. process.env.DEBUG = namespaces;
  119. }
  120. }
  121. /**
  122. * Load `namespaces`.
  123. *
  124. * @return {String} returns the previously persisted debug modes
  125. * @api private
  126. */
  127. function load() {
  128. return process.env.DEBUG;
  129. }
  130. /**
  131. * Copied from `node/src/node.js`.
  132. *
  133. * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
  134. * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
  135. */
  136. function createWritableStdioStream (fd) {
  137. var stream;
  138. var tty_wrap = process.binding('tty_wrap');
  139. // Note stream._type is used for test-module-load-list.js
  140. switch (tty_wrap.guessHandleType(fd)) {
  141. case 'TTY':
  142. stream = new tty.WriteStream(fd);
  143. stream._type = 'tty';
  144. // Hack to have stream not keep the event loop alive.
  145. // See https://github.com/joyent/node/issues/1726
  146. if (stream._handle && stream._handle.unref) {
  147. stream._handle.unref();
  148. }
  149. break;
  150. case 'FILE':
  151. var fs = require('fs');
  152. stream = new fs.SyncWriteStream(fd, { autoClose: false });
  153. stream._type = 'fs';
  154. break;
  155. case 'PIPE':
  156. case 'TCP':
  157. var net = require('net');
  158. stream = new net.Socket({
  159. fd: fd,
  160. readable: false,
  161. writable: true
  162. });
  163. // FIXME Should probably have an option in net.Socket to create a
  164. // stream from an existing fd which is writable only. But for now
  165. // we'll just add this hack and set the `readable` member to false.
  166. // Test: ./node test/fixtures/echo.js < /etc/passwd
  167. stream.readable = false;
  168. stream.read = null;
  169. stream._type = 'pipe';
  170. // FIXME Hack to have stream not keep the event loop alive.
  171. // See https://github.com/joyent/node/issues/1726
  172. if (stream._handle && stream._handle.unref) {
  173. stream._handle.unref();
  174. }
  175. break;
  176. default:
  177. // Probably an error on in uv_guess_handle()
  178. throw new Error('Implement me. Unknown stream file type!');
  179. }
  180. // For supporting legacy API we put the FD here.
  181. stream.fd = fd;
  182. stream._isStdio = true;
  183. return stream;
  184. }
  185. /**
  186. * Init logic for `debug` instances.
  187. *
  188. * Create a new `inspectOpts` object in case `useColors` is set
  189. * differently for a particular `debug` instance.
  190. */
  191. function init (debug) {
  192. debug.inspectOpts = {};
  193. var keys = Object.keys(exports.inspectOpts);
  194. for (var i = 0; i < keys.length; i++) {
  195. debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
  196. }
  197. }
  198. /**
  199. * Enable namespaces listed in `process.env.DEBUG` initially.
  200. */
  201. exports.enable(load());