diff --git a/app.js b/app.js index ecbf096..686f07a 100644 --- a/app.js +++ b/app.js @@ -6,6 +6,8 @@ const xss = require('xss-clean'); const hpp = require('hpp'); const cors = require('cors'); +const httpLogger = require('./middlewares/httpLogger'); +const logger = require('./utils/logger'); const userRoutes = require('./routes/userRoutes'); const globalErrHandler = require('./controllers/errorController'); @@ -18,6 +20,9 @@ app.use(cors()); // Set security HTTP headers app.use(helmet()); +//implementation logging +app.use(httpLogger); + // Limit request from the same API const limiter = rateLimit({ max: 150, @@ -47,6 +52,7 @@ app.use('/api/v1/users', userRoutes); // handle undefined Routes app.use('*', (req, res, next) => { const err = new AppError(404, 'fail', 'undefined route'); + logger.info(`undefined route: ${req.baseUrl}`); next(err, req, res, next); }); diff --git a/controllers/authController.js b/controllers/authController.js index f961a24..3d22625 100644 --- a/controllers/authController.js +++ b/controllers/authController.js @@ -4,7 +4,7 @@ const { const jwt = require('jsonwebtoken'); const User = require('../models/userModel'); const AppError = require('../utils/appError'); - +const logger = require("./utils/logger"); const createToken = id => { return jwt.sign({ @@ -50,6 +50,7 @@ exports.login = async (req, res, next) => { }); } catch (err) { + logger.error(err); next(err); } }; @@ -77,6 +78,7 @@ exports.signup = async (req, res, next) => { }); } catch (err) { + logger.error(err); next(err); } @@ -107,6 +109,7 @@ exports.protect = async (req, res, next) => { next(); } catch (err) { + logger.error(err); next(err); } }; diff --git a/controllers/baseController.js b/controllers/baseController.js index 1b264ee..3312242 100644 --- a/controllers/baseController.js +++ b/controllers/baseController.js @@ -1,5 +1,6 @@ const AppError = require('../utils/appError'); const APIFeatures = require('../utils/apiFeatures'); +const logger = require('./utils/logger'); exports.deleteOne = Model => async (req, res, next) => { try { @@ -14,6 +15,7 @@ exports.deleteOne = Model => async (req, res, next) => { data: null }); } catch (error) { + logger.error(error); next(error); } }; @@ -37,6 +39,7 @@ exports.updateOne = Model => async (req, res, next) => { }); } catch (error) { + logger.error(error); next(error); } }; @@ -53,6 +56,7 @@ exports.createOne = Model => async (req, res, next) => { }); } catch (error) { + logger.error(error); next(error); } }; @@ -72,6 +76,7 @@ exports.getOne = Model => async (req, res, next) => { } }); } catch (error) { + logger.error(error); next(error); } }; @@ -93,6 +98,7 @@ exports.getAll = Model => async (req, res, next) => { }); } catch (error) { + logger.error(error); next(error); } diff --git a/controllers/userController.js b/controllers/userController.js index 261c25f..a4e88ad 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,5 +1,6 @@ const User = require('../models/userModel'); const base = require('./baseController'); +const logger = require('./utils/logger'); exports.deleteMe = async (req, res, next) => { try { @@ -14,6 +15,7 @@ exports.deleteMe = async (req, res, next) => { } catch (error) { + logger.error(error); next(error); } }; diff --git a/middlewares/httpLogger.js b/middlewares/httpLogger.js new file mode 100644 index 0000000..b6bc500 --- /dev/null +++ b/middlewares/httpLogger.js @@ -0,0 +1,13 @@ +const morgan = require('morgan'); +const logger = require('../utils/logger'); + +class LoggerStream { + write(message) { + logger.info(message.substring(0, message.lastIndexOf('\n'))); + } +} + +module.exports = morgan( + 'combined', + { stream: new LoggerStream() } +); \ No newline at end of file diff --git a/package.json b/package.json index f97b3b9..96c6323 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "jsonwebtoken": "^8.5.1", "mongoose": "^5.7.7", "validator": "^12.0.0", - "xss-clean": "^0.1.1" + "xss-clean": "^0.1.1", + "morgan": "^1.9.1", + "winston": "^3.2.1" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index e6fa9da..a14d94f 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,7 @@ const mongoose = require('mongoose'); const dotenv = require('dotenv'); +const logger = require("./utils/logger"); + dotenv.config({ path: './config.env' }); @@ -7,6 +9,7 @@ dotenv.config({ process.on('uncaughtException', err => { console.log('UNCAUGHT EXCEPTION!!! shutting down...'); console.log(err.name, err.message); + logger.error(`UNCAUGHT REJECTON!!! shutting down: ${err.name, err.message}`); process.exit(1); }); @@ -32,6 +35,7 @@ app.listen(port, () => { process.on('unhandledRejection', err => { console.log('UNHANDLED REJECTION!!! shutting down ...'); console.log(err.name, err.message); + logger.error(`UNHANDLED REJECTON!!! shutting down: ${err.name, err.message}`); server.close(() => { process.exit(1); }); diff --git a/utils/logger.js b/utils/logger.js new file mode 100644 index 0000000..e4d3785 --- /dev/null +++ b/utils/logger.js @@ -0,0 +1,19 @@ +const { createLogger, transports, format } = require('winston'); + +const logger = createLogger({ + format: format.combine( + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }), + format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) + ), + transports: [ + new transports.File({ + filename: './logs/all-logs.log', + json: false, + maxsize: 5242880, + maxFiles: 5, + }) + // ,new transports.Console() // log toconsole + ] +}); + +module.exports = logger; \ No newline at end of file