Profitați la maximum de fișierele dvs. jurnal PHP: un ghid practic

Publicat: 2022-03-11

S-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.

fișiere jurnal PHP

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 și sysklogd - 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ări logfile1 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ținutul tmpfile cu conținutul logfile1 :

     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șierului tmpfile 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 de logfile1 care conțin mesajul Bingo :

     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 formatul YYYY-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șier

  • tail afișează doar ultimele linii ale unui fișier

  • sort liniile din ieșire

  • uniq filtrează liniile duplicate

  • wc 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ă.