DEV Community

Cover image for log-fns: a new JS logging library
Pudding
Pudding

Posted on

log-fns: a new JS logging library

log-fns

Abstract

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

Quick Start

Installation

npm i log-fns

Enter fullscreen mode Exit fullscreen mode

Basic Usage

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!');
Enter fullscreen mode Exit fullscreen mode

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"}}
Enter fullscreen mode Exit fullscreen mode

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

{
  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: () => ''
}
Enter fullscreen mode Exit fullscreen mode
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:

['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
Enter fullscreen mode Exit fullscreen mode

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

const logger = createLogger({ 
  logLevel: 'DEBUG' 
});

logger.trace('Tracing...');
logger.debug('Debugging...');
logger.warn('Warning...');
Enter fullscreen mode Exit fullscreen mode

Output

{"timestamp":"2022-02-23T06:08:04.424Z","logLevel":"DEBUG","message":"Debugging..."}
{"timestamp":"2022-02-23T06:08:04.452Z","logLevel":"WARN","message":"Warning..."}
Enter fullscreen mode Exit fullscreen mode

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.

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

logger.normal('Normal log entry...');
logger.warning('Warning log entry...');
logger.error('Error log entry...');
Enter fullscreen mode Exit fullscreen mode

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..."}
Enter fullscreen mode Exit fullscreen mode

Customizing the Log Function Names

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...');
Enter fullscreen mode Exit fullscreen mode

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..."}
Enter fullscreen mode Exit fullscreen mode

Customizing the Log Format

By default, output is in JSON format, but this can be changed.

const formatOutput = ({ timestamp, logLevel, message }) => `${timestamp}|${logLevel}|${(typeof message === 'string') ? message : JSON.stringify(message)}`;
const logger = createLogger({ formatOutput });

logger.info('Info message...');
Enter fullscreen mode Exit fullscreen mode

Output

2022-02-24T02:28:54.858Z|INFO|Info message...
Enter fullscreen mode Exit fullscreen mode

Customizing the message enrichment

By default, messages are enriched with the timestamp and log level, but this can be changed.

const enrichMessage = ({ message, logLevel }) => ({
  unixTime: new Date().getTime(),
  appName: 'my-app',
  loggerName: 'my-logger',
  logLevel,
  message,
});
const logger = createLogger({ enrichMessage });

logger.info('Info message...');
Enter fullscreen mode Exit fullscreen mode

Output

{"unixTime":1645672340194,"appName":"my-app","loggerName":"my-logger","logLevel":"INFO","message":"Info message..."}
Enter fullscreen mode Exit fullscreen mode

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.

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...');
Enter fullscreen mode Exit fullscreen mode

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..."}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
dsaga profile image
Dusan Petkovic

Great introduction to LogFns! I love seeing innovative approaches to logging in JavaScript, especially ones that prioritize simplicity and developer experience.

I’ve worked on projects where effective log management was critical, and one of the biggest challenges was ensuring logs were structured and easy to parse without introducing too much overhead. Does LogFns support integration with centralized log management systems (like Logstash or Fluentd) out of the box, or would that require custom adapters?

On a related note, I’m working on a platform called TagLog, which focuses on real-time log streaming—essentially treating logs like Slack channels to let teams monitor logs live for better collaboration and debugging. I’d love to hear your thoughts—do you think live logging platforms add value to debugging workflows, or do you prefer the traditional batch-processing approach for logs?

Thanks for sharing LogFns! Excited to try it out in one of my side projects.