Holen Sie das Beste aus Ihren PHP-Protokolldateien heraus: Ein praktischer Leitfaden
Veröffentlicht: 2022-03-11Man könnte zu Recht sagen, dass Protokolle eines der am meisten unterschätzten und am wenigsten genutzten Werkzeuge sind, die einem freiberuflichen PHP-Entwickler zur Verfügung stehen. Trotz der Fülle an Informationen, die sie bieten können, ist es nicht ungewöhnlich, dass Protokolle der letzte Ort sind, an dem ein Entwickler nachsieht, wenn er versucht, ein Problem zu lösen.
Tatsächlich sollten PHP-Logdateien in vielen Fällen der erste Ort sein, an dem nach Hinweisen gesucht wird, wenn Probleme auftreten. Oftmals können die darin enthaltenen Informationen die Zeit, die Sie damit verbringen, sich die Haare auszureißen, um einen knorrigen Fehler aufzuspüren, erheblich reduzieren.
Aber vielleicht noch wichtiger ist, dass Ihre Protokolldateien mit ein wenig Kreativität und Voraussicht als wertvolle Quelle für Nutzungsinformationen und Analysen genutzt werden können. Die kreative Verwendung von Protokolldateien kann helfen, Fragen zu beantworten wie: Welche Browser werden am häufigsten verwendet, um meine Website zu besuchen? Was ist die durchschnittliche Antwortzeit von meinem Server? Wie hoch war der Prozentsatz der Anfragen an den Site-Root? Wie hat sich die Nutzung seit der Bereitstellung der neuesten Updates geändert? Und sehr viel mehr.
Dieser Artikel enthält eine Reihe von Tipps zur Konfiguration Ihrer Protokolldateien sowie zur Verarbeitung der darin enthaltenen Informationen, um den von ihnen bereitgestellten Nutzen zu maximieren.
Obwohl sich dieser Artikel technisch auf die Protokollierung für PHP-Entwickler konzentriert, sind viele der hier präsentierten Informationen ziemlich technologieunabhängig und auch für andere Sprachen und Technologie-Stacks relevant.
Hinweis: Dieser Artikel setzt grundlegende Vertrautheit mit der Unix-Shell voraus. Für diejenigen, denen dieses Wissen fehlt, wird ein Anhang bereitgestellt, der einige der Befehle vorstellt, die für den Zugriff auf und das Lesen von Protokolldateien auf einem Unix-System erforderlich sind.
Unser PHP-Logdatei-Beispielprojekt
Als Beispielprojekt für Diskussionszwecke in diesem Artikel nehmen wir Symfony Standard als funktionierendes Projekt und richten es auf Debian 7 Wheezy mit rsyslogd
, nginx
und PHP-FPM
ein.
composer create-project symfony/framework-standard-edition my "2.6.*"
Dadurch erhalten wir schnell ein funktionierendes Testprojekt mit einer schönen Benutzeroberfläche.
Tipps zum Konfigurieren Ihrer Protokolldateien
Hier sind einige Hinweise, wie Sie Ihre Protokolldateien konfigurieren können, um ihren Wert zu maximieren.
Konfiguration des Fehlerprotokolls
Fehlerprotokolle stellen die grundlegendste Form der Protokollierung dar; dh zusätzliche Informationen und Details erfassen, wenn Probleme auftreten. In einer idealen Welt möchten Sie also, dass keine Fehler auftreten und Ihre Fehlerprotokolle leer sind. Aber wenn Probleme auftreten (was immer der Fall ist), sollten Ihre Fehlerprotokolle einer der ersten Stopps sein, die Sie auf Ihrem Debugging-Trail machen.
Fehlerprotokolle sind in der Regel recht einfach zu konfigurieren.
Zum einen können alle Fehler- und Absturzmeldungen in genau demselben Format im Fehlerprotokoll protokolliert werden, in dem sie sonst einem Benutzer präsentiert würden. Mit einer einfachen Konfiguration muss der Endbenutzer diese hässlichen Fehlerspuren auf Ihrer Website nie sehen, während Entwickler immer noch in der Lage sind, das System zu überwachen und diese Fehlermeldungen in all ihren blutigen Details zu überprüfen. So richten Sie diese Art der Protokollierung in PHP ein:
log_errors = On error_reporting = E_ALL error_log = /path/to/my/error/log
Zwei weitere Zeilen, die unbedingt in eine Protokolldatei für eine Live-Site aufgenommen werden müssen, um zu verhindern, dass den Benutzern blutige Fehlerdetails angezeigt werden, sind:
display_errors = Off display_startup_errors = Off
Systemprotokoll ( syslog
) Konfiguration
Es gibt viele allgemein kompatible Implementierungen des syslog
-Daemons in der Open-Source-Welt, darunter:
-
syslogd
undsysklogd
– am häufigsten auf Systemen der BSD-Familie, CentOS, Mac OS X und anderen zu sehen -
syslog-ng
– Standard für moderne Gentoo- und SuSE-Builds -
rsyslogd
– weit verbreitet in den Betriebssystemfamilien Debian und Fedora
(Hinweis: In diesem Artikel verwenden wir rsyslogd
für unsere Beispiele.)
Die grundlegende Syslog-Konfiguration ist im Allgemeinen ausreichend, um Ihre Protokollmeldungen in einer systemweiten Protokolldatei zu erfassen (normalerweise /var/log/syslog
; kann je nach Distribution auch /var/log/messages
oder /var/log/system.log
Sie verwenden).
Das Systemprotokoll bietet mehrere Protokollfunktionen, von denen acht ( LOG_LOCAL0
bis LOG_LOCAL7
) für von Benutzern bereitgestellte Projekte reserviert sind. So könnten Sie beispielsweise LOG_LOCAL0
so einrichten, dass es basierend auf der Protokollierungsebene (dh Fehler, Warnung, Info, Debug) in 4 separate Protokolldateien schreibt:
# /etc/rsyslog.d/my.conf local0.err /var/log/my/err.log local0.warning /var/log/my/warning.log local0.info -/var/log/my/info.log local0.debug -/var/log/my/debug.log
Wenn Sie jetzt eine Protokollnachricht in die Einrichtung LOG_LOCAL0 schreiben, werden die Fehlermeldungen in LOG_LOCAL0
/var/log/my/err.log
, Warnmeldungen in /var/log/my/warning.log
und so weiter. Beachten Sie jedoch, dass der Syslog-Daemon Nachrichten für jede Datei basierend auf der Regel „diese Stufe und höher“ filtert. Im obigen Beispiel erscheinen also alle Fehlermeldungen in allen vier konfigurierten Dateien, Warnmeldungen erscheinen in allen außer dem Fehlerprotokoll, Info-Meldungen erscheinen in den Info- und Debug-Logs und Debug-Meldungen werden nur in debug.log
.
Ein weiterer wichtiger Hinweis; Die -
Zeichen vor den Info- und Debug-Level-Dateien im obigen Konfigurationsdateibeispiel zeigen an, dass Schreibvorgänge in diese Dateien asynchron ausgeführt werden sollten (da diese Operationen nicht blockieren). Dies ist normalerweise in Ordnung (und in den meisten Situationen sogar empfohlen) für Info- und Debug-Protokolle, aber es ist am besten, wenn Schreibvorgänge in das Fehlerprotokoll (und höchstwahrscheinlich auch in das Warnungsprotokoll) synchron sind.
Um eine weniger wichtige Protokollierungsebene (z. B. auf einem Produktionsserver) abzuschalten, können Sie zugehörige Nachrichten einfach nach /dev/null
(d. h. ins Nirgendwo) umleiten:
local0.debug /dev/null # -/var/log/my/debug.log
Eine spezifische Anpassung, die nützlich ist, insbesondere um einige der PHP-Protokolldateianalysen zu unterstützen, die wir später in diesem Artikel besprechen werden, ist die Verwendung von Tabulatoren als Trennzeichen in Protokollmeldungen. Dies kann einfach durch Hinzufügen der folgenden Datei in /etc/rsyslog.d
:
# /etc/rsyslog.d/fixtab.conf $EscapeControlCharactersOnReceive off
Und schließlich vergessen Sie nicht, den Syslog-Daemon neu zu starten, nachdem Sie Konfigurationsänderungen vorgenommen haben, damit sie wirksam werden:
service rsyslog restart
Konfiguration des Serverprotokolls
Im Gegensatz zu beschreibbaren Anwendungslogs und Fehlerlogs werden Serverlogs ausschließlich von den entsprechenden Server-Daemons (zB Webserver, Datenbankserver etc.) bei jeder Anfrage geschrieben. Die einzige „Kontrolle“, die Sie über diese Protokolle haben, besteht in dem Umfang, in dem der Server Ihnen erlaubt, seine Protokollierungsfunktionalität zu konfigurieren. Obwohl es in diesen Dateien eine Menge zu durchsuchen gibt, sind sie oft die einzige Möglichkeit, ein klares Gefühl dafür zu bekommen, was „unter der Haube“ Ihres Servers vor sich geht.
Stellen wir unsere Symfony Standard-Beispielanwendung in einer Nginx-Umgebung mit MySQL-Speicher-Backend bereit. Hier ist die nginx-Hostkonfiguration, die wir verwenden werden:
server { server_name my.log-sandbox; root /var/www/my/web; location / { # try to serve file directly, fallback to app.php try_files $uri /app.php$is_args$args; } # DEV # This rule should only be placed on your development environment # In production, don't include this and don't deploy app_dev.php or config.php location ~ ^/(app_dev|config)\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; } # PROD location ~ ^/app\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; # Prevents URIs that include the front controller. This will 404: # http://domain.tld/app.php/some-path # Remove the internal directive to allow URIs like this internal; } error_log /var/log/nginx/my_error.log; access_log /var/log/nginx/my_access.log; }
In Bezug auf die letzten beiden Anweisungen oben: access_log
stellt das allgemeine Anforderungsprotokoll dar, während error_log
für Fehler steht, und wie bei Anwendungsfehlerprotokollen lohnt es sich, eine zusätzliche Überwachung einzurichten, um bei Problemen gewarnt zu werden, damit Sie schnell reagieren können.
Hinweis: Dies ist eine absichtlich stark vereinfachte Nginx-Konfigurationsdatei, die nur zu Beispielzwecken bereitgestellt wird. Es achtet fast nicht auf Sicherheit und Leistung und sollte nicht so wie es ist in einer „echten“ Umgebung verwendet werden.
Dies ist, was wir in /var/log/nginx/my_access.log
erhalten, nachdem wir http://my.log-sandbox/app_dev.php/
in den Browser eingegeben und die Enter
gedrückt haben.
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /app_dev.php/ HTTP/1.1" 200 6715 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/body.css HTTP/1.1" 200 6657 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/structure.css HTTP/1.1" 200 1191 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/css/demo.css HTTP/1.1" 200 2204 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-quick-tour.gif HTTP/1.1" 200 4770 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-demo.gif HTTP/1.1" 200 4053 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-configure.gif HTTP/1.1" 200 3530 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /favicon.ico HTTP/1.1" 200 6518 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:30 +0300] "GET /app_dev.php/_wdt/e50d73 HTTP/1.1" 200 13265 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
Dies zeigt, dass der Browser zum Bereitstellen einer Seite tatsächlich 9 HTTP-Aufrufe durchführt. 7 davon sind jedoch Anforderungen an statische Inhalte, die einfach und leichtgewichtig sind. Sie nehmen jedoch immer noch Netzwerkressourcen in Anspruch, und dies kann durch die Verwendung verschiedener Sprites und Minifizierungstechniken optimiert werden.
Während diese Optimierungen in einem anderen Artikel diskutiert werden sollen, ist hier relevant, dass wir Anforderungen an statische Inhalte separat protokollieren können, indem wir eine andere location
für sie verwenden:
location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js)$ { access_log /var/log/nginx/my_access-static.log; }
Denken Sie daran, dass nginx location
einen einfachen Abgleich regulärer Ausdrücke durchführt, sodass Sie so viele statische Inhaltserweiterungen einschließen können, wie Sie erwarten, dass sie auf Ihrer Website versendet werden.
Das Analysieren solcher Protokolle unterscheidet sich nicht vom Analysieren von Anwendungsprotokollen.
Andere erwähnenswerte Protokolle
Zwei weitere erwähnenswerte PHP-Protokolle sind das Debug-Protokoll und das Datenspeicherprotokoll.
Das Debug-Log
Eine weitere praktische Sache bei Nginx-Protokollen ist das Debug-Protokoll. Wir können es aktivieren, indem wir die error_log
-Zeile der Konfiguration durch Folgendes ersetzen (erfordert, dass das nginx-Debug-Modul installiert ist):
error_log /var/log/nginx/my_error.log debug;
Die gleiche Einstellung gilt für Apache oder einen anderen von Ihnen verwendeten Webserver.
Übrigens haben Debug-Protokolle nichts mit Fehlerprotokollen zu tun, obwohl sie in der error_log
Direktive konfiguriert sind.
Obwohl das Debug-Protokoll tatsächlich ausführlich sein kann (eine einzelne Nginx-Anfrage hat beispielsweise 127 KB an Protokolldaten generiert!), kann es dennoch sehr nützlich sein. Das Durchsuchen einer Protokolldatei kann umständlich und mühsam sein, aber es kann oft schnell Hinweise und Informationen liefern, die den Debugging-Prozess erheblich beschleunigen.
Insbesondere das Debug-Protokoll kann beim Debuggen von Nginx-Konfigurationen sehr hilfreich sein, insbesondere bei den kompliziertesten Teilen wie location
und rewrite
Ketten.
Natürlich sollten Debug-Protokolle niemals in einer Produktionsumgebung aktiviert werden. Die Menge an Speicherplatz, die sie verwenden, und die Menge an Informationen, die sie speichern, bedeuten eine große I/O-Last auf Ihrem Server, was die Leistung des gesamten Systems erheblich beeinträchtigen kann.
Datenspeicherprotokolle
Eine andere Art von Serverprotokoll (nützlich zum Debuggen) sind Datenspeicherprotokolle. In MySQL können Sie sie aktivieren, indem Sie diese Zeilen hinzufügen:
[mysqld] general_log = 1 general_log_file = /var/log/mysql/query.log
Diese Protokolle enthalten einfach eine Liste von Abfragen, die vom System ausgeführt werden, während Datenbankanforderungen in chronologischer Reihenfolge verarbeitet werden, was für verschiedene Debugging- und Tracing-Anforderungen hilfreich sein kann. Sie sollten jedoch auf Produktionssystemen nicht aktiviert bleiben, da sie zusätzliche unnötige E/A-Last erzeugen, die sich auf die Leistung auswirkt.
Schreiben in Ihre Protokolldateien
PHP selbst bietet Funktionen zum Öffnen, Schreiben und Schließen von Protokolldateien ( openlog()
, syslog()
bzw. closelog()
).
Es gibt auch zahlreiche Protokollierungsbibliotheken für PHP-Entwickler, wie Monolog (beliebt bei Symfony- und Laravel-Benutzern), sowie verschiedene Framework-spezifische Implementierungen, wie die in CakePHP integrierten Protokollierungsfunktionen. Im Allgemeinen verpacken Bibliotheken wie Monolog nicht nur syslog()
-Aufrufe, sondern ermöglichen auch die Verwendung anderer Backend-Funktionen und -Tools.

Hier ist ein einfaches Beispiel für das Schreiben in das Protokoll:
<?php openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'It works!');
Unser Aufruf hier an openlog
:
- konfiguriert PHP so, dass jeder Systemprotokollnachricht während der Lebensdauer des Skripts eine eindeutige Kennung vorangestellt wird
- setzt es so, dass das Öffnen der Syslog-Verbindung verzögert wird, bis der erste Aufruf von
syslog()
stattgefunden hat - legt
LOG_LOCAL0
als Standardprotokollierungseinrichtung fest
So würde der Inhalt der Protokolldatei nach dem Ausführen des obigen Codes aussehen:
# cat /var/log/my/info.log Mar 2 00:23:29 log-sandbox 54f39161a2e55: It works!
Maximieren Sie den Wert Ihrer PHP-Protokolldateien
Nun, da wir alle mit Theorie und Grundlagen vertraut sind, wollen wir sehen, wie viel wir aus Protokollen herausholen können, wenn wir so wenig Änderungen wie möglich an unserem Symfony Standard-Beispielprojekt vornehmen.
Zuerst erstellen wir die Skripte src/log-begin.php
(um unsere Protokolle richtig zu öffnen und zu konfigurieren) und src/log-end.php
(um Informationen über den erfolgreichen Abschluss zu protokollieren). Beachten Sie, dass wir der Einfachheit halber alle Meldungen in das Infolog schreiben.
# src/log-begin.php <?php define('START_TIME', microtime(true)); openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'BEGIN'); syslog(LOG_INFO, "URI\t{$_SERVER['REQUEST_URI']}"); $browserHash = substr(md5($_SERVER['HTTP_USER_AGENT']), 0, 7); syslog(LOG_INFO, "CLIENT\t{$_SERVER['REMOTE_ADDR']}\t{$browserHash}"); <br /> # src/log-end.php <?php syslog(LOG_INFO, "DISPATCH TIME\t" . round(microtime(true) - START_TIME, 2)); syslog(LOG_INFO, 'END');
Und lassen Sie uns diese Skripte in app.php
:
<?php require_once(dirname(__DIR__) . '/src/log-begin.php'); syslog(LOG_INFO, "MODE\tPROD"); # original app.php contents require_once(dirname(__DIR__) . '/src/log-end.php');
Für die Entwicklungsumgebung wollen wir diese Skripte auch in app_dev.php
fordern. Der Code dafür wäre derselbe wie oben, außer dass wir MODE
auf DEV
und nicht auf PROD
.
Wir möchten auch verfolgen, welche Controller aufgerufen werden, also fügen wir eine weitere Zeile in Acme\DemoBundle\EventListener\ControllerListener
, direkt am Anfang der Methode ControllerListener::onKernelController()
:
syslog(LOG_INFO, "CONTROLLER\t" . get_class($event->getController()[0]));
Beachten Sie, dass diese Änderungen lediglich 15 zusätzliche Codezeilen ausmachen, aber insgesamt eine Fülle von Informationen liefern können.
Analysieren der Daten in Ihren Protokolldateien
Sehen wir uns zunächst an, wie viele HTTP-Anforderungen erforderlich sind, um jeden Seitenladevorgang zu bedienen.
Hier sind die Informationen in den Protokollen für eine Anfrage, basierend auf der Art und Weise, wie wir unsere Protokollierung konfiguriert haben:
Mar 3 12:04:20 log-sandbox 54f58724b1ccc: BEGIN Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ Mar 3 12:04:20 log-sandbox 54f58724b1ccc: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:20 log-sandbox 54f58724b1ccc: MODE DEV Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController Mar 3 12:04:25 log-sandbox 54f58724b1ccc: DISPATCH TIME 4.51 Mar 3 12:04:25 log-sandbox 54f58724b1ccc: END Mar 3 12:04:25 log-sandbox 54f5872967dea: BEGIN Mar 3 12:04:25 log-sandbox 54f5872967dea: URI /app_dev.php/_wdt/59b8b6 Mar 3 12:04:25 log-sandbox 54f5872967dea: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:25 log-sandbox 54f5872967dea: MODE DEV Mar 3 12:04:28 log-sandbox 54f5872967dea: CONTROLLER Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController Mar 3 12:04:29 log-sandbox 54f5872967dea: DISPATCH TIME 4.17 Mar 3 12:04:29 log-sandbox 54f5872967dea: END
Jetzt wissen wir also, dass jeder Seitenladevorgang tatsächlich mit zwei HTTP-Anforderungen bedient wird.
Eigentlich sind hier zwei Punkte erwähnenswert. Erstens dienen die zwei Anfragen pro Seitenladevorgang der Verwendung von Symfony im Entwicklermodus (was ich in diesem Artikel getan habe). Sie können Aufrufe im Entwicklungsmodus identifizieren, indem Sie nach /app-dev.php/
URL-Blöcken suchen. Nehmen wir zweitens an, dass jeder Seitenladevorgang mit zwei aufeinanderfolgenden Anfragen an die Symfony-App bedient wird. Wie wir zuvor in den nginx-Zugriffsprotokollen gesehen haben, gibt es tatsächlich mehr HTTP-Aufrufe, von denen einige für statische Inhalte bestimmt sind.
OK, jetzt surfen wir ein bisschen auf der Demoseite (um die Daten in den Protokolldateien aufzubauen) und sehen wir uns an, was wir sonst noch aus diesen Protokollen lernen können.
Wie viele Anfragen wurden seit Beginn der Protokolldatei insgesamt bedient?
# grep -c BEGIN info.log 10
Ist einer von ihnen fehlgeschlagen (wurde das Skript beendet, ohne das Ende zu erreichen)?
# grep -c END info.log 10
Wir sehen, dass die Anzahl der BEGIN
und END
Datensätze übereinstimmen, was uns sagt, dass alle Aufrufe erfolgreich waren. (Wenn das PHP-Skript nicht erfolgreich abgeschlossen worden wäre, hätte es die Ausführung des Skripts src/log-end.php
nicht erreicht.)
Wie hoch war der Prozentsatz der Anfragen an den Site-Root?
# `grep -cE "\s/app_dev.php/$" info.log` 2
Dies sagt uns, dass es 2 Seitenladevorgänge des Site-Roots gab. Da wir zuvor erfahren haben, dass (a) es 2 Anfragen an die App pro Seitenladevorgang gibt und (b) es insgesamt 10 HTTP-Anfragen gab, betrug der Prozentsatz der Anfragen an den Site-Root 40 % (d. h. 2 x 2/10).
Welche Controller-Klasse ist für die Bereitstellung von Anforderungen an den Standortstamm verantwortlich?
# grep -E "\s/$|\s/app_dev.php/$" info.log | head -n1 Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ # grep 54f58724b1ccc info.log | grep CONTROLLER Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController
Hier haben wir die eindeutige ID einer Anfrage verwendet, um alle Protokollmeldungen zu dieser einzelnen Anfrage zu überprüfen. Dadurch konnten wir feststellen, dass die Controller-Klasse, die für das Zustellen von Anforderungen an den Standortstamm verantwortlich ist, Acme\DemoBundle\Controller\WelcomeController
ist.
Welche Clients mit IPs des Subnetzes
192.168.0.0/16
haben auf die Site zugegriffen?
# grep CLIENT info.log | cut -d":" -f4 | cut -f2 | sort | uniq 192.168.56.1
Wie in diesem einfachen Testfall erwartet, hat nur mein Host-Computer auf die Site zugegriffen. Dies ist natürlich ein sehr vereinfachtes Beispiel, aber die Fähigkeit, die es demonstriert (in der Lage zu sein, die Quellen des Verkehrs auf Ihrer Website zu analysieren), ist offensichtlich ziemlich leistungsfähig und wichtig.
Wie viel Traffic auf meiner Website stammt von FireFox?
Mit 1b101cd
als Hash meines Firefox User-Agent kann ich diese Frage wie folgt beantworten:
# grep -c 1b101cd info.log 8 # grep -c CLIENT info.log 10
Antwort: 80 % (dh 8/10)
Wie hoch ist der Prozentsatz der Anfragen, die zu einer langsamen Antwort geführt haben?
Für die Zwecke dieses Beispiels definieren wir „langsam“ als mehr als 5 Sekunden, um eine Antwort zu geben. Entsprechend:
# grep "DISPATCH TIME" info.log | grep -cE "\s[0-9]{2,}\.|\s[5-9]\." 2
Antwort: 20 % (dh 2/10)
Hat jemand jemals GET-Parameter angegeben?
# grep URI info.log | grep \?
Nein, der Symfony-Standard verwendet nur URL-Slugs, also sagt uns das hier auch, dass niemand versucht hat, die Seite zu hacken.
Dies sind nur einige wenige relativ rudimentäre Beispiele dafür, wie Protokolldateien kreativ genutzt werden können, um wertvolle Nutzungsinformationen und sogar grundlegende Analysen zu erhalten.
Andere Dinge, die Sie beachten sollten
Dinge sicher halten
Ein weiteres Heads-up betrifft die Sicherheit. Sie denken vielleicht, dass das Protokollieren von Anfragen eine gute Idee ist, in den meisten Fällen ist dies tatsächlich der Fall. Es ist jedoch wichtig, äußerst vorsichtig zu sein, wenn es darum geht, potenziell sensible Benutzerinformationen zu entfernen, bevor sie im Protokoll gespeichert werden.
Kampf gegen das Aufblähen von Protokolldateien
Da Protokolldateien Textdateien sind, an die Sie immer Informationen anhängen , wachsen sie ständig. Da dies ein bekanntes Problem ist, gibt es einige ziemlich standardmäßige Ansätze, um das Wachstum von Protokolldateien zu kontrollieren.
Am einfachsten ist es, die Stämme zu drehen . Rundholz bedeutet:
- Regelmäßiges Ersetzen des Protokolls durch eine neue leere Datei zum weiteren Schreiben
- Speichern der alten Datei für den Verlauf
- Entfernen von Dateien, die ausreichend „gealtert“ sind, um Speicherplatz freizugeben
- Stellen Sie sicher, dass die Anwendung ohne Unterbrechung in die Protokolle schreiben kann, wenn diese Dateiänderungen auftreten
Die gebräuchlichste Lösung dafür ist logrotate
, das mit den meisten *nix-Distributionen vorinstalliert geliefert wird. Sehen wir uns eine einfache Konfigurationsdatei zum Rotieren unserer Protokolle an:
/var/log/my/debug.log /var/log/my/info.log /var/log/my/warning.log /var/log/my/error.log { rotate 7 daily missingok notifempty delaycompress compress sharedscripts postrotate invoke-rc.d rsyslog rotate > /dev/null endscript }
Ein weiterer, fortschrittlicherer Ansatz besteht darin, rsyslogd
dazu zu bringen, Nachrichten in Dateien zu schreiben, die basierend auf dem aktuellen Datum und der aktuellen Uhrzeit dynamisch erstellt werden. Dies würde immer noch eine benutzerdefinierte Lösung zum Entfernen älterer Dateien erfordern, ermöglicht es Entwicklern jedoch, Zeitrahmen für jede Protokolldatei genau zu verwalten. Für unser Beispiel:
$template DynaLocal0Err, "/var/log/my/error-%$NOW%-%$HOUR%.log" $template DynaLocal0Info, "/var/log/my/info-%$NOW%-%$HOUR%.log" $template DynaLocal0Warning, "/var/log/my/warning-%$NOW%-%$HOUR%.log" $template DynaLocal0Debug, "/var/log/my/debug-%$NOW%-%$HOUR%.log" local1.err -?DynaLocal0Err local1.info -?DynaLocal0Info local1.warning -?DynaLocal0Warning local1.debug -?DynaLocal0Debug
Auf diese Weise rsyslog
jede Stunde eine individuelle Protokolldatei, und es besteht keine Notwendigkeit, sie zu rotieren und den Daemon neu zu starten. So können Protokolldateien, die älter als 5 Tage sind, entfernt werden, um diese Lösung zu erreichen:
find /var/log/my/ -mtime +5 -print0 | xargs -0 rm
Remote-Protokolle
Wenn das Projekt wächst, wird das Analysieren von Informationen aus Protokollen immer ressourcenintensiver. Dies bedeutet nicht nur die Schaffung zusätzlicher Serverlast; Es bedeutet auch, dass zu Zeiten, in denen Sie Protokolle parsen, Spitzenlasten auf der CPU und den Festplattenlaufwerken erzeugt werden, was die Antwortzeit des Servers für Benutzer verkürzen kann (oder im schlimmsten Fall sogar die Website zum Erliegen bringen kann).
Erwägen Sie zur Lösung dieses Problems die Einrichtung eines zentralisierten Protokollierungsservers . Alles, was Sie dazu brauchen, ist eine weitere Box mit geöffnetem UDP-Port 514 (Standard). Damit rsyslogd
auf Verbindungen lauscht, fügen Sie die folgende Zeile zu seiner Konfigurationsdatei hinzu:
$UDPServerRun 514
Damit ist die Einrichtung des Clients so einfach wie:
*.* @HOSTNAME:514
(wobei HOSTNAME
der Hostname Ihres entfernten Protokollierungsservers ist).
Fazit
Während dieser Artikel einige der kreativen Möglichkeiten aufgezeigt hat, wie Protokolldateien viel wertvollere Informationen bieten können, als Sie sich vielleicht bisher vorgestellt haben, ist es wichtig zu betonen, dass wir nur an der Oberfläche dessen gekratzt haben, was möglich ist. Das Ausmaß, der Umfang und das Format dessen, was Sie protokollieren können, ist nahezu unbegrenzt. Das bedeutet, dass Sie – wenn Sie Nutzungs- oder Analysedaten aus Ihren Protokollen extrahieren möchten – diese einfach so protokollieren müssen, dass sie später einfach analysiert und analysiert werden können. Darüber hinaus kann diese Analyse oft mit standardmäßigen Linux-Befehlszeilentools wie grep
, sed
oder awk
durchgeführt werden.
In der Tat sind PHP-Protokolldateien ein äußerst leistungsfähiges Werkzeug, das von enormem Nutzen sein kann.
Ressourcen
Code auf GitHub: https://github.com/isanosyan/toptal-blog-logs-post-example
Anhang: Protokolldateien in der Unix-Shell lesen und bearbeiten
Hier ist eine kurze Einführung in einige der gebräuchlicheren *nix-Befehlszeilentools, mit denen Sie sich zum Lesen und Bearbeiten Ihrer Protokolldateien vertraut machen sollten.
cat
ist vielleicht die einfachste. Es druckt die gesamte Datei in den Ausgabestrom. Der folgende Befehl gibt beispielsweiselogfile1
auf der Konsole aus:cat logfile1
>
Zeichen ermöglicht es dem Benutzer, die Ausgabe umzuleiten, beispielsweise in eine andere Datei. Öffnet den Zielstream im Schreibmodus (was bedeutet, dass der Zielinhalt gelöscht wird). So ersetzen wir den Inhalt vontmpfile
durch den Inhalt vonlogfile1
:cat logfile1 > tmpfile
>>
Leitet die Ausgabe um und öffnet den Zielstream im Anfügemodus. Der aktuelle Inhalt der Zieldatei wird beibehalten, neue Zeilen werden unten hinzugefügt. Dadurch wird der Inhalt vonlogfile1
antmpfile
:cat logfile1 >> tmpfile
grep
filtert die Datei nach einem bestimmten Muster und gibt nur übereinstimmende Zeilen aus. Der folgende Befehl druckt nur Zeilen vonlogfile1
, die dieBingo
-Nachricht enthalten:grep Bingo logfile1
cut
druckt den Inhalt einer einzelnen Spalte (nach Nummer beginnend bei 1). Sucht standardmäßig nach Tabulatorzeichen als Trennzeichen zwischen Spalten. Wenn Sie beispielsweise eine Datei voller Zeitstempel im FormatYYYY-MM-DD HH:MM:SS
haben, können Sie nur Jahre drucken:cut -d"-" -f1 logfile1
head
zeigt nur die ersten Zeilen einer Datei antail
zeigt nur die letzten Zeilen einer Datei ansort
sortiert Zeilen in der Ausgabeuniq
filtert doppelte Zeilen herauswc
zählt Wörter (oder Zeilen, wenn es mit dem Flag-l
verwendet wird)|
(dh das „Pipe“-Symbol) liefert die Ausgabe von einem Befehl als Eingabe für den nächsten. Pipe ist sehr praktisch zum Kombinieren von Befehlen. So können wir zum Beispiel Monate des Jahres 2014 finden, die innerhalb einer Reihe von Zeitstempeln liegen:grep -E "^2014" logfile1 | cut -d"-" -f2 | sort | uniq
Hier gleichen wir zuerst die Zeilen mit dem regulären Ausdruck „beginnt mit 2014“ ab und schneiden dann die Monate ab. Schließlich verwenden wir eine Kombination aus sort
und uniq
, um Vorkommen nur einmal zu drucken.