This repository has been archived by the owner on May 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 65
/
loggers.js
125 lines (111 loc) · 3.78 KB
/
loggers.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
const util = require('util');
const logLevels = ['debug', 'info', 'warn', 'error', 'none'];
/**
* A simple logger that writes to stderr. See index.d.ts
*/
function basicLogger(options) {
const destination = (options && options.destination) || console.error;
if (typeof destination !== 'function') {
throw new Error('destination for basicLogger was set to a non-function');
}
let minLevel = 1; // default is 'info'
if (options && options.level) {
for (let i = 0; i < logLevels.length; i++) {
if (logLevels[i] === options.level) {
minLevel = i;
}
}
}
function write(prefix, args) {
if (args.length < 1) {
return;
}
let line;
if (args.length === 1) {
line = prefix + args[0];
} else {
const tempArgs = [...args];
tempArgs[0] = prefix + tempArgs[0];
line = util.format(...tempArgs);
}
destination(line);
}
const logger = {};
for (let i = 0; i < logLevels.length; i++) {
const levelName = logLevels[i];
if (levelName !== 'none') {
if (i < minLevel) {
logger[levelName] = () => {};
} else {
const prefix = levelName + ': [LaunchDarkly] ';
logger[levelName] = function () {
// can't use arrow function with "arguments"
write(prefix, arguments);
};
}
}
}
return logger;
}
/**
* Returns a logger that does nothing.
*/
function nullLogger() {
return {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
};
}
// The safeLogger logic exists because we allow the application to pass in a custom logger, but
// there is no guarantee that the logger works correctly and if it ever throws exceptions there
// could be serious consequences (e.g. an uncaught exception within an error event handler, due
// to the SDK trying to log the error, can terminate the application). An exception could result
// from faulty logic in the logger implementation, or it could be that this is not a logger at
// all but some other kind of object; the former is handled by a catch block that logs an error
// message to the SDK's default logger, and we can at least partly guard against the latter by
// checking for the presence of required methods at configuration time.
/**
* Asserts that the caller-supplied logger contains all required methods
* and wraps it in an exception handler that falls back to the fallbackLogger.
* @param {LDLogger} logger
* @param {LDLogger} fallbackLogger
*/
function safeLogger(logger, fallbackLogger) {
validateLogger(logger);
const wrappedLogger = {};
logLevels.forEach(level => {
if (level !== 'none') {
wrappedLogger[level] = wrapLoggerLevel(logger, fallbackLogger, level);
}
});
return wrappedLogger;
}
function validateLogger(logger) {
logLevels.forEach(level => {
if (level !== 'none' && (!logger[level] || typeof logger[level] !== 'function')) {
throw new Error('Provided logger instance must support logger.' + level + '(...) method');
// Note that the SDK normally does not throw exceptions to the application, but that rule
// does not apply to LDClient.init() which will throw an exception if the parameters are so
// invalid that we cannot proceed with creating the client. An invalid logger meets those
// criteria since the SDK calls the logger during nearly all of its operations.
}
});
}
function wrapLoggerLevel(logger, fallbackLogger, level) {
const logFn = logger[level];
return function wrappedLoggerMethod() {
try {
return logFn.apply(logger, arguments);
} catch (err) {
fallbackLogger.error('Error calling provided logger instance method ' + level + ': ' + err);
fallbackLogger[level].apply(fallbackLogger, arguments);
}
};
}
module.exports = {
basicLogger,
nullLogger,
safeLogger,
};