/
console.js
163 lines (138 loc) · 4.75 KB
/
console.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
"use strict";
var tinytim = require('tinytim'), dateFormat = require('dateformat'), utils = require('./utils'), path = require('path'), settings = require('./settings').settings;
var noop = function(){};
var fwrap = function(fn){
return function(str){ return fn(str) };
};
// Stack trace format :
// https://github.com/v8/v8/wiki/Stack%20Trace%20API
var stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i;
var stackReg2 = /at\s+()(.*):(\d*):(\d*)/i;
// main log method
function logMain(config, level, title, format, filters, needstack, args) {
//check level of global settings
var gLevel = settings.level;
if (typeof (gLevel) == 'string')
gLevel = config.methods.indexOf(gLevel);
if (level < gLevel) { return; }
var data = {
timestamp : dateFormat(new Date(), config.dateformat),
message : "",
title : title,
level : level,
args : args
};
data.method = data.path = data.line = data.pos = data.file = data.folder = '';
if (needstack) {
// get call stack, and analyze it
// get all file,method and line number
var stacklist = (new Error()).stack.split('\n').slice(3);
var s = stacklist[config.stackIndex] || stacklist[0],
sp = stackReg.exec(s) || stackReg2.exec(s);
if (sp && sp.length === 5) {
data.method = sp[1];
data.path = sp[2];
data.line = sp[3];
data.pos = sp[4];
data.folder = path.dirname(config.rootDir && path.isAbsolute(config.rootDir)
? data.path.replace(new RegExp('^'+config.rootDir+path.sep+'?'), '')
: path.resolve(data.path));
data.file = path.basename(data.path);
data.stack = stacklist.join('\n');
}
}
config.preprocess(data);
var msg = utils.format.apply(config, data.args);
data.message = msg;
// call micro-template to ouput
data.output = tinytim.tim(format, data);
// save unprocessed output
data.rawoutput = data.output;
// process every filter method
var len = filters.length;
for ( var i = 0; i < len; i += 1) {
data.output = fwrap(filters[i])(data.output);
if (!data.output)
return data;
// cancel next process if return a false(include null, undefined)
}
// trans the final result
config.transport.forEach(function(tras) {
tras(data);
});
return data;
}
module.exports = (function() {
// default config
var _config = {
rootDir: '',
format : "{{timestamp}} <{{title}}> {{file}}:{{line}} ({{method}}) {{message}}",
dateformat : "isoDateTime",
preprocess : function() {
},
transport : function(data) {
if (data.level >= 4) { // warn and more critical
console.error(data.output);
} else {
console.log(data.output);
}
},
filters : [],
level : 'log',
methods : [ 'log', 'trace', 'debug', 'info', 'warn', 'error', 'fatal' ],
stackIndex : 0, // get the specified index of stack as file information. It is userful for development package.
inspectOpt : {
showHidden : false, //if true then the object's non-enumerable properties will be shown too. Defaults to false
depth : 2 //tells inspect how many times to recurse while formatting the object. This is useful for inspecting large complicated objects. Defaults to 2. To make it recurse indefinitely pass null.
},
supportConsoleMethods : true
};
var userConfig = arguments;
if(typeof userConfig[0] === 'string') {
userConfig = [require(userConfig[0])];
}
// union user's config and default
_config = utils.union(_config, userConfig);
var _self = {};
_config.format = Array.isArray(_config.format) ? _config.format
: [ _config.format ];
_config.filters = Array.isArray(_config.filters) ? _config.filters
: [ _config.filters ];
_config.transport = Array.isArray(_config.transport) ? _config.transport : [_config.transport];
var fLen = _config.filters.length, lastFilter;
if (fLen > 0)
if (Object.prototype.toString.call(_config.filters[--fLen]) != '[object Function]') {
lastFilter = _config.filters[fLen];
_config.filters = _config.filters.slice(0, fLen);
}
if (typeof (_config.level) == 'string')
_config.level = _config.methods.indexOf(_config.level);
_config.methods.forEach(function(title, i) {
if (i < _config.level)
_self[title] = noop;
else {
var format = _config.format[0];
if (_config.format.length === 2 && _config.format[1][title])
format = _config.format[1][title];
var needstack = /{{(method|path|line|pos|file|folder|stack)}}/i.test(format);
var filters;
if (lastFilter && lastFilter[title])
filters = Array.isArray(lastFilter[title]) ? lastFilter[title]
: [ lastFilter[title] ];
else
filters = _config.filters;
// interface
_self[title] = function() {
return logMain(_config, i, title, format, filters, needstack, arguments);
};
}
});
if(_config.supportConsoleMethods) {
Object.getOwnPropertyNames(console).forEach(function(title) {
if (!_self[title]) {
_self[title] = console[title];
}
});
}
return _self;
});