Zwei Bash-Skripte zur Analyse der NGINX Access Logs

Beim Durchwühlen des Internets bin ich auf eine Perle gestoßen, die ich hier festhalten möchte. In „Bash Script to Parse and Analyze Nginx Access Logs“ stellt Ruan Bekker ein kurzes Bash-Skript vor, welches die NGINX Access Logs analysiert, um einen Bericht mit folgenden Sektionen auszugeben:

  • Top 10 Request IPs (aus dem aktuellen Access Log)
  • Top Request Methods (aus dem aktuellen Access Log)
  • Top 10 Request Pages (aus dem aktuellen Access Log)
  • Top 10 Request Pages (aus dem aktuellen und Gzipten Logs)
  • Top 10 HTTP 404 Page Responses (aus dem aktuellen und Gzipten Logs)

Ich selbst nutze aktuell den Fork von Marc Brunet, welchen ich meinen My-IT-Scripts hinzugefügt habe:

#!/bin/bash

# URL: https://github.com/Tronde/My-IT-Scripts/blob/master/bash/analyze_nginx_access_logs.sh

# variables
LOGFILE="/var/www/jkastning/sites/logs/www.my-it-brain.de_access.log"
LOGFILE_GZ="/var/www/jkastning/sites/logs/www.my-it-brain.de_access.log.*"
RESPONSE_CODE="200"

# functions
filters(){
grep -w $RESPONSE_CODE \
| grep -v "\/rss\/" \
| grep -v robots.txt \
| grep -v "\.css" \
| grep -v "\.jss*" \
| grep -v "\.png" \
| grep -v "\.ico"
}

filters_404(){
grep -w "404"
}

request_ips(){
awk '{print $1}'
}

request_method(){
awk '{print $6}' \
| cut -d'"' -f2
}

request_pages(){
awk '{print $7}'
}

wordcount(){
sort \
| uniq -c
}

sort_desc(){
sort -rn
}

return_kv(){
awk '{print $1, $2}'
}

request_pages(){
awk '{print $7}'
}

return_top_ten(){
head -10
}

## actions
get_request_ips(){
echo ""
echo "Top 10 Request IP's:"
echo "===================="

cat $LOGFILE \
| filters \
| request_ips \
| wordcount \
| sort_desc \
| return_kv \
| return_top_ten
echo ""
}

get_request_methods(){
echo "Top Request Methods:"
echo "===================="
cat $LOGFILE \
| filters \
| request_method \
| wordcount \
| return_kv
echo ""
}

get_request_pages_404(){
echo "Top 10: 404 Page Responses:"
echo "==========================="
zgrep '-' $LOGFILE $LOGFILE_GZ\
| filters_404 \
| request_pages \
| wordcount \
| sort_desc \
| return_kv \
| return_top_ten
echo ""
}


get_request_pages(){
echo "Top 10 Request Pages:"
echo "====================="
cat $LOGFILE \
| filters \
| request_pages \
| wordcount \
| sort_desc \
| return_kv \
| return_top_ten
echo ""
}

get_request_pages_all(){
echo "Top 10 Request Pages from All Logs:"
echo "==================================="
zgrep '-' --no-filename $LOGFILE $LOGFILE_GZ \
| filters \
| request_pages \
| wordcount \
| sort_desc \
| return_kv \
| return_top_ten
echo ""
}

# executing
get_request_ips
get_request_methods
get_request_pages
get_request_pages_all
get_request_pages_404

Selbstverständlich erhalte ich damit keine genauen Statistiken, da meine Logs nach einem Monat automatisch gelöscht werden. Für einen kurzen Rückblick und der Erstellung eines monatlichen Berichts scheint das kleine Skript jedoch gut geeignet zu sein. Ich probiere es gerade aus, um zu sehen, wie gut es mir auf Dauer gefällt.

Auf Basis des ersten Skripts habe ich ein zweites geschrieben, mit dessen Hilfe ich die Requests für einen spezifischen Beitrag abfragen kann (Quelle):

#!/bin/bash

# variables
LOGFILE="/var/www/jkastning/sites/logs/www.my-it-brain.de_access.log"
LOGFILE_GZ="/var/www/jkastning/sites/logs/www.my-it-brain.de_access.log.*"
RESPONSE_CODE="200"
ARG1=$1

# functions
filters(){
grep -w $RESPONSE_CODE \
| grep -v "\/rss\/" \
| grep -v robots.txt \
| grep -v "\.css" \
| grep -v "\.jss*" \
| grep -v "\.png" \
| grep -v "\.ico"
}

request_ips(){
awk '{print $1}'
}

request_page(){
awk '{print $7}' \
| grep -w $ARG1
}

wordcount(){
sort \
| uniq -c
}

return_kv(){
awk '{print $1, $2}'
}

get_request_page(){
echo "Page requests in current log:"
echo "====================="
cat $LOGFILE \
| filters \
| request_page \
| wordcount \
| return_kv
echo ""
}

get_request_page_all(){
echo "Page requests in all logs (last month):"
echo "==================================="
zgrep '-' --no-filename $LOGFILE $LOGFILE_GZ \
| filters \
| request_page \
| wordcount \
| return_kv
echo ""
}

# execute
get_request_page
get_request_page_all

Der folgende Code-Block zeigt ein Beispiel, wie das Skript angewendet wird. Dabei wird der Permalink als Argument übergeben:

:~/bin$ sh get_page_requests_from_nginx_access_logs.sh kommentar-linux-container-spreu-und-weizen
Page requests in current log:
=====================
262 /wordpress/kommentar-linux-container-spreu-und-weizen/
6 /wordpress/kommentar-linux-container-spreu-und-weizen/feed/

Page requests in all logs (last month):
===================================
5124 /wordpress/kommentar-linux-container-spreu-und-weizen/
49 /wordpress/kommentar-linux-container-spreu-und-weizen/feed/
2 /wordpress/wp-json/oembed/1.0/embed?url=https://www.my-it-brain.de/wordpress/kommentar-linux-container-spreu-und-weizen/

Noch nicht schön, aber zweckmäßig.

Was haltet ihr davon? Falls ihr beim Drübergucken zufällig noch einen Fehler in den Skripten entdeckt, freue ich mich, wenn ihr mir einen Kommentar hinterlasst.

6 Kommentare zu „Zwei Bash-Skripte zur Analyse der NGINX Access Logs

    1. Jörg Kastning Beitragsautor

      Guten Morgen Dirk.
      Und Danke für den Tipp. Goaccess ist direkt auf meine „Muss ich mir anschauen Liste“ gewandert. :)

      *Jedi-Geste* Du möchtest kein JavaScript. *Jedi-Geste*
      *Jedi-Geste* Du möchtest darüber nachdenken, wie es ohne JavaScript noch scöner geht. *Jedi-Geste*

      Hab einen schönen Tag. :)

      Antworten
  1. Bernd

    Es gibt ansehnliche Webanalyzer, die aber in die Seite eingebunden werden müssen und leicht ausgetrickst werden können. Das über Log-File-Analyse zu machen ist smarter. Ich mache lieber das.

    Auf der Suche nach Inspiration, habe ich diese Seite gefunden. Danke fürs Teilen!

    Ich habe das Bekker-Script auch um ein paar Funktionen erweitert. Nun lasse ich mir auch die Top Domain Aufrufe, Top Domain All Aufrufe und Top Bad Boy Aufrufe anzeigen. Letztere mit Hilfe von fail2ban, der den Statuscode sowieso auf 444 ändert, um die IP ggf. in die Firewall zu schreiben.

    Die Domain der aufgerufenen Seite trägt Nginx normalerweise nicht mit ins Log ein. Dafür gibt es die Direktive log_format, die ich entsprechend in die nginx.conf eingetragen habe. Ich habe den Host ans Ende verschoben, um die Filter von fail2ban weiter ohne Änderung nutzen zu können.

    Fall du interessiert bist, melde dich. Steht aber auch in der Nginx-Dokumentation, wie man das macht.

    Antworten
    1. Jörg Kastning Beitragsautor

      Hallo Bernd,
      hast du die erweiterte Version des Skripts zufällig irgendwo in einem öffentlichen Repository abgelegt? Falls nicht, magst du sie mir anderweitig zukommen lassen? Ich habe schon interesse daran mir das mal anzusehen.

      Viele Grüße
      Jörg

      Antworten

Antworte auf den Kommentar von Dirk Deimeke Antwort abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert