Abstract
The log-fns
project is a simple lightweight logging library for JavaScript.
Quick Start
Installation
npm i log-fns
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!');
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
{
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 ofcreateLogger()
(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']
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...');
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.
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
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.
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.
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
.
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..."}
Top comments (1)
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.