Ask Your Question
1

apache.log a grep [closed]

asked 2015-04-25 17:04:34 +0100

Petr Gondek gravatar image

Náš oblíbený soubor apache.log zase zlobí tentokrát chceme ip adresy i z errorů :o)

Zadání:
Vypište nejčetnější IP adresu nebo adresy, pokud je jich více. Každou unikátní adresu vypište na samostatný řádek, seřazené vzestupně podle jednotlivých oktetů IP adresy zleva. Začleňte i chybové zprávy.

Náhled správného řádku a chybného z progtestu:

Oct 12 00:02:31 edux ap2[rpx]: 147.32.124.135 - - [10/1/2011:00:02:31 +0] "GET /BI-UOS/lec/03/3prednaska.pdf HTTP/1.1" 206 5830
Oct 12 00:02:59 edux ap2[rpx]: [Wed Oct 12 00:02:59 2011] [error] [client 147.32.123.136] File does not exist: /apache/data/muieblackcat

moje scripty

otázky:

  • Protože se to musí ukotvit " ", tak tam pravděpodobně bude nějaký řádek rozbitý (ve špatným formátu). Mám pravdu?
  • Proč 2. script nevezme IP adresy z "error" i z "ok" řádky?

nemam rád kočičky

edit retag flag offensive reopen delete

The question has been closed for the following reason "the question is answered, right answer was accepted" by Petr Gondek
close date 2015-05-15 12:50:12.451858

2 Answers

Sort by » oldest newest most voted
1

answered 2015-04-26 00:57:32 +0100

VojtechMyslivec gravatar image

Většina již byla řečena @Josef Kokeš, ale přeci jen pár detailů:

  1. egrep používá ERE, je tedy možné zvolit "operátor" nebo -- | (tedy: (RE1|RE2)). Tím je možné grepovat najednou dva odlišné výrazy.
    • U grep-u je možné si zase pomoci více přepínači: grep -e RE1 -e RE2 funguje jako nebo.
    • Pozor na to, že iterátor {1,3} nemusí dle POSIX normy funguvat.
  2. Pozor na to, že přepínač -o vypíše všechny nalezené vzory. Pokud se jich na řádce vyskytne více, vypíše všechny. Pomocí sed-u je možné spolehlivěji uričit např. první.
    • To může být jeden z problémů v první verzi.
  3. Nakonec stejně voláš awk. Lze to tedy všechno zjednodušit do jedné "roury".
    Jako podmínku pro danou akci pro awk je možné porovnávat s číslem řádku. NR == 1 je např. podmínka splněná pouze na 1. řádku resp. prvním záznamu.
  4. Doporučil bych nedělat nebo alespoň posléze smazat dočasné soubory.
  5. Ohledně druhé verze: řekl bych, že ne vždy musí být za IP adresou po mezeře pomlčka (: 1.2.3.4 -). Zkusil bych to ohraničit pouze mezerou (ještě lépe koncem slova -- odpadne tak nutnost filtrovat daný znak).
    • Každopádně je vidět, že třetí verze je lepší
    • Obecně pomocí RE se špatně rozlišuje 1.2.3.4.5 od 1.2.3.4 nebo podobných vychytávek. Múže se ale využít toho, že v tomto logu je před IP vždy mezera a za IP je buď mezera nebo hranatá závorka.
    • Lze to tedy popsat jedním výrazem, popřípadě si v awk odfiltrovat dané sloupce.

PS ohledně zabíjení kočiček: grep, awk, tail i další programy dokáží pracovat se soubory, stačí je předat jako argument. cat není opravdu potřeba. A i kdyby, přesměrování ze souboru funguje také ;]

edit flag offensive delete publish link more

Comments

ad 5 - Určitě bych ukončoval mezerou. "Konec slova" má smysl tam, kde se konce slova mohou lišit, např. ve zdrojácích. V logu by měl být fixně znak mezera, žádná variabilita, takže je podle mě chyba variabilitu zavádět do regexpu.

Josef Kokeš ( 2015-04-26 05:25:09 +0100 )edit

ad 3 - vůbec netuším, k čemu by v této úloze mělo být awk a porovnání čísla řádku. Zjevně ten samý nápad má víc lidí, koukal jsem teď na FIŤákovi, že někdo porovnává NR s dřívějším řádkem, ale vůbec nechápu proč. Co by to mělo řešit za problém?

Josef Kokeš ( 2015-04-26 05:35:07 +0100 )edit

3. Viz pastebin @gondepet. Druhá "sada" příkazů zjišťuje maximum na prvním řádku (to, co spočítá uniq -c) a pak se to dává jako proměnná pro awk.
Chtěl jsem tím jen říct, že awk si rovnou to maximum umí zjistit samo. Víme totiž, že je to na prvním řádku v prvním sloupci.
5. Jde o to, že v tomto logu se počítají IP adresy na dvou různých řádcích:
- Na normálních řádcích je IP adresa ohraničená zleva i zprava mezerou
- Na chybových řádcích je IP adresa ohraničená zleva mezerou a zprava hranatou závorkou
- Konec slova je obyčejně univerzální, ale \<IP\> neodfiltruje např. 1.2.3.4.5 (sedí to totiž na 1.2.3.4)

VojtechMyslivec ( 2015-04-26 15:11:33 +0100 )edit
2

answered 2015-04-25 19:41:08 +0100

Josef Kokeš gravatar image

updated 2015-04-25 19:46:54 +0100

  1. Vaší otázce nerozumím. Zkuste ji prosím zprecizovat, co přesně myslíte tím, že bude některý řádek rozbitý (a proč to podle vás vadí). Takhle mohu jenom říct, že nějaké omezení kolem IP adresy je nutné, protože jinak vám vyhoví také řádky obsahující třeba 1.2.3.4.5.6.7.8.9.10 někde uvnitř URL.

  2. Proč konkrétně to selže nevím, ale jeden z důvodů by mohl být, že mezi prvním a druhým voláním grepu do souboru apache.log přibyly nové řádky, které by první grep měl zachytit, ale nezachytí, protože už proběhl. Jde o stejný problém race condition, jako byl loni s těmi datumy. Měl byste rozhodně celý soubor zpracovat jedním příkazem.

Kdybych to měl řešit já, tak to udělám sedem, tím by to mělo jít dost snadno.

"Prošlo na 100%" je podle mě špatně, chybí zakončení IP adresy. Že to Progtest vzal, to je hezké, ale stejně je to špatně. Nespoléhal bych na to. (Ale aspoň máte důvod, proč preferovat testy na počítači - člověk by vám tohle ohodnotil jako chybné, zatímco Progtest má udělanou nějakou sadu testů a může se vám stát, že se vám podaří zkonstruovat špatné řešení, které projde.)

edit flag offensive delete publish link more

Comments

na otázku č. 1 jste mi odpověděl. Jak by jste to dělal tím sedem? Sed moc neumím a dělám všechno bez něj.

Petr Gondek ( 2015-04-26 00:39:18 +0100 )edit

sed umí nahrazovat. Takže bych nedělal jenom vyhledání výrazu IPregexp, kde potom budu muset řešit ještě vytáhnutí IP adresy (dvě různá vytáhnutí pro dva různé typy řádků), ale rovnou nahrazení výrazu ^.*(IPregexp).*$ výrazem \1. Tím bych nejen našel požadované řádky, jako to dělá vaše současné řešení, ale zároveň bych je zbavil nesmyslů kolem IP adresy a sjednotil tak obsah. Díky tomu bych pak mohl zpracovat oba typy řádků najednou.

Josef Kokeš ( 2015-04-26 05:19:13 +0100 )edit

@Josef Kokeš tady bych jen doplnil, že v BRE je potřeba kulaté závorky "escape-ovat" zpětným lomítkem. Jinak se berou jako obyčejné znaky.
Též je zde potřeba ohraničit podvýraz IPregexp tou mezerou a případně koncem slova. Jinak to opět sežere adresy 1.2.3.4.5, jak si sám už zmiňoval.
A ano, toto řešení je rozhodně lepší, protože se všechno zvládne v jednom příkazu a není potřeba žádný tr, cut apod.

VojtechMyslivec ( 2015-04-26 15:16:04 +0100 )edit

Psal jsem to jako koncept řešení, ne jako hotový příkaz. Předpokládal jsem, že IPregexp bude obsahovat všechno, i potřebné oddělovače.

Josef Kokeš ( 2015-04-26 15:25:50 +0100 )edit

Ty oddělovače by ale měly být mimo \( a \), aby se právě ušetřily ty příkazy cut.
Chtěl jsem to jen doplnit, aby se pak někdo neopíral o to, že to "říkal Pepa na askfit"... ;]

VojtechMyslivec ( 2015-04-26 15:32:32 +0100 )edit

Question tools

Follow
1 follower

Stats

Asked: 2015-04-25 17:04:34 +0100

Seen: 248 times

Last updated: Apr 26 '15