PERL - czytanie logow seserwa co godzine

Problemy dotyczące programowania.

Moderatorzy: Moderatorzy, Administratorzy

Awatar użytkownika
Sektor
Użytkownik
Posty: 271
Rejestracja: 2004-08-28, 12:21
Lokalizacja: Kraków

PERL - czytanie logow seserwa co godzine

Post autor: Sektor »

Witam,

Jak napisac skrypt ktory po uruchomieniu, sprawdzi czas systemowy i wyswietli linijka po linijce nazwy domen oraz ilosc ich odwiedzin w ciagu ostatnich 5 minut ?

Np. serwer www obsluguje 5 domen, efekt powinien byc mniej wiecej taki:
domena1.com 2
domena2.pl 10
domena3.net 14
domena4.com 7
domena5.net 20
Najwiekszy problem mam z wybraniem tych linii z logow ktore odpowiadaja warunkowi czasowemu (tylko z ostatnich 5 minut), nie ma przeciez sensu leciec co 5 minut z gory na dol po calym pliku i porownywac, mozna byc zrobic dodatkowy plik z informacja o ostatnio czytanej pozycji. Nie mam tylko pomyslu jak to zrobic.

Poradzcie cos :)

Pozdrawiam

[ Komentarz dodany przez: Zielony: 2007-08-03, 14:25 ]
Quote!
Ostatnio zmieniony 2007-08-03, 13:25 przez Sektor, łącznie zmieniany 1 raz.
Awatar użytkownika
mina86
Moderator
Posty: 3343
Rejestracja: 2004-06-14, 21:58
Lokalizacja: Linux 5.x x86_64
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: mina86 »

Jeżeli chcesz czytać logi co godzinę to możesz sobie lecieć po całym pliku. Jeżeli chcesz mieć statystyki uaktualniane co 5 minut to możesz trzymać skrypt ciągle uruchomiony, który będzie czytał do oporu linje, generował statystyki i zasypiał na 5 minut, aby potem ponownie czytać linie do oporu. Drugie wyjście to zapisywać pozycję w pliku i przy uruchamianiu odczytywać ją, aby potem skoczyć w odpowiednie miejsce. W obu przypadkach trzeba jeszcze wziąć pod uwagę rotacje logów itp.
Zastrzegam sobie prawo nieanalizowania postów pisanych niepoprawną polszczyzną.
Post generated automatically by A.I. system code name ‘mina86’ in response to the previous one.
Awatar użytkownika
Zielony
Użytkownik
Posty: 535
Rejestracja: 2005-03-17, 18:22
Lokalizacja: Poznań
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: Zielony »

No i jeżeli trafimy na daną domenę, to zapisujemy jej nazwę w kluczu tablicy asocjacyjnej, który od razu autoinkrementujemy.

Kod: Zaznacz cały

$domeny{$1}++;
$1 będzie nazwą domeny wyciągniętą z logów przy pomocy wyrażeń regularnych.

Na końcu lecimy w pętli for po kluczach tablicy i wyświetlamy wyjście.
Żyję - nie każdemu się zdarza - a we krwi mam chlorofil.
[url=http://scxd.info/][img]http://scxd.info/pub/scxdbar/scxd-bar.png[/img][/url]
[b]Registered User #448882[/b]
[img]http://scxd.info/say/img.php[/img]
miszmaniac
Moderator
Posty: 1510
Rejestracja: 2006-03-19, 12:00
Lokalizacja: Gdynia
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: miszmaniac »

Jest taki program logtail, który sam sobie zapisuje pozycje pliku.
Jakbyś się przerzucił na basha, to bardzo łatwo by się to dało napisać za pomocą właśnie, taillog, grep, i wc
Pamiętaj,
Jeśli Twój problem został rozwiązany dopisz [b] [Rozw.] [/b]w tytule.
Projektowanie stron WWW: [url=http://www.miszewski.net.pl]www.miszewski.net.pl[/url]
malyrd
Użytkownik
Posty: 26
Rejestracja: 2006-08-10, 19:22

Re: PERL - czytanie logow seserwa co godzine

Post autor: malyrd »

moze w ten sposob ?
zbyt zaawansowany nie jestem ale to dziala:

Kod: Zaznacz cały

#!/usr/bin/perl -w
#
#
use strict;
use Date::Calc qw/Delta_DHMS/;

my $file = '/var/log/syslog';
my @table;

open FH, "<$file";
 @table = <FH>;
close FH;

my %months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11, );

my ($sec1, $min1, $hour1, $day1, $month1, $year1) = localtime();

my $year2 = '107';
foreach my $line ( reverse(@table) ) {
    next unless $line =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)/;
    my $month2 = $months{$1};
    my $day2 = $2;
    my $hour2 = $3;
    my $min2 = $4;
    my $sec2 = $5;

    my ($days, $hours, $minutes, $seconds) = Delta_DHMS( $year2, $month2, $day2, $hour2, $min2, $sec2,
                                                         $year1, $month1, $day1, $hour1, $min1, $sec1);

    last if ! ( $days == 0 and $hours == 0 and $minutes < 50 );
        #
        # tu zliczanie wywolan poszczegolnych domen
        #
        #print $line;
}
Awatar użytkownika
mina86
Moderator
Posty: 3343
Rejestracja: 2004-06-14, 21:58
Lokalizacja: Linux 5.x x86_64
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: mina86 »

wc jest raczej zbędny. Wystarczy opcja -c grepa.

malyrd, bez sensu wczytywać cały plik.

Kod: Zaznacz cały

my %domains;
open LOG, '<', '/var/log/apache/costam/costam';
1 while (defined($_ = <LOG>) && !checkTime($_));
while (defined $_) {
    my $domain = extractDomain($_);
    $domains{$domain}++ if $domain;
    $_ = <LOG>;
}
close LOG;
printf "%-40s %5d\n", $_, $domains{$_} for sort keys %domains;
Gdzie checkTime sprawdza czy mamy dobrą datę, a extractDomain wyciąga nazwę domeny.
Ostatnio zmieniony 2007-08-03, 14:27 przez mina86, łącznie zmieniany 2 razy.
Zastrzegam sobie prawo nieanalizowania postów pisanych niepoprawną polszczyzną.
Post generated automatically by A.I. system code name ‘mina86’ in response to the previous one.
Awatar użytkownika
Sektor
Użytkownik
Posty: 271
Rejestracja: 2004-08-28, 12:21
Lokalizacja: Kraków

Re: PERL - czytanie logow seserwa co godzine

Post autor: Sektor »

Dziekuje za liczne pomysly

Ja wpadlem dzieki Waszym wypowiedziom na taki pomysl:

Z czasu systemowego wyciagam minuty i mam np '34', biore z nich sama koncowke, czyli '4'.
Dla rozwazan algorytmu przypisuje ta koncowke jako N.
W logach czas (data) rosnie z gory w dol pliku.
Czytam plik od konca (tak, tak, od tylu tez jest fajnie...), czyli data w czytanym pliku maleje, czyli minuty czytanych linii maleja. Sprawdzam czy koncowka czasu bierzacej linii pliku jest mniejsza od 5 dla N<=5 lub, wieksza lub rowna 5 dla N=5, jesli tak to parsuje linie, liczac domeny itd. Jesli nie, koncze dzialanie poniewaz nie bedzie wiecej linii spelniajacych kryterium zakresu 5 minut.

Wydaje mi sie ze taki algorytm bedzie najbardziej efektywny, gorzej z jego implementacja :)

znalazlem cos o czytaniu pliku od tylu w perl'u tu

Jakby ktos bardziej obeznany w Perl'u niz ja (takich sie znajdzie cala masa) cos poradzil bylbym wdzieczny

Pozdrawiam
malyrd
Użytkownik
Posty: 26
Rejestracja: 2006-08-10, 19:22

Re: PERL - czytanie logow seserwa co godzine

Post autor: malyrd »

mina86 z tego co widze to tez czytasz caly plik (z tym ze linia po linii).

najlepiej chyba byloby uzyc systemowy 'tac' (jak w powyzszej lince) i od przodu (czyli od tylu) zczytywac linie z odpowiadajacym czasem a reszte pominac...

co do logow to zalezy w jakim masz formacie czy data (mi przychodzi do glowy date::calc) czy ilosc sekund ktore uplynely od... itd. (wtedy poprostu porownujesz roznice obu czasow)
Awatar użytkownika
Sektor
Użytkownik
Posty: 271
Rejestracja: 2004-08-28, 12:21
Lokalizacja: Kraków

Re: PERL - czytanie logow seserwa co godzine

Post autor: Sektor »

[02/Aug/2007:15:30:08 +200] mam w logach :)

Pozdrawiam
malyrd
Użytkownik
Posty: 26
Rejestracja: 2006-08-10, 19:22

Re: PERL - czytanie logow seserwa co godzine

Post autor: malyrd »

cos mi tu sciemniasz :) my mamy za ciebie napisac ten skrypt ? wogole umiesz chociaz troszke perla ? bo inaczej o bedziemy sie krecic w koleczko. takze mow szybciutko jak na spowiedzi jak wyglada sprawa :)
Awatar użytkownika
Sektor
Użytkownik
Posty: 271
Rejestracja: 2004-08-28, 12:21
Lokalizacja: Kraków

Re: PERL - czytanie logow seserwa co godzine

Post autor: Sektor »

U mnie znajomosc Perla sprowadza sie do napisania kilku prostych programow typu hello world, mimo usilnych prob, nigdy jakos nie byle w stanie zajac sie nim na dluzej, bo jak sie uczyc czego co ma tak "pokrecona" skladnie. Jak nie napisze ktos rozwiazania w Perl'u to sobie skrobne w PHP, aczkolwiek Perl tu jest bardziej przydatny, dlatego tez napisalem ten temat na forum.

Pozdrawiam
Awatar użytkownika
Zielony
Użytkownik
Posty: 535
Rejestracja: 2005-03-17, 18:22
Lokalizacja: Poznań
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: Zielony »

malyrd pisze:mina86 z tego co widze to tez czytasz caly plik (z tym ze linia po linii)
Tylko że nie zapisuje go w tablicy tudzież innej zmiennej. Jest to dosyć istotne, gdyż logi mogą mieć wielkości kilkuset MB w ekstremalnych sytuacjach. Wtedy skrypt zajmie dodatkowo tyle MB RAMu, ile ma dany log, albo jeszcze więcej. Tak się po prostu nie robi, nawet jeżeli skrypt nie będzie przeznaczony do działania z taką ilością danych.
Żyję - nie każdemu się zdarza - a we krwi mam chlorofil.
[url=http://scxd.info/][img]http://scxd.info/pub/scxdbar/scxd-bar.png[/img][/url]
[b]Registered User #448882[/b]
[img]http://scxd.info/say/img.php[/img]
malyrd
Użytkownik
Posty: 26
Rejestracja: 2006-08-10, 19:22

Re: PERL - czytanie logow seserwa co godzine

Post autor: malyrd »

dzieki za podpowiedz jak napisalem ja tez jestem poczatkujacy :)

a teraz teoretyczne pytanie....
probuje skryptem robic sobie dhcpd.conf.
po kolei pobieram linie z /etc/hosts z ip i nazwa hosta a pozniej poszukuje w /etc/hosts.arp linii z ip i mac adresem jak cos takiego rozwiazac bez pakowania ktoregos z plikow w tablice ?
otwierac za kazdym krokiem petli jeden z plikow ? a jesli te pliki waza kilkanascie lub kilkaset mb ? i otwarc i zamkniec moze byc tysiace lub dziesiatki tysiecy ? jak wybrac mniejsze zlo lub moze zrobic to inaczej ?

dodam tylko ze dla pliku hosts (200 wpisow i podobnie w hosts.arp) metoda tablicy jest ok 2 razy szybsza :/
Ostatnio zmieniony 2007-08-03, 18:20 przez malyrd, łącznie zmieniany 2 razy.
Awatar użytkownika
mina86
Moderator
Posty: 3343
Rejestracja: 2004-06-14, 21:58
Lokalizacja: Linux 5.x x86_64
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: mina86 »

Sektor, IMO czytanie linii od końca to za dużo kłopotu. Jeżeli bardzo Ci zależy na przyśpieszeniu to możesz się zabawić w wyszukiwanie binarne, coś na zasadzie:

Kod: Zaznacz cały

my $start = 0;
my $end = get_file_size();
while ($end - $start > 262144) {
    fseek(LOG, ($end + $start)>>1);
    <>;
    $_ = <>;
    last if (checkDate($_));
    $start = ftell();
}
# I tutaj dalej to co podałem wcześniej
Tak mniej więcej z dokładnością do jakichś prostych błędów i nazw funkcji.
[02/Aug/2007:15:30:08 +200] mam w logach :)
No to funkcja checkTime(), którą używałem wygląda mniej więcej tak:

Kod: Zaznacz cały

{
    use POSIX;
    my $checkTimeValue = undef;
    my %months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11 };
    sub checkTime($) {
        my $line = shift;
        return 0 unless $line =~ m#\[(\d\d)/(...)/(\d\d\d\d):(\d\d):(\d\d):(\d\d)#;
        $checkTimeValue = time() unless defined $checkTimeValue;
        POSIX::mktime($6, $5, $4, $3, $months{$2}, $1) > $checkTImeValue - 300;
    }
}
Ostatnio zmieniony 2007-08-03, 20:02 przez mina86, łącznie zmieniany 1 raz.
Zastrzegam sobie prawo nieanalizowania postów pisanych niepoprawną polszczyzną.
Post generated automatically by A.I. system code name ‘mina86’ in response to the previous one.
Awatar użytkownika
Zielony
Użytkownik
Posty: 535
Rejestracja: 2005-03-17, 18:22
Lokalizacja: Poznań
Kontakt:

Re: PERL - czytanie logow seserwa co godzine

Post autor: Zielony »

malyrd pisze:jak cos takiego rozwiazac bez pakowania ktoregos z plikow w tablice ?
Może transformacje Schwartza byłyby tu jakoś pomocne, ale nie mogę wymyślić algorytmu.

Do analnego czytania plików najłatwiej użyć modułu File::ReadBackwards.
Żyję - nie każdemu się zdarza - a we krwi mam chlorofil.
[url=http://scxd.info/][img]http://scxd.info/pub/scxdbar/scxd-bar.png[/img][/url]
[b]Registered User #448882[/b]
[img]http://scxd.info/say/img.php[/img]
ODPOWIEDZ