Skip to content

Commit

Permalink
WRLGS-11: Generic function for timestamp in stderr
Browse files Browse the repository at this point in the history
  • Loading branch information
BourgoisMickael committed Jun 24, 2024
1 parent 60cc71b commit 8005e24
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
37 changes: 37 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const API = require('./lib/api.js');
const stderrUtils = require('./lib/stderrUtils');

/*
* For convenience purposes, we provide an already instanciated API; so that
Expand All @@ -11,4 +12,40 @@ module.exports = {
Logger: werelogs.Logger,
configure: werelogs.reconfigure.bind(werelogs),
Werelogs: API,
/**
* Log to stderr with timestamp
*
* @example <caption>Simplest usage</caption>
* ```
* const { stderrUtils } = require('werelogs');
* stderrUtils.catchAndTimestampStderr();
* ```
*
* @example <caption>Manage process exit</caption>
* ```
* const { stderrUtils } = require('werelogs');
* // set exitCode to null to keep process running on uncaughtException
* stderrUtils.catchAndTimestampStderr(undefined, null);
* // application code
* process.on('uncaughtException', (err) => {
* // custom handling, close connections, files
* this.worker.kill(); // or process.exit(1);
* });
* // Note you could use prependListener to execute your callback first
* // and then let stderrUtils exit the process.
* ```
*
* @example <caption>Custom listener</caption>
* ```
* const { stderrUtils } = require('werelogs');
* stderrUtils.catchAndTimestampWarning();
* // application code
* process.on('uncaughtException', (err, origin) => {
* stderrUtils.printErrorWithTimestamp(err, origin);
* // close and stop everything
* process.exit(1);
* });
* ```
*/
stderrUtils,
};
97 changes: 97 additions & 0 deletions lib/stderrUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/** Returns a timestamp in ISO format YYYY-MM-DDThh:mm:ss.sssZ */
const defaultTimestamp = () => new Date().toISOString()

/**
* Prints on stderr a timestamp, the origin and the error
*
* If no other instructions are needed on uncaughtException,
* consider using `catchAndTimestampStderr` directly.
*
* @example
* process.on('uncaughtException', (err, origin) => {
* printErrorWithTimestamp(err, origin);
* // server.close();
* // file.close();
* process.nextTick(() => process.exit(1));
* });
* // Don't forget to timestamp warning
* catchAndTimestampWarning();
* @param {Error} err see process event uncaughtException
* @param {uncaughtException|unhandledRejection} origin see process event
* @param {string} [date=`defaultTimestamp()`] Date to print
*/
function printErrorWithTimestamp(
err, origin, date = defaultTimestamp()
) {
process.stderr.write(`${date}: ${origin}:\n${err.stack}\n`)
}

/**
* Prefer using `catchAndTimestampStderr` instead of this function.
*
* Adds listener for uncaughtException to print with timestamp.
*
* If you want to manage the end of the process, you can set exitCode to null.
* Or you can use `printErrorWithTimestamp` in your own uncaughtException listener.
*
* @param {Function} [dateFct=`defaultTimestamp`] Function returning a formatted date
* @param {*} [exitCode=1] On uncaughtException, if not null, `process.exit` will
* be called with this value
*/
function catchAndTimestampUncaughtException(
date = defaultTimestamp, exitCode = 1
) {
process.on('uncaughtException', function timestampUncaughtException (err, origin) {
printErrorWithTimestamp(err, origin, date());
if (exitCode !== null) {
process.nextTick(() => process.exit(exitCode));
}
})
}

/**
* Forces the use of `--trace-warnings` and adds a date in warning detail
* The warning will be printed by the default `onWarning`
*
* @param {string} [date=`defaultTimestamp`] Function returning a formatted date
*/
function catchAndTimestampWarning(date = defaultTimestamp) {
process.traceProcessWarnings = true;
// must be executed first, before the default `onWarning`
process.prependListener('warning', function timestampWarning (warning) {
if (warning.detail)
warning.detail += `\nAbove Warning Date: ${defaultTimestamp()}`
else
warning.detail = `Above Warning Date: ${defaultTimestamp()}`
});
}

/**
* Adds listener for uncaughtException and warning to print them with timestamp.
*
* If you want to manage the end of the process, you can set exitCode to null.
* Or you can use `printErrorWithTimestamp` in your own uncaughtException listener.
*
* @example
* const { stderrUtils } = require('werelogs');
* // first instruction in your index.js or entrypoint
* stderrUtils.catchAndTimestampStderr();
*
* @param {Function} [date=`defaultTimestamp`] Function returning a formatted date
* @param {*} [exitCode=1] On uncaughtException, if not null, `process.exit` will
* be called with this value
*/
function catchAndTimestampStderr(
date = defaultTimestamp, exitCode = 1
) {
catchAndTimestampUncaughtException(date, exitCode);
catchAndTimestampWarning(date);
}

module.exports = {
defaultTimestamp,
printErrorWithTimestamp,
catchAndTimestampUncaughtException,
catchAndTimestampWarning,
catchAndTimestampStderr
}

0 comments on commit 8005e24

Please sign in to comment.