flaschenpost
flaschenpost is a logger for cloud-based applications.
A /ˈflaʃənˌpɔst/ is a „message written on a scrap of paper, rolled-up and put in an empty bottle and set adrift on the ocean; traditionally, a method used by castaways to advertise their distress to the outside world”. (from Wiktionary)
Status
Category | Status |
---|
Version | |
Dependencies | |
Dev dependencies | |
Build | |
License | |
Installation
$ npm install flaschenpost
Quick start
First you need to add a reference to flaschenpost to your application:
const { flaschenpost } = require('flaschenpost');
If you use TypeScript, use the following code instead:
import { flaschenpost } from 'flaschenpost';
Then, call the getLogger
function to get a logger for the current file. Ideally, this is only done once per file:
const logger = flaschenpost.getLogger();
With this logger you can now log messages, using its fatal
, error
, info
, warn
and debug
functions. E.g., to log an info message, call the info
function with an appropriate log message:
logger.info('Server started.');
From time to time you may want to also provide additional metadata for the log message. For this, hand over a metadata object as second parameter:
logger.info('Server started.', { port: 3000 });
Please note that the metadata parameter must be an object. If you want to use other data types as metadata, such as booleans, numbers or strings, you need to wrap them within an object.
If at any point in your application code you want to check wether debug logging is enabled (to e.g. measure times for more detailled logging), you can do so via the public readonly property isDebugMode
on the logger instance:
if (logger.isDebugMode) {
}
Managing log levels
By default flaschenpost only logs fatal
, error
, warn
and info
messages, but not debug
messages. To change this, set the LOG_LEVEL
environment variable to the log level that you would like to log message up to. E.g., to enable logging for all log levels, set its value to debug
:
$ export LOG_LEVEL=debug
If you only want to see log messages with levels fatal
and error
, set it to error
. The same concept applies to all other log levels.
Setting the log level to debug
may result in a huge amount of log messages, which may not be what you want. Hence you can limit which modules you would like to see debug output for by setting the LOG_DEBUG_MODULE_FILTER
environment variable to the name or a comma-separated list of the names of the appropriate modules.
E.g., to only get debug log messages for modules foo
and bar
, use the following line:
$ export LOG_DEBUG_MODULE_FILTER=foo,bar
Formatting log messages
The core concept of flaschenpost is to always log to the standard output stream of a process, according to the 12 Factor Apps principles. However, it makes a difference if you use flaschenpost in an interactive shell session, or in a scripted environment.
If flaschenpost detects a TTY, you will get the log messages as human-readable output. If it doesn't detect a TTY, you will get them formatted as newline-separated JSON.
Sometimes it is necessary to override this default behavior, e.g. in tests. For this, set the LOG_FORMATTER
environment variable to human
or to json
, to enforce one of the two styles:
$ LOG_FORMATTER=human
Faking log sources
Basically, when calling the getLogger
function, flaschenpost automatically detects the file from which this call is done, and infers the appropriate file name. Sometimes, this is not desired, as you may want to manually set the file name used as source.
Therefore, you can provide a file path as a parameter to the getLogger
function. Please note that this file path must be an absolute path, and that it must point to an existing file:
const logger = flaschenpost.getLogger('/.../app.js');
To provide a virtual file path that does not exist, pass an additional parameter defining the module the file belongs to:
const logger = flaschenpost.getLogger(
'/virtual/path/.../app.js',
{
name: 'custom-package',
version: '1.0.1'
}
);
Using the flaschenpost middleware
flaschenpost can be used as a middleware for Express. For this, first load flaschenpost's getMiddleware
function:
const { getMiddleware } = require('flaschenpost');
If you use TypeScript, use the following code instead:
import { getMiddleware } from 'flaschenpost';
Create an instance of the middleware by calling getMiddleware
and register it via the usual way in your Express application:
app.use(getMiddleware());
Sometimes you may want to log when the request is received, not when the response was sent, e.g. for long-running connections. For these cases, provide the logOn
option and set it to request
:
app.use(getMiddleware({ logOn: 'request' }));
By default, the middleware uses info
as log level. To change this, provide the logLevel
option and set it to the desired value:
app.use(getMiddleware({ logLevel: 'warn' }));
Configuring flaschenpost programmatically
Sometimes, you may need to change the configuration of flaschenpost programmatically. To do this, first get the current configuration using the getConfiguration
function:
const configuration = flaschenpost.getConfiguration();
The configuration object now has a number of functions (see section below) to adjust the configuration. E.g., if you want to change the hostname being used, call the withHostname
function:
const updatedConfiguration = configuration.withHostname('localhost');
Please note that all of the functions on the configuration object do not mutate the configuration, but return a new instance instead!
Finally, set the new configuration using the configure
function. Typically, because of the configuration object's immutability, you may want to do all of this in a single line:
flaschenpost.configure(
flaschenpost.getConfiguration().
withHighestEnabledLogLevel('debug').
withHostname('localhost')
);
Setting application data
To set the name and version of the application, use the withApplication
function:
const updatedConfiguration =
configuration.withApplication({ name: 'foo', version: '1.0.0' });
Setting the debug module filter
To set the list of modules for which debug messages should be logged, use the withDebugModuleFilter
function:
const updatedConfiguration =
configuration.withDebugModuleFilter([ 'foo', 'bar' ]);
Setting the formatter
To set the formatter, use the withFormatter
function. As parameter, provide a function that takes a LogEntry
and returns a string:
const updatedConfiguration =
configuration.withFormatter(logEntry => '...');
For details on this see the Formatter
interface and the LogEntry
class.
If you want to programmatically enforce human-readable or JSON output, you first have to load all builtin formatters:
const { formatters } = require('flaschenpost');
If you use TypeScript, use the following code instead:
import { formatters } from 'flaschenpost';
Then access the asHumanReadable
or the asJson
function and hand it over using the withFormatter
function.
Setting the log level
To set the log level, use the withHighestEnabledLogLevel
function:
const updatedConfiguration =
configuration.withHighestEnabledLogLevel('debug');
Setting the hostname
To set the hostname, use the withHostname
function:
const updatedConfiguration =
configuration.withHostname('localhost');
Setting the log entry ID generator
To set the log entry ID generator, use the withLogEntryIdGenerator
function. As parameter, provide a generator function that endlessly returns new IDs, either of type number
or of type string
:
const updatedConfiguration =
configuration.withLogEntryIdGenerator(function * () {
while (true) {
const nextId =
yield nextId;
}
});
Running quality assurance
To run quality assurance for this module use roboter:
$ npx roboter