Pryv config and logging boilerplate for Node.js
Usage
Initialization
The "boiler" must be initialized with the application name and configuration files settings, before invoking getConfig()
or getLogger()
:
require('@pryv/boiler').init({
appName: 'my-app',
baseFilesDir: path.resolve(__dirname, '..'),
baseConfigDir: path.resolve(__dirname, '../config'),
extraConfigs: [{
scope: 'extra-config',
file: path.resolve(__dirname, '../config/extras.js')
}]
});
Configuration
We use nconf.
Base config directory structure
During initialization default-config.yml
and ${NODE_ENV}-config.yml
will be loaded if present in baseConfigDir
.
Loading order and precedence
The order configuration sources are loaded is important. Each source is loaded with a "scope" name, which can be used to replace the source's contents at any point of time.
The configuration sources are loaded in the following order, the first taking precedence:
- 'test': Empty slot reserved for tests to override any other config parameter
- 'argv': Command line arguments
- 'env': Environment variables
- 'base': File
${NODE_ENV}-config.yml
(if present) or specified by the --config
command line argument - 'extra-config': Additional source(s) as specified by the
extraConfigs
option (see below) - Defaults:
- 'default-file':
${baseConfigDir}/default-config.yml
- 'defaults': Hard-coded defaults for logger
Additional configuration sources can be set or reserved at initialization with the extraConfigs
option, which expects an array of objects with one of the following structures:
- File:
{scope: <name>, file: <path to file> }
. Accepts .yml
, .json
and .js
files. Note .js
content is loaded with require(<path to file>)
. - Data:
{scope: <name>, key: <optional key>, data: <object> }
. If key
is provided, the content of data
will be accessible by this key, otherwise it is loaded at the root of the configuration. - Remote URL:
{scope: <name>, key: <optional key>, url: <URL to json content> }
. The JSON contents of this URL will be loaded asynchronously. - URL from key:
{scope: <name>, key: <optional key>, urlFromKey: <key> }
. Similar to remove URL, with the URL obtained from an existing configuration key.
Working with the configuration
Retrieving the configuration object:
const { getConfigUnsafe } = require('@pryv/boiler');
const config = await getConfigUnsafe();
const { getConfig } = require('@pryv/boiler');
const config = await getConfig();
Retrieving settings:
const foo = config.get('foo');
const bar = config.get('foo:bar');
const barExists = config.has('bar');
Assigning settings:
config.set('foo', 'bye bye');
const foo = config.get('foo');
Changing a scope's contents:
config.get('foo');
config.replaceScopeConfig('test', {foo: 'test'});
config.get('foo');
config.replaceScopeConfig('test', {});
config.get('foo');
Finding out from which scope a key applies:
As nconf is hierachical sometimes you migth want to search from which scope the value of a key is issued.
config.getScopeAndValue('foo');
"Learn" mode
To help detect unused configuration settings, a "learn" mode can be activated to track all calls to config.get()
in files.
Example when running tests:
export CONFIG_LEARN_DIR="{absolute path}/service-core/learn-config"
yarn test
Note, if CONFIG_LEARN_DIR is not given {process.cwd()}/learn-config
will be used
Logging
All messages are prefixed by the appName
value provided at initialization (see above)). appName
can be postfixed with a string by setting the environment variable PRYV_BOILER_SUFFIX
, which is useful when spawning several concurrent processes of the same application.
Using the logger
const {getLogger} = require('@pryv/boiler');
logger.info('Message', item);
logger.warn('Message', item);
logger.error('Message', item);
logger.debug('Message', item);
logger.getLogger('sub');
logger.info()
, logger.warn()
and logger.error()
use Winston logger.debug()
is based on debug.
Outputting debug messages
Set the DEBUG
environment variable. For example: DEBUG="*" node app.js
will output all debug messages.
As "debug" is a widely used package, you might get way more debug lines than expected, so you can use the appName
property to only output messages from your application code: DEBUG="<appName>*" node app.js
Using a custom logger
A custom logger can be used by providing logs:custom
information to the configuration. A working sample of custom Logger is provided in ./examples/customLogger
.
The module must implement async init(settings)
and log(level, key, message, meta)
Log configuration sample
logs: {
console: {
active: true,
level: 'info',
format: {
color: true,
time: true,
aligned: true
}
},
file: {
active: true,
path: 'application.log'
},
custom: {
active: true,
path 'path/to/node/package',
settings: { }
}
}
TODO
- Make config an eventEmitter ? // to track when read or if config changes
- FIX realtive PATH logic for config.loadFromFile()
Contributing
npm run lint
lints the code with Semi-Standard.
npm run license
updates license information.
License
BSD-3-Clause