UNPKG

6.17 kBJavaScriptView Raw
1/* Copyright @ 2015-present 8x8, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*jslint latedef:false*/
16
17/**
18 * Ordered log levels.
19 */
20var levels = {
21 "trace": 0,
22 "debug": 1,
23 "info": 2,
24 "log": 3,
25 "warn": 4,
26 "error": 5
27};
28
29/**
30 * The default transport - console
31 * @type LoggerTransport
32 */
33Logger.consoleTransport = console;
34
35/**
36 * The array which stores currently registered global transports.
37 * @type {[LoggerTransport]}
38 */
39var globalTransports = [ Logger.consoleTransport ];
40
41/**
42 * Adds given {@link LoggerTransport} instance to the list of global
43 * transports which means that it'll be used by all {@link Logger}s
44 * @param {LoggerTransport} transport
45 */
46Logger.addGlobalTransport = function(transport) {
47 if (globalTransports.indexOf(transport) === -1) {
48 globalTransports.push(transport);
49 }
50};
51
52/**
53 * Removes given {@link LoggerTransport} instance from the list of global
54 * transports
55 * @param {LoggerTransport} transport
56 */
57Logger.removeGlobalTransport = function(transport) {
58 var transportIdx = globalTransports.indexOf(transport);
59 if (transportIdx !== -1) {
60 globalTransports.splice(transportIdx, 1);
61 }
62};
63
64/**
65 * The global configuration options.
66 */
67var globalOptions = {};
68
69/**
70 * Sets global options which will be used by all loggers. Changing these works
71 * even after other loggers are created.
72 */
73Logger.setGlobalOptions = function(options) {
74 globalOptions = options || {};
75};
76
77/**
78 * Parses Error's object stack trace and extracts information about the last
79 * caller before the log method was called.
80 * @returns JS object with info about the caller - method name, file location,
81 * line and column.
82 */
83function getCallerInfo() {
84 var callerInfo = {
85 methodName: "",
86 fileLocation: "",
87 line: null,
88 column: null
89 };
90 //gets the part of the stack without the logger wrappers
91 var error = new Error();
92 var stack = error.stack? error.stack.split("\n") : [];
93 if(!stack || stack.length < 3) {
94 return callerInfo;
95 }
96 var m = null;
97 if(stack[3]) {
98 m = stack[3].match(/\s*at\s*(.+?)\s*\((\S*)\s*:(\d*)\s*:(\d*)\)/);
99 }
100 if(!m || m.length <= 4) {
101 //Firefox && Safari
102 if(stack[2].indexOf("log@") === 0){
103 //Safari
104 callerInfo.methodName = stack[3].substr(0, stack[3].indexOf("@"));
105 } else {
106 //Firefox
107 callerInfo.methodName = stack[2].substr(0, stack[2].indexOf("@"));
108 }
109 return callerInfo;
110 }
111
112 callerInfo.methodName = m[1];
113 callerInfo.fileLocation = m[2];
114 callerInfo.line = m[3];
115 callerInfo.column = m[4];
116 return callerInfo;
117}
118
119/**
120 * Logs messages using the transports and level from the logger.
121 * @param logger a logger instance.
122 * @param level the log level of the message. See the levels variable.
123 * @param arguments array with arguments that will be logged.
124 */
125function log() {
126 var logger = arguments[0], level = arguments[1],
127 args = Array.prototype.slice.call(arguments, 2);
128 if(levels[level] < logger.level) {
129 return;
130 }
131
132 var callerInfo
133 = !(logger.options.disableCallerInfo || globalOptions.disableCallerInfo) &&
134 getCallerInfo();
135 var transports = globalTransports.concat(logger.transports);
136 for(var i = 0; i < transports.length; i++) {
137 var t = transports[i];
138 var l = t[level];
139 if(l && typeof(l) === "function") {
140 var logPrefixes = [];
141
142 logPrefixes.push(new Date().toISOString());
143
144 if (logger.id) {
145 logPrefixes.push("[" + logger.id + "]");
146 }
147
148 if (callerInfo && callerInfo.methodName.length > 1) {
149 logPrefixes.push("<" + callerInfo.methodName + ">: ");
150 }
151
152 var fullLogParts = logPrefixes.concat(args);
153
154 try {
155 l.bind(t).apply(t, fullLogParts);
156 } catch (error) {
157 // It would be nice to send the error to the logger but this could send us into an endless loop.
158 // That's why we use only console for logging here.
159 console.error("An error occured when trying to log with one of the available transports", error);
160 }
161 }
162 }
163}
164
165/**
166 *
167 * Constructs new logger object.
168 * @param level the logging level for the new logger
169 * @param id optional identifier for the logger instance.
170 * @param {LoggerTransport} transports optional list of handlers(objects) for
171 * the logs. The handlers must support - log, warn, error, debug, info, trace.
172 * @param options optional configuration file for how the logger should behave.
173 * @param {boolean} options.disableCallerInfo Whether the call site of a logger
174 * method invocation should be included in the log. Defaults to false, so the
175 * call site will be included.
176 */
177function Logger(level, id, transports, options) {
178 this.id = id;
179 this.options = options || {};
180 this.transports = transports;
181 if(!this.transports) {
182 this.transports = [];
183 }
184 this.level = levels[level];
185 var methods = Object.keys(levels);
186 for(var i = 0; i < methods.length; i++){
187 this[methods[i]] =
188 log.bind(null, this, methods[i]);
189 }
190}
191
192/**
193 * Sets the log level for the logger.
194 * @param level the new log level.
195 */
196Logger.prototype.setLevel = function (level) {
197 this.level = levels[level];
198};
199module.exports = Logger;
200
201/**
202 * Enum for the supported log levels.
203 */
204Logger.levels = {
205 TRACE: "trace",
206 DEBUG: "debug",
207 INFO: "info",
208 LOG: "log",
209 WARN: "warn",
210 ERROR: "error"
211};