niveau
Node.js package to switch log level per request in Cloud Foundry
Goals
- Change the log level without restart - no downtime
- Change the log level per request. Setting the log level to debug on an app with high load could result in log flood and even loss of log messages.
- All application instances use the same log level.
- Set the log level from server-side as it is often hard to change client requests. This is also less susceptible to DoS attacks.
- Temporary log level change
- Time based
- Request count based
- Integrate with different logging libraries. Logging lib agnostic.
Requirements
- Node.js 6 (or later)
- Cloud Foundry
- Redis
Design
We need some persistence of the log level, so new instances can load it.
To achieve this, we use Redis as it provides both storage and change notification via keyspace notifications.
This package provides a CLI interface to change the log configuration.
There are several options to invoke it:
Deployment options:
- As part of an existing Node.js app
- As a separate app
- Can be used with applications that do not run on Node.js
- Does not need to run. Executing CF task will start a temporary instance automatically
- One more app to manage
In any case the application should be bound to a Redis instance.
Usage
In the application
Install the package.
npm install --save niveau
With npm 5 you don't need the --save
option.
Configure niveau and add it as a middleware:
const express = require('express');
const niveau = require('niveau');
let nv = niveau();
nv.on('error', err => {
console.error(err);
});
nv.on('config', config => {
});
nv.on('request', (req, config) => {
});
let app = express();
app.use(nv);
app.use((req, res, next) => {
});
See example applications in examples folder.
niveau([options])
options
Redis connection options + additional properties:
redisKey
name of the Redis key that stores the configuration, default is log-config
Creates niveau middleware. It matches incoming requests against the criteria in the log configuration.
For matching requests it sets logLevel
property on the request object to the log level from the configuration.
If options
is not provided, use bound Redis service.
If no Redis service is bound, use local Redis on default port.
The middleware also listens for log configuration changes and emits some events.
Event 'error'
Event arguments:
Emitted in case of error, e.g. Redis connection failed.
Event 'config'
Event arguments:
Emitted when log configuration is changed or deleted.
Event 'request'
Event arguments:
Emitted when an HTTP request matches the criteria in the log configuration.
nv.logConfig
Contains the current log configuration.
It is null
if no log configuration is set.
Log configuration
Log configuration object:
request
(optional) request matching criteria,
if missing or empty, the log level should be used for all requests
url
(optional) RegExp
to match against the request URLip
(optional) RegExp
to match against the client IP addressheaders
(optional) an object to match against request headers, each values is a RegExp
level
log level as a string to use for matching requests
Changing the log level
This package provides a command line tool to change the log level.
The provided log level will be used only for HTTP requests that match all the given criteria.
Each command invocation overwrites any previous settings.
set-log-level [options...] [<level>]
Options
-l, --url <regex>
- matches request URL (without protocol, host, port)-h, --header <name>:<regex>
- matches given request header value-i, --ip <regex>
- matches sender IP address-x, --expire <value>
- expiration time with s/m/h
suffix-r, --reset
- reset log level to default (do not provide level)--help
- print usage<level>
- log level to use for matching requests, supported values depend on your log library
Invoke via CF task
This will start a temporary instance of the application, run the task inside and stop that instance.
cf run-task APP-NAME "set-log-level [options] [<level>]" [-m MEMORY] [--name TASK_NAME]
Check the output in the logs
cf logs --recent APP-NAME
Invoke via SSH to the application
Log into the container of a running application and execute the command:
cf ssh APP-NAME
export PATH=$PATH:~/deps/0/bin:~/app/node_modules/.bin
set-log-level [options...] <level>
This is useful if you need to run it multiple times and see the output immediately.
Examples
Set log level to debug for requests on URLs starting with /api/v2
. Reset log level after 15 min.
set-log-level -l '^/api/v2/' --expire 15m debug
Contributing
Install all dependencies:
npm install
Run static code checks with eslint and unit tests:
npm test
Integration tests require Redis to run on localhost on default port 6379.
Install docker, unless you have it already.
Start Redis:
npm run redis
Run the integration tests against Redis:
npm run itest
Generate test coverage report:
npm run coverage
After editing README.md update its table of contents:
npm run toc
Future
Ideas for new features are tracked in GitHub issues. You are encouraged to comment, add new ideas and contribute in any way.