diff --git a/rest-express-mongo/app.js b/rest-express-mongo/app.js index 2438c45..bfd5424 100644 --- a/rest-express-mongo/app.js +++ b/rest-express-mongo/app.js @@ -4,88 +4,113 @@ const Note = require("./models/model"); const User = require("./models/users"); const auth = require("./authentication"); const cookieParser = require("cookie-parser"); +const logger = require("./utils/logger"); +const morgan = require("morgan"); const app = express(); + + +// Middleware setup +app.use(morgan('combined', { stream: logger.stream })); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); +app.use(express.static('public')); -//link for database connection -const db = - "mongo://localhost:27017"; +// Database connection +mongoose.set('strictQuery', false); +const db = "mongodb://localhost:27017/local"; -//connecting to the database -mongoose - .connect(db) +mongoose.connect(db) .then((res) => { - app.listen(3000); //after connnecting to the database listen to this port... + app.listen(3000); + logger.info("Connected to MongoDB"); + logger.info("Server listening on port 3000"); }) - .catch((err) => console.log(err)); + .catch((err) => logger.error("MongoDB connection error:", err)); app.set("view engine", "ejs"); -//...............for signup ......................... - +// Routes - Maintaining your original structure with added logging app.get("/signup", (req, res) => { + logger.debug("Rendering signup page"); res.render("signup"); }); + app.post("/signup", auth.signIn); app.get("/login", (req, res) => { + logger.debug("Rendering login page"); res.render("login"); }); + app.post("/login", auth.logIn); app.get("/logout", auth.logout); -//.....................end of signup ........................ - app.get("*", auth.checkUser); -//for home page +// Home route app.get("/", auth.showNotes); -//for posting a new note... + +// Note creation app.post("/", (req, res) => { + logger.debug("Creating new note"); const note = new Note(req.body); - note - .save() + note.save() .then((result) => { + logger.info("Note created successfully"); res.redirect("/"); }) .catch((err) => { - console.log(err); + logger.error("Note creation error:", err); + console.log(err); }); }); -//for new note +// New note page app.get("/note", function (req, res) { + logger.debug("New note page request"); res.render("note"); }); -//get individual notes +// Individual note app.get("/note/:id", (req, res) => { const id = req.params.id; + logger.debug(`Fetching note with ID: ${id}`); Note.findById(id) .then((result) => { + logger.debug("Note found, rendering individual view"); res.render("indi", { result }); }) .catch((err) => { - console.log(err); + logger.error("Error fetching note:", err); + console.log(err); }); }); -//delete notes +// Delete note app.delete("/:id", (req, res) => { const id = req.params.id; + logger.debug(`Deleting note with ID: ${id}`); Note.findByIdAndDelete(id) .then((result) => { + logger.info("Note deleted successfully"); res.json({ redirect: "/" }); }) .catch((err) => { - console.log(err); + logger.error("Note deletion error:", err); + console.log(err); // Keeping your original error handling }); }); -//for page not found +// 404 handler app.use((req, res) => { + logger.warn(`404 - Not Found: ${req.originalUrl}`); res.render("error"); }); + +// Error handler middleware - new addition to catch any unhandled errors +app.use((err, req, res, next) => { + logger.error(`Unhandled error: ${err.stack}`); + res.status(500).render('error'); +}); \ No newline at end of file diff --git a/rest-express-mongo/authentication.js b/rest-express-mongo/authentication.js index a3730ae..66f8171 100644 --- a/rest-express-mongo/authentication.js +++ b/rest-express-mongo/authentication.js @@ -1,75 +1,143 @@ -const { append } = require("express/lib/response"); const jwt = require("jsonwebtoken"); const User = require("./models/users"); const Note = require("./models/model"); +const logger = require("./utils/logger"); const createToken = (id) => { + logger.debug(`Creating token for user ID: ${id}`); return jwt.sign({ id }, "MONKE", { expiresIn: 24 * 60 * 60 }); }; + module.exports.createToken = createToken; + module.exports.checkUser = (req, res, next) => { const token = req.cookies.jwt; if (token) { jwt.verify(token, "MONKE", async (err, decToken) => { if (err) { + logger.warn(`Invalid JWT token: ${err.message}`); res.locals.user = null; next(); } else { - let user = await User.findById(decToken.id); - res.locals.user = user; - next(); + logger.debug(`Valid token for user ID: ${decToken.id}`); + try { + let user = await User.findById(decToken.id); + if (!user) { + logger.warn(`User not found for ID: ${decToken.id}`); + res.locals.user = null; + } else { + logger.debug(`Authenticated user: ${user.username}`); + res.locals.user = user; + } + next(); + } catch (err) { + logger.error(`User lookup error: ${err.message}`); + res.locals.user = null; + next(); + } } }); } else { + logger.debug("No JWT token found, redirecting to signup"); res.redirect("/signup"); } }; -//to get the username of the current user........ module.exports.showNotes = (req, res) => { const token = req.cookies.jwt; jwt.verify(token, "MONKE", async (err, decoded) => { if (err) { + logger.warn(`Invalid token in showNotes: ${err.message}`); res.redirect("/login"); } else { - const user = await User.findById(decoded.id); - Note.find({ username: user.username }) - .then((result) => { - res.render("index", { result }); - }) - .catch((err) => { - console.log(err); - }); + try { + const user = await User.findById(decoded.id); + if (!user) { + logger.warn(`User not found for ID: ${decoded.id}`); + return res.redirect("/login"); + } + + logger.debug(`Fetching notes for user: ${user.username}`); + const notes = await Note.find({ username: user.username }); + + logger.debug(`Found ${notes.length} notes for user`); + res.render("index", { result: notes }); + } catch (err) { + logger.error(`Error in showNotes: ${err.message}`); + res.status(500).render("error", { message: "Error loading notes" }); + } } }); }; module.exports.signIn = async (req, res) => { const { username, password } = req.body; + logger.debug(`Signup attempt for username: ${username}`); + try { const user = await User.create({ username, password }); + logger.info(`New user created: ${username}`); + const token = createToken(user._id); - res.cookie("jwt", token, { expiresIn: 24 * 60 * 60 * 1000 }); + res.cookie("jwt", token, { + httpOnly: true, + maxAge: 24 * 60 * 60 * 1000 + }); + + logger.debug(`Session cookie set for user: ${username}`); res.redirect("/"); } catch (err) { - console.log(err); - res.redirect("/signup"); + logger.error(`Signup error for ${username}: ${err.message}`); + + // Handle specific error cases + if (err.code === 11000) { + logger.warn(`Duplicate username attempt: ${username}`); + return res.render("signup", { error: "Username already exists" }); + } + + res.status(500).render("signup", { + error: "Registration failed. Please try again." + }); } }; + module.exports.logIn = async (req, res) => { const { username, password } = req.body; + logger.debug(`Login attempt for username: ${username}`); + try { const user = await User.login(username, password); + logger.info(`Successful login for user: ${username}`); + const token = createToken(user._id); - res.cookie("jwt", token, { expiresIn: 24 * 60 * 60 * 1000 }); + res.cookie("jwt", token, { + httpOnly: true, + maxAge: 24 * 60 * 60 * 1000 + }); + + logger.debug(`Session cookie set for user: ${username}`); res.redirect("/"); } catch (err) { - console.log(err); - res.sendStatus(500); + logger.warn(`Failed login attempt for ${username}: ${err.message}`); + + // Differentiate between wrong password and non-existent user + const errorMessage = err.message.includes("incorrect password") + ? "Incorrect password" + : "User not found"; + + res.status(401).render("login", { + error: errorMessage, + username: username // Return username for convenience + }); } }; module.exports.logout = (req, res) => { - res.cookie("jwt", "", { maxAge: 1 }); + logger.debug("Logout request received"); + res.cookie("jwt", "", { + httpOnly: true, + maxAge: 1 + }); + logger.info("User logged out, session cleared"); res.redirect("/login"); -}; +}; \ No newline at end of file diff --git a/rest-express-mongo/package-lock.json b/rest-express-mongo/package-lock.json index 6f1ef95..230347f 100644 --- a/rest-express-mongo/package-lock.json +++ b/rest-express-mongo/package-lock.json @@ -14,7 +14,9 @@ "ejs": "^3.1.6", "express": "^4.17.3", "jsonwebtoken": "^8.5.1", - "mongoose": "^6.2.2" + "mongoose": "^6.2.2", + "morgan": "^1.10.0", + "winston": "^3.17.0" }, "devDependencies": { "jest": "^29.7.0" @@ -1329,6 +1331,26 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2382,6 +2404,12 @@ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -2686,6 +2714,24 @@ } ] }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", @@ -2977,6 +3023,16 @@ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2993,6 +3049,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -3001,6 +3067,31 @@ "color-support": "bin.js" } }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3238,6 +3329,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3433,6 +3530,12 @@ "bser": "2.1.1" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -3502,6 +3605,12 @@ "node": ">=8" } }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3937,7 +4046,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -4746,6 +4854,12 @@ "node": ">=6" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -4808,6 +4922,29 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5040,6 +5177,34 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", @@ -5227,6 +5392,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5235,6 +5409,15 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -5622,6 +5805,15 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5751,6 +5943,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -5822,6 +6029,15 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -5976,6 +6192,12 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -6022,6 +6244,15 @@ "node": ">=12" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -6200,6 +6431,42 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/rest-express-mongo/package.json b/rest-express-mongo/package.json index f8435e9..c54cdb7 100644 --- a/rest-express-mongo/package.json +++ b/rest-express-mongo/package.json @@ -17,7 +17,9 @@ "ejs": "^3.1.6", "express": "^4.17.3", "jsonwebtoken": "^8.5.1", - "mongoose": "^6.2.2" + "mongoose": "^6.2.2", + "morgan": "^1.10.0", + "winston": "^3.17.0" }, "devDependencies": { "jest": "^29.7.0" diff --git a/rest-express-mongo/public/cp.jpg b/rest-express-mongo/public/cp.jpg new file mode 100644 index 0000000..b4a5839 Binary files /dev/null and b/rest-express-mongo/public/cp.jpg differ diff --git a/rest-express-mongo/public/favicon.ico b/rest-express-mongo/public/favicon.ico new file mode 100644 index 0000000..75d7b7a Binary files /dev/null and b/rest-express-mongo/public/favicon.ico differ diff --git a/rest-express-mongo/public/pengu.jpg b/rest-express-mongo/public/pengu.jpg new file mode 100644 index 0000000..626ea6f Binary files /dev/null and b/rest-express-mongo/public/pengu.jpg differ diff --git a/rest-express-mongo/utils/logger.js b/rest-express-mongo/utils/logger.js new file mode 100644 index 0000000..78da0b1 --- /dev/null +++ b/rest-express-mongo/utils/logger.js @@ -0,0 +1,41 @@ +// utils/logger.js +const winston = require('winston'); +const { combine, timestamp, printf, colorize, errors } = winston.format; +const path = require('path'); + +// Custom log format +const logFormat = printf(({ level, message, timestamp, stack }) => { + return `${timestamp} [${level}]: ${stack || message}`; +}); + +// Create logger instance +const logger = winston.createLogger({ + level: 'debug', + format: combine( + colorize(), + timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + errors({ stack: true }), + logFormat + ), + transports: [ + // Console transport + new winston.transports.Console(), + // Combined log file + new winston.transports.File({ + filename: path.join(__dirname, '../logs/combined.log'), + level: 'info' + }), + // Error log file + new winston.transports.File({ + filename: path.join(__dirname, '../logs/errors.log'), + level: 'error' + }) + ] +}); + +// For morgan HTTP request logging +logger.stream = { + write: (message) => logger.http(message.trim()) +}; + +module.exports = logger; \ No newline at end of file