pax_global_header 0000666 0000000 0000000 00000000064 13565055024 0014517 g ustar 00root root 0000000 0000000 52 comment=f42038628addf746e0ff04f294b18d2bb3432f61
log4js-node-6.1.0/ 0000775 0000000 0000000 00000000000 13565055024 0013650 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/.editorconfig 0000664 0000000 0000000 00000000752 13565055024 0016331 0 ustar 00root root 0000000 0000000 # http://editorconfig.org
root = true
[*]
indent_style = space
end_of_line = lf
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.js]
quote_type = single
curly_bracket_next_line = true
indent_brace_style = Allman
spaces_around_operators = true
spaces_around_brackets = inside
continuation_indent_size = 2
[*.html]
# indent_size = 4
[*{.yml,.yaml,.json}]
indent_style = space
indent_size = 2
[.eslintrc]
indent_style = space
indent_size = 2
log4js-node-6.1.0/.eslintignore 0000664 0000000 0000000 00000000001 13565055024 0016342 0 ustar 00root root 0000000 0000000
log4js-node-6.1.0/.eslintrc 0000664 0000000 0000000 00000000631 13565055024 0015474 0 ustar 00root root 0000000 0000000 {
"root": true,
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"extends": ["airbnb-base", "prettier"],
"plugins": ["prettier", "import"],
"rules": {
"comma-dangle": 0,
"indent": 2,
"func-names": 0,
"max-len": [1, 120, 2],
"no-use-before-define": ["warn"],
"no-param-reassign": 0,
"strict": 1,
"import/no-extraneous-dependencies": 1
}
}
log4js-node-6.1.0/.gitattributes 0000664 0000000 0000000 00000001323 13565055024 0016542 0 ustar 00root root 0000000 0000000 # Automatically normalize line endings for all text-based files
# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
* text=auto
# For the following file types, normalize line endings to LF on
# checkin and prevent conversion to CRLF when they are checked out
# (this is required in order to prevent newline related issues like,
# for example, after the build script is run)
.* text eol=lf
*.css text eol=lf
*.html text eol=lf
*.js text eol=lf
*.json text eol=lf
*.md text eol=lf
*.sh text eol=lf
*.txt text eol=lf
*.xml text eol=lf
# Exclude the `.htaccess` file from GitHub's language statistics
# https://github.com/github/linguist#using-gitattributes
dist/.htaccess linguist-vendored
log4js-node-6.1.0/.gitignore 0000664 0000000 0000000 00000000364 13565055024 0015643 0 ustar 00root root 0000000 0000000 # Logs
logs
*.log*
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
build
node_modules
.bob/
test/streams/test-*
.idea
.vscode
.DS_Store
yarn.lock
coverage/
.nyc_output/
_site
Gemfile.lock
Dockerfile
docker-compose.yml
#personal config
.env
log4js-node-6.1.0/.npmignore 0000664 0000000 0000000 00000000321 13565055024 0015643 0 ustar 00root root 0000000 0000000 # Created by .ignore support plugin
**/.*
node_modules
bower_components
test
tests
support
benchmarks
examples
sample
lib-cov
coverage.html
Makefile
coverage
Gemfile
Gemfile.lock
docker-compose.yml
Dockerfile
log4js-node-6.1.0/.travis.yml 0000664 0000000 0000000 00000000176 13565055024 0015765 0 ustar 00root root 0000000 0000000 language: node_js
os:
- linux
- windows
sudo: false
node_js:
- "12"
- "10"
- "8"
after_success:
- npm run codecov
log4js-node-6.1.0/CHANGELOG.md 0000664 0000000 0000000 00000011757 13565055024 0015474 0 ustar 00root root 0000000 0000000 # log4js-node changelog
## 6.1.0
- [Add pause event to dateFile appender](https://github.com/log4js-node/log4js-node/pull/965) - thanks [@shayantabatabaee](https://github.com/shayantabatabaee)
- [Add pause event to file appender](https://github.com/log4js-node/log4js-node/pull/938) - thanks [@shayantabatabaee](https://github.com/shayantabatabaee)
- [Add pause/resume event to docs](https://github.com/log4js-node/log4js-node/pull/966)
## 6.0.0
- [Update streamroller to fix unhandled promise rejection](https://github.com/log4js-node/log4js-node/pull/962)
- [Updated date-format library](https://github.com/log4js-node/log4js-node/pull/960)
## 5.3.0
- [Padding and truncation changes](https://github.com/log4js-node/log4js-node/pull/956)
## 5.2.2
- [Update streamroller to fix overwriting old files when using date rolling](https://github.com/log4js-node/log4js-node/pull/951)
## 5.2.1
- [Update streamroller to fix numToKeep not working with dateFile pattern that is all digits](https://github.com/log4js-node/log4js-node/pull/949)
## 5.2.0
- [Update streamroller to 2.2.0 (copy and truncate when file is busy)](https://github.com/log4js-node/log4js-node/pull/948)
## 5.1.0
- [Update streamroller to 2.1.0 (windows fixes)](https://github.com/log4js-node/log4js-node/pull/933)
## 5.0.0
- [Update streamroller to 2.0.0 (remove support for node v6)](https://github.com/log4js-node/log4js-node/pull/922)
- [Update dependencies (mostly dev deps)](https://github.com/log4js-node/log4js-node/pull/923)
- [Fix error when cluster not available](https://github.com/log4js-node/log4js-node/pull/930)
- [Test coverage improvements](https://github.com/log4js-node/log4js-node/pull/925)
## 4.5.1
- [Update streamroller 1.0.5 -> 1.0.6 (to fix overwriting old backup log files)](https://github.com/log4js-node/log4js-node/pull/918)
- [Dependency update: lodash 4.17.4 (dependency of a dependency, not log4js)](https://github.com/log4js-node/log4js-node/pull/917) - thanks Github Automated Security Thing.
- [Dependency update: lodash 4.4.0 -> 4.5.0 (dependency of a dependency, not log4js)](https://github.com/log4js-node/log4js-node/pull/915) - thanks Github Automated Security Thing.
## 4.5.0
- [Override call stack parsing](https://github.com/log4js-node/log4js-node/pull/914) - thanks [@rommni](https://github.com/rommni)
- [patternLayout filename depth token](https://github.com/log4js-node/log4js-node/pull/913) - thanks [@rommni](https://github.com/rommni)
## 4.4.0
- [Add option to pass appender module in config](https://github.com/log4js-node/log4js-node/pull/833) - thanks [@kaxelson](https://github.com/kaxelson)
- [Added docs for passing appender module](https://github.com/log4js-node/log4js-node/pull/904)
- [Updated dependencies](https://github.com/log4js-node/log4js-node/pull/900)
## 4.3.2
- [Types for enableCallStack](https://github.com/log4js-node/log4js-node/pull/897) - thanks [@citrusjunoss](https://github.com/citrusjunoss)
## 4.3.1
- [Fix for maxLogSize in dateFile appender](https://github.com/log4js-node/log4js-node/pull/889)
## 4.3.0
- [Feature: line number support](https://github.com/log4js-node/log4js-node/pull/879) - thanks [@victor0801x](https://github.com/victor0801x)
- [Fix for missing core appenders in webpack](https://github.com/log4js-node/log4js-node/pull/882)
## 4.2.0
- [Feature: add appender and level inheritance](https://github.com/log4js-node/log4js-node/pull/863) - thanks [@pharapiak](https://github.com/pharapiak)
- [Feature: add response to context for connectLogger](https://github.com/log4js-node/log4js-node/pull/862) - thanks [@leak4mk0](https://github.com/leak4mk0)
- [Fix for broken sighup handler](https://github.com/log4js-node/log4js-node/pull/873)
- [Add missing types for Level](https://github.com/log4js-node/log4js-node/pull/872) - thanks [@Ivkaa](https://github.com/Ivkaa)
- [Typescript fixes for connect logger context](https://github.com/log4js-node/log4js-node/pull/876) - thanks [@leak4mk0](https://github.com/leak4mk0)
- [Upgrade to streamroller-1.0.5 to fix log rotation bug](https://github.com/log4js-node/log4js-node/pull/878)
## 4.1.1
- [Various test fixes for node v12](https://github.com/log4js-node/log4js-node/pull/870)
- [Fix layout problem in node v12](https://github.com/log4js-node/log4js-node/pull/860) - thanks [@bjornstar](https://github.com/bjornstar)
- [Add missing types for addLevels](https://github.com/log4js-node/log4js-node/pull/867) - thanks [@Ivkaa](https://github.com/Ivkaa)
- [Allow any return type for layout function](https://github.com/log4js-node/log4js-node/pull/845) - thanks [@xinbenlv](https://github.com/xinbenlv)
## 4.1.0
- Updated streamroller to 1.0.4, to fix a bug where the inital size of an existing file was ignored when appending
- [Updated streamroller to 1.0.3](https://github.com/log4js-node/log4js-node/pull/841), to fix a crash bug if the date pattern was all digits.
- [Updated dependencies](https://github.com/log4js-node/log4js-node/pull/840)
## Previous versions
Change information for older versions can be found by looking at the milestones in github.
log4js-node-6.1.0/LICENSE 0000664 0000000 0000000 00000001136 13565055024 0014656 0 ustar 00root root 0000000 0000000 Copyright 2015 Gareth Jones (with contributions from many other people)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
log4js-node-6.1.0/README.md 0000664 0000000 0000000 00000012424 13565055024 0015132 0 ustar 00root root 0000000 0000000 # log4js-node [](http://travis-ci.org/log4js-node/log4js-node) [](https://codecov.io/gh/log4js-node/log4js-node)
[](https://nodei.co/npm/log4js/)
This is a conversion of the [log4js](https://github.com/stritti/log4js)
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.
The full documentation is available [here](https://log4js-node.github.io/log4js-node/).
[Changes in version 3.x](https://log4js-node.github.io/log4js-node/v3-changes.md)
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.
Out of the box it supports the following features:
* coloured console logging to stdout or stderr
* file appender, with configurable log rolling based on file size or date
* a logger for connect/express servers
* configurable log message layout/patterns
* different log levels for different log categories (make some parts of your app log as DEBUG, others only ERRORS, etc.)
Optional appenders are available:
* [SMTP](https://github.com/log4js-node/smtp)
* [GELF](https://github.com/log4js-node/gelf)
* [Loggly](https://github.com/log4js-node/loggly)
* Logstash ([UDP](https://github.com/log4js-node/logstashUDP) and [HTTP](https://github.com/log4js-node/logstashHTTP))
* logFaces ([UDP](https://github.com/log4js-node/logFaces-UDP) and [HTTP](https://github.com/log4js-node/logFaces-HTTP))
* [RabbitMQ](https://github.com/log4js-node/rabbitmq)
* [Redis](https://github.com/log4js-node/redis)
* [Hipchat](https://github.com/log4js-node/hipchat)
* [Slack](https://github.com/log4js-node/slack)
* [mailgun](https://github.com/log4js-node/mailgun)
## Getting help
Having problems? Jump on the [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtNzkyMTIzODgxMDQ2LWZmZGEzOGQzN2MzMmE3YWNiNDVmZDY3MjM2MTM3ZTlhOTg0ODkyODc3ODc5OWQ3MWNmMjU1M2U4ZmUzNTViNzI) 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.
## installation
```bash
npm install log4js
```
## usage
Minimalist version:
```javascript
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.level = 'debug';
logger.debug("Some debug messages");
```
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:
```bash
[2010-01-17 11:43:37.987] [DEBUG] [default] - Some debug messages
```
See example.js for a full example, but here's a snippet (also in `examples/fromreadme.js`):
```javascript
const log4js = require('log4js');
log4js.configure({
appenders: { cheese: { type: 'file', filename: 'cheese.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = log4js.getLogger('cheese');
logger.trace('Entering cheese testing');
logger.debug('Got cheese.');
logger.info('Cheese is Comté.');
logger.warn('Cheese is quite smelly.');
logger.error('Cheese is too ripe!');
logger.fatal('Cheese was breeding ground for listeria.');
```
Output (in `cheese.log`):
```bash
[2010-01-17 11:43:37.987] [ERROR] cheese - Cheese is too ripe!
[2010-01-17 11:43:37.990] [FATAL] cheese - Cheese was breeding ground for listeria.
```
## Note for library makers
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).
## Documentation
Available [here](https://log4js-node.github.io/log4js-node/).
There's also [an example application](https://github.com/log4js-node/log4js-example).
## TypeScript
```ts
import { configure, getLogger } from 'log4js';
configure('./filename');
const logger = getLogger();
logger.level = 'debug';
logger.debug("Some debug messages");
configure({
appenders: { cheese: { type: 'file', filename: 'cheese.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
});
```
## Contributing
We're always looking for people to help out. Jump on [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtNzkyMTIzODgxMDQ2LWZmZGEzOGQzN2MzMmE3YWNiNDVmZDY3MjM2MTM3ZTlhOTg0ODkyODc3ODc5OWQ3MWNmMjU1M2U4ZmUzNTViNzI) 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.
## License
The original log4js was distributed under the Apache 2.0 License, and so is this. I've tried to
keep the original copyright and author credits in place, except in sections that I have rewritten
extensively.
log4js-node-6.1.0/docs/ 0000775 0000000 0000000 00000000000 13565055024 0014600 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/docs/Gemfile 0000664 0000000 0000000 00000000111 13565055024 0016064 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins
log4js-node-6.1.0/docs/_config.yml 0000664 0000000 0000000 00000000101 13565055024 0016717 0 ustar 00root root 0000000 0000000 theme: jekyll-theme-minimal
repository: nomiddlename/log4js-node
log4js-node-6.1.0/docs/_layouts/ 0000775 0000000 0000000 00000000000 13565055024 0016437 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/docs/_layouts/default.html 0000664 0000000 0000000 00000005636 13565055024 0020763 0 ustar 00root root 0000000 0000000
{{ site.title | default: site.github.repository_name }} by {{ site.github.owner_name }}
{% if site.google_analytics %}
{% endif %}
log4js-node-6.1.0/docs/api.md 0000664 0000000 0000000 00000016015 13565055024 0015676 0 ustar 00root root 0000000 0000000 ## API
## configuration - `log4js.configure(object || string)`
There is one entry point for configuring log4js. A string argument is treated as a filename to load configuration from. Config files should be JSON, and contain a configuration object (see format below). You can also pass a configuration object directly to `configure`.
Configuration should take place immediately after requiring log4js for the first time in your application. If you do not call `configure`, log4js will use `LOG4JS_CONFIG` (if defined) or the default config. The default config defines one appender, which would log to stdout with the coloured layout, but also defines the default log level to be `OFF` - which means no logs will be output.
If you are using `cluster`, then include the call to `configure` in the worker processes as well as the master. That way the worker processes will pick up the right levels for your categories, and any custom levels you may have defined. Appenders will only be defined on the master process, so there is no danger of multiple processes attempting to write to the same appender. No special configuration is needed to use log4js with clusters, unlike previous versions.
Configuration objects must define at least one appender, and a default category. Log4js will throw an exception if the configuration is invalid.
`configure` method call returns the configured log4js object.
### Configuration Object
Properties:
* `levels` (optional, object) - used for defining custom log levels, or redefining existing ones; this is a map with the level name as the key (string, case insensitive), and an object as the value. The object should have two properties: the level value (integer) as the value, and the colour. Log levels are used to assign importance to log messages, with the integer value being used to sort them. If you do not specify anything in your configuration, the default values are used (ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < MARK < OFF - note that OFF is intended to be used to turn off logging, not as a level for actual logging, i.e. you would never call `logger.off('some log message')`). Levels defined here are used in addition to the default levels, with the integer value being used to determine their relation to the default levels. If you define a level with the same name as a default level, then the integer value in the config takes precedence. Level names must begin with a letter, and can only contain letters, numbers and underscores.
* `appenders` (object) - a map of named appenders (string) to appender definitions (object); appender definitions must have a property `type` (string) - other properties depend on the appender type.
* `categories` (object) - a map of named categories (string) to category definitions (object). You must define the `default` category which is used for all log events that do not match a specific category. Category definitions have two properties:
* `appenders` (array of strings) - the list of appender names to be used for this category. A category must have at least one appender.
* `level` (string, case insensitive) - the minimum log level that this category will send to the appenders. For example, if set to 'error' then the appenders will only receive log events of level 'error', 'fatal', 'mark' - log events of 'info', 'warn', 'debug', or 'trace' will be ignored.
* `enableCallStack` (boolean, optional, defaults to `false`) - setting this to `true` will make log events for this category use the call stack to generate line numbers and file names in the event. See [pattern layout](layouts.md) for how to output these values in your appenders.
* `pm2` (boolean) (optional) - set this to true if you're running your app using [pm2](http://pm2.keymetrics.io), otherwise logs will not work (you'll also need to install pm2-intercom as pm2 module: `pm2 install pm2-intercom`)
* `pm2InstanceVar` (string) (optional, defaults to 'NODE_APP_INSTANCE') - set this if you're using pm2 and have changed the default name of the NODE_APP_INSTANCE variable.
* `disableClustering` (boolean) (optional) - set this to true if you liked the way log4js used to just ignore clustered environments, or you're having trouble with PM2 logging. Each worker process will do its own logging. Be careful with this if you're logging to files, weirdness can occur.
## Loggers - `log4js.getLogger([category])`
This function takes a single optional string argument to denote the category to be used for log events on this logger. If no category is specified, the events will be routed to the appender for the `default` category. The function returns a `Logger` object which has its level set to the level specified for that category in the config and implements the following functions:
* `(args...)` - where `` can be any of the lower case names of the levels (including any custom levels defined). For example: `logger.info('some info')` will dispatch a log event with a level of info. If you're using the basic, coloured or message pass-through [layouts](layouts.md), the logged string will have its formatting (placeholders like `%s`, `%d`, etc) delegated to [util.format](https://nodejs.org/api/util.html#util_util_format_format_args).
* `isEnabled()` - returns true if a log event of level (camel case) would be dispatched to the appender defined for the logger's category. For example: `logger.isInfoEnabled()` will return true if the level for the logger is INFO or lower.
* `addContext(,)` - where `` is a string, `` can be anything. This stores a key-value pair that is added to all log events generated by the logger. Uses would be to add ids for tracking a user through your application. Currently only the `logFaces` appenders make use of the context values.
* `removeContext()` - removes a previously defined key-value pair from the context.
* `clearContext()` - removes all context pairs from the logger.
* `setParseCallStackFunction(function)` - Allow to override the default way to parse the callstack data for the layout pattern, a generic javascript Error object is passed to the function. Must return an object with properties : `functionName` / `fileName` / `lineNumber` / `columnNumber` / `callStack`. Can for example be used if all of your log call are made from one "debug" class and you would to "erase" this class from the callstack to only show the function which called your "debug" class.
The `Logger` object has the following property:
* `level` - where `level` is a log4js level or a string that matches a level (e.g. 'info', 'INFO', etc). This allows overriding the configured level for this logger. Changing this value applies to all loggers of the same category.
## Shutdown - `log4js.shutdown(cb)`
`shutdown` accepts a callback that will be called when log4js has closed all appenders and finished writing log events. Use this when your programme exits to make sure all your logs are written to files, sockets are closed, etc.
## Custom Layouts - `log4js.addLayout(type, fn)`
This function is used to add user-defined layout functions. See [layouts](layouts.md) for more details and an example.
log4js-node-6.1.0/docs/appenders.md 0000664 0000000 0000000 00000007550 13565055024 0017112 0 ustar 00root root 0000000 0000000 # Log4js - Appenders
Appenders serialise log events to some form of output. They can write to files, send emails, send data over the network. All appenders have a `type` which determines which appender gets used. For example:
```javascript
const log4js = require('log4js');
log4js.configure({
appenders: {
out: { type: 'stdout' },
app: { type: 'file', filename: 'application.log' }
},
categories: {
default: { appenders: [ 'out', 'app' ], level: 'debug' }
}
});
```
This defines two appenders named 'out' and 'app'. 'out' uses the [stdout](stdout.md) appender which writes to standard out. 'app' uses the [file](file.md) appender, configured to write to 'application.log'.
## Core Appenders
The following appenders are included with log4js. Some require extra dependencies that are not included as part of log4js (the [smtp](smtp.md) appender needs [nodemailer](https://www.npmjs.org/packages/nodemailer) for example), and these will be noted in the docs for that appender. If you don't use those appenders, then you don't need the extra dependencies.
* [categoryFilter](categoryFilter.md)
* [console](console.md)
* [dateFile](dateFile.md)
* [file](file.md)
* [fileSync](fileSync.md)
* [logLevelFilter](logLevelFilter.md)
* [multiFile](multiFile.md)
* [multiprocess](multiprocess.md)
* [recording](recording.md)
* [stderr](stderr.md)
* [stdout](stdout.md)
* [tcp](tcp.md)
* [tcp-server](tcp-server.md)
## Optional Appenders
The following appenders are supported by log4js, but are no longer distributed with log4js core from version 3 onwards.
* [gelf](https://github.com/log4js-node/gelf)
* [hipchat](https://github.com/log4js-node/hipchat)
* [logFaces-HTTP](https://github.com/log4js-node/logFaces-HTTP)
* [logFaces-UDP](https://github.com/log4js-node/logFaces-UDP)
* [loggly](https://github.com/log4js-node/loggly)
* [logstashHTTP](https://github.com/log4js-node/logstashHTTP)
* [logstashUDP](https://github.com/log4js-node/logstashUDP)
* [mailgun](https://github.com/log4js-node/mailgun)
* [rabbitmq](https://github.com/log4js-node/rabbitmq)
* [redis](https://github.com/log4js-node/redis)
* [slack](https://github.com/log4js-node/slack)
* [smtp](https://github.com/log4js-node/smtp)
For example, if you were previously using the gelf appender (`type: 'gelf'`) then you should add `@log4js-node/gelf` to your dependencies and change the type to `type: '@log4js-node/gelf'`.
## Other Appenders
Log4js can load appenders from outside the core appenders. The `type` config value is used as a require path if no matching appender can be found. For example, the following configuration will attempt to load an appender from the module 'cheese/appender', passing the rest of the config for the appender to that module:
```javascript
log4js.configure({
appenders: { gouda: { type: 'cheese/appender', flavour: 'tasty' } },
categories: { default: { appenders: ['gouda'], level: 'debug' }}
});
```
Log4js checks the following places (in this order) for appenders based on the type value:
1. The core appenders: `require('./appenders/' + type)`
2. node_modules: `require(type)`
3. relative to the main file of your application: `require(path.dirname(require.main.filename) + '/' + type)`
4. relative to the process' current working directory: `require(process.cwd() + '/' + type)`
If you want to write your own appender, read the [documentation](writing-appenders.md) first.
## Advanced configuration
If you've got a custom appender of your own, or are using webpack (or some other bundler), you may find it easier to pass
in the appender module in the config instead of loading from the node.js require path. Here's an example:
```javascript
const myAppenderModule = {
configure: (config, layouts, findAppender, levels) => { /* ...your appender config... */ }
};
log4js.configure({
appenders: { custom: { type: myAppenderModule } },
categories: { default: { appenders: ['custom'], level: 'debug' } }
});
```
log4js-node-6.1.0/docs/assets/ 0000775 0000000 0000000 00000000000 13565055024 0016102 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/docs/assets/css/ 0000775 0000000 0000000 00000000000 13565055024 0016672 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/docs/assets/css/style.scss 0000664 0000000 0000000 00000000630 13565055024 0020726 0 ustar 00root root 0000000 0000000 @import "{{ site.theme }}";
header ul {
display: block;
background-color: white;
border: none;
width: auto;
height: auto;
padding: 0;
list-style: disc;
clear:both;
margin-left: 20px;
}
header li {
display: list-item;
width: auto;
border: none;
float: none;
height: auto;
}
header ul a {
display: inline;
width: auto;
text-align: left;
color: #39c;
font-size: 14px;
}
log4js-node-6.1.0/docs/categoryFilter.md 0000664 0000000 0000000 00000003303 13565055024 0020104 0 ustar 00root root 0000000 0000000 # Category Filter
This is not strictly an appender - it wraps around another appender and stops log events from specific categories from being written to that appender. This could be useful when debugging your application, but you have one component that logs noisily, or is irrelevant to your investigation.
## Configuration
* `type` - `"categoryFilter"`
* `exclude` - `string | Array` - the category (or categories if you provide an array of values) that will be excluded from the appender.
* `appender` - `string` - the name of the appender to filter.
## Example
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' },
'no-noise': { type: 'categoryFilter', exclude: 'noisy.component', appender: 'everything' }
},
categories: {
default: { appenders: [ 'no-noise' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
const noisyLogger = log4js.getLogger('noisy.component');
logger.debug('I will be logged in all-the-logs.log');
noisyLogger.debug('I will not be logged.');
```
Note that you can achieve the same outcome without using the category filter, like this:
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug' },
'noisy.component': { appenders: ['everything'], level: 'off' }
}
});
const logger = log4js.getLogger();
const noisyLogger = log4js.getLogger('noisy.component');
logger.debug('I will be logged in all-the-logs.log');
noisyLogger.debug('I will not be logged.');
```
Category filter becomes useful when you have many categories you want to exclude, passing them as an array.
log4js-node-6.1.0/docs/clustering.md 0000664 0000000 0000000 00000004157 13565055024 0017310 0 ustar 00root root 0000000 0000000 # Clustering / Multi-process Logging
If you're running log4js in an application that uses [node's core cluster](https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html) then log4js will transparently handle making sure the processes don't try to log at the same time. All logging is done on the master process, with the worker processes sending their log messages to the master via `process.send`. This ensures that you don't get multiple processes trying to write to the same file (or rotate the log files) at the same time.
This can cause problems in some rare circumstances, if you're experiencing weird logging problems, then use the `disableClustering: true` option in your log4js configuration to have every process behave as if it were the master process. Be careful if you're logging to files.
## I'm using PM2, but I'm not getting any logs!
To get log4js working with [PM2](http://pm2.keymetrics.io), you'll need to install the [pm2-intercom](https://www.npmjs.com/package/pm2-intercom) module.
```bash
pm2 install pm2-intercom
```
Then add the value `pm2: true` to your log4js configuration. If you're also using `node-config`, then you'll probably have renamed your `NODE_APP_INSTANCE` environment variable. If so, you'll also need to add `pm2InstanceVar: ''` where `` should be replaced with the new name you gave the instance environment variable.
```javascript
log4js.configure({
appenders: { out: { type: 'stdout'}},
categories: { default: { appenders: ['out'], level: 'info'}},
pm2: true,
pm2InstanceVar: 'INSTANCE_ID'
});
```
## I'm using Passenger, but I'm not getting any logs!
[Passenger](https://www.phusionpassenger.com/library/) replaces the node.js core cluster module with a non-functional stub, so you won't see any output using log4js. To fix this, add `disableClustering: true` to your configuration. Again, be careful if you're logging to files.
## I'm not using clustering/pm2/passenger but I do have multiple processes that I'd like to all log to the same place
Ok, you probably want to look at the [tcp-server](tcp-server.md) and [tcp appender](tcp.md) documentation.
log4js-node-6.1.0/docs/connect-logger.md 0000664 0000000 0000000 00000007504 13565055024 0020036 0 ustar 00root root 0000000 0000000 # Connect / Express Logger
The connect/express logger was added to log4js by [danbell](https://github.com/danbell). This allows connect/express servers to log using log4js. See `example-connect-logger.js`.
```javascript
var log4js = require('log4js');
var express = require('express');
log4js.configure({
appenders: {
console: { type: 'console' },
file: { type: 'file', filename: 'cheese.log' }
},
categories: {
cheese: { appenders: ['file'], level: 'info' },
default: { appenders: ['console'], level: 'info' }
}
});
var logger = log4js.getLogger('cheese');
var app = express();
app.use(log4js.connectLogger(logger, { level: 'info' }));
app.get('/', function(req,res) {
res.send('hello world');
});
app.listen(5000);
```
The log4js.connectLogger supports the passing of an options object that can be used to set the following:
- log level
- log format string or function (the same as the connect/express logger)
- nolog expressions (represented as a string, regexp, or array)
- status code rulesets
For example:
```javascript
app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO, format: ':method :url' }));
```
or:
```javascript
app.use(log4js.connectLogger(logger, {
level: 'auto',
// include the Express request ID in the logs
format: (req, res, format) => format(`:remote-addr - ${req.id} - ":method :url HTTP/:http-version" :status :content-length ":referrer" ":user-agent"`)
}));
```
When you request of POST, you want to log the request body parameter like JSON.
The log format function is very useful.
Please use log format function instead “tokens” property for use express's request or response.
```javascript
app.use(log4js.connectLogger(logger, {
level: 'info',
format: (req, res, format) => format(`:remote-addr :method :url ${JSON.stringify(req.body)}`)
}));
```
Added automatic level detection to connect-logger, depends on http status response, compatible with express 3.x and 4.x.
* http responses 3xx, level = WARN
* http responses 4xx & 5xx, level = ERROR
* else, level = INFO
```javascript
app.use(log4js.connectLogger(logger, { level: 'auto' }));
```
The levels of returned status codes can be configured via status code rulesets.
```javascript
app.use(log4js.connectLogger(logger, { level: 'auto', statusRules: [
{ from: 200, to: 299, level: 'debug' },
{ codes: [303, 304], level: 'info' }
]}));
```
The log4js.connectLogger also supports a nolog option where you can specify a string, regexp, or array to omit certain log messages. Example of 1.2 below.
```javascript
app.use(log4js.connectLogger(logger, { level: 'auto', format: ':method :url', nolog: '\\.gif|\\.jpg$' }));
```
The log4js.connectLogger can add a response of express to context if `context` flag is set to `true`.
Application can use it in layouts or appenders.
In application:
```javascript
app.use(log4js.connectLogger(logger, { context: true }));
```
In layout:
```javascript
log4js.addLayout('customLayout', () => {
return (loggingEvent) => {
const res = loggingEvent.context.res;
return util.format(...loggingEvent.data, res ? `status: ${res.statusCode}` : '');
};
});
```
## Example nolog values
| nolog value | Will Not Log | Will Log |
|-------------|--------------|----------|
| `"\\.gif"` | http://example.com/hoge.gif http://example.com/hoge.gif?fuga | http://example.com/hoge.agif |
| `"\\.gif\|\\.jpg$"` | http://example.com/hoge.gif http://example.com/hoge.gif?fuga http://example.com/hoge.jpg?fuga | http://example.com/hoge.agif http://example.com/hoge.ajpg http://example.com/hoge.jpg?hoge |
| `"\\.(gif\|jpe?g\|png)$"` | http://example.com/hoge.gif http://example.com/hoge.jpeg | http://example.com/hoge.gif?uid=2 http://example.com/hoge.jpg?pid=3 |
| `/\.(gif\|jpe?g\|png)$/` | as above | as above |
| `["\\.jpg$", "\\.png", "\\.gif"]` | same as `"\\.jpg\|\\.png\|\\.gif"` | same as `"\\.jpg\|\\.png\|\\.gif"` |
log4js-node-6.1.0/docs/console.md 0000664 0000000 0000000 00000001447 13565055024 0016572 0 ustar 00root root 0000000 0000000 # Console Appender
This appender uses node's console object to write log events. It can also be used in the browser, if you're using browserify or something similar. Be aware that writing a high volume of output to the console can make your application use a lot of memory. If you experience this problem, try switching to the [stdout](stdout.md) appender.
# Configuration
* `type` - `console`
* `layout` - `object` (optional, defaults to colouredLayout) - see [layouts](layouts.md)
Note that all log events are output using `console.log` regardless of the event's level (so `ERROR` events will not be logged using `console.error`).
# Example
```javascript
log4js.configure({
appenders: { console: { type: 'console' } },
categories: { default: { appenders: [ 'console' ], level: 'info' } }
});
```
log4js-node-6.1.0/docs/contrib-guidelines.md 0000664 0000000 0000000 00000001474 13565055024 0020716 0 ustar 00root root 0000000 0000000 # Want to help?
I love pull requests, and I need all the help I can get. However, there are a few rules to follow if you want a better chance of having your pull request merged:
* Fork the repo, make a feature branch just for your changes
* On the branch, only commit changes for the feature you're adding. Each pull request should concentrate on a single change - don't mix multiple features.
* Your feature should be covered by tests. Run the tests with npm test. This is very important - without tests, your feature may be broken by subsequent changes and I may never know. Plus it's always nice to know that your changes work :-)
* Don't bump the npm version - yours may not be the only feature that makes it into a version, and you don't know when your pull request may get merged (the version may have changed by then).
log4js-node-6.1.0/docs/contributors.md 0000664 0000000 0000000 00000001226 13565055024 0017660 0 ustar 00root root 0000000 0000000 # Contributors
Many people have helped make log4js what it is today. Here's a list of everyone who has contributed to the code. There are lots of people who've helped by submitting bug reports or pull requests that I haven't merged, but I have used their ideas to implement a different way. Thanks to you all. This library also owes a huge amount to the [original log4js project](https://github.com/stritti/log4js). If you'd like to help out, take a look at the [contributor guidelines](contrib-guidelines.md).
log4js-node-6.1.0/docs/dateFile.md 0000664 0000000 0000000 00000010743 13565055024 0016644 0 ustar 00root root 0000000 0000000 # Date Rolling File Appender
This is a file appender that rolls log files based on a configurable time, rather than the file size. When using the date file appender, you should also call `log4js.shutdown` when your application terminates, to ensure that any remaining asynchronous writes have finished. Although the date file appender uses the [streamroller](https://github.com/nomiddlename/streamroller) library, this is included as a dependency of log4js so you do not need to include it yourself.
## Configuration
* `type` - `"dateFile"`
* `filename` - `string` - the path of the file where you want your logs written.
* `pattern` - `string` (optional, defaults to `.yyyy-MM-dd`) - the pattern to use to determine when to roll the logs.
* `layout` - (optional, defaults to basic layout) - see [layouts](layouts.md)
Any other configuration parameters will be passed to the underlying [streamroller](https://github.com/nomiddlename/streamroller) implementation (see also node.js core file streams):
* `encoding` - `string` (default "utf-8")
* `mode`- `integer` (default 0o644 - [node.js file modes](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_file_modes))
* `flags` - `string` (default 'a')
* `compress` - `boolean` (default false) - compress the backup files during rolling (backup files will have `.gz` extension)
* `alwaysIncludePattern` - `boolean` (default false) - include the pattern in the name of the current log file as well as the backups.
* `daysToKeep` - `integer` (default 0) - if this value is greater than zero, then files older than that many days will be deleted during log rolling.
* `keepFileExt` - `boolean` (default false) - preserve the file extension when rotating log files (`file.log` becomes `file.2017-05-30.log` instead of `file.log.2017-05-30`).
The `pattern` is used to determine when the current log file should be renamed and a new log file created. For example, with a filename of 'cheese.log', and the default pattern of `.yyyy-MM-dd` - on startup this will result in a file called `cheese.log` being created and written to until the next write after midnight. When this happens, `cheese.log` will be renamed to `cheese.log.2017-04-30` and a new `cheese.log` file created. The appender uses the [date-format](https://github.com/nomiddlename/date-format) library to parse the `pattern`, and any of the valid formats can be used. Also note that there is no timer controlling the log rolling - changes in the pattern are determined on every log write. If no writes occur, then no log rolling will happen. If your application logs infrequently this could result in no log file being written for a particular time period.
Note that, from version 4.x of log4js onwards, the file appender can take any of the options for the [file appender](file.md) as well. So you could roll files by both date and size.
## Example (default daily log rolling)
```javascript
log4js.configure({
appenders: {
everything: { type: 'dateFile', filename: 'all-the-logs.log' }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug' }
}
});
```
This example will result in files being rolled every day. The initial file will be `all-the-logs.log`, with the daily backups being `all-the-logs.log.2017-04-30`, etc.
## Example with hourly log rolling (and compressed backups)
```javascript
log4js.configure({
appenders: {
everything: { type: 'dateFile', filename: 'all-the-logs.log', pattern: '.yyyy-MM-dd-hh', compress: true }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug'}
}
});
```
This will result in one current log file (`all-the-logs.log`). Every hour this file will be compressed and renamed to `all-the-logs.log.2017-04-30-08.gz` (for example) and a new `all-the-logs.log` created.
## Memory usage
If your application logs a large volume of messages, and find memory usage increasing due to buffering log messages before being written to a file, then you can listen for "log4js:pause" events emitted by the file appenders. Your application should stop logging when it receives one of these events with a value of `true` and resume when it receives an event with a value of `false`.
```javascript
log4js.configure({
appenders: {
output: { type: 'dateFile', filename: 'out.log' }
},
categories: { default: { appenders: ['output'], level: 'debug'}}
});
let paused = false;
process.on("log4js:pause", (value) => paused = value);
const logger = log4js.getLogger();
while (!paused) {
logger.info("I'm logging, but I will stop once we start buffering");
}
```
log4js-node-6.1.0/docs/faq.md 0000664 0000000 0000000 00000006223 13565055024 0015674 0 ustar 00root root 0000000 0000000 # Frequently Asked Questions
## I want errors to go to a special file, but still want everything written to another file - how do I do that?
You'll need to use the [logLevelFilter](logLevelFilter.md). Here's an example configuration:
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' },
emergencies: { type: 'file', filename: 'oh-no-not-again.log' },
'just-errors': { type: 'logLevelFilter', appender: 'emergencies', level: 'error' }
},
categories: {
default: { appenders: ['just-errors', 'everything'], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('This goes to all-the-logs.log');
logger.info('As does this.');
logger.error('This goes to all-the-logs.log and oh-no-not-again.log');
```
## I want to reload the configuration when I change my config file - how do I do that?
Previous versions of log4js used to watch for changes in the configuration file and reload when it changed. It didn't always work well, sometimes leaving file handles or sockets open. This feature was removed in version 2.x. As a replacement, I'd suggest using a library like [watchr](https://www.npmjs.com/package/watchr) to notify you of file changes. Then you can call `log4js.shutdown` followed by `log4js.configure` again.
## What happened to `replaceConsole` - it doesn't work any more?
I removed `replaceConsole` - it caused a few weird errors, and I wasn't entirely comfortable with messing around with a core part of node. If you still want to do this, then code like this should do the trick:
```javascript
log4js.configure(...); // set up your categories and appenders
const logger = log4js.getLogger('console');
console.log = logger.info.bind(logger); // do the same for others - console.debug, etc.
```
## I'm using pm2/passenger/some other third thing and I'm not getting any logs!
Take a look at the [clustering](clustering.md) docs, they should help you out.
## NPM complains about nodemailer being deprecated, what should I do?
Nodemailer version 4.0.1 (the not-deprecated version) requires a node version >= 6, but log4js supports node versions >= 4. So until I stop supporting node versions less than 6 I can't update the dependency. It's only an optional dependency anyway, so you're free to install nodemailer@4.0.1 if you want - as far as I know it should work, the API looks the same to me. If you know that the smtp appender definitely doesn't work with nodemailer v4, then please create an issue with some details about the problem.
## I want line numbers in my logs!
You need to enable call stack for the category, and use pattern layout to output the values. e.g.
```javascript
const log4js = require('log4js');
log4js.configure({
appenders: {
out: {
type: 'stdout',
layout: {
type: 'pattern', pattern: '%d %p %c %f:%l %m%n'
}
}
},
categories: {
default: { appenders: ['out'], level: 'info', enableCallStack: true }
}
});
const logger = log4js.getLogger('thing');
logger.info('this should give me a line number now');
```
Would output something like this:
```bash
2019-05-22T08:41:07.312 INFO thing index.js:16 this should give me a line number now
```
log4js-node-6.1.0/docs/file.md 0000664 0000000 0000000 00000007103 13565055024 0016042 0 ustar 00root root 0000000 0000000 # File Appender
The file appender writes log events to a file. It supports an optional maximum file size, and will keep a configurable number of backups. When using the file appender, you should also call `log4js.shutdown` when your application terminates, to ensure that any remaining asynchronous writes have finished. Although the file appender uses the [streamroller](https://github.com/nomiddlename/streamroller) library, this is included as a dependency of log4js so you do not need to include it yourself.
## Configuration
* `type` - `"file"`
* `filename` - `string` - the path of the file where you want your logs written.
* `maxLogSize` - `integer` (optional) - the maximum size (in bytes) for the log file. If not specified, then no log rolling will happen.
* `backups` - `integer` (optional, default value = 5) - the number of old log files to keep during log rolling.
* `layout` - (optional, defaults to basic layout) - see [layouts](layouts.md)
Any other configuration parameters will be passed to the underlying [streamroller](https://github.com/nomiddlename/streamroller) implementation (see also node.js core file streams):
* `encoding` - `string` (default "utf-8")
* `mode`- `integer` (default 0o644 - [node.js file modes](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_file_modes))
* `flags` - `string` (default 'a')
* `compress` - `boolean` (default false) - compress the backup files during rolling (backup files will have `.gz` extension)
* `keepFileExt` - `boolean` (default false) - preserve the file extension when rotating log files (`file.log` becomes `file.1.log` instead of `file.log.1`)
Note that, from version 4.x of log4js onwards, the file appender can take any of the options for the [dateFile appender](dateFile.md) as well. So you could roll files by both date and size.
## Example
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('I will be logged in all-the-logs.log');
```
This example will result in a single log file (`all-the-logs.log`) containing the log messages.
## Example with log rolling (and compressed backups)
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log', maxLogSize: 10485760, backups: 3, compress: true }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug'}
}
});
```
This will result in one current log file (`all-the-logs.log`). When that reaches 10Mb in size, it will be renamed and compressed to `all-the-logs.log.1.gz` and a new file opened called `all-the-logs.log`. When `all-the-logs.log` reaches 10Mb again, then `all-the-logs.log.1.gz` will be renamed to `all-the-logs.log.2.gz`, and so on.
## Memory usage
If your application logs a large volume of messages, and find memory usage increasing due to buffering log messages before being written to a file, then you can listen for "log4js:pause" events emitted by the file appenders. Your application should stop logging when it receives one of these events with a value of `true` and resume when it receives an event with a value of `false`.
```javascript
log4js.configure({
appenders: {
output: { type: 'file', filename: 'out.log' }
},
categories: { default: { appenders: ['output'], level: 'debug'}}
});
let paused = false;
process.on("log4js:pause", (value) => paused = value);
const logger = log4js.getLogger();
while (!paused) {
logger.info("I'm logging, but I will stop once we start buffering");
}
```
log4js-node-6.1.0/docs/fileSync.md 0000664 0000000 0000000 00000004364 13565055024 0016705 0 ustar 00root root 0000000 0000000 # Synchronous File Appender
The sync file appender writes log events to a file, the only difference to the normal file appender is that all the writes are synchronous. This can make writing tests easier, or in situations where you need an absolute guarantee that a log message has been written to the file. Making synchronous I/O calls does mean you lose a lot of the benefits of using node.js though. It supports an optional maximum file size, and will keep a configurable number of backups. Note that the synchronous file appender, unlike the asynchronous version, does not support compressing the backup files.
## Configuration
* `type` - `"fileSync"`
* `filename` - `string` - the path of the file where you want your logs written.
* `maxLogSize` - `integer` (optional) - the maximum size (in bytes) for the log file. If not specified, then no log rolling will happen.
* `backups` - `integer` (optional, default value = 5) - the number of old log files to keep during log rolling.
* `layout` - (optional, defaults to basic layout) - see [layouts](layouts.md)
Any other configuration parameters will be passed to the underlying node.js core stream implementation:
* `encoding` - `string` (default "utf-8")
* `mode`- `integer` (default 0644)
* `flags` - `string` (default 'a')
## Example
```javascript
log4js.configure({
appenders: {
everything: { type: 'fileSync', filename: 'all-the-logs.log' }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('I will be logged in all-the-logs.log');
```
This example will result in a single log file (`all-the-logs.log`) containing the log messages.
## Example with log rolling
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log', maxLogSize: 10458760, backups: 3 }
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug'}
}
});
```
This will result in one current log file (`all-the-logs.log`). When that reaches 10Mb in size, it will be renamed and compressed to `all-the-logs.log.1.gz` and a new file opened called `all-the-logs.log`. When `all-the-logs.log` reaches 10Mb again, then `all-the-logs.log.1.gz` will be renamed to `all-the-logs.log.2.gz`, and so on.
log4js-node-6.1.0/docs/index.md 0000664 0000000 0000000 00000004635 13565055024 0016241 0 ustar 00root root 0000000 0000000 # log4js-node
This is a conversion of the [log4js](https://github.com/stritti/log4js)
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.
[Changes in version 3.x](v3-changes.md)
## Migrating from log4js < v2.x?
There have been a few changes between log4js 1.x and 2.x (and 0.x too). You should probably read this [migration guide](migration-guide.md) if things aren't working.
## Features
* coloured console logging to [stdout](stdout.md) or [stderr](stderr.md)
* [file appender](file.md), with configurable log rolling based on file size or [date](dateFile.md)
* [SMTP appender](https://github.com/log4js-node/smtp)
* [GELF appender](https://github.com/log4js-node/gelf)
* [Loggly appender](https://github.com/log4js-node/loggly)
* [Logstash UDP appender](https://github.com/log4js-node/logstashUDP)
* logFaces ([UDP](logFaces-UDP.md) and [HTTP](logFaces-HTTP.md)) appender
* [TCP appender](tcp.md) (useful when you've got multiple servers but want to centralise logging)
* a [logger for connect/express](connect-logger.md) servers
* configurable log message [layout/patterns](layouts.md)
* different log levels for different log categories (make some parts of your app log as DEBUG, others only ERRORS, etc.)
* built-in support for logging with node core's `cluster` module
## Installation
```bash
npm install log4js
```
## Usage
Minimalist version:
```javascript
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.level = 'debug'; // default level is OFF - which means no logs at all.
logger.debug("Some debug messages");
```
## Clustering
If you use node's cluster, or passenger, or pm2, then you should read this [clustering guide](clustering.md)
## Note for library makers
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).
## License
The original log4js was distributed under the Apache 2.0 License, and so is this. I've tried to
keep the original copyright and author credits in place, except in sections that I have rewritten
extensively.
log4js-node-6.1.0/docs/layouts.md 0000664 0000000 0000000 00000022247 13565055024 0016631 0 ustar 00root root 0000000 0000000 # Layouts
Layouts are functions used by appenders to format log events for output. They take a log event as an argument and return a string. Log4js comes with several appenders built-in, and provides ways to create your own if these are not suitable.
For most use cases you will not need to configure layouts - there are some appenders which do not need layouts defined (for example, [logFaces-UDP](logFaces-UDP.md)); all the appenders that use layouts will have a sensible default defined.
## Configuration
Most appender configuration will take a field called `layout`, which is an object - typically with a single field `type` which is the name of a layout defined below. Some layouts require extra configuration options, which should be included in the same object.
## Example
```javascript
log4js.configure({
appenders: { out: { type: 'stdout', layout: { type: 'basic' } } },
categories: { default: { appenders: ['out'], level: 'info' } }
});
```
This configuration replaces the [stdout](stdout.md) appender's default `coloured` layout with `basic` layout.
# Built-in Layouts
## Basic
* `type` - `basic`
Basic layout will output the timestamp, level, category, followed by the formatted log event data.
## Example
```javascript
log4js.configure({
appenders: { 'out': { type: 'stdout', layout: { type: 'basic' } } },
categories: { default: { appenders: ['out'], level: 'info' } }
});
const logger = log4js.getLogger('cheese');
logger.error('Cheese is too ripe!');
```
This will output:
```
[2017-03-30 07:57:00.113] [ERROR] cheese - Cheese is too ripe!
```
## Coloured
* `type` - `coloured` (or `colored`)
This layout is the same as `basic`, except that the timestamp, level and category will be coloured according to the log event's level (if your terminal/file supports it - if you see some weird characters in your output and no colour then you should probably switch to `basic`). The colours used are:
* `TRACE` - 'blue'
* `DEBUG` - 'cyan'
* `INFO` - 'green'
* `WARN` - 'yellow'
* `ERROR` - 'red'
* `FATAL` - 'magenta'
## Message Pass-Through
* `type` - `messagePassThrough`
This layout just formats the log event data, and does not output a timestamp, level or category. It is typically used in appenders that serialise the events using a specific format (e.g. [gelf](gelf.md)).
## Example
```javascript
log4js.configure({
appenders: { out: { type: 'stdout', layout: { type: 'messagePassThrough' } } },
categories: { default: { appenders: [ 'out' ], level: 'info' } }
});
const logger = log4js.getLogger('cheese');
const cheeseName = 'gouda';
logger.error('Cheese is too ripe! Cheese was: ', cheeseName);
```
This will output:
```
Cheese is too ripe! Cheese was: gouda
```
## Dummy
* `type` - `dummy`
This layout only outputs the first value in the log event's data. It was added for the [logstashUDP](logstashUDP.md) appender, and I'm not sure there's much use for it outside that.
## Example
```javascript
log4js.configure({
appenders: { out: { type: 'stdout', layout: { type: 'dummy' } } },
categories: { default: { appenders: [ 'out' ], level: 'info' } }
});
const logger = log4js.getLogger('cheese');
const cheeseName = 'gouda';
logger.error('Cheese is too ripe! Cheese was: ', cheeseName);
```
This will output:
```
Cheese is too ripe! Cheese was:
```
## Pattern
* `type` - `pattern`
* `pattern` - `string` - specifier for the output format, using placeholders as described below
* `tokens` - `object` (optional) - user-defined tokens to be used in the pattern
## Pattern format
The pattern string can contain any characters, but sequences beginning with `%` will be replaced with values taken from the log event, and other environmental values.
Format for specifiers is `%[padding].[truncation][field]{[format]}` - padding and truncation are optional, and format only applies to a few tokens (notably, date). Both padding and truncation values can be negative.
* Positive truncation - truncate the string starting from the beginning
* Negative truncation - truncate the string starting from the end of the string
* Positive padding - left pad the string to make it this length, if the string is longer than the padding value then nothing happens
* Negative padding - right pad the string to make it this length, if the string is longer than the padding value then nothing happens
To make fixed-width columns in your log output, set padding and truncation to the same size (they don't have to have the same sign though, you could have right truncated, left padded columns that are always 10 characters wide with a pattern like "%10.-10m").
e.g. %5.10p - left pad the log level by up to 5 characters, keep the whole string to a max length of 10.
So, for a log level of INFO the output would be " INFO", for DEBUG it would be "DEBUG" and for a (custom) log level of CATASTROPHIC it would be "CATASTROPH".
Fields can be any of:
* `%r` time in toLocaleTimeString format
* `%p` log level
* `%c` log category
* `%h` hostname
* `%m` log data
* `%d` date, formatted - default is `ISO8601`, format options are: `ISO8601`, `ISO8601_WITH_TZ_OFFSET`, `ABSOLUTE`, `DATE`, or any string compatible with the [date-format](https://www.npmjs.com/package/date-format) library. e.g. `%d{DATE}`, `%d{yyyy/MM/dd-hh.mm.ss}`
* `%%` % - for when you want a literal `%` in your output
* `%n` newline
* `%z` process id (from `process.pid`)
* `%f` full path of filename (requires `enableCallStack: true` on the category, see [configuration object](api.md))
* `%f{depth}` path's depth let you chose to have only filename (`%f{1}`) or a chosen number of directories
* `%l` line number (requires `enableCallStack: true` on the category, see [configuration object](api.md))
* `%o` column postion (requires `enableCallStack: true` on the category, see [configuration object](api.md))
* `%s` call stack (requires `enableCallStack: true` on the category, see [configuration object](api.md))
* `%x{}` add dynamic tokens to your log. Tokens are specified in the tokens parameter.
* `%X{}` add values from the Logger context. Tokens are keys into the context values.
* `%[` start a coloured block (colour will be taken from the log level, similar to `colouredLayout`)
* `%]` end a coloured block
## Tokens
User-defined tokens can be either a string or a function. Functions will be passed the log event, and should return a string. For example, you could define a custom token that outputs the log event's context value for 'user' like so:
```javascript
log4js.configure({
appenders: {
out: { type: 'stdout', layout: {
type: 'pattern',
pattern: '%d %p %c %x{user} %m%n',
tokens: {
user: function(logEvent) {
return AuthLibrary.currentUser();
}
}
}}
},
categories: { default: { appenders: ['out'], level: 'info' } }
});
const logger = log4js.getLogger();
logger.info('doing something.');
```
This would output:
```
2017-06-01 08:32:56.283 INFO default charlie doing something.
```
You can also use the Logger context to store tokens (sometimes called Nested Diagnostic Context, or Mapped Diagnostic Context) and use them in your layouts.
```javascript
log4js.configure({
appenders: {
out: { type: 'stdout', layout: {
type: 'pattern',
pattern: '%d %p %c %X{user} %m%n'
}}
},
categories: { default: { appenders: ['out'], level: 'info' } }
});
const logger = log4js.getLogger();
logger.addContext('user', 'charlie');
logger.info('doing something.');
```
This would output:
```
2017-06-01 08:32:56.283 INFO default charlie doing something.
```
Note that you can also add functions to the Logger Context, and they will be passed the logEvent as well.
# Adding your own layouts
You can add your own layouts by calling `log4js.addLayout(type, fn)` before calling `log4js.configure`. `type` is the label you want to use to refer to your layout in appender configuration. `fn` is a function that takes a single object argument, which will contain the configuration for the layout instance, and returns a layout function. A layout function takes a log event argument and returns a string (usually, although you could return anything as long as the appender knows what to do with it).
## Custom Layout Example
This example can also be found in examples/custom-layout.js.
```javascript
const log4js = require('log4js');
log4js.addLayout('json', function(config) {
return function(logEvent) { return JSON.stringify(logEvent) + config.separator; }
});
log4js.configure({
appenders: {
out: { type: 'stdout', layout: { type: 'json', separator: ',' } }
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
const logger = log4js.getLogger('json-test');
logger.info('this is just a test');
logger.error('of a custom appender');
logger.warn('that outputs json');
log4js.shutdown(() => {});
```
This example outputs the following:
```javascript
{"startTime":"2017-06-05T22:23:08.479Z","categoryName":"json-test","data":["this is just a test"],"level":{"level":20000,"levelStr":"INFO"},"context":{}},
{"startTime":"2017-06-05T22:23:08.483Z","categoryName":"json-test","data":["of a custom appender"],"level":{"level":40000,"levelStr":"ERROR"},"context":{}},
{"startTime":"2017-06-05T22:23:08.483Z","categoryName":"json-test","data":["that outputs json"],"level":{"level":30000,"levelStr":"WARN"},"context":{}},
```
log4js-node-6.1.0/docs/logLevelFilter.md 0000664 0000000 0000000 00000002506 13565055024 0020044 0 ustar 00root root 0000000 0000000 # Log Level Filter
The log level filter allows you to restrict the log events that an appender will record based on the level of those events. This is useful when you want most logs to go to a file, but errors to be sent as emails, for example. The filter works by wrapping around another appender and controlling which events get sent to it.
## Configuration
* `type` - `logLevelFilter`
* `appender` - `string` - the name of an appender, defined in the same configuration, that you want to filter
* `level` - `string` - the minimum level of event to allow through the filter
* `maxLevel` - `string` (optional, defaults to `FATAL`) - the maximum level of event to allow through the filter
If an event's level is greater than or equal to `level` and less than or equal to `maxLevel` then it will be sent to the appender.
## Example
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' },
emergencies: { type: 'file', filename: 'panic-now.log' },
just-errors: { type: 'logLevelFilter', appender: 'emergencies', level: 'error' }
},
categories: {
default: { appenders: ['just-errors', 'everything' ], level: 'debug' }
}
});
```
Log events of `debug`, `info`, `error`, and `fatal` will go to `all-the-logs.log`. Events of `error` and `fatal` will also go to `panic-now.log`.
log4js-node-6.1.0/docs/migration-guide.md 0000664 0000000 0000000 00000007716 13565055024 0020221 0 ustar 00root root 0000000 0000000 # Migrating from log4js versions older than 2.x
## Configuration
If you try to use your v1 configuration with v2 code, you'll most likely get an error that says something like 'must have property "appenders" of type object'. The format of the configuration object has changed (see the [api](api.md) docs for details). The main changes are a need for you to name your appenders, and you also have to define the default category. For example, if your v1 config looked like this:
```javascript
{ appenders: [
{ type: 'console' },
{
type: 'dateFile',
filename: 'logs/task',
pattern:"-dd.log",
alwaysIncludePattern: true,
category: 'task'
}
] }
```
Then your v2 config should be something like this:
```javascript
{
appenders: {
out: { type: 'console' },
task: {
type: 'dateFile',
filename: 'logs/task',
pattern: '-dd.log',
alwaysIncludePattern: true
}
},
categories: {
default: { appenders: [ 'out' ], level: 'info' },
task: { appenders: [ 'task' ], level: 'info' }
}
}}
```
The functions to define the configuration programmatically have been remove (`addAppender`, `loadAppender`, etc). All configuration should now be done through the single `configure` function, passing in a filename or object.
## Console replacement
V1 used to allow you to replace the node.js console functions with versions that would log to a log4js appender. This used to cause some weird errors, so I decided it was better to remove it from the log4js core functionality. If you still want to do this, you can replicate the behaviour with code similar to this:
```javascript
log4js.configure(...); // set up your categories and appenders
const logger = log4js.getLogger('console'); // any category will work
console.log = logger.info.bind(logger); // do the same for others - console.debug, etc.
```
## Config Reloading
Previous versions of log4js used to watch for changes in the configuration file and reload when it changed. It didn't always work well, sometimes leaving file handles or sockets open. This feature was removed in version 2.x. As a replacement, I'd suggest using a library like [watchr](https://www.npmjs.com/package/watchr) to notify you of file changes. Then you can call `log4js.shutdown` followed by `log4js.configure` again.
## Appenders
If you have written your own custom appenders, they will not work without modification in v2. See the guide to [writing appenders](writing-appenders.md) for details on how appenders work in 2.x. Note that if you want to write your appender to work with both 1.x and 2.x, then you can tell what version you're running in by examining the number of arguments passed to the `configure` function of your appender: 2 arguments means v1, 4 arguments means v2.
All the core appenders have been upgraded to work with v2, except for the clustered appender which has been removed. The core log4js code handles cluster mode transparently.
The `logFaces` appender was split into two versions to make testing easier and the code simpler; one has HTTP support, the other UDP.
## Exit listeners
Some appenders used to define their own `exit` listeners, and it was never clear whose responsibility it was to clean up resources. Now log4js does not define any `exit` listeners. Instead your application should register an `exit` listener, and call `log4js.shutdown` to be sure that all log messages get written before your application terminates.
## New Features
* MDC contexts - you can now add key-value pairs to a logger (for grouping all log messages from a particular user, for example). Support for these values exists in the [pattern layout](layouts.md), the [logFaces appenders](logFaces-UDP.md), and the [multi-file appender](multiFile.md).
* Automatic cluster support - log4js now handles clusters transparently
* Custom levels - you can define your own log levels in the configuration object, including the colours
* Improved performance - several changes have been made to improve performance, especially for the file appenders.
log4js-node-6.1.0/docs/multiFile.md 0000664 0000000 0000000 00000005006 13565055024 0017055 0 ustar 00root root 0000000 0000000 # MultiFile Appender
The multiFile appender can be used to dynamically write logs to multiple files, based on a property of the logging event. Use this as a way to write separate log files for each category when the number of categories is unknown, for instance. It creates [file](file.md) appenders under the hood, so all the options that apply to that appender (apart from filename) can be used with this one, allowing the log files to be rotated and capped at a certain size.
## Configuration
* `type` - `"multiFile"`
* `base` - `string` - the base part of the generated log filename
* `property` - `string` - the value to use to split files (see below).
* `extension` - `string` - the suffix for the generated log filename.
* `timeout` - `integer` - optional activity timeout in ms after which the file will be closed.
All other properties will be passed to the created [file](file.md) appenders. For the property value, `categoryName` is probably the most useful - although you could use `pid` or `level`. If the property is not found then the appender will look for the value in the context map. If that fails, then the logger will not output the logging event, without an error. This is to allow for dynamic properties which may not exist for all log messages.
## Example (split on category)
```javascript
log4js.configure({
appenders: {
multi: { type: 'multiFile', base: 'logs/', property: 'categoryName', extension: '.log' }
},
categories: {
default: { appenders: [ 'multi' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('I will be logged in logs/default.log');
const otherLogger = log4js.getLogger('cheese');
logger.info('Cheese is cheddar - this will be logged in logs/cheese.log');
```
This example will result in two log files (`logs/default.log` and `logs/cheese.log`) containing the log messages.
## Example with log rolling (and compressed backups)
```javascript
log4js.configure({
appenders: {
everything: {
type: 'multiFile', base: 'logs/', property: 'userID', extension: '.log',
maxLogSize: 10485760, backups: 3, compress: true
}
},
categories: {
default: { appenders: [ 'everything' ], level: 'debug'}
}
});
const userLogger = log4js.getLogger('user');
userLogger.addContext('userID', user.getID());
userLogger.info('this user just logged in');
```
This will result in one log file (`logs/u12345.log`), capped at 10Mb in size, with three backups kept when rolling the file. If more users were logged, each user would get their own files, and their own backups.
log4js-node-6.1.0/docs/multiprocess.md 0000664 0000000 0000000 00000004156 13565055024 0017661 0 ustar 00root root 0000000 0000000 # Multiprocess Appender
*You probably want to use the [tcp server](tcp-server.md) or [tcp appender](tcp.md) instead of this - they are more flexible*
*Note that if you're just using node core's `cluster` module then you don't need to use this appender - log4js will handle logging within the cluster transparently.*
The multiprocess appender sends log events to a master server over TCP sockets. It can be used as a simple way to centralise logging when you have multiple servers or processes. It uses the node.js core networking modules, and so does not require any extra dependencies. Remember to call `log4js.shutdown` when your application terminates, so that the sockets get closed cleanly.
## Configuration
* `type` - `multiprocess`
* `mode` - `master|worker` - controls whether the appender listens for log events sent over the network, or is responsible for serialising events and sending them to a server.
* `appender` - `string` (only needed if `mode` == `master`)- the name of the appender to send the log events to
* `loggerPort` - `integer` (optional, defaults to `5000`) - the port to listen on, or send to
* `loggerHost` - `string` (optional, defaults to `localhost`) - the host/IP address to listen on, or send to
## Example (master)
```javascript
log4js.configure({
appenders: {
file: { type: 'file', filename: 'all-the-logs.log' },
server: { type: 'multiprocess', mode: 'master', appender: 'file', loggerHost: '0.0.0.0' }
},
categories: {
default: { appenders: ['file'], level: 'info' }
}
});
```
This creates a log server listening on port 5000, on all IP addresses the host has assigned to it. Note that the appender is not included in the appenders listed for the categories. Also note that the multiprocess master appender will send every event it receives to the underlying appender, regardless of level settings.
## Example (worker)
```javascript
log4js.configure({
appenders: {
network: { type: 'multiprocess', mode: 'worker', loggerHost: 'log.server' }
},
categories: {
default: { appenders: ['network'], level: 'error' }
}
});
```
This will send all error messages to `log.server:5000`.
log4js-node-6.1.0/docs/noLogFilter.md 0000664 0000000 0000000 00000003756 13565055024 0017361 0 ustar 00root root 0000000 0000000 # Category Filter
The no log filter allows you to exclude the log events that an appender will record.
The log events will be excluded depending on the regular expressions provided in the configuration.
This can be useful when you debug your application and you want to exclude some noisily logs that are irrelevant to your investigation.
You can stop to log them through a regular expression.
## Configuration
* `type` - `"noLogFilter"`
* `exclude` - `string | Array` - the regular expression (or the regular expressions if you provide an array of values) will be used for evaluating the events to pass to the appender. The events, which will match the regular expression, will be excluded and so not logged.
* `appender` - `string` - the name of an appender, defined in the same configuration, that you want to filter.
## Example
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' },
filtered: {
type: 'noLogFilter',
exclude: 'not',
appender: 'everything' }
},
categories: {
default: { appenders: [ 'filtered' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('I will be logged in all-the-logs.log');
logger.debug('I will be not logged in all-the-logs.log');
```
Note that:
* an array of strings can be specified in the configuration
* a case insensitive match will be done
* empty strings will be not considered and so removed from the array of values
```javascript
log4js.configure({
appenders: {
everything: { type: 'file', filename: 'all-the-logs.log' },
filtered: {
type: 'noLogFilter',
exclude: ['NOT', '\\d', ''],
appender: 'everything' }
},
categories: {
default: { appenders: [ 'filtered' ], level: 'debug' }
}
});
const logger = log4js.getLogger();
logger.debug('I will be logged in all-the-logs.log');
logger.debug('I will be not logged in all-the-logs.log');
logger.debug('A 2nd message that will be excluded in all-the-logs.log');
``` log4js-node-6.1.0/docs/recording.md 0000664 0000000 0000000 00000002164 13565055024 0017101 0 ustar 00root root 0000000 0000000 # Recording Appender
This appender stores the log events in memory. It is mainly useful for testing (see the tests for the category filter, for instance).
## Configuration
* `type` - `recording`
There is no other configuration for this appender.
## Usage
The array that stores log events is shared across all recording appender instances, and is accessible from the recording module. `require('/appenders/recording')` returns a module with the following functions exported:
* `replay` - returns `Array` - get all the events recorded.
* `playback` - synonym for `replay`
* `reset` - clears the array of events recorded.
* `erase` - synonyms for `reset`
## Example
```javascript
const recording = require('log4js/lib/appenders/recording');
const log4js = require('log4js');
log4js.configure({
appenders: { vcr: { type: 'recording' } },
categories: { default: { appenders: ['vcr'], level: 'info' } }
});
const logger = log4js.getLogger();
logger.info("some log event");
const events = recording.replay(); // events is an array of LogEvent objects.
recording.erase(); // clear the appender's array.
```
log4js-node-6.1.0/docs/stderr.md 0000664 0000000 0000000 00000000575 13565055024 0016434 0 ustar 00root root 0000000 0000000 # Standard Error Appender
This appender writes all log events to the standard error stream.
# Configuration
* `type` - `stderr`
* `layout` - `object` (optional, defaults to colouredLayout) - see [layouts](layouts.md)
# Example
```javascript
log4js.configure({
appenders: { err: { type: 'stderr' } },
categories: { default: { appenders: ['err'], level: 'ERROR' } }
});
```
log4js-node-6.1.0/docs/stdout.md 0000664 0000000 0000000 00000000646 13565055024 0016452 0 ustar 00root root 0000000 0000000 # Standard Output Appender
This appender writes all log events to the standard output stream. It is the default appender for log4js.
# Configuration
* `type` - `stdout`
* `layout` - `object` (optional, defaults to colouredLayout) - see [layouts](layouts.md)
# Example
```javascript
log4js.configure({
appenders: { 'out': { type: 'stdout' } },
categories: { default: { appenders: ['out'], level: 'info' } }
});
```
log4js-node-6.1.0/docs/tcp-server.md 0000664 0000000 0000000 00000002637 13565055024 0017224 0 ustar 00root root 0000000 0000000 # TCP Server Appender
Strictly speaking, this is not an appender - but it is configured as one. The TCP server listens for log messages on a port, taking JSON-encoded log events and then forwarding them to the other appenders. It can be used as a simple way to centralise logging when you have multiple servers or processes. It uses the node.js core networking modules, and so does not require any extra dependencies. Remember to call `log4js.shutdown` when your application terminates, so that the sockets get closed cleanly. It is designed to work with the [tcp appender](tcp.md), but could work with anything that sends correctly formatted JSON log events.
## Configuration
* `type` - `tcp-server`
* `port` - `integer` (optional, defaults to `5000`) - the port to listen on
* `host` - `string` (optional, defaults to `localhost`) - the host/IP address to listen on
## Example (master)
```javascript
log4js.configure({
appenders: {
file: { type: 'file', filename: 'all-the-logs.log' },
server: { type: 'tcp-server', host: '0.0.0.0' }
},
categories: {
default: { appenders: ['file'], level: 'info' }
}
});
```
This creates a log server listening on port 5000, on all IP addresses the host has assigned to it. Note that the appender is not included in the appenders listed for the categories. All events received on the socket will be forwarded to the other appenders, as if they had originated on the same server.
log4js-node-6.1.0/docs/tcp.md 0000664 0000000 0000000 00000002004 13565055024 0015704 0 ustar 00root root 0000000 0000000 # TCP Appender
The TCP appender sends log events to a master server over TCP sockets. It can be used as a simple way to centralise logging when you have multiple servers or processes. It uses the node.js core networking modules, and so does not require any extra dependencies. Remember to call `log4js.shutdown` when your application terminates, so that the sockets get closed cleanly. It's designed to work with the [tcp-server](tcp-server.md), but it doesn't necessarily have to, just make sure whatever is listening at the other end is expecting JSON objects as strings.
## Configuration
* `type` - `tcp`
* `port` - `integer` (optional, defaults to `5000`) - the port to send to
* `host` - `string` (optional, defaults to `localhost`) - the host/IP address to send to
## Example
```javascript
log4js.configure({
appenders: {
network: { type: 'tcp', host: 'log.server' }
},
categories: {
default: { appenders: ['network'], level: 'error' }
}
});
```
This will send all error messages to `log.server:5000`.
log4js-node-6.1.0/docs/terms.md 0000664 0000000 0000000 00000004013 13565055024 0016252 0 ustar 00root root 0000000 0000000 ## Terminology
`Level` - a log level is the severity or priority of a log event (debug, info, etc). Whether an _appender_ will see the event or not is determined by the _category_'s level. If this is less than or equal to the event's level, it will be sent to the category's appender(s).
`Category` - a label for grouping log events. This can be based on module (e.g. 'auth', 'payment', 'http'), or anything you like. Log events with the same _category_ will go to the same _appenders_. Log4js supports a hierarchy for categories, using dots to separate layers - for example, log events in the category 'myapp.submodule' will use the level for 'myapp' if none is defined for 'myapp.submodule', and also any appenders defined for 'myapp'. (This behaviour can be disabled by setting inherit=false on the sub-category.) The category for log events is defined when you get a _Logger_ from log4js (`log4js.getLogger('somecategory')`).
`Appender` - appenders are responsible for output of log events. They may write events to files, send emails, store them in a database, or anything. Most appenders use _layouts_ to serialise the events to strings for output.
`Logger` - this is your code's main interface with log4js. A logger instance may have an optional _category_, defined when you create the instance. Loggers provide the `info`, `debug`, `error`, etc functions that create _LogEvents_ and pass them on to appenders.
`Layout` - a function for converting a _LogEvent_ into a string representation. Log4js comes with a few different implementations: basic, coloured, and a more configurable pattern based layout.
`LogEvent` - a log event has a timestamp, a level, and optional category, data, and context properties. When you call `logger.info('cheese value:', edam)` the _logger_ will create a log event with the timestamp of now, a _level_ of INFO, a _category_ that was chosen when the logger was created, and a data array with two values (the string 'cheese value:', and the object 'edam'), along with any context data that was added to the logger.
log4js-node-6.1.0/docs/v3-changes.md 0000664 0000000 0000000 00000002341 13565055024 0017060 0 ustar 00root root 0000000 0000000 # Changes in version 3.x of log4js
log4js no longer supports node versions less than 6.
The following appenders have been removed from the core, and moved to their own projects:
* [gelf](https://github.com/log4js-node/gelf)
* [hipchat](https://github.com/log4js-node/hipchat)
* [logFaces-HTTP](https://github.com/log4js-node/logFaces-HTTP)
* [logFaces-UDP](https://github.com/log4js-node/logFaces-UDP)
* [loggly](https://github.com/log4js-node/loggly)
* [logstashHTTP](https://github.com/log4js-node/logstashHTTP)
* [logstashUDP](https://github.com/log4js-node/logstashUDP)
* [mailgun](https://github.com/log4js-node/mailgun)
* [rabbitmq](https://github.com/log4js-node/rabbitmq)
* [redis](https://github.com/log4js-node/redis)
* [slack](https://github.com/log4js-node/slack)
* [smtp](https://github.com/log4js-node/smtp)
If you were using them, you'll need to `npm i @log4js-node/`.
Removing the optional appenders removed all the security vulnerabilities.
The TCP [client](tcp.md)/[server](tcp-server.md) was introduced to replace the multiprocess appender.
[Issues resolved in 3.0.0](https://github.com/log4js-node/log4js-node/milestone/31?closed=1)
[PR for the code changes](https://github.com/log4js-node/log4js-node/pull/754)
log4js-node-6.1.0/docs/webpack.md 0000664 0000000 0000000 00000000610 13565055024 0016533 0 ustar 00root root 0000000 0000000 # Working with webpack
Log4js uses dynamic require for loading appenders. Webpack doesn't know at build time which appender will be used at runtime so a small workaround is necessary.
```
const stdout = require('log4js/lib/appenders/stdout');
import * as Configuration from 'log4js/lib/configuration';
Configuration.prototype.loadAppenderModule = function(type) {
return stdout;
};
```
log4js-node-6.1.0/docs/writing-appenders.md 0000664 0000000 0000000 00000007520 13565055024 0020570 0 ustar 00root root 0000000 0000000 # Writing Appenders for Log4js
Log4js can load appenders from outside its core set. To add a custom appender, the easiest way is to make it a stand-alone module and publish to npm. You can also load appenders from your own application, but they must be defined in a module.
## Loading mechanism
When log4js parses your configuration, it loops through the defined appenders. For each one, it will `require` the appender initially using the `type` value prepended with './appenders' as the module identifier - this is to try loading from the core appenders first. If that fails (the module could not be found in the core appenders), then log4js will try to require the module using variations of the `type` value.
Log4js checks the following places (in this order) for appenders based on the type value:
1. The core appenders: `require('./appenders/' + type)`
2. node_modules: `require(type)`
3. relative to the main file of your application: `require(path.dirname(require.main.filename) + '/' + type)`
4. relative to the process' current working directory: `require(process.cwd() + '/' + type)`
If that fails, an error will be raised.
## Appender Modules
An appender module should export a single function called `configure`. The function should accept the following arguments:
* `config` - `object` - the appender's configuration object
* `layouts` - `module` - gives access to the [layouts](layouts.md) module, which most appenders will need
* `layout` - `function(type, config)` - this is the main function that appenders will use to find a layout
* `findAppender` - `function(name)` - if your appender is a wrapper around another appender (like the [logLevelFilter](logLevelFilter.md) for example), this function can be used to find another appender by name
* `levels` - `module` - gives access to the [levels](levels.md) module, which most appenders will need
`configure` should return a function which accepts a logEvent, which is the appender itself. One of the simplest examples is the [stdout](stdout.md) appender. Let's run through the code.
## Example
```javascript
// This is the function that generates an appender function
function stdoutAppender(layout, timezoneOffset) {
// This is the appender function itself
return (loggingEvent) => {
process.stdout.write(`${layout(loggingEvent, timezoneOffset)}\n`);
};
}
// stdout configure doesn't need to use findAppender, or levels
function configure(config, layouts) {
// the default layout for the appender
let layout = layouts.colouredLayout;
// check if there is another layout specified
if (config.layout) {
// load the layout
layout = layouts.layout(config.layout.type, config.layout);
}
//create a new appender instance
return stdoutAppender(layout, config.timezoneOffset);
}
//export the only function needed
exports.configure = configure;
```
# Shutdown functions
It's a good idea to implement a `shutdown` function on your appender instances. This function will get called by `log4js.shutdown` and signals that `log4js` has been asked to stop logging. Usually this is because of a fatal exception, or the application is being stopped. Your shutdown function should make sure that all asynchronous operations finish, and that any resources are cleaned up. The function must be named `shutdown`, take one callback argument, and be a property of the appender instance. Let's add a shutdown function to the `stdout` appender as an example.
## Example (shutdown)
```javascript
// This is the function that generates an appender function
function stdoutAppender(layout, timezoneOffset) {
// This is the appender function itself
const appender = (loggingEvent) => {
process.stdout.write(`${layout(loggingEvent, timezoneOffset)}\n`);
};
// add a shutdown function.
appender.shutdown = (done) => {
process.stdout.write('', done);
};
return appender;
}
// ... rest of the code as above
```
log4js-node-6.1.0/examples/ 0000775 0000000 0000000 00000000000 13565055024 0015466 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/examples/cluster.js 0000664 0000000 0000000 00000001230 13565055024 0017501 0 ustar 00root root 0000000 0000000 'use strict';
const cluster = require('cluster');
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: { type: 'stdout' }
},
categories: { default: { appenders: ['out'], level: 'debug' } }
});
let logger;
if (cluster.isMaster) {
logger = log4js.getLogger('master');
cluster.fork();
logger.info('master is done', process.pid, new Error('flaps'));
} else {
logger = log4js.getLogger('worker');
logger.info("I'm a worker, with pid ", process.pid, new Error('pants'));
logger.info("I'm a worker, with pid ", process.pid, new Error());
logger.info('cluster.worker ', cluster.worker);
cluster.worker.disconnect();
}
log4js-node-6.1.0/examples/custom-layout.js 0000664 0000000 0000000 00000001014 13565055024 0020645 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.addLayout('json', config => function (logEvent) {
return JSON.stringify(logEvent) + config.separator;
});
log4js.configure({
appenders: {
out: { type: 'stdout', layout: { type: 'json', separator: ',' } }
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
const logger = log4js.getLogger('json-test');
logger.info('this is just a test');
logger.error('of a custom appender');
logger.warn('that outputs json');
log4js.shutdown(() => {});
log4js-node-6.1.0/examples/date-file-rolling.js 0000664 0000000 0000000 00000000575 13565055024 0021331 0 ustar 00root root 0000000 0000000 'use strict';
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
file: {
type: 'dateFile', filename: 'thing.log', daysToKeep: 3, pattern: '.mm'
}
},
categories: {
default: { appenders: ['file'], level: 'debug' }
}
});
const logger = log4js.getLogger('thing');
setInterval(() => {
logger.info('just doing the thing');
}, 1000);
log4js-node-6.1.0/examples/example-connect-logger.js 0000664 0000000 0000000 00000002626 13565055024 0022371 0 ustar 00root root 0000000 0000000 // The connect/express logger was added to log4js by danbell. This allows connect/express servers to log using log4js.
// https://github.com/nomiddlename/log4js-node/wiki/Connect-Logger
// load modules
const log4js = require('log4js');
const express = require('express');
const app = express();
// config
log4js.configure({
appenders: {
console: { type: 'console' },
file: { type: 'file', filename: 'logs/log4jsconnect.log' }
},
categories: {
default: { appenders: ['console'], level: 'debug' },
log4jslog: { appenders: ['file'], level: 'debug' }
}
});
// define logger
const logger = log4js.getLogger('log4jslog');
// set at which time msg is logged print like: only on error & above
// logger.setLevel('ERROR');
// express app
app.use(express.favicon(''));
// app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO }));
// app.use(log4js.connectLogger(logger, { level: 'auto', format: ':method :url :status' }));
// ### AUTO LEVEL DETECTION
// http responses 3xx, level = WARN
// http responses 4xx & 5xx, level = ERROR
// else.level = INFO
app.use(log4js.connectLogger(logger, { level: 'auto' }));
// route
app.get('/', (req, res) => {
res.send('hello world');
});
// start app
app.listen(5000);
console.log('server runing at localhost:5000');
console.log('Simulation of normal response: goto localhost:5000');
console.log('Simulation of error response: goto localhost:5000/xxx');
log4js-node-6.1.0/examples/example-socket.js 0000664 0000000 0000000 00000002111 13565055024 0020740 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
let i = 0;
if (cluster.isMaster) {
log4js.configure({
appenders: {
console: { type: 'console' },
master: {
type: 'multiprocess',
mode: 'master',
appender: 'console'
}
},
categories: {
default: { appenders: ['console'], level: 'info' }
}
});
console.info('Master creating %d workers', numCPUs);
for (i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('death', (worker) => {
console.info('Worker %d died.', worker.pid);
});
} else {
log4js.configure({
appenders: {
worker: { type: 'multiprocess', mode: 'worker' }
},
categories: {
default: { appenders: ['worker'], level: 'info' }
}
});
const logger = log4js.getLogger('example-socket');
console.info('Worker %d started.', process.pid);
for (i = 0; i < 1000; i++) {
logger.info('Worker %d - logging something %d', process.pid, i);
}
log4js.shutdown(() => {
process.exit();
});
}
log4js-node-6.1.0/examples/example.js 0000664 0000000 0000000 00000003331 13565055024 0017457 0 ustar 00root root 0000000 0000000 'use strict';
const log4js = require('../lib/log4js');
// log the cheese logger messages to a file, and the console ones as well.
log4js.configure({
appenders: {
cheeseLogs: { type: 'file', filename: 'cheese.log' },
console: { type: 'console' }
},
categories: {
cheese: { appenders: ['cheeseLogs'], level: 'error' },
another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console', 'cheeseLogs'], level: 'trace' }
}
});
// a custom logger outside of the log4js/lib/appenders directory can be accessed like so
// log4js.configure({
// appenders: { outside: { type: 'what/you/would/put/in/require', otherArgs: 'blah' } }
// ...
// });
const logger = log4js.getLogger('cheese');
// only errors and above get logged.
const otherLogger = log4js.getLogger();
// this will get coloured output on console, and appear in cheese.log
otherLogger.error('AAArgh! Something went wrong', { some: 'otherObject', useful_for: 'debug purposes' });
otherLogger.log('This should appear as info output');
// these will not appear (logging level beneath error)
logger.trace('Entering cheese testing');
logger.debug('Got cheese.');
logger.info('Cheese is Gouda.');
logger.log('Something funny about cheese.');
logger.warn('Cheese is quite smelly.');
// these end up only in cheese.log
logger.error('Cheese %s is too ripe!', 'gouda');
logger.fatal('Cheese was breeding ground for listeria.');
// these don't end up in cheese.log, but will appear on the console
const anotherLogger = log4js.getLogger('another');
anotherLogger.debug('Just checking');
// will also go to console and cheese.log, since that's configured for all categories
const pantsLog = log4js.getLogger('pants');
pantsLog.debug('Something for pants');
log4js-node-6.1.0/examples/flush-on-exit.js 0000664 0000000 0000000 00000001264 13565055024 0020531 0 ustar 00root root 0000000 0000000 /**
* run this, then "ab -c 10 -n 100 localhost:4444/" to test (in
* another shell)
*/
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
cheese: { type: 'file', filename: 'cheese.log' }
},
categories: {
default: { appenders: ['cheese'], level: 'debug' }
}
});
const logger = log4js.getLogger('cheese');
const http = require('http');
http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
const rd = Math.random() * 50;
logger.info(`hello ${rd}`);
response.write('hello ');
if (Math.floor(rd) === 30) {
log4js.shutdown(() => { process.exit(1); });
}
response.end();
}).listen(4444);
log4js-node-6.1.0/examples/fromreadme.js 0000664 0000000 0000000 00000001113 13565055024 0020141 0 ustar 00root root 0000000 0000000 // remember to change the require to just 'log4js' if you've npm install'ed it
const log4js = require('../lib/log4js');
log4js.configure({
appenders: { cheese: { type: 'file', filename: 'cheese.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = log4js.getLogger('cheese');
logger.level = 'ERROR';
logger.trace('Entering cheese testing');
logger.debug('Got cheese.');
logger.info('Cheese is Gouda.');
logger.warn('Cheese is quite smelly.');
logger.error('Cheese is too ripe!');
logger.fatal('Cheese was breeding ground for listeria.');
log4js-node-6.1.0/examples/hipchat-appender.js 0000664 0000000 0000000 00000003404 13565055024 0021241 0 ustar 00root root 0000000 0000000 /**
* !!! The hipchat-appender requires `hipchat-notifier` from npm, e.g.
* - list as a dependency in your application's package.json ||
* - npm install hipchat-notifier
*/
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
hipchat: {
type: 'hipchat',
hipchat_token: process.env.HIPCHAT_TOKEN || '< User token with Notification Privileges >',
hipchat_room: process.env.HIPCHAT_ROOM || '< Room ID or Name >'
}
},
categories: {
default: { appenders: ['hipchat'], level: 'trace' }
}
});
const logger = log4js.getLogger('hipchat');
logger.warn('Test Warn message');
logger.info('Test Info message');
logger.debug('Test Debug Message');
logger.trace('Test Trace Message');
logger.fatal('Test Fatal Message');
logger.error('Test Error Message');
// alternative configuration demonstrating callback + custom layout
// /////////////////////////////////////////////////////////////////
// use a custom layout function (in this case, the provided basicLayout)
// format: [TIMESTAMP][LEVEL][category] - [message]
log4js.configure({
appenders: {
hipchat: {
type: 'hipchat',
hipchat_token: process.env.HIPCHAT_TOKEN || '< User token with Notification Privileges >',
hipchat_room: process.env.HIPCHAT_ROOM || '< Room ID or Name >',
hipchat_from: 'Mr. Semantics',
hipchat_notify: false,
hipchat_response_callback: function (err, response, body) {
if (err || response.statusCode > 300) {
throw new Error('hipchat-notifier failed');
}
console.log('mr semantics callback success');
},
layout: { type: 'basic' }
}
},
categories: { default: { appenders: ['hipchat'], level: 'trace' } }
});
logger.info('Test customLayout from Mr. Semantics');
log4js-node-6.1.0/examples/layouts.js 0000664 0000000 0000000 00000000474 13565055024 0017531 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: { type: 'stdout', layout: { type: 'messagePassThrough' } }
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
const logger = log4js.getLogger('thing');
logger.info('This should not have a timestamp');
log4js-node-6.1.0/examples/log-rolling-bug.js 0000664 0000000 0000000 00000001211 13565055024 0021017 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
handler: {
type: 'file',
filename: 'logs/handler.log',
maxLogSize: 100000,
backups: 5,
keepFileExt: true,
compress: true
}
},
categories: {
default: { appenders: ['handler'], level: 'debug' },
handler: { appenders: ['handler'], level: 'debug' },
}
});
const logsToTest = [
'handler'
];
const logStartDate = new Date();
const loggers = logsToTest.map(log => log4js.getLogger(log));
// write out a lot
setInterval(() => {
loggers.forEach(logger => logger.info(`TESTING LOGGER!!!!!!${logStartDate}`));
}, 10);
log4js-node-6.1.0/examples/log-rolling.js 0000664 0000000 0000000 00000000751 13565055024 0020254 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
console: {
type: 'console'
},
file: {
type: 'file',
filename: 'tmp-test.log',
maxLogSize: 1024,
backups: 3
}
},
categories: {
default: { appenders: ['console', 'file'], level: 'info' }
}
});
const log = log4js.getLogger('test');
function doTheLogging(x) {
log.info('Logging something %d', x);
}
let i = 0;
for (; i < 5000; i += 1) {
doTheLogging(i);
}
log4js-node-6.1.0/examples/log-to-files.js 0000664 0000000 0000000 00000001756 13565055024 0020336 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure(
{
appenders: {
file: {
type: 'file',
filename: 'important-things.log',
maxLogSize: 10 * 1024 * 1024, // = 10Mb
backups: 5, // keep five backup files
compress: true, // compress the backups
encoding: 'utf-8',
mode: 0o0640,
flags: 'w+'
},
dateFile: {
type: 'dateFile',
filename: 'more-important-things.log',
pattern: 'yyyy-MM-dd-hh',
compress: true
},
out: {
type: 'stdout'
}
},
categories: {
default: { appenders: ['file', 'dateFile', 'out'], level: 'trace' }
}
}
);
const logger = log4js.getLogger('things');
logger.debug('This little thing went to market');
logger.info('This little thing stayed at home');
logger.error('This little thing had roast beef');
logger.fatal('This little thing had none');
logger.trace('and this little thing went wee, wee, wee, all the way home.');
log4js-node-6.1.0/examples/logFaces-appender.js 0000664 0000000 0000000 00000001513 13565055024 0021343 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
/*
logFaces server configured with UDP receiver, using JSON format,
listening on port 55201 will receive the logs from the appender below.
*/
log4js.configure({
appenders: {
logFaces: {
type: '@log4js-node/logfaces-udp', // (mandatory) appender type
application: 'MY-NODEJS', // (optional) name of the application (domain)
remoteHost: 'localhost', // (optional) logFaces server host or IP address
port: 55201, // (optional) logFaces UDP receiver port (must use JSON format)
layout: { // (optional) the layout to use for messages
type: 'pattern',
pattern: '%m'
}
}
},
categories: { default: { appenders: ['logFaces'], level: 'info' } }
});
const logger = log4js.getLogger('myLogger');
logger.info('Testing message %s', 'arg1');
log4js-node-6.1.0/examples/loggly-appender.js 0000664 0000000 0000000 00000001261 13565055024 0021115 0 ustar 00root root 0000000 0000000 // Note that loggly appender needs node-loggly to work.
// If you haven't got node-loggly installed, you'll get cryptic
// "cannot find module" errors when using the loggly appender
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
console: {
type: 'console'
},
loggly: {
type: 'loggly',
token: '12345678901234567890',
subdomain: 'your-subdomain',
tags: ['test']
}
},
categories: {
default: { appenders: ['console'], level: 'info' },
loggly: { appenders: ['loggly'], level: 'info' }
}
});
const logger = log4js.getLogger('loggly');
logger.info('Test log message');
// logger.debug("Test log message");
log4js-node-6.1.0/examples/logstashHTTP.js 0000664 0000000 0000000 00000001112 13565055024 0020343 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
console: {
type: 'console'
},
logstash: {
url: 'http://172.17.0.5:9200/_bulk',
type: '@log4js-node/logstash-http',
logType: 'application',
logChannel: 'node',
application: 'logstash-log4js',
layout: {
type: 'pattern',
pattern: '%m'
}
}
},
categories: {
default: { appenders: ['console', 'logstash'], level: 'info' }
}
});
const logger = log4js.getLogger('myLogger');
logger.info('Test log message %s', 'arg1', 'arg2');
log4js-node-6.1.0/examples/logstashUDP.js 0000664 0000000 0000000 00000001500 13565055024 0020215 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
/*
Sample logstash config:
udp {
codec => json
port => 10001
queue_size => 2
workers => 2
type => myAppType
}
*/
log4js.configure({
appenders: {
console: {
type: 'console'
},
logstash: {
host: '127.0.0.1',
port: 10001,
type: 'logstashUDP',
logType: 'myAppType', // Optional, defaults to 'category'
fields: { // Optional, will be added to the 'fields' object in logstash
field1: 'value1',
field2: 'value2'
},
layout: {
type: 'pattern',
pattern: '%m'
}
}
},
categories: {
default: { appenders: ['console', 'logstash'], level: 'info' }
}
});
const logger = log4js.getLogger('myLogger');
logger.info('Test log message %s', 'arg1', 'arg2');
log4js-node-6.1.0/examples/memory-test.js 0000664 0000000 0000000 00000001551 13565055024 0020313 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure(
{
appenders: {
logs: {
type: 'file',
filename: 'memory-test.log'
},
console: {
type: 'stdout',
},
file: {
type: 'file',
filename: 'memory-usage.log',
layout: {
type: 'messagePassThrough'
}
}
},
categories: {
default: { appenders: ['console'], level: 'info' },
'memory-test': { appenders: ['logs'], level: 'info' },
'memory-usage': { appenders: ['console', 'file'], level: 'info' }
}
}
);
const logger = log4js.getLogger('memory-test');
const usage = log4js.getLogger('memory-usage');
for (let i = 0; i < 1000000; i += 1) {
if ((i % 5000) === 0) {
usage.info('%d %d', i, process.memoryUsage().rss);
}
logger.info('Doing something.');
}
log4js.shutdown(() => {});
log4js-node-6.1.0/examples/patternLayout-tokens.js 0000664 0000000 0000000 00000000700 13565055024 0022175 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: {
type: 'console',
layout: {
type: 'pattern',
pattern: '%[%r (%x{pid}) %p %c -%] %m%n',
tokens: {
pid: function () { return process.pid; }
}
}
}
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
const logger = log4js.getLogger('app');
logger.info('Test log message');
log4js-node-6.1.0/examples/pm2.js 0000664 0000000 0000000 00000001622 13565055024 0016523 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
// NOTE: for PM2 support to work you'll need to install the pm2-intercom module
// `pm2 install pm2-intercom`
log4js.configure({
appenders: {
out: { type: 'file', filename: 'pm2logs.log' }
},
categories: {
default: { appenders: ['out'], level: 'info' }
},
pm2: true,
pm2InstanceVar: 'INSTANCE_ID'
});
const logger = log4js.getLogger('app');
logger.info("I'm forever blowing bubbles ", process.env.INSTANCE_ID);
logger.info("I'm forever blowing bubbles ", process.env.INSTANCE_ID);
logger.info("I'm forever blowing bubbles ", process.env.INSTANCE_ID);
logger.info("I'm forever blowing bubbles ", process.env.INSTANCE_ID);
logger.info('last bubbles', process.env.INSTANCE_ID);
// give pm2 time to set everything up, before we tear it down
setTimeout(() => {
log4js.shutdown(() => {
console.error('All done, shutdown cb returned.');
});
}, 5000);
log4js-node-6.1.0/examples/pm2.json 0000664 0000000 0000000 00000000235 13565055024 0017057 0 ustar 00root root 0000000 0000000 { "apps": [
{ "name": "testing",
"script": "pm2.js",
"instances": 0,
"instance_var": "INSTANCE_ID",
"exec_mode": "cluster"
}
]
}
log4js-node-6.1.0/examples/rabbitmq-appender.js 0000775 0000000 0000000 00000002144 13565055024 0021425 0 ustar 00root root 0000000 0000000 // Note that rabbitmq appender needs install amqplib to work.
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: {
type: 'console'
},
file: {
type: 'dateFile',
filename: 'logs/log.txt',
pattern: 'yyyyMMdd',
alwaysIncludePattern: false
},
mq: {
type: '@log4js-node/rabbitmq',
host: '127.0.0.1',
port: 5672,
username: 'guest',
password: 'guest',
routing_key: 'logstash',
exchange: 'exchange_logs',
mq_type: 'direct',
durable: true,
layout: {
type: 'pattern',
pattern: '%d{yyyy-MM-dd hh:mm:ss:SSS}#%p#%m'
}
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
dateFile: { appenders: ['file'], level: 'info' },
rabbitmq: { appenders: ['mq'], level: 'info' }
}
});
const log = log4js.getLogger('console');
const logRabbitmq = log4js.getLogger('rabbitmq');
function doTheLogging(x) {
log.info('Logging something %d', x);
logRabbitmq.info('Logging something %d', x);
}
for (let i = 0; i < 500; i += 1) {
doTheLogging(i);
}
log4js-node-6.1.0/examples/redis-appender.js 0000664 0000000 0000000 00000001730 13565055024 0020727 0 ustar 00root root 0000000 0000000 // Note that redis appender needs install redis to work.
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: {
type: 'console'
},
file: {
type: 'dateFile',
filename: 'logs/log.txt',
pattern: 'yyyyMMdd',
alwaysIncludePattern: false
},
db: {
type: '@log4js-node/redis',
host: '127.0.0.1',
port: 6379,
pass: '',
channel: 'q_log',
layout: {
type: 'pattern',
pattern: '%d{yyyy-MM-dd hh:mm:ss:SSS}#%p#%m'
}
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
dateFile: { appenders: ['file'], level: 'info' },
redis: { appenders: ['db'], level: 'info' }
}
});
const log = log4js.getLogger('console');
const logRedis = log4js.getLogger('redis');
function doTheLogging(x) {
log.info('Logging something %d', x);
logRedis.info('Logging something %d', x);
}
for (let i = 0; i < 500; i += 1) {
doTheLogging(i);
}
log4js-node-6.1.0/examples/slack-appender.js 0000664 0000000 0000000 00000001221 13565055024 0020711 0 ustar 00root root 0000000 0000000 // Note that slack appender needs slack-node package to work.
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
slack: {
type: '@log4js-node/slack',
token: 'TOKEN',
channel_id: '#CHANNEL',
username: 'USERNAME',
format: 'text',
icon_url: 'ICON_URL'
}
},
categories: {
default: { appenders: ['slack'], level: 'info' }
}
});
const logger = log4js.getLogger('slack');
logger.warn('Test Warn message');
logger.info('Test Info message');
logger.debug('Test Debug Message');
logger.trace('Test Trace Message');
logger.fatal('Test Fatal Message');
logger.error('Test Error Message');
log4js-node-6.1.0/examples/smtp-appender.js 0000664 0000000 0000000 00000002034 13565055024 0020602 0 ustar 00root root 0000000 0000000 // Note that smtp appender needs nodemailer to work.
// If you haven't got nodemailer installed, you'll get cryptic
// "cannot find module" errors when using the smtp appender
const log4js = require('../lib/log4js');
log4js.configure({
appenders: {
out: {
type: 'console'
},
mail: {
type: '@log4js-node/smtp',
recipients: 'logfilerecipient@logging.com',
sendInterval: 5,
transport: 'SMTP',
SMTP: {
host: 'smtp.gmail.com',
secureConnection: true,
port: 465,
auth: {
user: 'someone@gmail',
pass: '********************'
},
debug: true
}
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
mailer: { appenders: ['mail'], level: 'info' }
}
});
const log = log4js.getLogger('test');
const logmailer = log4js.getLogger('mailer');
function doTheLogging(x) {
log.info('Logging something %d', x);
logmailer.info('Logging something %d', x);
}
for (let i = 0; i < 500; i += 1) {
doTheLogging(i);
}
log4js-node-6.1.0/examples/stacktrace.js 0000664 0000000 0000000 00000000721 13565055024 0020150 0 ustar 00root root 0000000 0000000 const log4js = require('../lib/log4js');
log4js.configure({
"appenders": {
"console-appender": {
"type": "console",
"layout": {
"type": "pattern",
"pattern": "%[[%p]%] - %10.-100f{2} | %7.12l:%7.12o - %[%m%]"
}
}
},
"categories": {
"default": {
"appenders": ["console-appender"],
"enableCallStack": true,
"level": "info"
}
}
})
log4js.getLogger().info('This should not cause problems');
log4js-node-6.1.0/lib/ 0000775 0000000 0000000 00000000000 13565055024 0014416 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/lib/LoggingEvent.js 0000664 0000000 0000000 00000004341 13565055024 0017346 0 ustar 00root root 0000000 0000000 const flatted = require('flatted');
const levels = require('./levels');
/**
* @name LoggingEvent
* @namespace Log4js
*/
class LoggingEvent {
/**
* Models a logging event.
* @constructor
* @param {String} categoryName name of category
* @param {Log4js.Level} level level of message
* @param {Array} data objects to log
* @author Seth Chisamore
*/
constructor(categoryName, level, data, context, location) {
this.startTime = new Date();
this.categoryName = categoryName;
this.data = data;
this.level = level;
this.context = Object.assign({}, context);
this.pid = process.pid;
if (location) {
this.functionName = location.functionName;
this.fileName = location.fileName;
this.lineNumber = location.lineNumber;
this.columnNumber = location.columnNumber;
this.callStack = location.callStack;
}
}
serialise() {
const logData = this.data.map((e) => {
// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
// The following allows us to serialize errors correctly.
if (e && e.message && e.stack) {
e = Object.assign({ message: e.message, stack: e.stack }, e);
}
return e;
});
this.data = logData;
return flatted.stringify(this);
}
static deserialise(serialised) {
let event;
try {
const rehydratedEvent = flatted.parse(serialised);
rehydratedEvent.data = rehydratedEvent.data.map((e) => {
if (e && e.message && e.stack) {
const fakeError = new Error(e);
Object.keys(e).forEach((key) => { fakeError[key] = e[key]; });
e = fakeError;
}
return e;
});
event = new LoggingEvent(
rehydratedEvent.categoryName,
levels.getLevel(rehydratedEvent.level.levelStr),
rehydratedEvent.data,
rehydratedEvent.context
);
event.startTime = new Date(rehydratedEvent.startTime);
event.pid = rehydratedEvent.pid;
event.cluster = rehydratedEvent.cluster;
} catch (e) {
event = new LoggingEvent(
'log4js',
levels.ERROR,
['Unable to parse log:', serialised, 'because: ', e]
);
}
return event;
}
}
module.exports = LoggingEvent;
log4js-node-6.1.0/lib/appenders/ 0000775 0000000 0000000 00000000000 13565055024 0016377 5 ustar 00root root 0000000 0000000 log4js-node-6.1.0/lib/appenders/adapters.js 0000664 0000000 0000000 00000002261 13565055024 0020541 0 ustar 00root root 0000000 0000000 function maxFileSizeUnitTransform(maxLogSize) {
if (typeof maxLogSize === 'number' && Number.isInteger(maxLogSize)) {
return maxLogSize;
}
const units = {
K: 1024,
M: 1024 * 1024,
G: 1024 * 1024 * 1024,
};
const validUnit = Object.keys(units);
const unit = maxLogSize.substr(maxLogSize.length - 1).toLocaleUpperCase();
const value = maxLogSize.substring(0, maxLogSize.length - 1).trim();
if (validUnit.indexOf(unit) < 0 || !Number.isInteger(Number(value))) {
throw Error(`maxLogSize: "${maxLogSize}" is invalid`);
} else {
return value * units[unit];
}
}
function adapter(configAdapter, config) {
const newConfig = Object.assign({}, config);
Object.keys(configAdapter).forEach((key) => {
if (newConfig[key]) {
newConfig[key] = configAdapter[key](config[key]);
}
});
return newConfig;
}
function fileAppenderAdapter(config) {
const configAdapter = {
maxLogSize: maxFileSizeUnitTransform
};
return adapter(configAdapter, config);
}
const adapters = {
file: fileAppenderAdapter,
fileSync: fileAppenderAdapter
};
module.exports.modifyConfig = config => (adapters[config.type] ? adapters[config.type](config) : config);
log4js-node-6.1.0/lib/appenders/categoryFilter.js 0000664 0000000 0000000 00000001126 13565055024 0021720 0 ustar 00root root 0000000 0000000 const debug = require('debug')('log4js:categoryFilter');
function categoryFilter(excludes, appender) {
if (typeof excludes === 'string') excludes = [excludes];
return (logEvent) => {
debug(`Checking ${logEvent.categoryName} against ${excludes}`);
if (excludes.indexOf(logEvent.categoryName) === -1) {
debug('Not excluded, sending to appender');
appender(logEvent);
}
};
}
function configure(config, layouts, findAppender) {
const appender = findAppender(config.appender);
return categoryFilter(config.exclude, appender);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/console.js 0000664 0000000 0000000 00000000756 13565055024 0020407 0 ustar 00root root 0000000 0000000 // eslint-disable-next-line no-console
const consoleLog = console.log.bind(console);
function consoleAppender(layout, timezoneOffset) {
return (loggingEvent) => {
consoleLog(layout(loggingEvent, timezoneOffset));
};
}
function configure(config, layouts) {
let layout = layouts.colouredLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
return consoleAppender(layout, config.timezoneOffset);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/dateFile.js 0000664 0000000 0000000 00000003150 13565055024 0020451 0 ustar 00root root 0000000 0000000 const streams = require('streamroller');
const os = require('os');
const eol = os.EOL;
/**
* File appender that rolls files according to a date pattern.
* @filename base filename.
* @pattern the format that will be added to the end of filename when rolling,
* also used to check when to roll files - defaults to '.yyyy-MM-dd'
* @layout layout function for log messages - defaults to basicLayout
* @timezoneOffset optional timezone offset in minutes - defaults to system local
*/
function appender(
filename,
pattern,
layout,
options,
timezoneOffset
) {
// the options for file appender use maxLogSize, but the docs say any file appender
// options should work for dateFile as well.
options.maxSize = options.maxLogSize;
const logFile = new streams.DateRollingFileStream(
filename,
pattern,
options
);
logFile.on("drain", () => {
process.emit("log4js:pause", false);
});
const app = function (logEvent) {
if (!logFile.write(layout(logEvent, timezoneOffset) + eol, "utf8")) {
process.emit("log4js:pause", true);
}
};
app.shutdown = function (complete) {
logFile.write('', 'utf-8', () => {
logFile.end(complete);
});
};
return app;
}
function configure(config, layouts) {
let layout = layouts.basicLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
if (!config.alwaysIncludePattern) {
config.alwaysIncludePattern = false;
}
return appender(
config.filename,
config.pattern,
layout,
config,
config.timezoneOffset
);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/file.js 0000664 0000000 0000000 00000005401 13565055024 0017654 0 ustar 00root root 0000000 0000000 const debug = require('debug')('log4js:file');
const path = require('path');
const streams = require('streamroller');
const os = require('os');
const eol = os.EOL;
function openTheStream(file, fileSize, numFiles, options) {
const stream = new streams.RollingFileStream(
file,
fileSize,
numFiles,
options
);
stream.on('error', (err) => {
console.error('log4js.fileAppender - Writing to file %s, error happened ', file, err); //eslint-disable-line
});
stream.on('drain', () => {
process.emit("log4js:pause", false);
});
return stream;
}
/**
* File Appender writing the logs to a text file. Supports rolling of logs by size.
*
* @param file file log messages will be written to
* @param layout a function that takes a logEvent and returns a string
* (defaults to basicLayout).
* @param logSize - the maximum size (in bytes) for a log file,
* if not provided then logs won't be rotated.
* @param numBackups - the number of log files to keep after logSize
* has been reached (default 5)
* @param options - options to be passed to the underlying stream
* @param timezoneOffset - optional timezone offset in minutes (default system local)
*/
function fileAppender(file, layout, logSize, numBackups, options, timezoneOffset) {
file = path.normalize(file);
numBackups = numBackups === undefined ? 5 : numBackups;
// there has to be at least one backup if logSize has been specified
numBackups = numBackups === 0 ? 1 : numBackups;
debug(
'Creating file appender (',
file, ', ',
logSize, ', ',
numBackups, ', ',
options, ', ',
timezoneOffset, ')'
);
let writer = openTheStream(file, logSize, numBackups, options);
const app = function (loggingEvent) {
if (!writer.write(layout(loggingEvent, timezoneOffset) + eol, "utf8")) {
process.emit('log4js:pause', true);
}
};
app.reopen = function () {
writer.end(() => { writer = openTheStream(file, logSize, numBackups, options); });
};
app.sighupHandler = function () {
debug('SIGHUP handler called.');
app.reopen();
};
app.shutdown = function (complete) {
process.removeListener('SIGHUP', app.sighupHandler);
writer.end('', 'utf-8', complete);
};
// On SIGHUP, close and reopen all files. This allows this appender to work with
// logrotate. Note that if you are using logrotate, you should not set
// `logSize`.
process.on('SIGHUP', app.sighupHandler);
return app;
}
function configure(config, layouts) {
let layout = layouts.basicLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
return fileAppender(
config.filename,
layout,
config.maxLogSize,
config.backups,
config,
config.timezoneOffset
);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/fileSync.js 0000775 0000000 0000000 00000012442 13565055024 0020517 0 ustar 00root root 0000000 0000000 const debug = require('debug')('log4js:fileSync');
const path = require('path');
const fs = require('fs');
const os = require('os');
const eol = os.EOL || '\n';
function touchFile(file, options) {
// if the file exists, nothing to do
if (fs.existsSync(file)) {
return;
}
// touch the file to apply flags (like w to truncate the file)
const id = fs.openSync(file, options.flags, options.mode);
fs.closeSync(id);
}
class RollingFileSync {
constructor(filename, size, backups, options) {
debug('In RollingFileStream');
function throwErrorIfArgumentsAreNotValid() {
if (!filename || !size || size <= 0) {
throw new Error('You must specify a filename and file size');
}
}
throwErrorIfArgumentsAreNotValid();
this.filename = filename;
this.size = size;
this.backups = backups || 1;
this.options = options;
this.currentSize = 0;
function currentFileSize(file) {
let fileSize = 0;
try {
fileSize = fs.statSync(file).size;
} catch (e) {
// file does not exist
touchFile(file, options);
}
return fileSize;
}
this.currentSize = currentFileSize(this.filename);
}
shouldRoll() {
debug('should roll with current size %d, and max size %d', this.currentSize, this.size);
return this.currentSize >= this.size;
}
roll(filename) {
const that = this;
const nameMatcher = new RegExp(`^${path.basename(filename)}`);
function justTheseFiles(item) {
return nameMatcher.test(item);
}
function index(filename_) {
return parseInt(filename_.substring((`${path.basename(filename)}.`).length), 10) || 0;
}
function byIndex(a, b) {
if (index(a) > index(b)) {
return 1;
}
if (index(a) < index(b)) {
return -1;
}
return 0;
}
function increaseFileIndex(fileToRename) {
const idx = index(fileToRename);
debug(`Index of ${fileToRename} is ${idx}`);
if (idx < that.backups) {
// on windows, you can get a EEXIST error if you rename a file to an existing file
// so, we'll try to delete the file we're renaming to first
try {
fs.unlinkSync(`${filename}.${idx + 1}`);
} catch (e) {
// ignore err: if we could not delete, it's most likely that it doesn't exist
}
debug(`Renaming ${fileToRename} -> ${filename}.${idx + 1}`);
fs.renameSync(path.join(path.dirname(filename), fileToRename), `${filename}.${idx + 1}`);
}
}
function renameTheFiles() {
// roll the backups (rename file.n to file.n+1, where n <= numBackups)
debug('Renaming the old files');
const files = fs.readdirSync(path.dirname(filename));
files.filter(justTheseFiles).sort(byIndex).reverse().forEach(increaseFileIndex);
}
debug('Rolling, rolling, rolling');
renameTheFiles();
}
/* eslint no-unused-vars:0 */
write(chunk, encoding) {
const that = this;
function writeTheChunk() {
debug('writing the chunk to the file');
that.currentSize += chunk.length;
fs.appendFileSync(that.filename, chunk);
}
debug('in write');
if (this.shouldRoll()) {
this.currentSize = 0;
this.roll(this.filename);
}
writeTheChunk();
}
}
/**
* File Appender writing the logs to a text file. Supports rolling of logs by size.
*
* @param file file log messages will be written to
* @param layout a function that takes a logevent and returns a string
* (defaults to basicLayout).
* @param logSize - the maximum size (in bytes) for a log file,
* if not provided then logs won't be rotated.
* @param numBackups - the number of log files to keep after logSize
* has been reached (default 5)
* @param timezoneOffset - optional timezone offset in minutes
* (default system local)
* @param options - passed as is to fs options
*/
function fileAppender(file, layout, logSize, numBackups, timezoneOffset, options) {
debug('fileSync appender created');
file = path.normalize(file);
numBackups = numBackups === undefined ? 5 : numBackups;
// there has to be at least one backup if logSize has been specified
numBackups = numBackups === 0 ? 1 : numBackups;
function openTheStream(filePath, fileSize, numFiles) {
let stream;
if (fileSize) {
stream = new RollingFileSync(
filePath,
fileSize,
numFiles,
options
);
} else {
stream = (((f) => {
// touch the file to apply flags (like w to truncate the file)
touchFile(f, options);
return {
write(data) {
fs.appendFileSync(f, data);
}
};
}))(filePath);
}
return stream;
}
const logFile = openTheStream(file, logSize, numBackups);
return (loggingEvent) => {
logFile.write(layout(loggingEvent, timezoneOffset) + eol);
};
}
function configure(config, layouts) {
let layout = layouts.basicLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
const options = {
flags: config.flags || 'a',
encoding: config.encoding || 'utf8',
mode: config.mode || 0o644
};
return fileAppender(
config.filename,
layout,
config.maxLogSize,
config.backups,
config.timezoneOffset,
options
);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/index.js 0000664 0000000 0000000 00000007150 13565055024 0020047 0 ustar 00root root 0000000 0000000 const path = require('path');
const debug = require('debug')('log4js:appenders');
const configuration = require('../configuration');
const clustering = require('../clustering');
const levels = require('../levels');
const layouts = require('../layouts');
const adapters = require('./adapters');
// pre-load the core appenders so that webpack can find them
const coreAppenders = new Map();
coreAppenders.set('console', require('./console'));
coreAppenders.set('stdout', require('./stdout'));
coreAppenders.set('stderr', require('./stderr'));
coreAppenders.set('logLevelFilter', require('./logLevelFilter'));
coreAppenders.set('categoryFilter', require('./categoryFilter'));
coreAppenders.set('noLogFilter', require('./noLogFilter'));
coreAppenders.set('file', require('./file'));
coreAppenders.set('dateFile', require('./dateFile'));
const appenders = new Map();
const tryLoading = (modulePath, config) => {
debug('Loading module from ', modulePath);
try {
return require(modulePath); //eslint-disable-line
} catch (e) {
// if the module was found, and we still got an error, then raise it
configuration.throwExceptionIf(
config,
e.code !== 'MODULE_NOT_FOUND',
`appender "${modulePath}" could not be loaded (error was: ${e})`
);
return undefined;
}
};
const loadAppenderModule = (type, config) => coreAppenders.get(type)
|| tryLoading(`./${type}`, config)
|| tryLoading(type, config)
|| (require.main && tryLoading(path.join(path.dirname(require.main.filename), type), config))
|| tryLoading(path.join(process.cwd(), type), config);
const createAppender = (name, config) => {
const appenderConfig = config.appenders[name];
const appenderModule = appenderConfig.type.configure
? appenderConfig.type : loadAppenderModule(appenderConfig.type, config);
configuration.throwExceptionIf(
config,
configuration.not(appenderModule),
`appender "${name}" is not valid (type "${appenderConfig.type}" could not be found)`
);
if (appenderModule.appender) {
debug(`DEPRECATION: Appender ${appenderConfig.type} exports an appender function.`);
}
if (appenderModule.shutdown) {
debug(`DEPRECATION: Appender ${appenderConfig.type} exports a shutdown function.`);
}
debug(`${name}: clustering.isMaster ? ${clustering.isMaster()}`);
debug(`${name}: appenderModule is ${require('util').inspect(appenderModule)}`); // eslint-disable-line
return clustering.onlyOnMaster(() => {
debug(`calling appenderModule.configure for ${name} / ${appenderConfig.type}`);
return appenderModule.configure(
adapters.modifyConfig(appenderConfig),
layouts,
appender => appenders.get(appender),
levels
);
}, () => {});
};
const setup = (config) => {
appenders.clear();
Object.keys(config.appenders).forEach((name) => {
debug(`Creating appender ${name}`);
appenders.set(name, createAppender(name, config));
});
};
setup({ appenders: { out: { type: 'stdout' } } });
configuration.addListener((config) => {
configuration.throwExceptionIf(
config,
configuration.not(configuration.anObject(config.appenders)),
'must have a property "appenders" of type object.'
);
const appenderNames = Object.keys(config.appenders);
configuration.throwExceptionIf(
config,
configuration.not(appenderNames.length),
'must define at least one appender.'
);
appenderNames.forEach((name) => {
configuration.throwExceptionIf(
config,
configuration.not(config.appenders[name].type),
`appender "${name}" is not valid (must be an object with property "type")`
);
});
});
configuration.addListener(setup);
module.exports = appenders;
log4js-node-6.1.0/lib/appenders/logLevelFilter.js 0000664 0000000 0000000 00000001156 13565055024 0021657 0 ustar 00root root 0000000 0000000 function logLevelFilter(minLevelString, maxLevelString, appender, levels) {
const minLevel = levels.getLevel(minLevelString);
const maxLevel = levels.getLevel(maxLevelString, levels.FATAL);
return (logEvent) => {
const eventLevel = logEvent.level;
if (eventLevel.isGreaterThanOrEqualTo(minLevel) && eventLevel.isLessThanOrEqualTo(maxLevel)) {
appender(logEvent);
}
};
}
function configure(config, layouts, findAppender, levels) {
const appender = findAppender(config.appender);
return logLevelFilter(config.level, config.maxLevel, appender, levels);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/multiFile.js 0000664 0000000 0000000 00000004544 13565055024 0020676 0 ustar 00root root 0000000 0000000
const debug = require('debug')('log4js:multiFile');
const path = require('path');
const fileAppender = require('./file');
const findFileKey = (property, event) => event[property] || event.context[property];
module.exports.configure = (config, layouts) => {
debug('Creating a multi-file appender');
const files = new Map();
const timers = new Map();
function checkForTimeout(fileKey) {
const timer = timers.get(fileKey);
const app = files.get(fileKey);
if (timer && app) {
if (Date.now() - timer.lastUsed > timer.timeout) {
debug('%s not used for > %d ms => close', fileKey, timer.timeout);
clearInterval(timer.interval);
timers.delete(fileKey);
files.delete(fileKey);
app.shutdown((err) => {
if (err) {
debug('ignore error on file shutdown: %s', err.message);
}
});
}
}
}
const appender = (logEvent) => {
const fileKey = findFileKey(config.property, logEvent);
debug('fileKey for property ', config.property, ' is ', fileKey);
if (fileKey) {
let file = files.get(fileKey);
debug('existing file appender is ', file);
if (!file) {
debug('creating new file appender');
config.filename = path.join(config.base, fileKey + config.extension);
file = fileAppender.configure(config, layouts);
files.set(fileKey, file);
if (config.timeout) {
debug('creating new timer');
timers.set(fileKey, {
timeout: config.timeout,
lastUsed: Date.now(),
interval: setInterval(checkForTimeout.bind(null, fileKey), config.timeout)
});
}
} else if (config.timeout) {
timers.get(fileKey).lastUsed = Date.now();
}
file(logEvent);
} else {
debug('No fileKey for logEvent, quietly ignoring this log event');
}
};
appender.shutdown = (cb) => {
let shutdownFunctions = files.size;
if (shutdownFunctions <= 0) {
cb();
}
let error;
timers.forEach((timer) => {
clearInterval(timer.interval);
});
files.forEach((app, fileKey) => {
debug('calling shutdown for ', fileKey);
app.shutdown((err) => {
error = error || err;
shutdownFunctions -= 1;
if (shutdownFunctions <= 0) {
cb(error);
}
});
});
};
return appender;
};
log4js-node-6.1.0/lib/appenders/multiprocess.js 0000664 0000000 0000000 00000012406 13565055024 0021471 0 ustar 00root root 0000000 0000000
const debug = require('debug')('log4js:multiprocess');
const net = require('net');
const LoggingEvent = require('../LoggingEvent');
const END_MSG = '__LOG4JS__';
/**
* Creates a server, listening on config.loggerPort, config.loggerHost.
* Output goes to config.actualAppender (config.appender is used to
* set up that appender).
*/
function logServer(config, actualAppender, levels) {
/**
* Takes a utf-8 string, returns an object with
* the correct log properties.
*/
function deserializeLoggingEvent(clientSocket, msg) {
debug('(master) deserialising log event');
const loggingEvent = LoggingEvent.deserialise(msg);
loggingEvent.remoteAddress = clientSocket.remoteAddress;
loggingEvent.remotePort = clientSocket.remotePort;
return loggingEvent;
}
/* eslint prefer-arrow-callback:0 */
const server = net.createServer(function connectionHandler(clientSocket) {
debug('(master) connection received');
clientSocket.setEncoding('utf8');
let logMessage = '';
function logTheMessage(msg) {
if (logMessage.length > 0) {
debug('(master) deserialising log event and sending to actual appender');
actualAppender(deserializeLoggingEvent(clientSocket, msg));
}
}
function chunkReceived(chunk) {
debug('(master) chunk of data received');
let event;
logMessage += chunk || '';
if (logMessage.indexOf(END_MSG) > -1) {
event = logMessage.substring(0, logMessage.indexOf(END_MSG));
logTheMessage(event);
logMessage = logMessage.substring(event.length + END_MSG.length) || '';
// check for more, maybe it was a big chunk
chunkReceived();
}
}
function handleError(error) {
const loggingEvent = {
startTime: new Date(),
categoryName: 'log4js',
level: levels.ERROR,
data: ['A worker log process hung up unexpectedly', error],
remoteAddress: clientSocket.remoteAddress,
remotePort: clientSocket.remotePort
};
actualAppender(loggingEvent);
}
clientSocket.on('data', chunkReceived);
clientSocket.on('end', chunkReceived);
clientSocket.on('error', handleError);
});
server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost', function (e) {
debug('(master) master server listening, error was ', e);
// allow the process to exit, if this is the only socket active
server.unref();
});
function app(event) {
debug('(master) log event sent directly to actual appender (local event)');
return actualAppender(event);
}
app.shutdown = function (cb) {
debug('(master) master shutdown called, closing server');
server.close(cb);
};
return app;
}
function workerAppender(config) {
let canWrite = false;
const buffer = [];
let socket;
let shutdownAttempts = 3;
function write(loggingEvent) {
debug('(worker) Writing log event to socket');
socket.write(loggingEvent.serialise(), 'utf8');
socket.write(END_MSG, 'utf8');
}
function emptyBuffer() {
let evt;
debug('(worker) emptying worker buffer');
/* eslint no-cond-assign:0 */
while ((evt = buffer.shift())) {
write(evt);
}
}
function createSocket() {
debug(
`(worker) worker appender creating socket to ${config.loggerHost || 'localhost'}:${config.loggerPort || 5000}`
);
socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
socket.on('connect', () => {
debug('(worker) worker socket connected');
emptyBuffer();
canWrite = true;
});
socket.on('timeout', socket.end.bind(socket));
// don't bother listening for 'error', 'close' gets called after that anyway
socket.on('close', createSocket);
}
createSocket();
function log(loggingEvent) {
if (canWrite) {
write(loggingEvent);
} else {
debug('(worker) worker buffering log event because it cannot write at the moment');
buffer.push(loggingEvent);
}
}
log.shutdown = function (cb) {
debug('(worker) worker shutdown called');
if (buffer.length && shutdownAttempts) {
debug('(worker) worker buffer has items, waiting 100ms to empty');
shutdownAttempts -= 1;
setTimeout(() => {
log.shutdown(cb);
}, 100);
} else {
socket.removeAllListeners('close');
socket.end(cb);
}
};
return log;
}
function createAppender(config, appender, levels) {
if (config.mode === 'master') {
debug('Creating master appender');
return logServer(config, appender, levels);
}
debug('Creating worker appender');
return workerAppender(config);
}
function configure(config, layouts, findAppender, levels) {
let appender;
debug(`configure with mode = ${config.mode}`);
if (config.mode === 'master') {
if (!config.appender) {
debug(`no appender found in config ${config}`);
throw new Error('multiprocess master must have an "appender" defined');
}
debug(`actual appender is ${config.appender}`);
appender = findAppender(config.appender);
if (!appender) {
debug(`actual appender "${config.appender}" not found`);
throw new Error(`multiprocess master appender "${config.appender}" not defined`);
}
}
return createAppender(config, appender, levels);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/noLogFilter.js 0000664 0000000 0000000 00000002466 13565055024 0021171 0 ustar 00root root 0000000 0000000
const debug = require('debug')('log4js:noLogFilter');
/**
* The function removes empty or null regexp from the array
* @param {Array} regexp
* @returns {Array} a filtered string array with not empty or null regexp
*/
function removeNullOrEmptyRegexp(regexp) {
const filtered = regexp.filter(el => ((el != null) && (el !== '')));
return filtered;
}
/**
* Returns a function that will exclude the events in case they match
* with the regular expressions provided
* @param {string | Array} filters contains the regexp that will be used for the evaluation
* @param {*} appender
* @returns {function}
*/
function noLogFilter(filters, appender) {
return (logEvent) => {
debug(`Checking data: ${logEvent.data} against filters: ${filters}`);
if (typeof filters === 'string') {
filters = [filters];
}
filters = removeNullOrEmptyRegexp(filters);
const regex = new RegExp(filters.join('|'), 'i');
if (filters.length === 0
|| logEvent.data.findIndex(value => regex.test(value)) < 0) {
debug('Not excluded, sending to appender');
appender(logEvent);
}
};
}
function configure(config, layouts, findAppender) {
const appender = findAppender(config.appender);
return noLogFilter(config.exclude, appender);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/recording.js 0000664 0000000 0000000 00000000762 13565055024 0020716 0 ustar 00root root 0000000 0000000
const debug = require('debug')('log4js:recording');
const recordedEvents = [];
function configure() {
return function (logEvent) {
debug(`received logEvent, number of events now ${recordedEvents.length + 1}`);
debug('log event was ', logEvent);
recordedEvents.push(logEvent);
};
}
function replay() {
return recordedEvents.slice();
}
function reset() {
recordedEvents.length = 0;
}
module.exports = {
configure,
replay,
playback: replay,
reset,
erase: reset
};
log4js-node-6.1.0/lib/appenders/stderr.js 0000664 0000000 0000000 00000000651 13565055024 0020242 0 ustar 00root root 0000000 0000000
function stderrAppender(layout, timezoneOffset) {
return (loggingEvent) => {
process.stderr.write(`${layout(loggingEvent, timezoneOffset)}\n`);
};
}
function configure(config, layouts) {
let layout = layouts.colouredLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
return stderrAppender(layout, config.timezoneOffset);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/appenders/stdout.js 0000664 0000000 0000000 00000000642 13565055024 0020261 0 ustar 00root root 0000000 0000000
function stdoutAppender(layout, timezoneOffset) {
return (loggingEvent) => {
process.stdout.write(`${layout(loggingEvent, timezoneOffset)}\n`);
};
}
function configure(config, layouts) {
let layout = layouts.colouredLayout;
if (config.layout) {
layout = layouts.layout(config.layout.type, config.layout);
}
return stdoutAppender(layout, config.timezoneOffset);
}
exports.configure = configure;
log4js-node-6.1.0/lib/appenders/tcp-server.js 0000664 0000000 0000000 00000002563 13565055024 0021035 0 ustar 00root root 0000000 0000000 const debug = require('debug')('log4js:tcp-server');
const net = require('net');
const clustering = require('../clustering');
const LoggingEvent = require('../LoggingEvent');
const DELIMITER = '__LOG4JS__';
exports.configure = (config) => {
debug('configure called with ', config);
// dummy shutdown if we're not master
let shutdown = (cb) => { cb(); };
clustering.onlyOnMaster(() => {
const server = net.createServer((socket) => {
let dataSoFar = '';
const send = (data) => {
if (data) {
dataSoFar += data;
if (dataSoFar.indexOf(DELIMITER)) {
const events = dataSoFar.split(DELIMITER);
if (!dataSoFar.endsWith(DELIMITER)) {
dataSoFar = events.pop();
} else {
dataSoFar = '';
}
events.filter(e => e.length).forEach((e) => {
clustering.send(LoggingEvent.deserialise(e));
});
}
}
};
socket.setEncoding('utf8');
socket.on('data', send);
socket.on('end', send);
});
server.listen(config.port || 5000, config.host || 'localhost', () => {
debug(`listening on ${config.host || 'localhost'}:${config.port || 5000}`);
server.unref();
});
shutdown = (cb) => {
debug('shutdown called.');
server.close(cb);
};
});
return {
shutdown
};
};
log4js-node-6.1.0/lib/appenders/tcp.js 0000664 0000000 0000000 00000003546 13565055024 0017533 0 ustar 00root root 0000000 0000000
const debug = require('debug')('log4js:tcp');
const net = require('net');
function appender(config) {
let canWrite = false;
const buffer = [];
let socket;
let shutdownAttempts = 3;
function write(loggingEvent) {
debug('Writing log event to socket');
canWrite = socket.write(`${loggingEvent.serialise()}__LOG4JS__`, 'utf8');
}
function emptyBuffer() {
let evt;
debug('emptying buffer');
/* eslint no-cond-assign:0 */
while ((evt = buffer.shift())) {
write(evt);
}
}
function createSocket() {
debug(`appender creating socket to ${config.host || 'localhost'}:${config.port || 5000}`);
socket = net.createConnection(config.port || 5000, config.host || 'localhost');
socket.on('connect', () => {
debug('socket connected');
emptyBuffer();
canWrite = true;
});
socket.on('drain', () => {
debug('drain event received, emptying buffer');
canWrite = true;
emptyBuffer();
});
socket.on('timeout', socket.end.bind(socket));
// don't bother listening for 'error', 'close' gets called after that anyway
socket.on('close', createSocket);
}
createSocket();
function log(loggingEvent) {
if (canWrite) {
write(loggingEvent);
} else {
debug('buffering log event because it cannot write at the moment');
buffer.push(loggingEvent);
}
}
log.shutdown = function (cb) {
debug('shutdown called');
if (buffer.length && shutdownAttempts) {
debug('buffer has items, waiting 100ms to empty');
shutdownAttempts -= 1;
setTimeout(() => {
log.shutdown(cb);
}, 100);
} else {
socket.removeAllListeners('close');
socket.end(cb);
}
};
return log;
}
function configure(config) {
debug(`configure with config = ${config}`);
return appender(config);
}
module.exports.configure = configure;
log4js-node-6.1.0/lib/categories.js 0000664 0000000 0000000 00000016066 13565055024 0017112 0 ustar 00root root 0000000 0000000 const debug = require('debug')('log4js:categories');
const configuration = require('./configuration');
const levels = require('./levels');
const appenders = require('./appenders');
const categories = new Map();
/**
* Add inherited config to this category. That includes extra appenders from parent,
* and level, if none is set on this category.
* This is recursive, so each parent also gets loaded with inherited appenders.
* Inheritance is blocked if a category has inherit=false
* @param {any} config
* @param {any} category the child category
* @param {string} categoryName dotted path to category
* @return {void}
*/
function inheritFromParent(config, category, categoryName) {
if (category.inherit === false) return;
const lastDotIndex = categoryName.lastIndexOf('.');
if (lastDotIndex < 0) return; // category is not a child
const parentCategoryName = categoryName.substring(0, lastDotIndex);
let parentCategory = config.categories[parentCategoryName];
if (!parentCategory) {
// parent is missing, so implicitly create it, so that it can inherit from its parents
parentCategory = { inherit: true, appenders: [] };
}
// make sure parent has had its inheritance taken care of before pulling its properties to this child
inheritFromParent(config, parentCategory, parentCategoryName);
// if the parent is not in the config (because we just created it above),
// and it inherited a valid configuration, add it to config.categories
if (!config.categories[parentCategoryName]
&& parentCategory.appenders
&& parentCategory.appenders.length
&& parentCategory.level) {
config.categories[parentCategoryName] = parentCategory;
}
category.appenders = category.appenders || [];
category.level = category.level || parentCategory.level;
// merge in appenders from parent (parent is already holding its inherited appenders)
parentCategory.appenders.forEach((ap) => {
if (!category.appenders.includes(ap)) {
category.appenders.push(ap);
}
});
category.parent = parentCategory;
}
/**
* Walk all categories in the config, and pull down any configuration from parent to child.
* This includes inherited appenders, and level, where level is not set.
* Inheritance is skipped where a category has inherit=false.
* @param {any} config
*/
function addCategoryInheritance(config) {
if (!config.categories) return;
const categoryNames = Object.keys(config.categories);
categoryNames.forEach((name) => {
const category = config.categories[name];
// add inherited appenders and level to this category
inheritFromParent(config, category, name);
});
}
configuration.addPreProcessingListener(config => addCategoryInheritance(config));
configuration.addListener((config) => {
configuration.throwExceptionIf(
config,
configuration.not(configuration.anObject(config.categories)),
'must have a property "categories" of type object.'
);
const categoryNames = Object.keys(config.categories);
configuration.throwExceptionIf(
config,
configuration.not(categoryNames.length),
'must define at least one category.'
);
categoryNames.forEach((name) => {
const category = config.categories[name];
configuration.throwExceptionIf(
config,
[
configuration.not(category.appenders),
configuration.not(category.level)
],
`category "${name}" is not valid (must be an object with properties "appenders" and "level")`
);
configuration.throwExceptionIf(
config,
configuration.not(Array.isArray(category.appenders)),
`category "${name}" is not valid (appenders must be an array of appender names)`
);
configuration.throwExceptionIf(
config,
configuration.not(category.appenders.length),
`category "${name}" is not valid (appenders must contain at least one appender name)`
);
if (Object.prototype.hasOwnProperty.call(category, 'enableCallStack')) {
configuration.throwExceptionIf(
config,
typeof category.enableCallStack !== 'boolean',
`category "${name}" is not valid (enableCallStack must be boolean type)`
);
}
category.appenders.forEach((appender) => {
configuration.throwExceptionIf(
config,
configuration.not(appenders.get(appender)),
`category "${name}" is not valid (appender "${appender}" is not defined)`
);
});
configuration.throwExceptionIf(
config,
configuration.not(levels.getLevel(category.level)),
`category "${name}" is not valid (level "${category.level}" not recognised;`
+ ` valid levels are ${levels.levels.join(', ')})`
);
});
configuration.throwExceptionIf(
config,
configuration.not(config.categories.default),
'must define a "default" category.'
);
});
const setup = (config) => {
categories.clear();
const categoryNames = Object.keys(config.categories);
categoryNames.forEach((name) => {
const category = config.categories[name];
const categoryAppenders = [];
category.appenders.forEach((appender) => {
categoryAppenders.push(appenders.get(appender));
debug(`Creating category ${name}`);
categories.set(
name,
{
appenders: categoryAppenders,
level: levels.getLevel(category.level),
enableCallStack: category.enableCallStack || false
}
);
});
});
};
setup({ categories: { default: { appenders: ['out'], level: 'OFF' } } });
configuration.addListener(setup);
const configForCategory = (category) => {
debug(`configForCategory: searching for config for ${category}`);
if (categories.has(category)) {
debug(`configForCategory: ${category} exists in config, returning it`);
return categories.get(category);
}
if (category.indexOf('.') > 0) {
debug(`configForCategory: ${category} has hierarchy, searching for parents`);
return configForCategory(category.substring(0, category.lastIndexOf('.')));
}
debug('configForCategory: returning config for default category');
return configForCategory('default');
};
const appendersForCategory = category => configForCategory(category).appenders;
const getLevelForCategory = category => configForCategory(category).level;
const setLevelForCategory = (category, level) => {
let categoryConfig = categories.get(category);
debug(`setLevelForCategory: found ${categoryConfig} for ${category}`);
if (!categoryConfig) {
const sourceCategoryConfig = configForCategory(category);
debug('setLevelForCategory: no config found for category, '
+ `found ${sourceCategoryConfig} for parents of ${category}`);
categoryConfig = { appenders: sourceCategoryConfig.appenders };
}
categoryConfig.level = level;
categories.set(category, categoryConfig);
};
const getEnableCallStackForCategory = category => configForCategory(category).enableCallStack === true;
const setEnableCallStackForCategory = (category, useCallStack) => {
configForCategory(category).enableCallStack = useCallStack;
};
module.exports = {
appendersForCategory,
getLevelForCategory,
setLevelForCategory,
getEnableCallStackForCategory,
setEnableCallStackForCategory,
};
log4js-node-6.1.0/lib/clustering.js 0000664 0000000 0000000 00000006033 13565055024 0017135 0 ustar 00root root 0000000 0000000 const debug = require("debug")("log4js:clustering");
const LoggingEvent = require("./LoggingEvent");
const configuration = require("./configuration");
let disabled = false;
let cluster = null;
try {
cluster = require("cluster"); //eslint-disable-line
} catch (e) {
debug("cluster module not present");
disabled = true;
}
const listeners = [];
let pm2 = false;
let pm2InstanceVar = "NODE_APP_INSTANCE";
const isPM2Master = () => pm2 && process.env[pm2InstanceVar] === "0";
const isMaster = () => disabled || cluster.isMaster || isPM2Master();
const sendToListeners = logEvent => {
listeners.forEach(l => l(logEvent));
};
// in a multi-process node environment, worker loggers will use
// process.send
const receiver = (worker, message) => {
// prior to node v6, the worker parameter was not passed (args were message, handle)
debug("cluster message received from worker ", worker, ": ", message);
if (worker.topic && worker.data) {
message = worker;
worker = undefined;
}
if (message && message.topic && message.topic === "log4js:message") {
debug("received message: ", message.data);
const logEvent = LoggingEvent.deserialise(message.data);
sendToListeners(logEvent);
}
};
if (!disabled) {
configuration.addListener(config => {
// clear out the listeners, because configure has been called.
listeners.length = 0;
({
pm2,
disableClustering: disabled,
pm2InstanceVar = "NODE_APP_INSTANCE"
} = config);
debug(`clustering disabled ? ${disabled}`);
debug(`cluster.isMaster ? ${cluster && cluster.isMaster}`);
debug(`pm2 enabled ? ${pm2}`);
debug(`pm2InstanceVar = ${pm2InstanceVar}`);
debug(`process.env[${pm2InstanceVar}] = ${process.env[pm2InstanceVar]}`);
// just in case configure is called after shutdown
if (pm2) {
process.removeListener("message", receiver);
}
if (cluster && cluster.removeListener) {
cluster.removeListener("message", receiver);
}
if (disabled || config.disableClustering) {
debug("Not listening for cluster messages, because clustering disabled.");
} else if (isPM2Master()) {
// PM2 cluster support
// PM2 runs everything as workers - install pm2-intercom for this to work.
// we only want one of the app instances to write logs
debug("listening for PM2 broadcast messages");
process.on("message", receiver);
} else if (cluster.isMaster) {
debug("listening for cluster messages");
cluster.on("message", receiver);
} else {
debug("not listening for messages, because we are not a master process");
}
});
}
module.exports = {
onlyOnMaster: (fn, notMaster) => (isMaster() ? fn() : notMaster),
isMaster,
send: msg => {
if (isMaster()) {
sendToListeners(msg);
} else {
if (!pm2) {
msg.cluster = {
workerId: cluster.worker.id,
worker: process.pid
};
}
process.send({ topic: "log4js:message", data: msg.serialise() });
}
},
onMessage: listener => {
listeners.push(listener);
}
};
log4js-node-6.1.0/lib/configuration.js 0000664 0000000 0000000 00000003247 13565055024 0017631 0 ustar 00root root 0000000 0000000
const util = require('util');
const debug = require('debug')('log4js:configuration');
const preProcessingListeners = [];
const listeners = [];
const not = thing => !thing;
const anObject = thing => thing && typeof thing === 'object' && !Array.isArray(thing);
const validIdentifier = thing => /^[A-Za-z][A-Za-z0-9_]*$/g.test(thing);
const anInteger = thing => thing && typeof thing === 'number' && Number.isInteger(thing);
const addListener = (fn) => {
listeners.push(fn);
debug(`Added listener, now ${listeners.length} listeners`);
};
const addPreProcessingListener = (fn) => {
preProcessingListeners.push(fn);
debug(`Added pre-processing listener, now ${preProcessingListeners.length} listeners`);
};
const throwExceptionIf = (config, checks, message) => {
const tests = Array.isArray(checks) ? checks : [checks];
tests.forEach((test) => {
if (test) {
throw new Error(`Problem with log4js configuration: (${util.inspect(config, { depth: 5 })})`
+ ` - ${message}`);
}
});
};
const configure = (candidate) => {
debug('New configuration to be validated: ', candidate);
throwExceptionIf(candidate, not(anObject(candidate)), 'must be an object.');
debug(`Calling pre-processing listeners (${preProcessingListeners.length})`);
preProcessingListeners.forEach(listener => listener(candidate));
debug('Configuration pre-processing finished.');
debug(`Calling configuration listeners (${listeners.length})`);
listeners.forEach(listener => listener(candidate));
debug('Configuration finished.');
};
module.exports = {
configure,
addListener,
addPreProcessingListener,
throwExceptionIf,
anObject,
anInteger,
validIdentifier,
not
};
log4js-node-6.1.0/lib/connect-logger.js 0000775 0000000 0000000 00000020664 13565055024 0017675 0 ustar 00root root 0000000 0000000 /* eslint-disable no-plusplus */
const levels = require("./levels");
const DEFAULT_FORMAT =
":remote-addr - -" +
' ":method :url HTTP/:http-version"' +
' :status :content-length ":referrer"' +
' ":user-agent"';
/**
* Return request url path,
* adding this function prevents the Cyclomatic Complexity,
* for the assemble_tokens function at low, to pass the tests.
*
* @param {IncomingMessage} req
* @return {String}
* @api private
*/
function getUrl(req) {
return req.originalUrl || req.url;
}
/**
* Adds custom {token, replacement} objects to defaults,
* overwriting the defaults if any tokens clash
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @param {Array} customTokens
* [{ token: string-or-regexp, replacement: string-or-replace-function }]
* @return {Array}
*/
function assembleTokens(req, res, customTokens) {
const arrayUniqueTokens = array => {
const a = array.concat();
for (let i = 0; i < a.length; ++i) {
for (let j = i + 1; j < a.length; ++j) {
// not === because token can be regexp object
/* eslint eqeqeq:0 */
if (a[i].token == a[j].token) {
a.splice(j--, 1);
}
}
}
return a;
};
const defaultTokens = [];
defaultTokens.push({ token: ":url", replacement: getUrl(req) });
defaultTokens.push({ token: ":protocol", replacement: req.protocol });
defaultTokens.push({ token: ":hostname", replacement: req.hostname });
defaultTokens.push({ token: ":method", replacement: req.method });
defaultTokens.push({
token: ":status",
replacement: res.__statusCode || res.statusCode
});
defaultTokens.push({
token: ":response-time",
replacement: res.responseTime
});
defaultTokens.push({ token: ":date", replacement: new Date().toUTCString() });
defaultTokens.push({
token: ":referrer",
replacement: req.headers.referer || req.headers.referrer || ""
});
defaultTokens.push({
token: ":http-version",
replacement: `${req.httpVersionMajor}.${req.httpVersionMinor}`
});
defaultTokens.push({
token: ":remote-addr",
replacement:
req.headers["x-forwarded-for"] ||
req.ip ||
req._remoteAddress ||
(req.socket &&
(req.socket.remoteAddress ||
(req.socket.socket && req.socket.socket.remoteAddress)))
});
defaultTokens.push({
token: ":user-agent",
replacement: req.headers["user-agent"]
});
defaultTokens.push({
token: ":content-length",
replacement:
res.getHeader("content-length") ||
(res.__headers && res.__headers["Content-Length"]) ||
"-"
});
defaultTokens.push({
token: /:req\[([^\]]+)]/g,
replacement(_, field) {
return req.headers[field.toLowerCase()];
}
});
defaultTokens.push({
token: /:res\[([^\]]+)]/g,
replacement(_, field) {
return (
res.getHeader(field.toLowerCase()) ||
(res.__headers && res.__headers[field])
);
}
});
return arrayUniqueTokens(customTokens.concat(defaultTokens));
}
/**
* Return formatted log line.
*
* @param {String} str
* @param {Array} tokens
* @return {String}
* @api private
*/
function format(str, tokens) {
for (let i = 0; i < tokens.length; i++) {
str = str.replace(tokens[i].token, tokens[i].replacement);
}
return str;
}
/**
* Return RegExp Object about nolog
*
* @param {String|Array} nolog
* @return {RegExp}
* @api private
*
* syntax
* 1. String
* 1.1 "\\.gif"
* NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
* LOGGING http://example.com/hoge.agif
* 1.2 in "\\.gif|\\.jpg$"
* NOT LOGGING http://example.com/hoge.gif and
* http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
* LOGGING http://example.com/hoge.agif,
* http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
* 1.3 in "\\.(gif|jpe?g|png)$"
* NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
* LOGGING http://example.com/hoge.gif?uid=2 and http://example.com/hoge.jpg?pid=3
* 2. RegExp
* 2.1 in /\.(gif|jpe?g|png)$/
* SAME AS 1.3
* 3. Array
* 3.1 ["\\.jpg$", "\\.png", "\\.gif"]
* SAME AS "\\.jpg|\\.png|\\.gif"
*/
function createNoLogCondition(nolog) {
let regexp = null;
if (nolog instanceof RegExp) {
regexp = nolog;
}
if (typeof nolog === "string") {
regexp = new RegExp(nolog);
}
if (Array.isArray(nolog)) {
// convert to strings
const regexpsAsStrings = nolog.map(reg => (reg.source ? reg.source : reg));
regexp = new RegExp(regexpsAsStrings.join("|"));
}
return regexp;
}
/**
* Allows users to define rules around status codes to assign them to a specific
* logging level.
* There are two types of rules:
* - RANGE: matches a code within a certain range
* E.g. { 'from': 200, 'to': 299, 'level': 'info' }
* - CONTAINS: matches a code to a set of expected codes
* E.g. { 'codes': [200, 203], 'level': 'debug' }
* Note*: Rules are respected only in order of prescendence.
*
* @param {Number} statusCode
* @param {Level} currentLevel
* @param {Object} ruleSet
* @return {Level}
* @api private
*/
function matchRules(statusCode, currentLevel, ruleSet) {
let level = currentLevel;
if (ruleSet) {
const matchedRule = ruleSet.find(rule => {
let ruleMatched = false;
if (rule.from && rule.to) {
ruleMatched = statusCode >= rule.from && statusCode <= rule.to;
} else {
ruleMatched = rule.codes.indexOf(statusCode) !== -1;
}
return ruleMatched;
});
if (matchedRule) {
level = levels.getLevel(matchedRule.level, level);
}
}
return level;
}
/**
* Log requests with the given `options` or a `format` string.
*
* Options:
*
* - `format` Format string, see below for tokens
* - `level` A log4js levels instance. Supports also 'auto'
* - `nolog` A string or RegExp to exclude target logs
* - `statusRules` A array of rules for setting specific logging levels base on status codes
* - `context` Whether to add a response of express to the context
*
* Tokens:
*
* - `:req[header]` ex: `:req[Accept]`
* - `:res[header]` ex: `:res[Content-Length]`
* - `:http-version`
* - `:response-time`
* - `:remote-addr`
* - `:date`
* - `:method`
* - `:url`
* - `:referrer`
* - `:user-agent`
* - `:status`
*
* @return {Function}
* @param logger4js
* @param options
* @api public
*/
module.exports = function getLogger(logger4js, options) {
/* eslint no-underscore-dangle:0 */
if (typeof options === "string" || typeof options === "function") {
options = { format: options };
} else {
options = options || {};
}
const thisLogger = logger4js;
let level = levels.getLevel(options.level, levels.INFO);
const fmt = options.format || DEFAULT_FORMAT;
const nolog = createNoLogCondition(options.nolog);
return (req, res, next) => {
// mount safety
if (req._logging) return next();
// nologs
if (nolog && nolog.test(req.originalUrl)) return next();
if (thisLogger.isLevelEnabled(level) || options.level === "auto") {
const start = new Date();
const { writeHead } = res;
// flag as logging
req._logging = true;
// proxy for statusCode.
res.writeHead = (code, headers) => {
res.writeHead = writeHead;
res.writeHead(code, headers);
res.__statusCode = code;
res.__headers = headers || {};
};
// hook on end request to emit the log entry of the HTTP request.
res.on("finish", () => {
res.responseTime = new Date() - start;
// status code response level handling
if (res.statusCode && options.level === "auto") {
level = levels.INFO;
if (res.statusCode >= 300) level = levels.WARN;
if (res.statusCode >= 400) level = levels.ERROR;
}
level = matchRules(res.statusCode, level, options.statusRules);
const combinedTokens = assembleTokens(req, res, options.tokens || []);
if (options.context) thisLogger.addContext("res", res);
if (typeof fmt === "function") {
const line = fmt(req, res, str => format(str, combinedTokens));
if (line) thisLogger.log(level, line);
} else {
thisLogger.log(level, format(fmt, combinedTokens));
}
if (options.context) thisLogger.removeContext("res");
});
}
// ensure next gets always called
return next();
};
};
log4js-node-6.1.0/lib/layouts.js 0000664 0000000 0000000 00000023370 13565055024 0016461 0 ustar 00root root 0000000 0000000 const dateFormat = require('date-format');
const os = require('os');
const util = require('util');
const path = require('path');
const styles = {
// styles
bold: [1, 22],
italic: [3, 23],
underline: [4, 24],
inverse: [7, 27],
// grayscale
white: [37, 39],
grey: [90, 39],
black: [90, 39],
// colors
blue: [34, 39],
cyan: [36, 39],
green: [32, 39],
magenta: [35, 39],
red: [91, 39],
yellow: [33, 39]
};
function colorizeStart(style) {
return style ? `\x1B[${styles[style][0]}m` : '';
}
function colorizeEnd(style) {
return style ? `\x1B[${styles[style][1]}m` : '';
}
/**
* Taken from masylum's fork (https://github.com/masylum/log4js-node)
*/
function colorize(str, style) {
return colorizeStart(style) + str + colorizeEnd(style);
}
function timestampLevelAndCategory(loggingEvent, colour) {
return colorize(
util.format(
'[%s] [%s] %s - ',
dateFormat.asString(loggingEvent.startTime),
loggingEvent.level.toString(),
loggingEvent.categoryName
),
colour
);
}
/**
* BasicLayout is a simple layout for storing the logs. The logs are stored
* in following format:
*