Profitați la maximum de fișierele dvs. jurnal PHP: un ghid practic
Publicat: 2022-03-11S-ar putea spune pe bună dreptate că jurnalele sunt unul dintre cele mai subestimate și subutilizate instrumente la dispoziția unui dezvoltator php independent. În ciuda multitudinii de informații pe care le pot oferi, nu este neobișnuit ca jurnalele să fie ultimul loc în care un dezvoltator caută atunci când încearcă să rezolve o problemă.
Într-adevăr, fișierele jurnal PHP ar trebui să fie în multe cazuri primul loc în care să căutați indicii atunci când apar probleme. Adesea, informațiile pe care le conțin ar putea reduce semnificativ timpul petrecut smulgându-ți părul încercând să găsești o insectă noduroasă.
Dar poate și mai important, cu puțină creativitate și gândire anticipată, fișierele dvs. de jurnal pot fi valorificate pentru a servi ca o sursă valoroasă de informații și analize de utilizare. Utilizarea creativă a fișierelor jurnal poate ajuta să răspundă la întrebări precum: Ce browsere sunt cele mai frecvent utilizate pentru a-mi vizita site-ul? Care este timpul mediu de răspuns de la serverul meu? Care a fost procentul de solicitări către rădăcina site-ului? Cum s-a schimbat utilizarea de când am implementat cele mai recente actualizări? Și mult, mult mai mult.
Acest articol oferă o serie de sfaturi despre cum să configurați fișierele jurnal, precum și despre cum să procesați informațiile pe care le conțin, pentru a maximiza beneficiile pe care le oferă.
Deși acest articol se concentrează din punct de vedere tehnic pe logare pentru dezvoltatorii PHP, multe dintre informațiile prezentate aici sunt destul de agnostice de tehnologie și sunt relevante și pentru alte limbi și stive de tehnologie.
Notă: Acest articol presupune familiaritatea de bază cu shell-ul Unix. Pentru cei care nu au aceste cunoștințe, este furnizat un apendice care introduce unele dintre comenzile necesare pentru accesarea și citirea fișierelor jurnal pe un sistem Unix.
Proiectul nostru exemplu de fișier jurnal PHP
Ca exemplu de proiect pentru discuții în acest articol, vom lua Symfony Standard ca proiect de lucru și îl vom configura pe Debian 7 Wheezy cu rsyslogd
, nginx
și PHP-FPM
.
composer create-project symfony/framework-standard-edition my "2.6.*"
Acest lucru ne oferă rapid un proiect de testare funcțional, cu o interfață de utilizare frumoasă.
Sfaturi pentru configurarea fișierelor jurnal
Iată câteva indicații despre cum să configurați fișierele jurnal pentru a ajuta la maximizarea valorii acestora.
Configurare jurnal de erori
Jurnalele de erori reprezintă cea mai simplă formă de înregistrare; adică captarea de informații suplimentare și detalii atunci când apar probleme. Deci, într-o lume ideală, ați dori să nu existe erori și ca jurnalele de erori să fie goale. Dar când apar probleme (așa cum se întâmplă în mod invariabil), jurnalele de erori ar trebui să fie una dintre primele opriri pe care le faceți pe traseul de depanare.
Jurnalele de erori sunt de obicei destul de ușor de configurat.
În primul rând, toate mesajele de eroare și de blocare pot fi înregistrate în jurnalul de erori exact în același format în care ar fi altfel prezentate unui utilizator. Cu o configurație simplă, utilizatorul final nu va trebui niciodată să vadă acele urme de eroare urâte pe site-ul dvs., în timp ce devopii vor putea în continuare să monitorizeze sistemul și să revizuiască aceste mesaje de eroare în toate detaliile lor sângeroase. Iată cum să configurați acest tip de logare în PHP:
log_errors = On error_reporting = E_ALL error_log = /path/to/my/error/log
Alte două rânduri care sunt importante de inclus într-un fișier jurnal pentru un site live, pentru a preveni ca nivelurile sângeroase de detalii ale erorii să fie prezentate utilizatorilor, sunt:
display_errors = Off display_startup_errors = Off
Configurare jurnal de sistem ( syslog
).
Există multe implementări compatibile în general ale demonului syslog
în lumea open source, inclusiv:
-
syslogd
șisysklogd
- cel mai adesea văzute pe sistemele familiei BSD, CentOS, Mac OS X și altele -
syslog-ng
– implicit pentru versiunile moderne Gentoo și SuSE -
rsyslogd
– utilizat pe scară largă pe familiile de sisteme de operare Debian și Fedora
(Notă: în acest articol, vom folosi rsyslogd
pentru exemplele noastre.)
Configurația de bază syslog este, în general, adecvată pentru captarea mesajelor dvs. de jurnal într-un fișier jurnal la nivelul întregului sistem (în mod normal /var/log/syslog
; poate fi, de asemenea, /var/log/messages
sau /var/log/system.log
, în funcție de distribuție). utilizați).
Jurnalul de sistem oferă mai multe facilități de jurnal, dintre care opt ( LOG_LOCAL0
până la LOG_LOCAL7
) sunt rezervate pentru proiectele implementate de utilizator. Iată, de exemplu, cum ați putea configura LOG_LOCAL0
pentru a scrie în 4 fișiere jurnal separate, pe baza nivelului de înregistrare (adică, eroare, avertisment, informații, depanare):
# /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
Acum, ori de câte ori scrieți un mesaj de jurnal la facilitatea LOG_LOCAL0
, mesajele de eroare vor merge la /var/log/my/err.log
, mesajele de avertizare vor merge la /var/log/my/warning.log
și așa mai departe. Rețineți, totuși, că demonul syslog filtrează mesajele pentru fiecare fișier pe baza regulii „acest nivel și superior”. Deci, în exemplul de mai sus, toate mesajele de eroare vor apărea în toate cele patru fișiere configurate, mesajele de avertizare vor apărea în toate, cu excepția jurnalului de erori, mesajele informative vor apărea în jurnalele de informații și de depanare, iar mesajele de depanare vor merge doar la debug.log
.
O notă importantă suplimentară; Semnele -
dinaintea fișierelor de nivel de informații și de depanare din exemplul de fișier de configurare de mai sus indică faptul că scrierile în acele fișiere ar trebui să fie efectuate asincron (deoarece aceste operațiuni sunt neblocante). Acest lucru este de obicei bine (și chiar recomandat în majoritatea situațiilor) pentru jurnalele de informații și de depanare, dar cel mai bine este ca scrierile în jurnalul de erori (și cel mai probabil și jurnalul de avertizare) să fie sincrone.
Pentru a opri un nivel mai puțin important de înregistrare (de exemplu, pe un server de producție), puteți pur și simplu să redirecționați mesajele asociate către /dev/null
(adică, către nicăieri):
local0.debug /dev/null # -/var/log/my/debug.log
O personalizare specifică care este utilă, în special pentru a sprijini unele dintre analizarea fișierelor jurnal PHP despre care vom discuta mai târziu în acest articol, este folosirea tabulatorului ca caracter delimitator în mesajele de jurnal. Acest lucru se poate face cu ușurință adăugând următorul fișier în /etc/rsyslog.d
:
# /etc/rsyslog.d/fixtab.conf $EscapeControlCharactersOnReceive off
Și, în sfârșit, nu uitați să reporniți demonul syslog după ce faceți modificări de configurare pentru ca acestea să aibă efect:
service rsyslog restart
Configurarea jurnalului serverului
Spre deosebire de jurnalele de aplicații și jurnalele de erori în care puteți scrie, jurnalele de server sunt scrise exclusiv de demonii de server corespunzători (de exemplu, serverul web, serverul de baze de date etc.) la fiecare cerere. Singurul „control” pe care îl aveți asupra acestor jurnale este în măsura în care serverul vă permite să configurați funcționalitatea de înregistrare. Deși pot fi multe de verificat în aceste fișiere, ele sunt adesea singura modalitate de a obține o idee clară a ceea ce se întâmplă „sub capotă” cu serverul tău.
Să implementăm aplicația noastră de exemplu Symfony Standard pe mediul nginx cu backend de stocare MySQL. Iată configurația gazdă nginx pe care o vom folosi:
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; }
În ceea ce privește ultimele două directive de mai sus: access_log
reprezintă jurnalul general de solicitări, în timp ce error_log
este pentru erori și, ca și în cazul jurnalelor de erori ale aplicației, merită să setați o monitorizare suplimentară pentru a fi alertat la probleme, astfel încât să puteți reacționa rapid.
Notă: Acesta este un fișier de configurare nginx suprasimplificat în mod intenționat, care este furnizat doar în scopuri de exemplu. Aproape că nu acordă atenție securității și performanței și nu ar trebui să fie folosit așa cum este în niciun mediu „real”.
Acesta este ceea ce obținem în /var/log/nginx/my_access.log
după ce http://my.log-sandbox/app_dev.php/
în browser și apăsăm Enter
.
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"
Aceasta arată că, pentru difuzarea unei pagini, browserul efectuează de fapt 9 apeluri HTTP. 7 dintre acestea, însă, sunt cereri de conținut static, care sunt simple și ușoare. Cu toate acestea, ei încă preiau resurse de rețea și aceasta este ceea ce poate fi optimizat folosind diverse sprite și tehnici de minificare.
În timp ce acele optimizări vor fi discutate într-un alt articol, ceea ce este relevant aici este că putem înregistra cererile în conținut static separat, utilizând o altă directivă de location
pentru ele:
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; }
Amintiți-vă că location
nginx realizează o potrivire simplă a expresiilor regulate, astfel încât să puteți include atâtea extensii de conținut static câte vă așteptați să expediați pe site-ul dvs.
Analizarea unor astfel de jurnale nu este diferită de analizarea jurnalelor de aplicație.
Alte jurnalele care merită menționate
Alte două jurnale PHP care merită menționate sunt jurnalul de depanare și jurnalul de stocare a datelor.
Jurnalul de depanare
Un alt lucru convenabil despre jurnalele nginx este jurnalul de depanare. Îl putem porni înlocuind linia error_log
a configurației cu următoarele (necesită ca modulul de depanare nginx să fie instalat):
error_log /var/log/nginx/my_error.log debug;
Aceeași setare se aplică pentru Apache sau orice alt server web pe care îl utilizați.
Și întâmplător, jurnalele de depanare nu au legătură cu jurnalele de erori, chiar dacă sunt configurate în directiva error_log
.
Deși jurnalul de depanare poate fi într-adevăr foarte pronunțat (o singură solicitare nginx, de exemplu, a generat 127 KB de date de jurnal!), poate fi totuși foarte util. Parcurgerea unui fișier jurnal poate fi greoaie și plictisitoare, dar adesea poate oferi rapid indicii și informații care ajută foarte mult la accelerarea procesului de depanare.
În special, jurnalul de depanare poate ajuta cu adevărat la depanarea configurațiilor nginx, în special în cele mai complicate părți, cum ar fi potrivirea location
și lanțurile de rewrite
.
Desigur, jurnalele de depanare nu ar trebui să fie niciodată activate într-un mediu de producție. De asemenea, cantitatea de spațiu pe care o folosesc și cantitatea de informații pe care o stochează înseamnă multă încărcare I/O pe serverul dvs., ceea ce poate degrada semnificativ performanța întregului sistem.
Jurnalele de stocare a datelor
Un alt tip de jurnal de server (util pentru depanare) sunt jurnalele de stocare a datelor. În MySQL, le puteți activa adăugând aceste linii:
[mysqld] general_log = 1 general_log_file = /var/log/mysql/query.log
Aceste jurnale conțin pur și simplu o listă de interogări executate de sistem în timp ce deservesc cererile de baze de date în ordine cronologică, ceea ce poate fi util pentru diverse nevoi de depanare și urmărire. Cu toate acestea, acestea nu ar trebui să rămână activate pe sistemele de producție, deoarece vor genera încărcare I/O suplimentară inutilă, care afectează performanța.
Scrierea în fișierele dvs. jurnal
PHP însuși oferă funcții pentru deschiderea, scrierea și închiderea fișierelor jurnal ( openlog()
, syslog()
și, respectiv, closelog()
) .

Există, de asemenea, numeroase biblioteci de jurnalizare pentru dezvoltatorul PHP, cum ar fi Monolog (popular printre utilizatorii Symfony și Laravel), precum și diverse implementări specifice cadrului, cum ar fi capacitățile de înregistrare încorporate în CakePHP. În general, bibliotecile precum Monolog nu numai că încapsulează apelurile syslog()
, dar permit și utilizarea altor funcționalități și instrumente backend.
Iată un exemplu simplu despre cum să scrieți în jurnal:
<?php openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'It works!');
Apelul nostru aici pentru openlog
:
- configurează PHP să prevadă un identificator unic fiecărui mesaj de jurnal de sistem pe durata de viață a scriptului
- îl setează să întârzie deschiderea conexiunii syslog până când a avut loc primul apel
syslog()
- setează
LOG_LOCAL0
ca facilitate implicită de înregistrare
Iată cum ar arăta conținutul fișierului jurnal după rularea codului de mai sus:
# cat /var/log/my/info.log Mar 2 00:23:29 log-sandbox 54f39161a2e55: It works!
Maximizarea valorii fișierelor dvs. jurnal PHP
Acum că ne pricepem cu toții la teorie și la elementele de bază, să vedem cât de mult putem obține din jurnalele făcând cât mai puține modificări posibil la proiectul nostru standard Symfony.
Mai întâi, să creăm scripturile src/log-begin.php
(pentru a deschide și configura corect jurnalele noastre) și src/log-end.php
(pentru a înregistra informații despre finalizarea cu succes). Rețineți că, pentru simplitate, vom scrie doar toate mesajele în jurnalul de informații.
# 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');
Și să cerem aceste scripturi în 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');
Pentru mediul de dezvoltare, dorim să solicităm aceste scripturi și în app_dev.php
. Codul pentru a face acest lucru ar fi același ca mai sus, cu excepția că am seta MODE
la DEV
, mai degrabă decât PROD
.
De asemenea, dorim să urmărim ce controlere sunt invocate, așa că haideți să mai adăugăm o linie în Acme\DemoBundle\EventListener\ControllerListener
, chiar la începutul metodei ControllerListener::onKernelController()
:
syslog(LOG_INFO, "CONTROLLER\t" . get_class($event->getController()[0]));
Rețineți că aceste modificări însumează doar 15 linii de cod în plus, dar pot genera în mod colectiv o mulțime de informații.
Analizarea datelor din fișierele dvs. jurnal
Pentru început, să vedem câte solicitări HTTP sunt necesare pentru a servi fiecare încărcare a paginii.
Iată informațiile din jurnalele pentru o solicitare, pe baza modului în care ne-am configurat înregistrarea:
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
Deci acum știm că fiecare încărcare a paginii este de fapt servită cu două solicitări HTTP.
De fapt, sunt două puncte care merită menționate aici. În primul rând, cele două solicitări pe încărcare de pagină sunt pentru utilizarea Symfony în modul dev (ceea ce am făcut pe parcursul acestui articol). Puteți identifica apelurile în modul dev căutând bucăți URL /app-dev.php/
. În al doilea rând, să presupunem că fiecare încărcare a paginii este servită cu două solicitări ulterioare către aplicația Symfony. După cum am văzut mai devreme în jurnalele de acces nginx, există de fapt mai multe apeluri HTTP, dintre care unele sunt pentru conținut static.
OK, acum haideți să navigam puțin pe site-ul demo (pentru a acumula datele în fișierele jurnal) și să vedem ce mai putem învăța din aceste jurnale.
Câte solicitări au fost servite în total de la începutul fișierului jurnal?
# grep -c BEGIN info.log 10
A eșuat vreuna dintre ele (scriptul s-a oprit fără a ajunge la sfârșit)?
# grep -c END info.log 10
Vedem că numărul de înregistrări BEGIN
și END
se potrivește, așa că acest lucru ne spune că toate apelurile au avut succes. (Dacă scriptul PHP nu s-ar fi finalizat cu succes, nu ar fi ajuns la execuția scriptului src/log-end.php
.)
Care a fost procentul de solicitări către rădăcina site-ului?
# `grep -cE "\s/app_dev.php/$" info.log` 2
Acest lucru ne spune că au existat 2 încărcări de pagini ale rădăcinii site-ului. Deoarece am aflat anterior că (a) există 2 solicitări către aplicație pe încărcare de pagină și (b) au existat un total de 10 solicitări HTTP, procentul de solicitări către rădăcina site-ului a fost de 40% (adică, 2x2/10).
Ce clasă de controler este responsabilă pentru deservirea cererilor către rădăcina site-ului?
# 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
Aici am folosit ID-ul unic al unei cereri pentru a verifica toate mesajele de jurnal legate de acea singură cerere. Prin urmare, am reușit să stabilim că clasa de controler responsabilă pentru deservirea cererilor către rădăcina site-ului este Acme\DemoBundle\Controller\WelcomeController
.
Ce clienți cu IP-uri de subrețea
192.168.0.0/16
au accesat site-ul?
# grep CLIENT info.log | cut -d":" -f4 | cut -f2 | sort | uniq 192.168.56.1
După cum era de așteptat în acest caz de testare simplu, doar computerul meu gazdă a accesat site-ul. Acesta este, desigur, un exemplu foarte simplist, dar capacitatea pe care o demonstrează (de a putea analiza sursele de trafic către site-ul dvs.) este evident destul de puternică și importantă.
Cât din traficul către site-ul meu a fost de la FireFox?
Având 1b101cd
ca hash al agentului meu de utilizator Firefox, pot răspunde la această întrebare după cum urmează:
# grep -c 1b101cd info.log 8 # grep -c CLIENT info.log 10
Răspuns: 80% (adică 8/10)
Care este procentul de cereri care au dat un răspuns lent?
În scopul acestui exemplu, vom defini „lent” ca fiind nevoie de mai mult de 5 secunde pentru a oferi un răspuns. În consecinţă:
# grep "DISPATCH TIME" info.log | grep -cE "\s[0-9]{2,}\.|\s[5-9]\." 2
Răspuns: 20% (adică, 2/10)
A furnizat cineva vreodată parametrii GET?
# grep URI info.log | grep \?
Nu, standardul Symfony folosește doar URL-uri, așa că acest lucru ne spune și aici că nimeni nu a încercat să pirateze site-ul.
Acestea sunt doar câteva exemple relativ rudimentare ale modurilor în care fișierele jurnal pot fi valorificate în mod creativ pentru a genera informații valoroase de utilizare și chiar analize de bază.
Alte lucruri de reținut
Păstrarea lucrurilor în siguranță
Un alt avertisment este pentru securitate. S-ar putea să credeți că solicitările de înregistrare este o idee bună, în cele mai multe cazuri chiar este. Cu toate acestea, este important să fiți extrem de atenți la eliminarea oricăror informații despre utilizator potențial sensibile înainte de a le stoca în jurnal.
Fighting Log File Balonare
Deoarece fișierele jurnal sunt fișiere text la care adăugați întotdeauna informații, acestea cresc constant. Deoarece aceasta este o problemă bine-cunoscută, există câteva abordări destul de standard pentru a controla creșterea fișierelor jurnal.
Cel mai simplu este să rotiți buștenii . Rotirea buștenilor înseamnă:
- Înlocuirea periodică a jurnalului cu un nou fișier gol pentru scriere ulterioară
- Stocarea fișierului vechi pentru istoric
- Eliminarea fișierelor care au „îmbătrânit” suficient pentru a elibera spațiu pe disc
- Asigurați-vă că aplicația poate scrie în jurnalele uniterrupted atunci când apar aceste modificări de fișier
Cea mai comună soluție pentru aceasta este logrotate
, care este livrat preinstalat cu majoritatea distribuțiilor *nix. Să vedem un fișier de configurare simplu pentru rotirea jurnalelor noastre:
/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 }
O altă abordare, mai avansată, este de a face ca rsyslogd
însuși să scrie mesaje în fișiere, create dinamic pe baza datei și orei curente. Acest lucru ar necesita în continuare o soluție personalizată pentru eliminarea fișierelor mai vechi, dar îi permite devopților să gestioneze intervalele de timp pentru fiecare fișier jurnal. Pentru exemplul nostru:
$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
În acest fel, rsyslog
va crea un fișier jurnal individual în fiecare oră și nu va fi nevoie să le rotiți și să reporniți demonul. Iată cum pot fi eliminate fișierele jurnal mai vechi de 5 zile pentru a realiza această soluție:
find /var/log/my/ -mtime +5 -print0 | xargs -0 rm
Jurnalele de la distanță
Pe măsură ce proiectul crește, analizarea informațiilor din jurnal devine din ce în ce mai multă nevoie de resurse. Acest lucru nu înseamnă doar crearea de încărcare suplimentară a serverului; înseamnă, de asemenea, crearea unei sarcini de vârf pe procesor și pe unitățile de disc în momentele în care analizați jurnalele, ceea ce poate degrada timpul de răspuns al serverului pentru utilizatori (sau, în cel mai rău caz, poate chiar distruge site-ul).
Pentru a rezolva acest lucru, luați în considerare configurarea unui server de înregistrare centralizat . Tot ce aveți nevoie pentru aceasta este o altă cutie cu portul UDP 514 (implicit) deschis. Pentru a face ca rsyslogd
să asculte conexiunile, adăugați următoarea linie la fișierul său de configurare:
$UDPServerRun 514
Având acest lucru, configurarea clientului este la fel de ușor ca:
*.* @HOSTNAME:514
(unde HOSTNAME
este numele gazdei serverului dvs. de înregistrare la distanță).
Concluzie
Deși acest articol a demonstrat câteva dintre modalitățile creative în care fișierele jurnal pot oferi informații mult mai valoroase decât v-ați imaginat anterior, este important să subliniem că am zgâriat doar suprafața a ceea ce este posibil. Amploarea, domeniul de aplicare și formatul a ceea ce puteți înregistra sunt aproape nelimitate. Aceasta înseamnă că – dacă există date de utilizare sau de analiză pe care doriți să le extrageți din jurnalele dvs. – trebuie pur și simplu să le înregistrați într-un mod care să fie ușor de analizat și analizat ulterior. Mai mult decât atât, această analiză poate fi adesea efectuată cu instrumente standard de linie de comandă Linux, cum ar fi grep
, sed
sau awk
.
Într-adevăr, fișierele jurnal PHP sunt cel mai puternic instrument care poate fi de un beneficiu extraordinar.
Resurse
Cod pe GitHub: https://github.com/isanosyan/toptal-blog-logs-post-example
Anexă: Citirea și manipularea fișierelor jurnal în Shell Unix
Iată o scurtă introducere la unele dintre cele mai comune instrumente de linie de comandă *nix cu care veți dori să vă familiarizați pentru citirea și manipularea fișierelor jurnal.
cat
este poate cea mai simplă. Tipărește întregul fișier în fluxul de ieșire. De exemplu, următoarea comandă va tipărilogfile1
pe consolă:cat logfile1
>
caracterul permite utilizatorului să redirecționeze ieșirea, de exemplu, într-un alt fișier. Deschide fluxul țintă în modul de scriere (ceea ce înseamnă ștergerea conținutului țintă). Iată cum înlocuim conținutultmpfile
cu conținutullogfile1
:cat logfile1 > tmpfile
>>
redirecționează ieșirea și deschide fluxul țintă în modul adăugare. Conținutul curent al fișierului țintă va fi păstrat, noi linii vor fi adăugate în partea de jos. Acest lucru va atașa conținutul fișieruluitmpfile
logfile1
cat logfile1 >> tmpfile
grep
filtrează fișierul după un model și imprimă numai linii care se potrivesc. Comanda de mai jos va tipări numai liniile din fișierul delogfile1
care conțin mesajulBingo
:grep Bingo logfile1
cut
printuri conținutul unei singure coloane (după număr începând de la 1). În mod implicit, caută caractere de tabulatură ca delimitatori între coloane. De exemplu, dacă aveți un fișier plin de marcaje temporale în formatulYYYY-MM-DD HH:MM:SS
, acest lucru vă va permite să imprimați numai ani:cut -d"-" -f1 logfile1
head
afișează doar primele rânduri ale unui fișiertail
afișează doar ultimele linii ale unui fișiersort
liniile din ieșireuniq
filtrează liniile duplicatewc
numără cuvintele (sau liniile atunci când sunt folosite cu-l
-l)|
(adică simbolul „țeavă”) furnizează ieșirea de la o comandă ca intrare la următoarea. Pipe este foarte convenabil pentru combinarea comenzilor. De exemplu, iată cum putem găsi luni din 2014 care apar într-un set de marcaje temporale:grep -E "^2014" logfile1 | cut -d"-" -f2 | sort | uniq
Aici potrivim mai întâi liniile cu expresia obișnuită „începe cu 2014”, apoi tăiem lunile. În cele din urmă, folosim combinația de sort
și uniq
pentru a tipări aparițiile o singură dată.