UNPKG

5.55 kBJavaScriptView Raw
1/* jshint undef:false */
2'use strict';
3
4var coaColor = require('coa/lib/color').Color,
5 W = require('winston'),
6 UTIL = require('util'),
7 BEMUTIL = require('./util'),
8 colorsDisabled = false,
9
10 propertiesFilter = [
11 '__self'
12 ];
13
14for(var i in W) exports[i] = W[i];
15
16init();
17
18/**
19 * Sets logging option max logging level
20 * @param {Stirng} [opts.level=info] logging level
21 * @param {Boolean} opts.noColors disable colorful output
22 */
23exports.configure = function(opts) {
24 init(opts.level || 'info', opts.noColors);
25};
26
27/**
28 * Log formatted message
29 *
30 * @param {String} level
31 * @param {String} message
32 * @param {*} ...args
33 */
34exports.flog = function(level) {
35 W[level](UTIL.format.apply(this, Array.prototype.slice.call(arguments, 1)));
36};
37
38exports.fatal = function() {
39 this.error.apply(this, arguments);
40 process.exit();
41};
42
43var times = {};
44exports.time = function(label) {
45 label = UTIL.format.apply(UTIL, arguments);
46 times[label] = Date.now();
47};
48
49exports.timeEnd = function(label) {
50 label = UTIL.format.apply(UTIL, arguments);
51 var duration = Date.now() - times[label];
52 exports.flog('info', '%s: ' + color('red', '%dms'), label, duration);
53 delete times[label];
54};
55
56
57exports.timeEndLevel = function(level, label) {
58 label = UTIL.format.apply(UTIL, Array.prototype.slice.call(arguments, 1));
59 var duration = Date.now() - times[label];
60 exports.flog(level, '%s: ' + color('red', '%dms'), label, duration);
61 delete times[label];
62};
63
64/**
65 * Adds tracing before and after executing specified function or specified object's methods
66 * @param {Object} options The object with properties:
67 * @param {Function} options.object pass object the methods of which you want to trace
68 * @param {Function} options.func pass function you want to trace (the method will return wrapper function in this case)
69 * @param {String} [options.objectName] this value is used in the traces to identify what object method is being executed
70 * @param {String[]} [options.whiteList] in case object was specified only methods in the whiteList will be wrapped
71 * @param {String[]} [options.blackList] in case object was specified the methods in blackList hash won't be wrapped
72 * @return {Function} The wrapped function in case options.func was specified or nothing otherwise
73 */
74exports.trace = function (options) {
75
76 return attach(
77 options,
78 function(f) {
79 exports.fsilly('>>> %s.%s', f.objectName || '?', f.functionName || '?');
80 },
81
82 function(f) {
83 exports.fsilly('<<< %s.%s', f.objectName || '?', f.functionName || '?');
84 }
85 );
86};
87
88/**
89 * The same as {@link trace} but uses specified callbacks to do tracing
90 *
91 * @param {Object} options
92 * @param {Function} [callbackBefore]
93 * @param {Function} [callbackAfter]
94 * @return {Function} The wrapped function in case options.func was specified or nothing otherwise
95 */
96var attach = exports.attach = function(options, callbackBefore, callbackAfter) {
97 if (options.object) {
98 var c = options.object.prototype || options.object;
99 if (!c) throw new Error('object has no prototype');
100
101 Object.keys(c)
102 .filter(function(prop) {
103 if (typeof c[prop] === 'function' && propertiesFilter.indexOf(prop) === -1) {
104 if (options.whiteList) return (options.whiteList.indexOf(prop) !== -1);
105
106 if (options.blackList) return (options.blackList.indexOf(prop) === -1);
107
108 return true;
109 }
110
111 return false;
112 })
113 .map(function(f) {
114 c[f] = wrapFunction(
115 {
116 objectName: options.objectName,
117 functionName: f,
118 func: c[f],
119 object: options.object
120 },
121 callbackBefore,
122 callbackAfter);
123 });
124
125 } else if (options.func) {
126 return wrapFunction(options.func, callbackBefore, callbackAfter);
127 }
128};
129
130function wrapFunction(options, callbackBefore, callbackAfter) {
131 var f = (typeof options === 'function')? options: options.func;
132
133 return function() {
134 callbackBefore && callbackBefore(options);
135 var res = f.apply(this, arguments);
136 callbackAfter && callbackAfter(options);
137
138 return res;
139 };
140}
141
142function init(level, noColors) {
143 W.remove(W.transports.Console);
144 W.add(W.transports.Console,
145 {
146 timestamp: function() {
147 var d = new Date();
148
149 return UTIL.format(
150 '%s:%s:%s.%s',
151 BEMUTIL.pad(d.getHours(), 2, '0'),
152 BEMUTIL.pad(d.getMinutes(), 2, '0'),
153 BEMUTIL.pad(d.getSeconds(), 2, '0'),
154 BEMUTIL.pad(d.getMilliseconds(), 3, '0'));
155 },
156 colorize: !noColors,
157 level: level
158 });
159
160 W.setLevels({
161 silly: 0,
162 debug: 1,
163 verbose: 2,
164 info: 3,
165 warn: 4,
166 error: 5
167 });
168
169 colorsDisabled = noColors;
170
171 Object.keys(W.levels).forEach(function (level) {
172 exports[level] = W[level];
173 exports['f' + level] = function() {
174 W[level](UTIL.format.apply(this, arguments));
175 };
176 });
177}
178
179function color(textColor, text) {
180 if (colorsDisabled) {
181 return text;
182 } else {
183 return coaColor(textColor, text);
184 }
185}