Morgan Node.js - Logs HTTP efficaces pour votre API Express

Xavier Moreau .

28 avril 2026

Logo MORGAN avec icônes JavaScript et code, évoquant le développement web et le npm.

Dans une API Node.js, les logs de requêtes HTTP sont souvent le premier outil qui permet de comprendre un incident, de mesurer une lenteur ou de vérifier qu’un reverse proxy transmet bien les bonnes informations. Le package morgan npm sert précisément à ça: produire des access logs lisibles, simples à brancher dans Express et assez souples pour s’adapter à un backend local, une API de production ou un service derrière un load balancer. Dans cet article, je vais montrer ce qu’il fait vraiment, comment je l’intègre proprement, quels formats choisir et où sont ses limites.

L’essentiel à garder avant de brancher Morgan sur une API

  • Morgan journalise les requêtes HTTP, pas les événements métier de l’application.
  • Le bon emplacement du middleware change directement la qualité des logs que vous récupérez.
  • `combined`, `common`, `dev` et `tiny` n’ont pas le même niveau de détail ni le même usage.
  • `skip` et `immediate` servent à réduire le bruit ou à capturer une requête au plus tôt.
  • En production, je combine souvent Morgan avec une sortie fichier, une rotation de logs et une politique de rétention claire.

Terminal affichant les logs d'une application Node.js, avec des messages d'info, d'avertissement, d'erreur et fatals. L'outil `morgan npm` est utilisé pour le logging.

À quoi sert Morgan dans une API Node.js

Je l’utilise quand je veux voir, en une ligne, qui appelle quoi, avec quel statut, et en combien de millisecondes. Morgan est un middleware de journalisation d’accès HTTP: il observe le trafic qui traverse Express et écrit des lignes de log avec des informations comme la méthode, l’URL, le code de réponse, la taille de la réponse, le referer, l’user-agent ou le temps de réponse.

Ce point est important: Morgan n’est pas un logger applicatif complet. Il ne remplace ni les logs métier, ni la télémétrie, ni les traces distribuées. En revanche, pour le diagnostic quotidien d’une API, il donne immédiatement de la visibilité sur les routes lentes, les erreurs 4xx/5xx et les appels inattendus. Autrement dit, il couvre très bien la couche HTTP, et c’est déjà énorme.

  • Je m’en sers pour vérifier qu’un endpoint reçoit bien du trafic.
  • Je l’active pour repérer rapidement les réponses en erreur.
  • Je l’exploite pour relier une plainte utilisateur à une requête concrète.
  • Je l’emploie aussi pour suivre les temps de réponse sans ouvrir un outil plus lourd.

Une fois ce rôle clair, la vraie question devient simple: comment le brancher sans rater des requêtes et sans noyer l’équipe sous le bruit inutile ?

Le brancher correctement dans Express

L’intégration de base est volontairement simple. On installe le package, on charge le middleware et on le place avant les routes que l’on veut observer. C’est ce placement qui évite une partie des erreurs classiques: si Morgan arrive trop bas dans la pile, certaines requêtes auront déjà été consommées par d’autres middlewares ou routes, et elles ne remonteront pas comme prévu.

const express = require('express');
const morgan = require('morgan');

const app = express();

app.use(morgan('combined'));

app.get('/health', (req, res) => {
  res.json({ ok: true });
});

app.get('/users', (req, res) => {
  res.json([]);
});

app.listen(3000, () => {
  console.log('API en écoute sur le port 3000');
});

Dans une API structurée, je préfère souvent le placer très tôt dans la chaîne, avant les routes, et parfois avant certains middlewares de transformation qui peuvent terminer la requête ou court-circuiter le flux. Si je veux limiter la journalisation à une partie de l’application, je peux aussi le monter sur un router précis plutôt que sur toute l’app. C’est utile quand on veut un comportement différent pour `/api`, `/admin` ou un sous-domaine interne.

Le point à retenir est pragmatique: Morgan doit voir passer la requête au bon endroit. Sinon, il logue moins que prévu, ou pas avec le contexte que vous attendiez. Une fois l’intégration en place, le choix du format devient le levier principal pour rendre ces logs vraiment utiles.

Choisir le bon format de journalisation

Le format n’est pas un détail esthétique. Il détermine la densité des logs, leur lisibilité et leur valeur en production. Pour moi, le bon format dépend surtout de deux choses: le volume de trafic et le niveau d’enquête dont l’équipe a besoin.

Format Ce qu’il apporte Quand je l’utilise Limite principale
combined Contexte riche avec IP, date, méthode, URL, statut, taille, referer et user-agent Production, staging, API qu’on veut diagnostiquer vite Plus verbeux que les autres
common Version plus légère du log Apache classique Quand je veux garder l’essentiel en réduisant le bruit Moins de contexte pour analyser un incident
dev Sortie lisible, colorée, très pratique en local Développement et débogage manuel Trop bavard pour une prod sérieuse
tiny Format minimal avec le strict nécessaire Services à fort trafic ou besoins de logs compacts Peu d’indices quand il faut enquêter
Format personnalisé Je choisis exactement les champs utiles Quand j’ai un besoin métier ou une contrainte d’observabilité Demande un peu plus de maintenance

Pour les mesures de performance, je fais bien la différence entre :response-time et :total-time. Le premier mesure le temps jusqu’à l’écriture des en-têtes de réponse; le second va jusqu’à la fin réelle de l’écriture sur la connexion. Sur une API qui renvoie des payloads un peu lourds, cet écart peut être intéressant à suivre.

Quand j’ai besoin d’un format plus riche, j’ajoute souvent un jeton personnalisé, par exemple un identifiant de requête ou un PID quand plusieurs processus Node tournent en parallèle. C’est ce genre de détail qui fait gagner du temps au moment d’aligner plusieurs logs sur un même incident.

const express = require('express');
const morgan = require('morgan');

morgan.token('request-id', (req) => req.headers['x-request-id'] || '-');

const app = express();
app.use(morgan(':request-id :method :url :status :response-time ms'));

Le bon format n’est donc pas le plus long, mais le plus exploitable. Une fois ce réglage posé, il reste à éviter le bruit superflu sans perdre les signaux utiles.

Réduire le bruit sans perdre l’information utile

Deux options changent vraiment la façon dont je travaille avec Morgan: `skip` et `immediate`. La première sert à exclure des requêtes qui n’apportent rien à l’analyse, comme `/health`, `/metrics` ou certains assets techniques. La seconde enregistre la requête dès son arrivée, avant la réponse, ce qui peut sauver une ligne si le serveur plante en cours de traitement.

const express = require('express');
const fs = require('fs');
const path = require('path');
const morgan = require('morgan');

const app = express();

const accessLogStream = fs.createWriteStream(
  path.join(process.cwd(), 'access.log'),
  { flags: 'a' }
);

app.use(morgan('combined', { stream: accessLogStream }));

app.use(morgan('dev', {
  skip: (req, res) => req.originalUrl === '/health' || req.originalUrl === '/metrics'
}));

Ce type de montage est utile parce que Morgan peut être utilisé plusieurs fois. Je peux envoyer tous les accès dans un fichier, tout en gardant les erreurs visibles en console. En pratique, c’est un compromis très sain: le flux principal reste exploitable par les outils d’observabilité, et les anomalies ressortent localement pendant le développement ou les tests.

Il y a toutefois un vrai arbitrage avec immediate. Oui, j’obtiens une trace plus tôt, mais je perds les données de réponse, donc le statut, la longueur et les temps de fin ne sont plus disponibles. Je réserve donc ce mode aux cas où le risque de crash ou d’interruption vaut davantage que la finesse du log. Pour tout le reste, le mode standard est plus utile.

Le bruit n’est pas seulement une question de volume. C’est aussi une question de conservation, de rotation et de qualité du signal. Une API bien instrumentée logue peu, mais logue juste.

Les pièges que je surveille avant la mise en production

Le premier piège, c’est l’emplacement du middleware. Morgan ne logue que ce qui passe réellement à travers lui. Si une route ou un autre middleware termine la réponse avant lui, la ligne de log ne sortira pas comme prévu. Sur un projet Express un peu ancien, je vérifie toujours l’ordre des app.use() avant de chercher un problème plus complexe.

Le deuxième piège, c’est le contexte réseau. Quand l’application est derrière un reverse proxy ou un load balancer, l’adresse client affichée par :remote-addr peut être celle du proxy au lieu du navigateur ou du client réel. Dans ce cas, je configure Express avec trust proxy avec précaution, parce que cette option ne doit jamais être activée à l’aveugle. Il faut qu’elle corresponde exactement à l’architecture réseau, sinon on ouvre la porte à des valeurs de confiance mal interprétées.

Le troisième piège, c’est la fuite d’information. Une URL journalisée peut contenir un token dans une chaîne de requête, et un token personnalisé peut exposer un identifiant sensible si je ne le filtre pas. Dans les APIs exposées au public, je fais donc attention aux paramètres, aux en-têtes récupérés dans des jetons custom et aux données personnelles qui peuvent se retrouver dans les logs sans que l’équipe s’en rende compte.

  • Je limite ce que j’ajoute dans les formats personnalisés.
  • Je contrôle les endpoints de santé pour éviter les milliers de lignes inutiles.
  • Je m’assure que la rétention des logs est cohérente avec l’usage réel.
  • Je vérifie que les accès aux fichiers ou au collecteur central sont bien restreints.

Enfin, je garde un œil sur la version installée. La branche récente du package a ajouté le jeton :pid et a corrigé un point de sécurité autour de :remote-user, ce qui rappelle une règle simple: un logger d’accès n’est pas un composant neutre, il mérite les mêmes réflexes de mise à jour que le reste de la pile backend.

Le réglage minimal que je recommande pour une API sérieuse

Si je devais résumer ma configuration de base pour une API Node.js, je partirais sur une approche très sobre: un format lisible en production, un format plus bavard en local, une sortie adaptée au flux réel et quelques exclusions ciblées. Rien de spectaculaire, mais c’est ce qui tient dans la durée.

  • En local, je garde dev pour lire vite ce qui se passe.
  • En production, je pars souvent sur combined ou sur un format personnalisé plus strict.
  • Pour les endpoints de santé, je coupe le bruit avec skip.
  • Si l’app est derrière un proxy, je valide la stratégie trust proxy avant de me fier à l’IP loguée.
  • Si le trafic augmente, je privilégie une sortie fichier ou un collecteur central avec rotation.
  • Si l’équipe a besoin de corrélation, j’ajoute un identifiant de requête dans un jeton dédié.

Ce que j’aime avec Morgan, c’est sa franchise technique: il fait peu de choses, mais il les fait proprement. Pour une API backend, c’est souvent exactement ce qu’il faut pour diagnostiquer vite sans transformer la journalisation en projet annexe.

Questions fréquentes

Morgan est un middleware Express qui journalise les requêtes HTTP. Il permet de visualiser rapidement les appels, statuts, URLs et temps de réponse, essentiel pour le diagnostic quotidien d'une API en repérant erreurs ou lenteurs.
Il faut installer le package et placer le middleware Morgan via `app.use(morgan('format'))` très tôt dans la chaîne de middlewares. Cela assure que toutes les requêtes sont capturées avant d'être potentiellement traitées ou court-circuitées par d'autres routes.
Le choix dépend du contexte : `dev` pour le développement (lisible, coloré), `combined` pour la production (riche en infos), ou `tiny` pour les services à fort trafic (compact). Des formats personnalisés permettent d'inclure des champs spécifiques comme un ID de requête.
Utilisez l'option `skip` pour exclure des requêtes non pertinentes (ex: `/health`). Vous pouvez aussi configurer plusieurs instances de Morgan pour envoyer tous les logs à un fichier et n'afficher que les erreurs en console, optimisant ainsi la clarté.
Surveillez l'emplacement du middleware pour ne pas rater de logs, configurez `trust proxy` si l'API est derrière un reverse proxy, et faites attention à la fuite d'informations sensibles dans les URLs ou les jetons personnalisés. Mettez à jour le package régulièrement.

Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

morgan npm morgan express morgan production
Autor Xavier Moreau
Xavier Moreau
Je m'appelle Xavier Moreau et je cumule 14 ans d'expérience dans le développement web, avec un accent particulier sur JavaScript, le backend, le NoSQL et la sécurité. Mon intérêt pour ces domaines a émergé dès mes débuts dans la programmation, où j'ai découvert la puissance des technologies web et leur capacité à transformer des idées en réalité. J'aime expliquer des concepts complexes de manière accessible, en aidant les lecteurs à naviguer dans les défis techniques qu'ils rencontrent. Au fil des ans, j'ai développé une expertise solide en vérifiant mes sources, en comparant les informations et en simplifiant des sujets parfois ardus. Je m'efforce toujours de fournir des contenus utiles, précis et à jour, en suivant les tendances du secteur et en organisant mes connaissances de manière claire. Mon objectif est d'accompagner les passionnés et les professionnels du développement web dans leur quête de compréhension et d'innovation.

Commentaires (0)

Ajouter un commentaire