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.
- 979 megtekintés
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.
- A hozzászóláshoz be kell jelentkezni
~> cat input
Apr 04 20:32:10 event01
Apr 04 20:32:13 event05
Apr 04 20:32:21 event02
Apr 04 20:33:02 event01
~> grep event01 input |grep 'Apr 04 20:' |wc -l
2
pipa kész, sör rendel.
- A hozzászóláshoz be kell jelentkezni
Ez az összes bejegyzést számolja egybe, nem az eventeket /időszak... szerintem.
- A hozzászóláshoz be kell jelentkezni
Igazából nem szorít az idő, van rá 1-2 nap.
Az időtartamok viszont brmikor lehetnek, a 24 órás periódus is indulhat mondjuk 14:38-kor.
Időközben addig jutottam, hogy az időpontokat sikerült linux timestamp-ra cserélni.
- A hozzászóláshoz be kell jelentkezni
akkor mar csak egy filterezés kell valami ilyesmi:
cat input2
1
2
3
4
5
6
7
~> cat a.sh
#!/bin/bash
min=3
max=5
while read line; do
if [ $line -le $max ] && [ $line -ge $min ]; then
echo $line
fi
done < input2
~> ./a.sh
3
4
5
- A hozzászóláshoz be kell jelentkezni
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...
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
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)
- A hozzászóláshoz be kell jelentkezni
Ha jól tévedek, ilyesmi volna:
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.
- A hozzászóláshoz be kell jelentkezni
Köszi mindenkinek. Nem gondoltom, hogy így pörögtök éjjel.
Közben ruby-ban írtam rá egyet magam is:
- A hozzászóláshoz be kell jelentkezni