Czytałem wszystkie artykuły mogę znaleźć, nawet zrozumiałe, kilka z nich, ale jako NEWB Pythona nadal jestem trochę zagubiony i licząc na pomoc :)Wielu pasującej linii w Pythonie
I "Pracuję nad skryptem do analizowania interesujących rzeczy z pliku dziennika specyficznego dla aplikacji, każda linia zaczyna się od znacznika czasu, który mogę dopasować i mogę zdefiniować dwie rzeczy do zidentyfikowania tego, co chcę przechwycić, częściową zawartość i ciąg znaków to będzie zakończenie tego, co chcę wydobyć.
Mój problem jest wieloliniowy, w większości przypadków każda linia dziennika jest zakończona znakiem nowej linii, ale niektóre pozycje zawierają kod SQL, który może zawierać nowe wiersze i dlatego tworzy nowe linie w dzienniku.
więc w najprostszym przypadku może mam to:
[8/21/13 11:30:33:557 PDT] 00000488 SystemOut O 21 Aug 2013 11:30:33:557 [WARN] [MXServerUI01] [CID-UIASYNC-17464] BMXAA6720W - USER = (ABCDEF) SPID = (2526) app (ITEM) object (ITEM) : select * from item where ((status != 'OBSOLETE' and itemsetid = 'ITEMSET1') and (exists (select 1 from maximo.invvendor where (exists (select 1 from maximo.companies where ((contains(name,' $AAAA ') > 0)) and (company=invvendor.manufacturer and orgid=invvendor.orgid))) and (itemnum = item.itemnum and itemsetid = item.itemsetid)))) and (itemtype in (select value from synonymdomain where domainid='ITEMTYPE' and maxvalue = 'ITEM')) order by itemnum asc (execution took 2083 milliseconds)
To wszystko pojawia się jako jednej linii, które można dopasować z tym:
re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2}).*(milliseconds)')
Jednak w niektórych przypadkach może być linia łamie w SQL, jako taki chcę go nadal przechwytywać (i potencjalnie zastępować linie spacjami). Obecnie czytam ten plik w wierszu, co oczywiście nie zadziała, więc ...
- Czy muszę przetworzyć cały plik za jednym razem? Zwykle mają rozmiar 20 mb. Jak czytać cały plik i przeglądać go, szukając bloków jedno- lub wieloliniowych?
- Jak napisać wieloliniowy raport RegEx, który pasowałby do całej rzeczy w jednym wierszu lub byłby rozłożony na wiele linii?
Moim nadrzędnym celem jest parametryzacji to więc można go używać do wydobywania wpisy dziennika, które odpowiadają różne wzory napisu początkowego (zawsze na początku linii), ciąg kończąc (gdzie chcę uchwycić to) i wartość, która jest między nimi jako identyfikator.
Dzięki z góry za wszelką pomoc!
Chris.
import sys, getopt, os, re
sourceFolder = 'C:/MaxLogs'
logFileName = sourceFolder + "/Test.log"
lines = []
print "--- START ----"
lineStartsWith = re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2})(\)')
lineContains = re.compile('.*BMXAA6720W.*')
lineEndsWith = re.compile('(?:.*milliseconds.*)')
lines = []
with open(logFileName, 'r') as f:
for line in f:
if lineStartsWith.match(line) and lineContains.match(line):
if lineEndsWith.match(line) :
print 'Full Line Found'
print line
print "- Record Separator -"
else:
print 'Partial Line Found'
print line
print "- Record Separator -"
print "--- DONE ----"
Następny krok, dla mojej częściowej linii będę kontynuować czytanie aż znajdę lineEndsWith i zmontuję linie do jednego bloku.
Nie jestem ekspertem, więc sugestie są zawsze mile widziane!
AKTUALIZACJA - Tak więc pracuję, dzięki wszystkim odpowiedziom, które pomogły mi w kierowaniu, zdaję sobie sprawę, że to nie jest ładne i muszę posprzątać mój bałagan/elif i sprawić, by był bardziej wydajny, ale DZIAŁA! Dzięki za całą pomoc.
import sys, getopt, os, re
sourceFolder = 'C:/MaxLogs'
logFileName = sourceFolder + "/Test.log"
print "--- START ----"
lineStartsWith = re.compile('\[(0?[1-9]|[12][0-9]|3[01])(\/)(0?[1-9]|[12][0-9]|3[01])(\/)([0-9]{2})(\)')
lineContains = re.compile('.*BMXAA6720W.*')
lineEndsWith = re.compile('(?:.*milliseconds.*)')
lines = []
multiLine = False
with open(logFileName, 'r') as f:
for line in f:
if lineStartsWith.match(line) and lineContains.match(line) and lineEndsWith.match(line):
lines.append(line.replace("\n", " "))
elif lineStartsWith.match(line) and lineContains.match(line) and not multiLine:
#Found the start of a multi-line entry
multiLineString = line
multiLine = True
elif multiLine and not lineEndsWith.match(line):
multiLineString = multiLineString + line
elif multiLine and lineEndsWith.match(line):
multiLineString = multiLineString + line
multiLineString = multiLineString.replace("\n", " ")
lines.append(multiLineString)
multiLine = False
for line in lines:
print line
Czy próbowałeś użyć flagi 're.DOTALL'? Będziesz musiał sprawić, że część '. *' Będzie leniwą ('. *?'), A ponieważ czytasz wiersz po linii, zadziała, jeśli przeczytasz cały plik za jednym razem. Nie jestem jednak pewien co do implikacji dotyczących pamięci/wydajności. – Jerry
Możesz spróbować odczytać cały plik, a następnie podzielić tekst za pomocą wyrażenia dopasowującego sygnatury czasowe bezpośrednio po znakach nowej linii. To powinno ci dać listę ciągłych pojedynczych logów, chyba że Twoi użytkownicy umieszczają rzeczy takie jak "\ n [8/21/13 11: 30: 33: 557 PDT]" "w swoich SQL ... w takim przypadku Ty Pewnie pojawiły się inne problemy. –
Zaczynam się teraz zastanawiać, czy lepiej byłoby wrócić do linii po linii tak, żebym czytał wiersz po linii, jeśli linia pasuje do moich wartości "start" i "zawiera", mam mecz, który następnie musisz sprawdzić znacznik "końca" lub, jeśli nie jest, czytaj dalej i dołączaj linie, dopóki go nie znajdę. Myślę, że mam szczęście, ponieważ wiem, że początek i koniec zawsze będą tam, po prostu muszę ich szukać. – Chris