forked from gmalysa/ld2l
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlogger.js
225 lines (199 loc) · 6.69 KB
/
logger.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/**
* Logging wrapper that helps simplify/unify several task types. Also
* adds some formatted printing and more color coding, because you can
* never have enough color coding.
*/
const module_name = 'Logger';
const module_version = '2.1.0';
// Node.js modules
require('colors');
const _ = require('underscore');
const spyglass = require('spyglass');
const fs = require('fs');
const sprintf = require('sprintf-js').sprintf;
// Styles for messages
var default_styles = {
time : ['grey'],
modname : ['green'],
version : ['cyan'],
init : ['grey'],
info : ['white', 'bold'],
warn : ['yellow'],
error : ['red', 'bold'],
debug : ['blue', 'bold'],
'??????' : ['rainbow']
};
// Options for logger
var default_options = {
styles : default_styles,
console : true,
file : true,
path : './default.log',
versionSize : 6,
modNameSize : 12,
typeSize : 8,
spyglass : {
stream : null,
skip : ['stack'],
hide : {'types' : ['null', 'undefined']}
},
};
/**
* Constructor for the logger. This is only called internally, everyone else calls configure
* @param options Object of options for the logger
*/
function Logger(options) {
this.configure(options);
}
/**
* Member variables. The logger is a singleton though, so it doesn't really matter where these are
*/
_.extend(Logger.prototype, {
gls : null, //!< Spyglass instance, this will be (re)set during configure() calls
anonCount : 0, //!< Count of anonymous variables printed via var_dump()
options : {}, //!< Options passed in to configure
RIGHT : 0, //!< Alignment constant, make text right aligned in a fixed-width field
CENTER : 1, //!< Alignment constant, make text centered
LEFT : 2, //!< Aignment constant, make text left aligned
outfile : null, //!< Stream to write output log file
unknown : '(unknown)', //!< Unknown source module substitute name
/**
* Merges together two or more options objects in a property-aware way
* @param arguments, any number of objects
* @return Object merged options from the left
*/
merge : function() {
var rtn = {'styles' : {}};
_.each(Array.prototype.slice.call(arguments), function(v) {
_.extend(rtn, _.omit(v, 'styles'));
_.extend(rtn.styles, v.styles);
});
return rtn;
},
/**
* Configures the logger with a set of options as given, useful for reconfiguring the module
* @param options The key/value pairs of options to configure
*/
configure : function(options) {
this.options = this.merge(this.options, options);
this.gls = new spyglass(this.options.spyglass);
this.unknown = this.pad('(unknown)', this.options.modNameSize, this.CENTER);
if (this.outfile) {
this.outfile.end();
this.outfile = null;
}
if (this.options.file)
this.outfile = fs.createWriteStream(this.options.path);
},
/**
* Stylize a string using the list of options
* @param str The string to stylize
* @param fmt The format to use for styling
* @return String the string with formatting applied courtesy of colors
*/
s : function(str, fmt) {
var styles = this.options.styles[fmt];
return _.reduce(styles, function(memo, v) {
return memo[v];
}, str);
},
/**
* Pad a string to a certain size with spaces, using additional alignment information
* @param str The string to pad
* @param size The number of characters to have in total
* @param align The alignment constant
* @return String the padded and aligned string
*/
pad : function(str, size, align) {
if (align === undefined)
align = this.LEFT;
if (str.length >= size)
return str.substring(0, size);
var padding = new Array(size-str.length).join(' ');
switch(align) {
case this.LEFT:
return str + padding;
case this.RIGHT:
return padding + str;
case this.CENTER:
var offset = Math.floor(padding.length/2);
return padding.substring(0, offset) + str + padding.substring(offset, padding.length);
}
},
/**
* Module init message function, color codes nicely and then prints to the console information about
* the module that just initialized.
* @param name The name of the module being initialized
* @param version The version string to display
* @param msg Startup message from the module
*/
module_init : function(name, version, msg) {
var msgText = msg || 'Startup';
var versionText = '[ ' + this.pad('v'+version, this.options.versionSize, this.RIGHT) + ' ]';
this.log('init', name, this.s(versionText, 'version') + ' ' + msgText);
},
/**
* Easy function used to format messages by type, color the module name, etc., and then print to the
* stdout.
* @param type The type of message to print
* @param src The source of the message
* @param msg The messae itself
*/
log : function(type, src, msg) {
var time = new Date();
var datestr = this.s(sprintf('%04d-%02d-%02d %02d:%02d:%02d.%03d ',
time.getFullYear(),
time.getMonth()+1,
time.getDate(),
time.getHours(),
time.getMinutes(),
time.getSeconds(),
time.getMilliseconds()
), 'time');
var typestr = this.s('[ ' + this.pad('-' + type + '-', this.options.typeSize) + ' ]', type);
var modname = this.s('[ ' + this.pad(src, this.options.modNameSize) + ' ]', 'modname');
var output = datestr + typestr + ' ' + modname + ' ' + msg;
if (this.options.console)
console.log(output);
if (this.options.file)
this.outfile.write(output.stripColors + '\n', 'utf8');
},
/**
* Wrapper for spyglass to make it play with the rest of our formatting
* @param obj The object to inspect
* @param options The options for inspection, plus 'name' the name of the object, and 'src,' the source module. Optional
*/
var_dump : function(obj, options) {
options = options || {};
if (typeof options == 'string' || options instanceof String)
options = {name : options};
var src = options.src || this.unknown;
var name = options.name || (this.anonCount += 1, '<' + this.anonCount + '>');
this.debug(this.gls.inspect(obj, 'var_dump(' + name + ')', _.omit(options, ['src', 'name'])), src);
},
/**
* Convenience functions to call log() with various message types
* @param msg The message
* @param src The source of the message
*/
info : function(msg, src) {
src = src || this.unknown;
this.log('info', src, msg);
},
warn : function(msg, src) {
src = src || this.unknown;
this.log('warn', src, msg);
},
error : function(msg, src) {
src = src || this.unknown;
this.log('error', src, msg);
},
debug : function(msg, src) {
src = src || this.unknown;
this.log('debug', src, msg);
}
});
// Export a singleton instance of the logger
module.exports = new Logger(default_options);
// Show off init function on load :D
module.exports.module_init(module_name, module_version);