Summary: This guide covers end-to-end steps for setting up structured logging in a Dockerized Node.js app using Winston, mapping logs to the EC2 host, and streaming them to AWS CloudWatch Logs. It includes all details and road bumps encountered.
CloudWatchAgentServerPolicy)
cd backend
npm install winston --save
Check and commit updated package.json and
package-lock.json.
logger.js
Inside backend directory:
const winston = require('winston');
const path = require('path');
const fs = require('fs');
const logDir = path.join(__dirname, 'logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: path.join(logDir, 'app.log') }),
new winston.transports.Console()
],
});
module.exports = logger;
server.js
const logger = require('./logger');
logger.info('Server starting...');
logger.error('Error connecting to DB');
// Replace any console.log() with logger.info() or logger.error().
git add package.json package-lock.json logger.js server.js
git commit -m "Add Winston logger with file and console support"
git push origin main
Check GitLab CI/CD pipeline → confirm it runs successfully.
docker-compose.yml
version: "3.8"
services:
frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- backend
restart: always
backend:
build: ./backend
ports:
- "5000:5000"
env_file:
- ./backend/.env
depends_on:
- mongo
restart: always
volumes:
- ./backend/logs:/app/logs
mongo:
image: mongo
ports:
- "27017:27017"
restart: always
On EC2 host:
mkdir -p ~/networth-Tracker/backend/logs
⚠️ Road bump: Container restart loop
Container
failed to start due to missing winston. Solved by running
npm install winston, committing, pushing, and
rebuilding Docker image.
⚠️ Road bump: Logs missing on host
Initially
logs existed only inside container. Fixed by adding Docker volume
mapping and creating host logs directory.
ssh -i your-key.pem ubuntu@<your-ec2-ip>
cd ~/networth-Tracker
git pull origin main
docker-compose down
docker-compose up --build -d
Check logs:
ls -l ~/networth-Tracker/backend/logs/
cat ~/networth-Tracker/backend/logs/app.log
✅ You should see log entries.
sudo apt update
sudo apt install -y amazon-cloudwatch-agent
sudo nano /opt/aws/amazon-cloudwatch-agent/bin/config.json
Paste:
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"metrics": {
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
},
"metrics_collected": {
"cpu": {
"measurement": ["cpu_usage_idle", "cpu_usage_user", "cpu_usage_system"],
"metrics_collection_interval": 60
},
"mem": {
"measurement": ["mem_used_percent"],
"metrics_collection_interval": 60
},
"disk": {
"measurement": ["used_percent"],
"metrics_collection_interval": 60,
"resources": ["/"]
}
}
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/home/ubuntu/networth-Tracker/backend/logs/app.log",
"log_group_name": "networth-tracker-logs",
"log_stream_name": "{instance_id}"
}
]
}
}
}
}
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a status
Go to CloudWatch → Logs → Log groups. You should see log streams from your app.