Skip to content

Instantly share code, notes, and snippets.

@tigranpetrossian
Last active January 10, 2021 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tigranpetrossian/741cda713a91babf06f97face758bcb3 to your computer and use it in GitHub Desktop.
Save tigranpetrossian/741cda713a91babf06f97face758bcb3 to your computer and use it in GitHub Desktop.
Winston logger with added ability of namespacing and controlling severity levels with environment variables
import winston, { format, createLogger, transports } from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
const { combine, timestamp, label, printf } = format;
const formatConsoleMessage = printf((info) => {
const { timestamp, label, level, message } = info;
return `${timestamp} ${(level + ':').padEnd(16)} [${label}] ${message}`;
});
const logger = createLogger({
level: 'info',
format: format.json(),
exitOnError: false,
transports: [
new winston.transports.DailyRotateFile({
filename: './logs/combined-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d',
}),
],
});
if (process.env.NODE_ENV === 'development') {
logger.level = process.env.LOG_LEVEL || 'debug';
logger.add(
new transports.Console({
format: combine(
format.colorize(),
timestamp({
format: 'YYYY-MM-DD HH:MM:SS',
}),
format.align(),
formatConsoleMessage,
),
}),
);
}
// Amend the logger with namespacing via environment variables
// Inspiration: https://github.com/visionmedia/debug
// LOG=app:fetch – log only messages labeled with 'app:fetch'
// LOG=app:* – Log anything that starts with 'app:'; 'app:fetch', 'app:cache', etc.
// LOG=* – Log everyting
// LOG=*,-not_this – log everything but messages labeled with 'not_this'
/**
* Check if the given label (namespace) is enabled through an environment variable.
* Examples:
*
* @param {String} label – label of the message
* @return {Boolean}
*
* */
const labelEnabled = (label) => {
const setting = process.env.LOG;
// Don't allow logging when no namespaces are specified
if (typeof setting !== 'string') {
return false;
}
// Split labels string into an array and convert '*' wildcards into valid JS regex
const labels = setting.split(',').map((label) => label.replace(/\*/g, '.*?'));
const included = labels.filter((label) => label[0] !== '-');
const exluded = labels
.filter((label) => label[0] === '-')
.map((label) => label.substring(1));
const includedMatch = included.find((lbl) =>
new RegExp('^' + lbl + '$').test(label),
);
const excludedMatch = exluded.find((lbl) =>
new RegExp('^' + lbl + '$').test(label),
);
if (excludedMatch) return false;
if (includedMatch) return true;
};
export default (label) => {
const log = (message, label, level) => {
if (process.env.NODE_ENV !== 'production' && !labelEnabled(label)) {
return;
}
logger.log({
level,
message,
label,
});
};
return Object.keys(logger.levels).reduce((acc, level) => {
acc[level] = (message) => log(message, label, level);
return acc;
}, {});
};
@ivanm376
Copy link

There is error:

format: 'YYYY-MM-DD HH:MM:SS', // prints months / fractional seconds - https://momentjs.com/docs/#/parsing/string-format/

format: 'YYYY-MM-DD HH:mm:ss', // correct one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment