log-fns: a new JS logging library
Tags: javascript, logging, lightweight, simple
Published: 2022-02-24 03:31:44

[log-fns](https://github.com/PuddingOnTheRitz/log-fns/wiki)

# Abstract
The `log-fns` project is a simple lightweight logging library for JavaScript.

# Quick Start
## Installation
```bash
npm i log-fns

```
## Basic Usage
```javascript
const { createLogger } = require('log-fns');

// Create a logger with the default configuration
const logger = createLogger();

// Log a string
logger.info('Hello, log-fns!');

// Log an object
logger.info({ greeting: 'Hello', name: 'Joan' });

// Defer calculation of an expensive message so it is not called if the log level isn't enabled
logger.trace(() => 'Hello, expensive trace message!');
```

_Output_
```
{"timestamp":"2022-02-23T03:06:35.206Z","logLevel":"INFO","message":"Hello, log-fns!"}
{"timestamp":"2022-02-23T03:06:35.207Z","logLevel":"INFO","message":{"greeting":"Hello","name":"Joan"}}
```

# Why?
Well, most of the time we are just logging to the console, and if that's all you are doing, `log-fns` is probably for you.

Also, if you are implementing your own logging solution, this may be a good starting point, as it is highly configurable.

# Features
* Easy to understand and use
* No object-oriented/imperative/mutable coding is required
* Tiny _(~5KB unpacked)_
* No dependencies
* Very customizable

# Configuration
## Default Configuration
```javascript
{
  logLevel: 'INFO',
  logLevels: ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'],
  getLogFunctionName: (logLevel) => logLevel.toLowerCase(),
  formatOutput: (o) => JSON.stringify(o),
  enrichMessage: ({ message, logLevel }) => ({
    timestamp: new Date().toISOString(),
    logLevel,
    message,
  }),
  writeOutput: ({ message }) => {
    console.log(message);
    return message;
  },
  noOp: () => ''
}
```
|Key|Type|Value|
|---|----|-----|
|`logLevel`|String|Threshold below which no log output will occur|
|`logLevels`|Array[String]|List of all available log levels in order from least severe to most|
|`getLogFunctionName`|Function|Determines the log function name for a given log level|
|`formatOutput`|Function|Formats the output of the log message|
|`enrichMessage`|Function|Adds data such as the current timestamp to the output|
|`writeOutput`|Function|Writes the output to a destination such as the console|
|`noOp`|Function|Does nothing - called when a function's corresponding log level is not enabled|

## Log Level
* A **log level** is a conceptual threshold _below_ which no log output will occur, and _at_ or _above_ which, it will.
* It is configured by setting the case-sensitive value of `logLevel` to one of the available levels in the configuration argument of `createLogger()` _(case-sensitive)_.
* Each log level is associated with a function of the _same name_, but in all _lower-case_.

### Available Levels
These log levels are available in order from _most_ verbose or _least_ severe, to _least_ verbose or _most_ severe:
```javascript
['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
```
The default log level is `'INFO'`, which means any messages associated with the `'TRACE'` OR `'DEBUG'` levels will not be output, and all others will.

### Configuring the Log Level
```javascript
const logger = createLogger({ 
  logLevel: 'DEBUG' 
});
    
logger.trace('Tracing...');
logger.debug('Debugging...');
logger.warn('Warning...');
```
_Output_
```
{"timestamp":"2022-02-23T06:08:04.424Z","logLevel":"DEBUG","message":"Debugging..."}
{"timestamp":"2022-02-23T06:08:04.452Z","logLevel":"WARN","message":"Warning..."}
```

## Custom Log Levels
By default, the log function names are the same as their corresponding log levels, but in all lowercase.

If log levels are not also legal javascript function names, you'll need to customize them using the `getLogFunctionName` configuration attribute.

You'll also need to configure the logLevel since it is 'INFO' by default, and if no log levels by that name exist, no log output will occur.

```javascript
const logger = createLogger({
  logLevel: 'NORMAL',
  logLevels: ['NORMAL', 'WARNING', 'ERROR'],
});

logger.normal('Normal log entry...');
logger.warning('Warning log entry...');
logger.error('Error log entry...');
```
_Output_
```
{"timestamp":"2022-02-24T01:47:23.238Z","logLevel":"NORMAL","message":"Normal log entry..."}
{"timestamp":"2022-02-24T01:47:23.263Z","logLevel":"WARNING","message":"Warning log entry..."}
{"timestamp":"2022-02-24T01:47:23.265Z","logLevel":"ERROR","message":"Error log entry..."}
```

## Customizing the Log Function Names
```javascript
const logger = createLogger({
  logLevel: 'REGULAR LOGGING',
  logLevels: ['VERBOSE LOGGING', 'REGULAR LOGGING', 'ERROR LOGGING'],
  getLogFunctionName: (logLevel) => ({
    'VERBOSE LOGGING': 'logVerbose',
    'REGULAR LOGGING': 'logRegular',
    'ERROR LOGGING': 'logError',
  })[logLevel],
});

logger.logVerbose('Verbose logging...');
logger.logRegular('Regular logging...');
logger.logError('Error logging...');
```
_Output_
```
{"timestamp":"2022-02-24T02:04:24.046Z","logLevel":"REGULAR LOGGING","message":"Regular logging..."}
{"timestamp":"2022-02-24T02:04:24.071Z","logLevel":"ERROR LOGGING","message":"Error logging..."}
```
## Customizing the Log Format
By default, output is in JSON format, but this can be changed.
```javascript
const formatOutput = ({ timestamp, logLevel, message }) => `${timestamp}|${logLevel}|${(typeof message === 'string') ? message : JSON.stringify(message)}`;
const logger = createLogger({ formatOutput });

logger.info('Info message...');
```
_Output_
```
2022-02-24T02:28:54.858Z|INFO|Info message...
```
## Customizing the message enrichment
By default, messages are enriched with the timestamp and log level, but this can be changed.
```javascript
const enrichMessage = ({ message, logLevel }) => ({
  unixTime: new Date().getTime(),
  appName: 'my-app',
  loggerName: 'my-logger',
  logLevel,
  message,
});
const logger = createLogger({ enrichMessage });

logger.info('Info message...');
```
_Output_
```
{"unixTime":1645672340194,"appName":"my-app","loggerName":"my-logger","logLevel":"INFO","message":"Info message..."}
```



## Customizing the Output 
By default, log entries are written to the console, but this can be changed.

For example, the configuration below writes errors to `console.error`, and everything else to `console.log`.
```javascript
const writeOutput = ({ logLevel, message }) => {
  (logLevel === 'ERROR' ? console.error : console.log)(message);
  return message;
};
const logger = createLogger({ writeOutput });

logger.info('Info message...');
logger.error('Error message...');
```
_Output_
```
(console.log)
{"timestamp":"2022-02-24T02:57:53.469Z","logLevel":"INFO","message":"Info message..."}
(console.error)
{"timestamp":"2022-02-24T02:57:53.497Z","logLevel":"ERROR","message":"Error message..."}
```