Objectifs
- Appliquer les connaissances acquises (boucles, pipes,
grep,awk) pour créer un outil concret. - Lire et analyser un fichier de log de serveur web.
- Extraire des informations structurées (IP, statut, URL) à partir de texte non structuré.
- Calculer des statistiques simples, comme le nombre d’erreurs ou les adresses IP les plus actives.
- Produire un résumé lisible des indicateurs clés (KPIs).
Le Scénario
Vous êtes administrateur système et vous devez analyser rapidement un fichier de log d’un serveur web Nginx pour comprendre ce qu’il s’est passé. Vous voulez connaître le nombre total de requêtes, identifier les erreurs et repérer les visiteurs les plus fréquents.
Format d’un log Nginx type
Chaque ligne ressemble à ceci. On voit l’adresse IP, la date, la requête HTTP, le code de statut, etc.
1.2.3.4 - - [10/Oct/2025:13:55:36 +0000] "GET /index.html HTTP/1.1" 200 5039 ...
Les Outils à Combiner
catou une redirection<pour lire le fichier.greppour filtrer les lignes intéressantes (ex: celles avec un code d’erreur).awkpour découper chaque ligne en colonnes et extraire des champs spécifiques (l’IP, le code de statut).sortpour regrouper les lignes identiques.uniq -cpour compter le nombre d’occurrences de chaque ligne.head/tailpour ne garder que les résultats les plus pertinents.
Le Script Complet
Voici un script complet qui met en œuvre ce projet. Il est basé sur le squelette de la leçon précédente.
#!/usr/bin/env bash
# Mode strict
set -euo pipefail
# --- Documentation ---
# Description:
# Analyse un fichier de log Nginx pour en extraire des statistiques de base.
#
# Usage:
# ./parse_logs.sh <fichier_log>
#
# Options:
# -h Affiche cette aide.
readonly SCRIPT_NAME="$(basename "$0")"
# --- Fonctions ---
die() {
echo >&2 "[ERREUR] $@"
exit 1
}
usage() {
echo "Usage: $SCRIPT_NAME [-h] <fichier_log>"
echo "Analyse un fichier de log Nginx."
exit 0
}
# --- Fonction Principale ---
main() {
# Pas d'options pour ce script simple, mais on garde la structure
while getopts ":h" opt; do
case "$opt" in
h) usage ;;
\?) die "Option invalide. Utilisez -h pour l'aide." ;;
esac
done
shift $((OPTIND - 1))
# Validation des arguments
if [[ $# -ne 1 ]]; then
usage
fi
local LOG_FILE="$1"
if [[ ! -f "$LOG_FILE" ]]; then
die "Le fichier '$LOG_FILE' n'existe pas."
fi
# --- Logique Principale ---
echo "Analyse du fichier de log : $LOG_FILE"
echo "------------------------------------"
# 1. Compter le nombre total de requêtes (nombre de lignes)
local TOTAL_REQUESTS
TOTAL_REQUESTS=$(wc -l < "$LOG_FILE")
echo "Requêtes totales : $TOTAL_REQUESTS"
# 2. Compter les erreurs 404 (Page non trouvée)
# On cherche les lignes contenant ' "404 ' (avec les espaces pour être précis)
local ERRORS_404
# Le '|| true' évite que le script ne s'arrête si grep ne trouve rien
ERRORS_404=$(grep ' "404 ' "$LOG_FILE" | wc -l || true)
echo "Erreurs 404 : $ERRORS_404"
# 3. Trouver le top 5 des adresses IP les plus actives
echo -e "\n--- Top 5 des adresses IP ---"
# awk '{print $1}' -> extrait la 1ère colonne (l'IP)
# sort -> regroupe les IPs identiques les unes à la suite des autres
# uniq -c -> compte chaque groupe d'IPs identiques
# sort -rn -> trie numériquement (-n) et en ordre inverse (-r) pour avoir les plus gros comptes en premier
# head -n 5 -> ne garde que les 5 premières lignes
awk '{ print $1 }' "$LOG_FILE" | sort | uniq -c | sort -rn | head -n 5
echo "------------------------------------"
echo "Analyse terminée."
}
# --- Point d'entrée ---
main "$@"
Bonnes Pratiques Mises en Œuvre
- Structure claire : Le script est découpé en fonctions
main,usage,die. - Validation : On vérifie que l’argument est bien un fichier qui existe avant de commencer.
- Pipes : On enchaîne des outils simples (
awk | sort | uniq | ...) pour construire une logique complexe. C’est la philosophie Unix. - Robustesse : Le
|| trueaprès legrepest une astuce pour s’assurer que le script ne s’arrête pas (à cause deset -e) sigrepne trouve aucune correspondance et renvoie un code d’erreur.
Pièges Évités
- Lecture de gros fichiers : En utilisant des pipes, chaque commande traite le texte ligne par ligne. Le fichier entier n’est jamais chargé en mémoire, ce qui rend le script efficace même sur des fichiers de plusieurs gigaoctets.
- Parsing fragile : Utiliser
awkest beaucoup plus robuste pour extraire des colonnes que des solutions basées surcutavec des délimiteurs d’espace, qui peuvent être incohérents.
Exercices
-
Créer un fichier de log de test :
- Créez un fichier
test.loget copiez-y une dizaine de lignes ressemblant au format Nginx, avec des IPs et des codes de statut variés. - Lancez votre script dessus pour vérifier qu’il fonctionne.
- Créez un fichier
-
Ajouter une statistique :
- Modifiez le script pour qu’il affiche également le top 5 des pages les plus demandées.
- Indice : La page demandée se trouve généralement dans la 7ème colonne du log (ex:
"/index.html").
-
(Avancé) Exporter en CSV :
- Modifiez le script pour qu’il accepte une option
-o <fichier.csv>. - Si cette option est présente, le script doit écrire le top 5 des IPs dans ce fichier au format CSV (
compte,ip). - Indice : Vous devrez reformater la sortie de la dernière commande du pipe avec
awk.
- Modifiez le script pour qu’il accepte une option