Request logging with morgan
A log is a record of every event on the server: who requested which address and when, and how the server answered. Logs help you find errors and understand what is happening on the site. In the middleware lesson we wrote such a function ourselves; the morgan package does this with ready-made formats.
Installing and enabling
npm install morganAdd morgan as the first middleware in src/app.js so it sees every request:
// src/app.js
import morgan from 'morgan';
const app = express();
app.use(morgan('dev'));Open a few blog pages. The terminal shows lines like GET /posts 200 4.512 ms - 1520: the method, address, status code, handling time and response size. The codes are coloured: success in green, errors in red.
Formats
| Format | Purpose |
|---|---|
dev | Short coloured output for development |
tiny | The minimum: method, address, code, time |
common | The standard web server format |
combined | Like common, plus where the visitor came from and their browser |
Different logs for development and the server
On a production server colours are not needed, and more details are. Choose the format by the setting from src/config.js:
// src/app.js
import { config } from './config.js';
app.use(morgan(config.isProduction ? 'combined' : 'dev'));When started with NODE_ENV=production, the lines get longer and contain the visitor's IP address, the date and the browser.
Writing to a file
The stream option sends the log to a file instead of the terminal:
// src/app.js
import fs from 'node:fs';
const accessLog = fs.createWriteStream('logs/access.log', { flags: 'a' });
app.use(morgan('combined', { stream: accessLog }));The 'a' flag appends lines to the end of the file instead of overwriting it. Create the logs/ folder beforehand and add it to .gitignore. More often, though, the log stays on standard output and the process manager collects it — see the deployment lesson.
Errors only
The skip option skips some requests. This way you can log only error responses:
// src/app.js
app.use(morgan('combined', {
skip: (req, res) => res.statusCode < 400,
}));Only responses with code 400 and above reach the log.
Application errors
morgan logs requests, but not exception details. Those are printed by the error handler from the middleware chapter, with the line console.error(error). Together the two records show which request broke what.
Common mistake
Do not log passwords, tokens or form contents. The combined format writes only the address, so a password from a POST body does not get there. But if you pass secrets in the query string, such as /reset?token=..., they end up in the log. Send secrets in the request body or in headers.