Monitoring and Logging
Monitoring and Logging
Once your API is live, you need visibility into what is happening. Logging records events in your application. Monitoring observes your app's health over time and alerts you when something goes wrong. Without these, production issues are invisible until users complain.
Structured Logging with Winston
Winston is the most popular logging library for Node.js. It supports multiple log levels, multiple output transports (console, file, external services), and structured JSON logging.
npm install winston
// utils/logger.js
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
),
}),
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' }),
],
});
module.exports = logger;
Log Levels
Winston provides six log levels in ascending severity:
| Level | Use case |
|---|---|
| silly | Extremely detailed debugging |
| debug | Development debugging |
| verbose | Detailed but not debug |
| info | Normal application events |
| warn | Potential problems, not yet errors |
| error | Errors that need attention |
const logger = require('./utils/logger');
logger.info('Server started on port 3000');
logger.info('User logged in', { userId: user._id, email: user.email });
logger.warn('Rate limit approaching for IP', { ip: req.ip, count: 95 });
logger.error('Database connection failed', { error: err.message, stack: err.stack });
logger.debug('Query executed', { collection: 'users', duration: '12ms' });
Request Logging Middleware
// Log every request with method, URL, status, and duration
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info('HTTP Request', {
method: req.method,
url: req.url,
status: res.statusCode,
duration: duration + 'ms',
ip: req.ip,
});
});
next();
});
Or use morgan integrated with Winston:
const morgan = require('morgan');
app.use(morgan('dev'));
Health Check Endpoint
A health check endpoint lets load balancers and uptime monitors verify your app is running:
app.get('/health', async (req, res) => {
const dbStatus = mongoose.connection.readyState === 1 ? 'connected' : 'disconnected';
res.json({
status: 'ok',
uptime: Math.floor(process.uptime()) + 's',
timestamp: new Date().toISOString(),
database: dbStatus,
memory: process.memoryUsage().heapUsed,
});
});
Error Tracking with Sentry
Sentry automatically captures unhandled exceptions and sends them to a dashboard with stack traces, user context, and environment details.
npm install @sentry/node
const Sentry = require('@sentry/node');
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
});
// Sentry middleware must come before routes
app.use(Sentry.Handlers.requestHandler());
// Routes...
// Sentry error handler must come BEFORE your error handler
app.use(Sentry.Handlers.errorHandler());
// Your error handler
app.use((err, req, res, next) => {
logger.error('Unhandled error', { error: err.message });
res.status(500).json({ error: 'Internal server error' });
});
Key Takeaways
- Logging records events; monitoring watches for problems over time and sends alerts.
- Winston provides structured JSON logging with configurable levels and transports.
- Use the correct log level: info for normal events, warn for potential issues, error for failures.
- A /health endpoint lets monitoring services verify your app is running and the database is connected.
- Sentry catches unhandled exceptions in production and provides full stack traces with context.
Practice Exercise
- Install winston and create a
utils/logger.jswith console and file transports. - Replace all
console.logandconsole.errorcalls in your app with the appropriate logger methods. - Add a request-logging middleware that records method, URL, status code, and response time for every request.
- Create a
GET /healthendpoint that returns uptime, database status, and a timestamp.
Try it yourself
Key Takeaways
- Winston provides production-grade structured JSON logging with configurable levels and multiple output transports.
- Use the correct log level: debug for development details, info for normal events, warn for potential issues, error for failures.
- A /health endpoint lets load balancers and monitoring services verify your app is running correctly.
- Sentry captures unhandled exceptions automatically in production and provides context-rich error reports.
- Structured logs (JSON) are machine-readable and can be searched, filtered, and aggregated in monitoring dashboards.
Quick Quiz
1.Which log level should you use when your application encounters a critical failure that needs immediate attention?
2.What is structured logging?
3.What information should a /health endpoint return?
4.What does Sentry do for a Node.js application?
Ready to go further?
CareerEx gives you structured 12-week training, live classes every Saturday and Sunday, real tutor feedback, and a certificate. Join the next cohort.
Join CareerEx