Skip to content

BerendKemper/filestream-logger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

filestream-logger

A logger that creates a log-dir, that may change the logger's filename, that may use a formatter and that allows and extending various logger types.
npm i filestream-logger
const FilestreamLogger = require("filestream-logger");

Class: FilestreamLogger

new FilestreamLogger(type[,options])

    type <string> parameter is required!
    The type parameter determines the name of the sub-directory in which the filestreamLogger creates log-files. If the sub-directory did not exists the creation is asynchronously queued.
    options <Object>
      dir <string> Default: "loggers"
      The dir option determines the name of the main-directory in which the filestreamLogger creates a sub-directory which in turn is where the log-files are created. If the main-directory did not exists the creation is asynchronously queued.
      name <string> Default: new Date().toLocaleDateString()
      The name option determines how the first log-file is named. If the log-file did not exists the creation is asynchronously queued.
      formatter <Function> Default: (data, callback) => callback(data.join(" "))
      function formatter(data, callback) {}
        data <Array>
        If the formatter cannot format objects into a formatted string, it is recommended that the data should contain only <primitive values>. This does not apply if a developer wrote a formatter that can format objects into formatted string such as console.log can.
        callback <Function> parameter is required!
        callback(text)
        Invoke callback and pass over a fromatted-string so that it can be written to the log-file.
      The formatter is a function that must produce a fromatted-string from the items of the data <Array>. When the formatter has finished to produce a fromatted-string, callback must be invoked and the fromatted-string must be passed as parameter.
      extend <Array>
      The extend option must contain filestreamLoggers. The created filestreamLogger stores the extended filestreamLoggers. Whenever this filestreamLogger is invoked to log data, the formatted text is also passed over to all extended filestreamLoggers. Checkout the examples to see how an logger.error is extended with a logger.log.

filestreamLogger(...data)

    ...data <Array>
    The data catches all parameters passed over into a single array, just like console.log(...data). The data is passed over as a whole array to formatter.
The filestreamLogger instance is the logging Function and when invoked it immediately invokes formatter followed by writing the formatted string to the log-file.

filestreamLogger.setName(name)

    name <string>
    If name is set to the name it already had nothing will happen.
This method immediately updates the name and filepath and when all previously queued functions have finished it opens a new fd to the new filepath, checks the size of the old filepath through fstat to see if it the log-file has content, closes the old filepath and deletes the old log-file if it has no content.

filestreamLogger.onReady(callback)

    callback <Function>
    function callback() {}
    If callback is not a function the extecution of callback throws a TypeError.
This method invokes callback when all previously queued functions have finished.

filestreamLogger.extend(filestreamLogger)

    filestreamLogger <FilestreamLogger> | <Array>
    If filestreamLogger is an Array checks if the values of the Array are FilestreamLogger, otherwise checks if filestreamLogger is a FilestreamLogger and throws a TypeError if not a FilestreamLogger.
This method allows additionaly extending a filestreamLogger after being created. It finds the filestreamLogger's xLog function and stored it. Whenever the filestreamLogger is invoked to log data, the formatted string is also passed over to all xLogs.

filestreamLogger.destroy(callback)

    callback <Function> Default: dirpath => console.log("destroyed", dirpath)
    function callback(dirpath) {}
      dirpath <string>
      The callback is invoked with the filestreamLogger's dirpath as parameter.
    If callback is not a function throws a TypeError. Since the logger is destroyed the internal callback queue is cleared and therefore a callback parameter is usefull.
This method checks the size of the log-file with fstat to see if it the log-file has content, closes the log-file's fd, deletes with unlink the log-file if it has no content, deletes with rmdir the directory if there were no log-files in it, removes this filestreamLogger from any other filestreamLogger's extending and sets any internal properties that have Object values to null so that everything can be garbage collected. Check out the example below where logger.noob get destroyed and entirely garbage collected.

filestreamLogger.dirpath

Readable property dirpath is created by path.join(dir, type). This property never changes and it used to get a filestreamLogger's xLog.

filestreamLogger.filepath

Readable property filepath is created by path.join(dirpath, name). This property is updated when setName has been invoked.

Examples

const FilestreamLogger = require("filestream-logger");
const TaskClock = require("task-clock");
const IndentModel = require("indent-model");
const LocaleTimezoneDate = require("locale-timezone-date");
//
// ...
//
// Choose a text formatter however you like,
const tabs5_4 = new IndentModel({ tabSize: 5, smallestSpace: 4 });
const formatter = (data, callback) => {
	// I want to see the time in my locale timezone
	const isoStr = new LocaleTimezoneDate().toLocaleISOString();
	// I want to see data aligned in tabs
	const logString = tabs5_4.tabify(isoStr, ...data);
	callback(logString);
	console.log(logString);
};
//
// ...
//
const logger = {};
logger.log = new FilestreamLogger("log", { formatter });
logger.error = new FilestreamLogger("error", { formatter, extend: [logger.log] });
logger.noob = new FilestreamLogger("noob");
logger.noob.extend([logger.log, logger.error]);
logger.noob.destroy();
logger.noob("never gonna happen");
logger.noob.onReady(() => console.log(`really never gonna happen,
all callbacks and logger.noob gets GC'd on the next line`));
delete (logger.noob);
//
// ...
//
// Every day at 24h in your locale timezone set logger's name to yyyy-mm-dd.log
class LoggerClock extends TaskClock {
	constructor() {
		super({ start: new Date(new Date().setHours(0, 0, 0, 0)), interval: { h: 24 } });
	};
	task(now, tick) {
		const yyyymmdd = now.yyyymmdd();
		logger.log.setName(yyyymmdd);
		logger.error.setName(yyyymmdd);
	};
	get DateModel() {
		return LocaleTimezoneDate;
	};
};
const clock = new LoggerClock();
//
// ...
//
console.log(logger); // logger.noob is gone
logger.log("GET", "/v1/someapi/mongol/1", "spider", "monkey");
logger.log("CLOSED", "/v1/someapi/mongol/1", "spider", "monkey");
logger.error("FAILED", "/v1/someapi/mongol/1", "find errors in " + logger.error.filepath, "monkey!");
logger.error("FAILED", "/v1/someapi/mongol/2", "find errors in " + logger.error.filepath, "monkey!");
logger.log.setName("test");
logger.error.setName("noob"); // is empty so auto removed
logger.error.setName("mongol"); // is empty so auto removed
logger.error.setName("monkey");
logger.error("FAILED", "/v1/someapi/mongol/3", "find errors in " + logger.error.filepath, "monkey!");
logger.log("GET", "/v1/someapi/mongol/2", "spider", "monkey");
logger.log("CLOSED", "/v1/someapi/mongol/2", "spider", "monkey");
logger.log.destroy(); // the next error will not log to logger.log
logger.error("FAILED", "/v1/someapi/mongol/4", "find errors in " + logger.error.filepath, "monkey!");
//
//
// CONSOLE OUTPUT:
// {
//   log: [Function (anonymous)] FilestreamLogger {
//     formatter: [Function: formatter]
//   },
//   error: [Function (anonymous)] FilestreamLogger {
//     formatter: [Function: formatter]
//   }
// }
// 2021-04-15T12:58:56.598+0200       GET       /v1/someapi/mongol/1     spider    monkey
// 2021-04-15T12:58:56.598+0200       CLOSED    /v1/someapi/mongol/1     spider    monkey
// 2021-04-15T12:58:56.598+0200       FAILED    /v1/someapi/mongol/1     find errors in loggers\error\2021-04-15.log       monkey!
// 2021-04-15T12:58:56.599+0200       FAILED    /v1/someapi/mongol/2     find errors in loggers\error\2021-04-15.log       monkey!
// 2021-04-15T12:58:56.599+0200       FAILED    /v1/someapi/mongol/3     find errors in loggers\error\monkey.log      monkey!
// 2021-04-15T12:58:56.599+0200       GET       /v1/someapi/mongol/2     spider    monkey
// 2021-04-15T12:58:56.600+0200       CLOSED    /v1/someapi/mongol/2     spider    monkey
// 2021-04-15T12:58:56.600+0200       FAILED    /v1/someapi/mongol/4     find errors in loggers\error\monkey.log      monkey!
// destroyed loggers\noob
// destroyed loggers\log
//
//
// OUTPUT TO WHICH LOG-FILES:
// 1st OUTPUT: /loggers/log/2021-04-15.log
// 2nd OUTPUT: /loggers/log/2021-04-15.log
// 3rd OUTPUT: /loggers/error/2021-04-15.log + OUTPUT: /loggers/log/2021-04-15.log
// 4th OUTPUT: /loggers/error/2021-04-15.log + OUTPUT: /loggers/log/2021-04-15.log
// 5th OUTPUT: /loggers/error/monkey.log + OUTPUT: /loggers/log/test.log
// 6th OUTPUT: /loggers/log/test.log
// 7th OUTPUT: /loggers/log/test.log
// 8th OUTPUT: /loggers/error/monkey.log
//
// ...
//
process.on("SIGINT", () => {
	logger.error("Node JS is now shutting down due to pressing ctrl + c");
	// finish up all logs before exiting process
	FilestreamLogger.destroyAll(() => process.exit());
	// CONSOLE OUTPUT:
	// 2021-04-15T13:01:37.152+0200       Node JS is now shutting down due to pressing ctrl + c
	// destroyed loggers\error
	//
	// OUTPUT TO WHICH LOG-FILES:
	// OUTPUT: /loggers/error/monkey.log
});

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors