Shell script kérdés

Sziasztok,

Van egy kb 400000 sor hosszú log, ami kb. fél éve gyűlik, az alábbi formátumban:

Apr 04 20:32:10 event01
Apr 04 20:32:13 event05
Apr 04 20:32:21 event02
Apr 04 20:33:02 event01
...

Ebből kellene kinyerni minden egyes event-re, hogy egy tetszőlegesen válaszott 60 perces vagy 24 órás időszakban az adott esemény hányszor következett be.
Tulajdonképpen azt kell megkapni, hogy mekkora az a legkisebb rate-limit, ami még nem akadályozta volna.

Sajnos most nem akar összeállni, hogy hogyan tudnám ezt kinyerni. Ha valakinek van rá jó ötlete, netán megoldása, azt hálásan megköszönném.

Hozzászólások

cat logfile | grep 'Apr 04 20' | grep -o 'event' | sort | uniq -c

Kiindulásképp (60 perces intervallum). Feltéve, hogy a 24 óra az egy nap és nem kifejezetten 24 darab óra, ami lehet akár egyik nap 14:00-tól köv. nap 14:00-ig is, és ugyanígy a 60 perc is adott órát jelent, mert azokra ez már nem jó.
És persze tudni kéne, hogy néz ki valójában az 'event<xx>'

Ha nem tegnapra kell és nincs jobb tipp addig, akkor holnap összerakhatok valamit perl-ben vagy pythonban.


cat input | while read a b c d; do echo $(date -d "$a $b $c" +%s)" $d"; done

Így már timestamp van a dátum helyett, vagyis 3600 illetve 86400 másodperces szakaszokat kell vizsgálni.

1522866730 event01
1522866733 event05
1522866741 event02
1522866782 event01

Sőt...

awk '{cmd="date -d \""$1" "$2" "$3"\" +%s"; cmd | getline timestamp; close(cmd); print timestamp,$4}' input

awk-ban talán már tudok vele valamit kezdeni...

Ha awk-ban megy a válogatás és tényleg csak a darabszám kell az egyes eventekhez, akkor (szerintem - bár gányolásnak tűnik), a legegyszerűbb amit lent is írtam: ha már csak az event van kirakva a stdout-ra, akkor mögé egy | sort | uniq -c

Picit egyszerűbb, mint awk-ban megírni.

Nagyjából (ízlés szerint memóriában is tarthatod):
1) végigszaladsz a fájlon és megkeresed az egyedi event-eket, beteszed őket egy set-be.
2) végigmész a set-ben levő eventeken és mindegyikre végignézed a fájlt, soronként. Ahol találsz egy olyan sort, ami olyan event, amit éppen nézel [felvésed, hogy hol állsz a fájlban], elindulsz tovább a fájlban és haladsz, amíg az időbélyegző a következő 60 percben/24 órában van és számolod őket - ha a kapott darabszámok valamelyike nagyobb, mint amit eddig láttál az adott event-hez, feljegyzed, hogy ez az új maximum. Ha több, mint 24 órára vagy, visszaállsz arra a pozícióra, amit feljegyeztél és folytatod a következő sorral. A fájl végéhez érve megnézed, mik voltak a legnagyobb maximumok és kiírod.

Szerk.:

pl. valami ilyen:


<?php
$lines = array_map(function($line) {
        list($month, $day, $time, $event) = explode(' ', rtrim($line), 4);
        return [strtotime("$month $day $time"), $event];
}, file('test.txt'));

$events = [];
foreach($lines as $line)
        $events[$line[1]] = [24 => -1, 60 => -1];

foreach($events as $event => &$stats) {
        for($i = 0; $i < count($lines); $i++) {
                if($lines[$i][1] !== $event) continue;
                $window = [24 => 1, 60 => 1];
                for($j = $i + 1; $j < count($lines); $j++) {
                        if(3600 * 24 < ($lines[$j][0] - $lines[$i][0])) break;
                        if($lines[$j][1] !== $event) continue;
                        $window[24]++;
                        $window[60] += (3600 > ($lines[$j][0] - $lines[$i][0])) ? 1 : 0;
                }
                if($window[60] > $stats[60]) {
                        $stats[60] = $window[60];
                }
                if($window[24] > $stats[24]) {
                        $stats[24] = $window[24];
                }
        }
        echo 'Limits for event ', $event, ': 60 minutes=', $stats[60], ', 24 hours=', $stats[24], PHP_EOL;
}

test.txt-ből olvassa az OP-ban levő formátumú sorokat, szokásos disclaimer, hogy nem vállalok érte felelősséget, nem biztos, hogy helyes és vagy sikerült benne elrejtenem egy sudo rm -rf / hívást vagy nem :) Na meg a Drupal és a hupper extension vagy belenyúlt vagy nem (Előnézetből vissza copy-pásztázva ugyanazt dobta a test file-ra, mint az eredeti, legalább)

Szerk 2.: "Szerk." felirat hozzáadása az első szerk-hez. És persze a fenti algoritmus/script feltételezi, hogy timestamp szerint időrendben vannak és ez végig igaz, úgyhogy az óraállítások idején csúnyán borulni fog a script az ugráló időpontok miatt.

Szerk 3.: hopsz... A $window[60] += ... sorban rossz irányba nézett a kacsa... javítva :)

Szerk 4.: lx lentebbi évváltós kommentje... teljesen jogos. Ha tényleg csak előző hat hónap, tehát nem lehet olyan tavalyi időpont benne, ami már idén is volt, akkor:


        list($month, $day, $time, $event) = explode(' ', rtrim($line), 4);
        $ts = strtotime("$month $day $time");
        if(time() < $ts)
                $ts = strtotime('-1 year', $ts);
        return [$ts, $event];

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Ha jól tévedek, ilyesmi volna:

https://pastebin.com/PE7W3q3K

A { period = substr($0,1,9) } sorban a 9 6-ra állításával lehet a napi számlálást elérni, vagy éppen 12-vel a percenkéntit - a 9 az órásat adja.

SZERK: éven túlmenő összegzés kellemetlen mellékhatással jár - de ez minden logra igaz, amelyből kispórolják az évszámokat.