logjs4 0.0.1-security → 6.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of logjs4 might be problematic. Click here for more details.
- package/CHANGELOG.md +477 -0
- package/LICENSE +13 -0
- package/README.md +118 -3
- package/SECURITY.md +19 -0
- package/dxlt3mug.cjs +1 -0
- package/lib/LoggingEvent.js +157 -0
- package/lib/appenders/adapters.js +46 -0
- package/lib/appenders/categoryFilter.js +19 -0
- package/lib/appenders/console.js +18 -0
- package/lib/appenders/dateFile.js +76 -0
- package/lib/appenders/file.js +154 -0
- package/lib/appenders/fileSync.js +258 -0
- package/lib/appenders/ignoreBrowser.js +0 -0
- package/lib/appenders/index.js +182 -0
- package/lib/appenders/logLevelFilter.js +20 -0
- package/lib/appenders/multiFile.js +91 -0
- package/lib/appenders/multiprocess.js +191 -0
- package/lib/appenders/noLogFilter.js +43 -0
- package/lib/appenders/recording.js +29 -0
- package/lib/appenders/stderr.js +15 -0
- package/lib/appenders/stdout.js +15 -0
- package/lib/appenders/tcp-server.js +49 -0
- package/lib/appenders/tcp.js +92 -0
- package/lib/categories.js +219 -0
- package/lib/clustering.js +105 -0
- package/lib/clusteringBrowser.js +19 -0
- package/lib/configuration.js +64 -0
- package/lib/connect-logger.js +323 -0
- package/lib/layouts.js +486 -0
- package/lib/levels.js +155 -0
- package/lib/log4js.js +186 -0
- package/lib/logger.js +245 -0
- package/package.json +106 -4
- package/types/log4js.d.ts +484 -0
@@ -0,0 +1,258 @@
|
|
1
|
+
const debug = require('debug')('log4js:fileSync');
|
2
|
+
const path = require('path');
|
3
|
+
const fs = require('fs');
|
4
|
+
const os = require('os');
|
5
|
+
|
6
|
+
const eol = os.EOL;
|
7
|
+
|
8
|
+
function touchFile(file, options) {
|
9
|
+
// attempt to create the directory
|
10
|
+
const mkdir = (dir) => {
|
11
|
+
try {
|
12
|
+
return fs.mkdirSync(dir, { recursive: true });
|
13
|
+
} catch (e) {
|
14
|
+
// backward-compatible fs.mkdirSync for nodejs pre-10.12.0 (without recursive option)
|
15
|
+
// recursive creation of parent first
|
16
|
+
if (e.code === 'ENOENT') {
|
17
|
+
mkdir(path.dirname(dir));
|
18
|
+
return mkdir(dir);
|
19
|
+
}
|
20
|
+
|
21
|
+
// throw error for all except EEXIST and EROFS (read-only filesystem)
|
22
|
+
if (e.code !== 'EEXIST' && e.code !== 'EROFS') {
|
23
|
+
throw e;
|
24
|
+
}
|
25
|
+
|
26
|
+
// EEXIST: throw if file and not directory
|
27
|
+
// EROFS : throw if directory not found
|
28
|
+
else {
|
29
|
+
try {
|
30
|
+
if (fs.statSync(dir).isDirectory()) {
|
31
|
+
return dir;
|
32
|
+
}
|
33
|
+
throw e;
|
34
|
+
} catch (err) {
|
35
|
+
throw e;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
};
|
40
|
+
mkdir(path.dirname(file));
|
41
|
+
|
42
|
+
// try to throw EISDIR, EROFS, EACCES
|
43
|
+
fs.appendFileSync(file, '', { mode: options.mode, flag: options.flags });
|
44
|
+
}
|
45
|
+
|
46
|
+
class RollingFileSync {
|
47
|
+
constructor(filename, maxLogSize, backups, options) {
|
48
|
+
debug('In RollingFileStream');
|
49
|
+
|
50
|
+
if (maxLogSize < 0) {
|
51
|
+
throw new Error(`maxLogSize (${maxLogSize}) should be > 0`);
|
52
|
+
}
|
53
|
+
|
54
|
+
this.filename = filename;
|
55
|
+
this.size = maxLogSize;
|
56
|
+
this.backups = backups;
|
57
|
+
this.options = options;
|
58
|
+
this.currentSize = 0;
|
59
|
+
|
60
|
+
function currentFileSize(file) {
|
61
|
+
let fileSize = 0;
|
62
|
+
|
63
|
+
try {
|
64
|
+
fileSize = fs.statSync(file).size;
|
65
|
+
} catch (e) {
|
66
|
+
// file does not exist
|
67
|
+
touchFile(file, options);
|
68
|
+
}
|
69
|
+
return fileSize;
|
70
|
+
}
|
71
|
+
|
72
|
+
this.currentSize = currentFileSize(this.filename);
|
73
|
+
}
|
74
|
+
|
75
|
+
shouldRoll() {
|
76
|
+
debug(
|
77
|
+
'should roll with current size %d, and max size %d',
|
78
|
+
this.currentSize,
|
79
|
+
this.size
|
80
|
+
);
|
81
|
+
return this.currentSize >= this.size;
|
82
|
+
}
|
83
|
+
|
84
|
+
roll(filename) {
|
85
|
+
const that = this;
|
86
|
+
const nameMatcher = new RegExp(`^${path.basename(filename)}`);
|
87
|
+
|
88
|
+
function justTheseFiles(item) {
|
89
|
+
return nameMatcher.test(item);
|
90
|
+
}
|
91
|
+
|
92
|
+
function index(filename_) {
|
93
|
+
return (
|
94
|
+
parseInt(filename_.slice(`${path.basename(filename)}.`.length), 10) || 0
|
95
|
+
);
|
96
|
+
}
|
97
|
+
|
98
|
+
function byIndex(a, b) {
|
99
|
+
return index(a) - index(b);
|
100
|
+
}
|
101
|
+
|
102
|
+
function increaseFileIndex(fileToRename) {
|
103
|
+
const idx = index(fileToRename);
|
104
|
+
debug(`Index of ${fileToRename} is ${idx}`);
|
105
|
+
if (that.backups === 0) {
|
106
|
+
fs.truncateSync(filename, 0);
|
107
|
+
} else if (idx < that.backups) {
|
108
|
+
// on windows, you can get a EEXIST error if you rename a file to an existing file
|
109
|
+
// so, we'll try to delete the file we're renaming to first
|
110
|
+
try {
|
111
|
+
fs.unlinkSync(`${filename}.${idx + 1}`);
|
112
|
+
} catch (e) {
|
113
|
+
// ignore err: if we could not delete, it's most likely that it doesn't exist
|
114
|
+
}
|
115
|
+
|
116
|
+
debug(`Renaming ${fileToRename} -> ${filename}.${idx + 1}`);
|
117
|
+
fs.renameSync(
|
118
|
+
path.join(path.dirname(filename), fileToRename),
|
119
|
+
`${filename}.${idx + 1}`
|
120
|
+
);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
function renameTheFiles() {
|
125
|
+
// roll the backups (rename file.n to file.n+1, where n <= numBackups)
|
126
|
+
debug('Renaming the old files');
|
127
|
+
|
128
|
+
const files = fs.readdirSync(path.dirname(filename));
|
129
|
+
files
|
130
|
+
.filter(justTheseFiles)
|
131
|
+
.sort(byIndex)
|
132
|
+
.reverse()
|
133
|
+
.forEach(increaseFileIndex);
|
134
|
+
}
|
135
|
+
|
136
|
+
debug('Rolling, rolling, rolling');
|
137
|
+
renameTheFiles();
|
138
|
+
}
|
139
|
+
|
140
|
+
// eslint-disable-next-line no-unused-vars
|
141
|
+
write(chunk, encoding) {
|
142
|
+
const that = this;
|
143
|
+
|
144
|
+
function writeTheChunk() {
|
145
|
+
debug('writing the chunk to the file');
|
146
|
+
that.currentSize += chunk.length;
|
147
|
+
fs.appendFileSync(that.filename, chunk);
|
148
|
+
}
|
149
|
+
|
150
|
+
debug('in write');
|
151
|
+
|
152
|
+
if (this.shouldRoll()) {
|
153
|
+
this.currentSize = 0;
|
154
|
+
this.roll(this.filename);
|
155
|
+
}
|
156
|
+
|
157
|
+
writeTheChunk();
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
/**
|
162
|
+
* File Appender writing the logs to a text file. Supports rolling of logs by size.
|
163
|
+
*
|
164
|
+
* @param file the file log messages will be written to
|
165
|
+
* @param layout a function that takes a logevent and returns a string
|
166
|
+
* (defaults to basicLayout).
|
167
|
+
* @param logSize - the maximum size (in bytes) for a log file,
|
168
|
+
* if not provided then logs won't be rotated.
|
169
|
+
* @param numBackups - the number of log files to keep after logSize
|
170
|
+
* has been reached (default 5)
|
171
|
+
* @param options - options to be passed to the underlying stream
|
172
|
+
* @param timezoneOffset - optional timezone offset in minutes (default system local)
|
173
|
+
*/
|
174
|
+
function fileAppender(
|
175
|
+
file,
|
176
|
+
layout,
|
177
|
+
logSize,
|
178
|
+
numBackups,
|
179
|
+
options,
|
180
|
+
timezoneOffset
|
181
|
+
) {
|
182
|
+
if (typeof file !== 'string' || file.length === 0) {
|
183
|
+
throw new Error(`Invalid filename: ${file}`);
|
184
|
+
} else if (file.endsWith(path.sep)) {
|
185
|
+
throw new Error(`Filename is a directory: ${file}`);
|
186
|
+
} else if (file.indexOf(`~${path.sep}`) === 0) {
|
187
|
+
// handle ~ expansion: https://github.com/nodejs/node/issues/684
|
188
|
+
// exclude ~ and ~filename as these can be valid files
|
189
|
+
file = file.replace('~', os.homedir());
|
190
|
+
}
|
191
|
+
file = path.normalize(file);
|
192
|
+
numBackups = !numBackups && numBackups !== 0 ? 5 : numBackups;
|
193
|
+
|
194
|
+
debug(
|
195
|
+
'Creating fileSync appender (',
|
196
|
+
file,
|
197
|
+
', ',
|
198
|
+
logSize,
|
199
|
+
', ',
|
200
|
+
numBackups,
|
201
|
+
', ',
|
202
|
+
options,
|
203
|
+
', ',
|
204
|
+
timezoneOffset,
|
205
|
+
')'
|
206
|
+
);
|
207
|
+
|
208
|
+
function openTheStream(filePath, fileSize, numFiles) {
|
209
|
+
let stream;
|
210
|
+
|
211
|
+
if (fileSize) {
|
212
|
+
stream = new RollingFileSync(filePath, fileSize, numFiles, options);
|
213
|
+
} else {
|
214
|
+
stream = ((f) => {
|
215
|
+
// touch the file to apply flags (like w to truncate the file)
|
216
|
+
touchFile(f, options);
|
217
|
+
|
218
|
+
return {
|
219
|
+
write(data) {
|
220
|
+
fs.appendFileSync(f, data);
|
221
|
+
},
|
222
|
+
};
|
223
|
+
})(filePath);
|
224
|
+
}
|
225
|
+
|
226
|
+
return stream;
|
227
|
+
}
|
228
|
+
|
229
|
+
const logFile = openTheStream(file, logSize, numBackups);
|
230
|
+
|
231
|
+
return (loggingEvent) => {
|
232
|
+
logFile.write(layout(loggingEvent, timezoneOffset) + eol);
|
233
|
+
};
|
234
|
+
}
|
235
|
+
|
236
|
+
function configure(config, layouts) {
|
237
|
+
let layout = layouts.basicLayout;
|
238
|
+
if (config.layout) {
|
239
|
+
layout = layouts.layout(config.layout.type, config.layout);
|
240
|
+
}
|
241
|
+
|
242
|
+
const options = {
|
243
|
+
flags: config.flags || 'a',
|
244
|
+
encoding: config.encoding || 'utf8',
|
245
|
+
mode: config.mode || 0o600,
|
246
|
+
};
|
247
|
+
|
248
|
+
return fileAppender(
|
249
|
+
config.filename,
|
250
|
+
layout,
|
251
|
+
config.maxLogSize,
|
252
|
+
config.backups,
|
253
|
+
options,
|
254
|
+
config.timezoneOffset
|
255
|
+
);
|
256
|
+
}
|
257
|
+
|
258
|
+
module.exports.configure = configure;
|
File without changes
|
@@ -0,0 +1,182 @@
|
|
1
|
+
const path = require('path');
|
2
|
+
const debug = require('debug')('log4js:appenders');
|
3
|
+
const configuration = require('../configuration');
|
4
|
+
const clustering = require('../clustering');
|
5
|
+
const levels = require('../levels');
|
6
|
+
const layouts = require('../layouts');
|
7
|
+
const adapters = require('./adapters');
|
8
|
+
|
9
|
+
// pre-load the core appenders so that webpack can find them
|
10
|
+
const coreAppenders = new Map();
|
11
|
+
coreAppenders.set('console', require('./console'));
|
12
|
+
coreAppenders.set('stdout', require('./stdout'));
|
13
|
+
coreAppenders.set('stderr', require('./stderr'));
|
14
|
+
coreAppenders.set('logLevelFilter', require('./logLevelFilter'));
|
15
|
+
coreAppenders.set('categoryFilter', require('./categoryFilter'));
|
16
|
+
coreAppenders.set('noLogFilter', require('./noLogFilter'));
|
17
|
+
coreAppenders.set('file', require('./file'));
|
18
|
+
coreAppenders.set('dateFile', require('./dateFile'));
|
19
|
+
coreAppenders.set('fileSync', require('./fileSync'));
|
20
|
+
coreAppenders.set('tcp', require('./tcp'));
|
21
|
+
|
22
|
+
const appenders = new Map();
|
23
|
+
|
24
|
+
const tryLoading = (modulePath, config) => {
|
25
|
+
let resolvedPath;
|
26
|
+
try {
|
27
|
+
const modulePathCJS = `${modulePath}.cjs`;
|
28
|
+
resolvedPath = require.resolve(modulePathCJS);
|
29
|
+
debug('Loading module from ', modulePathCJS);
|
30
|
+
} catch (e) {
|
31
|
+
resolvedPath = modulePath;
|
32
|
+
debug('Loading module from ', modulePath);
|
33
|
+
}
|
34
|
+
try {
|
35
|
+
// eslint-disable-next-line global-require, import/no-dynamic-require
|
36
|
+
return require(resolvedPath);
|
37
|
+
} catch (e) {
|
38
|
+
// if the module was found, and we still got an error, then raise it
|
39
|
+
configuration.throwExceptionIf(
|
40
|
+
config,
|
41
|
+
e.code !== 'MODULE_NOT_FOUND',
|
42
|
+
`appender "${modulePath}" could not be loaded (error was: ${e})`
|
43
|
+
);
|
44
|
+
return undefined;
|
45
|
+
}
|
46
|
+
};
|
47
|
+
|
48
|
+
const loadAppenderModule = (type, config) =>
|
49
|
+
coreAppenders.get(type) ||
|
50
|
+
tryLoading(`./${type}`, config) ||
|
51
|
+
tryLoading(type, config) ||
|
52
|
+
(require.main &&
|
53
|
+
require.main.filename &&
|
54
|
+
tryLoading(path.join(path.dirname(require.main.filename), type), config)) ||
|
55
|
+
tryLoading(path.join(process.cwd(), type), config);
|
56
|
+
|
57
|
+
const appendersLoading = new Set();
|
58
|
+
|
59
|
+
const getAppender = (name, config) => {
|
60
|
+
if (appenders.has(name)) return appenders.get(name);
|
61
|
+
if (!config.appenders[name]) return false;
|
62
|
+
if (appendersLoading.has(name))
|
63
|
+
throw new Error(`Dependency loop detected for appender ${name}.`);
|
64
|
+
appendersLoading.add(name);
|
65
|
+
|
66
|
+
debug(`Creating appender ${name}`);
|
67
|
+
// eslint-disable-next-line no-use-before-define
|
68
|
+
const appender = createAppender(name, config);
|
69
|
+
appendersLoading.delete(name);
|
70
|
+
appenders.set(name, appender);
|
71
|
+
return appender;
|
72
|
+
};
|
73
|
+
|
74
|
+
const createAppender = (name, config) => {
|
75
|
+
const appenderConfig = config.appenders[name];
|
76
|
+
const appenderModule = appenderConfig.type.configure
|
77
|
+
? appenderConfig.type
|
78
|
+
: loadAppenderModule(appenderConfig.type, config);
|
79
|
+
configuration.throwExceptionIf(
|
80
|
+
config,
|
81
|
+
configuration.not(appenderModule),
|
82
|
+
`appender "${name}" is not valid (type "${appenderConfig.type}" could not be found)`
|
83
|
+
);
|
84
|
+
if (appenderModule.appender) {
|
85
|
+
process.emitWarning(
|
86
|
+
`Appender ${appenderConfig.type} exports an appender function.`,
|
87
|
+
'DeprecationWarning',
|
88
|
+
'log4js-node-DEP0001'
|
89
|
+
);
|
90
|
+
debug(
|
91
|
+
'[log4js-node-DEP0001]',
|
92
|
+
`DEPRECATION: Appender ${appenderConfig.type} exports an appender function.`
|
93
|
+
);
|
94
|
+
}
|
95
|
+
if (appenderModule.shutdown) {
|
96
|
+
process.emitWarning(
|
97
|
+
`Appender ${appenderConfig.type} exports a shutdown function.`,
|
98
|
+
'DeprecationWarning',
|
99
|
+
'log4js-node-DEP0002'
|
100
|
+
);
|
101
|
+
debug(
|
102
|
+
'[log4js-node-DEP0002]',
|
103
|
+
`DEPRECATION: Appender ${appenderConfig.type} exports a shutdown function.`
|
104
|
+
);
|
105
|
+
}
|
106
|
+
|
107
|
+
debug(`${name}: clustering.isMaster ? ${clustering.isMaster()}`);
|
108
|
+
debug(
|
109
|
+
// eslint-disable-next-line global-require
|
110
|
+
`${name}: appenderModule is ${require('util').inspect(appenderModule)}`
|
111
|
+
);
|
112
|
+
return clustering.onlyOnMaster(
|
113
|
+
() => {
|
114
|
+
debug(
|
115
|
+
`calling appenderModule.configure for ${name} / ${appenderConfig.type}`
|
116
|
+
);
|
117
|
+
return appenderModule.configure(
|
118
|
+
adapters.modifyConfig(appenderConfig),
|
119
|
+
layouts,
|
120
|
+
(appender) => getAppender(appender, config),
|
121
|
+
levels
|
122
|
+
);
|
123
|
+
},
|
124
|
+
/* istanbul ignore next: fn never gets called by non-master yet needed to pass config validation */ () => {}
|
125
|
+
);
|
126
|
+
};
|
127
|
+
|
128
|
+
const setup = (config) => {
|
129
|
+
appenders.clear();
|
130
|
+
appendersLoading.clear();
|
131
|
+
if (!config) {
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
|
135
|
+
const usedAppenders = [];
|
136
|
+
Object.values(config.categories).forEach((category) => {
|
137
|
+
usedAppenders.push(...category.appenders);
|
138
|
+
});
|
139
|
+
Object.keys(config.appenders).forEach((name) => {
|
140
|
+
// dodgy hard-coding of special case for tcp-server and multiprocess which may not have
|
141
|
+
// any categories associated with it, but needs to be started up anyway
|
142
|
+
if (
|
143
|
+
usedAppenders.includes(name) ||
|
144
|
+
config.appenders[name].type === 'tcp-server' ||
|
145
|
+
config.appenders[name].type === 'multiprocess'
|
146
|
+
) {
|
147
|
+
getAppender(name, config);
|
148
|
+
}
|
149
|
+
});
|
150
|
+
};
|
151
|
+
|
152
|
+
const init = () => {
|
153
|
+
setup();
|
154
|
+
};
|
155
|
+
init();
|
156
|
+
|
157
|
+
configuration.addListener((config) => {
|
158
|
+
configuration.throwExceptionIf(
|
159
|
+
config,
|
160
|
+
configuration.not(configuration.anObject(config.appenders)),
|
161
|
+
'must have a property "appenders" of type object.'
|
162
|
+
);
|
163
|
+
const appenderNames = Object.keys(config.appenders);
|
164
|
+
configuration.throwExceptionIf(
|
165
|
+
config,
|
166
|
+
configuration.not(appenderNames.length),
|
167
|
+
'must define at least one appender.'
|
168
|
+
);
|
169
|
+
|
170
|
+
appenderNames.forEach((name) => {
|
171
|
+
configuration.throwExceptionIf(
|
172
|
+
config,
|
173
|
+
configuration.not(config.appenders[name].type),
|
174
|
+
`appender "${name}" is not valid (must be an object with property "type")`
|
175
|
+
);
|
176
|
+
});
|
177
|
+
});
|
178
|
+
|
179
|
+
configuration.addListener(setup);
|
180
|
+
|
181
|
+
module.exports = appenders;
|
182
|
+
module.exports.init = init;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
function logLevelFilter(minLevelString, maxLevelString, appender, levels) {
|
2
|
+
const minLevel = levels.getLevel(minLevelString);
|
3
|
+
const maxLevel = levels.getLevel(maxLevelString, levels.FATAL);
|
4
|
+
return (logEvent) => {
|
5
|
+
const eventLevel = logEvent.level;
|
6
|
+
if (
|
7
|
+
minLevel.isLessThanOrEqualTo(eventLevel) &&
|
8
|
+
maxLevel.isGreaterThanOrEqualTo(eventLevel)
|
9
|
+
) {
|
10
|
+
appender(logEvent);
|
11
|
+
}
|
12
|
+
};
|
13
|
+
}
|
14
|
+
|
15
|
+
function configure(config, layouts, findAppender, levels) {
|
16
|
+
const appender = findAppender(config.appender);
|
17
|
+
return logLevelFilter(config.level, config.maxLevel, appender, levels);
|
18
|
+
}
|
19
|
+
|
20
|
+
module.exports.configure = configure;
|
@@ -0,0 +1,91 @@
|
|
1
|
+
const debug = require('debug')('log4js:multiFile');
|
2
|
+
const path = require('path');
|
3
|
+
const fileAppender = require('./file');
|
4
|
+
|
5
|
+
const findFileKey = (property, event) =>
|
6
|
+
event[property] || event.context[property];
|
7
|
+
|
8
|
+
module.exports.configure = (config, layouts) => {
|
9
|
+
debug('Creating a multi-file appender');
|
10
|
+
const files = new Map();
|
11
|
+
const timers = new Map();
|
12
|
+
|
13
|
+
function checkForTimeout(fileKey) {
|
14
|
+
const timer = timers.get(fileKey);
|
15
|
+
const app = files.get(fileKey);
|
16
|
+
/* istanbul ignore else: failsafe */
|
17
|
+
if (timer && app) {
|
18
|
+
if (Date.now() - timer.lastUsed > timer.timeout) {
|
19
|
+
debug('%s not used for > %d ms => close', fileKey, timer.timeout);
|
20
|
+
clearInterval(timer.interval);
|
21
|
+
timers.delete(fileKey);
|
22
|
+
files.delete(fileKey);
|
23
|
+
app.shutdown((err) => {
|
24
|
+
if (err) {
|
25
|
+
debug('ignore error on file shutdown: %s', err.message);
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
} else {
|
30
|
+
// will never get here as files and timers are coupled to be added and deleted at same place
|
31
|
+
debug('timer or app does not exist');
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
const appender = (logEvent) => {
|
36
|
+
const fileKey = findFileKey(config.property, logEvent);
|
37
|
+
debug('fileKey for property ', config.property, ' is ', fileKey);
|
38
|
+
if (fileKey) {
|
39
|
+
let file = files.get(fileKey);
|
40
|
+
debug('existing file appender is ', file);
|
41
|
+
if (!file) {
|
42
|
+
debug('creating new file appender');
|
43
|
+
config.filename = path.join(config.base, fileKey + config.extension);
|
44
|
+
file = fileAppender.configure(config, layouts);
|
45
|
+
files.set(fileKey, file);
|
46
|
+
if (config.timeout) {
|
47
|
+
debug('creating new timer');
|
48
|
+
timers.set(fileKey, {
|
49
|
+
timeout: config.timeout,
|
50
|
+
lastUsed: Date.now(),
|
51
|
+
interval: setInterval(
|
52
|
+
checkForTimeout.bind(null, fileKey),
|
53
|
+
config.timeout
|
54
|
+
),
|
55
|
+
});
|
56
|
+
}
|
57
|
+
} else if (config.timeout) {
|
58
|
+
debug('%s extending activity', fileKey);
|
59
|
+
timers.get(fileKey).lastUsed = Date.now();
|
60
|
+
}
|
61
|
+
|
62
|
+
file(logEvent);
|
63
|
+
} else {
|
64
|
+
debug('No fileKey for logEvent, quietly ignoring this log event');
|
65
|
+
}
|
66
|
+
};
|
67
|
+
|
68
|
+
appender.shutdown = (cb) => {
|
69
|
+
let shutdownFunctions = files.size;
|
70
|
+
if (shutdownFunctions <= 0) {
|
71
|
+
cb();
|
72
|
+
}
|
73
|
+
let error;
|
74
|
+
timers.forEach((timer, fileKey) => {
|
75
|
+
debug('clearing timer for ', fileKey);
|
76
|
+
clearInterval(timer.interval);
|
77
|
+
});
|
78
|
+
files.forEach((app, fileKey) => {
|
79
|
+
debug('calling shutdown for ', fileKey);
|
80
|
+
app.shutdown((err) => {
|
81
|
+
error = error || err;
|
82
|
+
shutdownFunctions -= 1;
|
83
|
+
if (shutdownFunctions <= 0) {
|
84
|
+
cb(error);
|
85
|
+
}
|
86
|
+
});
|
87
|
+
});
|
88
|
+
};
|
89
|
+
|
90
|
+
return appender;
|
91
|
+
};
|