Skip to content

Commit 116b87f

Browse files
committed
logging implemented
1 parent 810450d commit 116b87f

File tree

8 files changed

+421
-4
lines changed

8 files changed

+421
-4
lines changed

server/app.js

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ const orderProductRouter = require('./routes/customer_order_product');
1313
const wishlistRouter = require('./routes/wishlist');
1414
var cors = require("cors");
1515

16+
// Import logging middleware
17+
const {
18+
addRequestId,
19+
requestLogger,
20+
errorLogger,
21+
securityLogger
22+
} = require('./middleware/requestLogger');
23+
1624
// Import rate limiting middleware
1725
const {
1826
generalLimiter,
@@ -33,6 +41,21 @@ const {
3341

3442
const app = express();
3543

44+
// Trust proxy for accurate IP addresses
45+
app.set('trust proxy', 1);
46+
47+
// Add request ID to all requests
48+
app.use(addRequestId);
49+
50+
// Security logging (check for suspicious patterns)
51+
app.use(securityLogger);
52+
53+
// Standard request logging
54+
app.use(requestLogger);
55+
56+
// Error logging (only logs 4xx and 5xx responses)
57+
app.use(errorLogger);
58+
3659
const allowedOrigins = [
3760
'http://localhost:3000',
3861
'http://localhost:3001',
@@ -104,7 +127,8 @@ app.get('/health', (req, res) => {
104127
res.status(200).json({
105128
status: 'OK',
106129
timestamp: new Date().toISOString(),
107-
rateLimiting: 'enabled'
130+
rateLimiting: 'enabled',
131+
requestId: req.reqId
108132
});
109133
});
110134

@@ -118,12 +142,31 @@ app.get('/rate-limit-info', (req, res) => {
118142
search: '30 searches per minute',
119143
orders: '15 order operations per 15 minutes',
120144
wishlist: '20 operations per 5 minutes',
121-
products: '60 requests per minute'
145+
products: '60 requests per minute',
146+
requestId: req.reqId
147+
});
148+
});
149+
150+
// 404 handler
151+
app.use('*', (req, res) => {
152+
res.status(404).json({
153+
error: 'Route not found',
154+
requestId: req.reqId
155+
});
156+
});
157+
158+
// Global error handler
159+
app.use((err, req, res, next) => {
160+
console.error('Error:', err.message);
161+
res.status(500).json({
162+
error: 'Internal server error',
163+
requestId: req.reqId
122164
});
123165
});
124166

125167
const PORT = process.env.PORT || 3001;
126168
app.listen(PORT, () => {
127169
console.log(`Server running on port ${PORT}`);
128-
console.log('Rate limiting enabled for all endpoints');
170+
console.log('Rate limiting and request logging enabled for all endpoints');
171+
console.log('Logs are being written to server/logs/ directory');
129172
});

server/logs/access.log

Lines changed: 79 additions & 0 deletions
Large diffs are not rendered by default.

server/logs/error.log

Whitespace-only changes.

server/middleware/requestLogger.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
const morgan = require('morgan');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
// Create logs directory if it doesn't exist
6+
const logsDir = path.join(__dirname, '..', 'logs');
7+
if (!fs.existsSync(logsDir)) {
8+
fs.mkdirSync(logsDir, { recursive: true });
9+
console.log('Created logs directory:', logsDir);
10+
}
11+
12+
// Custom format for logging
13+
morgan.token('reqId', (req) => req.reqId || 'unknown');
14+
morgan.token('userId', (req) => req.user?.id || 'anonymous');
15+
16+
// Create a simple log format
17+
const logFormat = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" reqId=:reqId userId=:userId';
18+
19+
// Create write stream for combined logs
20+
const accessLogStream = fs.createWriteStream(
21+
path.join(logsDir, 'access.log'),
22+
{ flags: 'a' }
23+
);
24+
25+
// Create write stream for error logs
26+
const errorLogStream = fs.createWriteStream(
27+
path.join(logsDir, 'error.log'),
28+
{ flags: 'a' }
29+
);
30+
31+
// Middleware to add request ID
32+
const addRequestId = (req, res, next) => {
33+
req.reqId = require('nanoid').nanoid(8);
34+
res.setHeader('X-Request-ID', req.reqId);
35+
next();
36+
};
37+
38+
// Standard request logger
39+
const requestLogger = morgan(logFormat, {
40+
stream: accessLogStream,
41+
skip: (req, res) => req.url === '/health' // Skip health checks
42+
});
43+
44+
// Error logger (only logs 4xx and 5xx responses)
45+
const errorLogger = morgan(logFormat, {
46+
stream: errorLogStream,
47+
skip: (req, res) => res.statusCode < 400
48+
});
49+
50+
// Security logger for suspicious activity
51+
const securityLogger = (req, res, next) => {
52+
// Log suspicious patterns
53+
const suspiciousPatterns = [
54+
/script.*alert/i,
55+
/union.*select/i,
56+
/drop.*table/i,
57+
/<script/i,
58+
/javascript:/i
59+
];
60+
61+
const url = req.url.toLowerCase();
62+
const userAgent = (req.get('User-Agent') || '').toLowerCase();
63+
64+
for (const pattern of suspiciousPatterns) {
65+
if (pattern.test(url) || pattern.test(userAgent)) {
66+
const logEntry = {
67+
timestamp: new Date().toISOString(),
68+
type: 'SECURITY_ALERT',
69+
ip: req.ip || req.connection.remoteAddress,
70+
method: req.method,
71+
url: req.url,
72+
userAgent: req.get('User-Agent'),
73+
reqId: req.reqId,
74+
pattern: pattern.source
75+
};
76+
77+
fs.appendFileSync(
78+
path.join(logsDir, 'security.log'),
79+
JSON.stringify(logEntry) + '\n'
80+
);
81+
}
82+
}
83+
84+
next();
85+
};
86+
87+
module.exports = {
88+
addRequestId,
89+
requestLogger,
90+
errorLogger,
91+
securityLogger
92+
};

server/package-lock.json

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"start": "node app.js",
9+
"logs": "node view-logs.js",
10+
"logs:access": "node view-logs.js access",
11+
"logs:error": "node view-logs.js error",
12+
"logs:security": "node view-logs.js security",
13+
"logs:analyze": "node view-logs.js analyze"
814
},
915
"keywords": [],
1016
"author": "",
@@ -15,6 +21,7 @@
1521
"bcryptjs": "^2.4.3",
1622
"cors": "^2.8.5",
1723
"express": "^4.18.3",
24+
"morgan": "^1.10.0",
1825
"mysql": "^2.18.1",
1926
"nanoid": "^5.0.6",
2027
"prisma": "^5.12.1"

server/test-logging.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const http = require('http');
2+
3+
console.log('Testing logging system...\n');
4+
5+
// Test health endpoint
6+
http.get('http://localhost:3001/health', (res) => {
7+
console.log('✓ Health check completed');
8+
});
9+
10+
// Test products endpoint
11+
http.get('http://localhost:3001/api/products', (res) => {
12+
console.log('✓ Products endpoint completed');
13+
});
14+
15+
// Test 404 endpoint
16+
http.get('http://localhost:3001/nonexistent', (res) => {
17+
console.log('✓ 404 test completed');
18+
});
19+
20+
// Test suspicious request
21+
http.get('http://localhost:3001/api/products?q=<script>alert("xss")</script>', (res) => {
22+
console.log('✓ Security test completed');
23+
});
24+
25+
setTimeout(() => {
26+
console.log('\nTest completed. Check logs with: npm run logs');
27+
}, 2000);

0 commit comments

Comments
 (0)