— nodejs — 1 min read
Changing log level at runtime without restarting the node server is an interesting idea. Didn't see much posts on it but everywhere it was said, its doable.
I am going to accomplish this using following techniques.
Below is the content of the environment file. We are going to change NEW_VALUE variable in this test, initially it has 'three'.
1PORT=40002NEW_VALUE=three
Below is the simple Node Express program and '/' route has the code to update environment variables. Basically we are reading the .env file and initializing values to process.env variable in a loop.
1// Express pickup updated environment variables2const express = require('express')3var dotenv = require('dotenv')4
5const app = express()6
7require('dotenv').config();8
9app.get('/', function (req, res) {10 const envConfig = dotenv.config().parsed;11 console.log(envConfig)12 for (let k in envConfig) { 13 process.env[k] = envConfig[k] 14 } 15 console.log(`Hello World ${process.env.PORT} - ${process.env.NEW_VALUE}`)16 res.send(`Hello World ${process.env.PORT} - ${process.env.NEW_VALUE}`)17})18 19app.listen(process.env.PORT)
Below is the console output
1>node app_envars 2{ PORT: '4000', NEW_VALUE: 'three' }3Hello World 4000 - three4{ PORT: '4000', NEW_VALUE: 'four' }5Hello World 4000 - four
Below is a simple NodeJS Winston program where log level is changed at runtime
1// Change the log level programatically2const winston = require('winston');3
4const transports = {5 console: new winston.transports.Console({ level: 'warn' }),6};7
8const logger = winston.createLogger({9 transports: [ 10 transports.console,11 ]12});13
14transports.console.level = 'info';15logger.info('Text Info');16logger.warn('Text Warn');17logger.error('Text error');18logger.debug('Text Debug 1');19
20transports.console.level = 'debug';21logger.debug('Text Debug 2');
Below is teh output, you can notice 'Text Debug 1' did not appear. But after changing log level to 'debug'. It shows up.
1>node win12{"level":"info","message":"Text Info"}3{"level":"warn","message":"Text Warn"}4{"level":"error","message":"Text error"}5{"level":"debug","message":"Text Debug 2"}
Logging levels in winston conform to the severity ordering specified by RFC5424: severity of all levels is assumed to be numerically ascending from most important to least important. When you set log level as info, you get all data above from info like error, warn and info.
Levels | Numbers |
---|---|
error | 0 |
warn | 1 |
info | 2 |
http | 3 |
verbose | 4 |
debug | 5 |
silly | 6 |
In the below program, i am going to combine above two concepts together.
Below is the main express program
1const express = require('express')2const dotenv = require('dotenv')3const path = require('path')4
5let {winston_logger, setLevel} = require('./winston-logger')6let logger = winston_logger();7
8dotenv.config({ path: path.resolve(__dirname, `./${process.env.NODE_ENV}.env`)});9
10if(process.env.NODE_ENV === 'development'){11 setLevel(process.env.LOG_LEVEL)12}else if(process.env.NODE_ENV === 'production'){13 setLevel(process.env.LOG_LEVEL)14}15
16// const dotenv = require('dotenv').config()17
18const app = express()19const port = 3000;20
21app.get('/', function (req, res) {22 res.send('Hello World '+process.env.LOG_LEVEL)23 console.log(`Started in ${process.env.NODE_ENV} mode`)24
25 logger.info('Text Info');26 logger.warn('Text Warn');27 logger.error('Text error');28 logger.debug('Text Debug');29});30
31app.get('/refresh', function (req, res) {32 // setLevel('debug')33 // const envConfig = dotenv.load().parsed;34 const envConfig = dotenv.config({ path: path.resolve(__dirname, `./${process.env.NODE_ENV}.env`)}).parsed;35 console.table(envConfig)36 for (let k in envConfig) {37 process.env[k] = envConfig[k]38 console.log(`Assigning : ${k} = ${envConfig[k]}`)39 }40
41 setLevel(process.env.LOG_LEVEL)42 res.send('Refreshed')43})44
45
46app.listen(port, () => {47 console.log(`Winston example app listening at http://localhost:${port}`)48})
Below program contains the funtions used in the above main program
1const winston = require('winston')2const {format, createLogger} = require('winston');3const {timestamp, combine, printf, errors} = format;4
5const transports = {6 console: new winston.transports.Console({ level: 'info' }),7};8
9function setLevel(level){10 transports.console.level = level;11}12
13function winston_logger(){14 const logFormat = printf(({ level, message, label, timestamp, stack }) => {15 return `${timestamp} [${level}] ${stack || message}`;16});17
18return createLogger({19 // level: process.env.LOG_LEVEL,20 // format: winston.format.simple(),21 format: combine(22 timestamp({ format: 'YYYY-MM-DD HH:mm:ss'}),23 errors({ stack:true }),24 logFormat25 ),26 // defaultMeta: { service: 'user-service' },27 transports: [28 transports.console,29 ]30});31
32}33
34module.exports = {winston_logger, setLevel};
Data in environment files
1>cat development.env2LOG_LEVEL=debug3>cat production.env4LOG_LEVEL=info
Below is the output of the program and able to change the log level at runtime.