Last active
January 10, 2021 00:07
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
}, {}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There is error: