Найти - Пользователи
Полная версия: Номера строк в файле
Начало » Python для новичков » Номера строк в файле
1
lomach
В питоне новичек. Использую CentOS 5.7 и python 2.4 (обновить python не проблема).
Пишу парсер логов.
Задача:
1) рекурсивно парсить файлы в директории и всех вложенных директориях.
2) при нахождении нужного шаблона, введенного в качестве аргумента скрипту вручную, подниматься и парсить несколько строк выше, чтобы получить дату и время события в логе (такова структура лога).

dir = '/var/log/mysoft/'
for root, dirs, files in os.walk(dir):
for name in files:
fullname = os.path.join(root, name)
fh = open(fullname)
for line in fh.readlines():
if re.search(sys.argv[1], line):
print fullname
print line
Проблема в следующем:
Не знаю как получить номер строки и соответственно при нахождении нужной строки не знаю, как начать парсить строки выше на предмет наличия даты.
Подойдет ли данной задачи что-то еще кроме readlines()?
Поиск по форуму выдал только это - http://python.su/forum/viewtopic.php?id=4103
Но я изначально не знаю, какая строка мне нужна.
s0rg
1. readlines - не самый оптимальный вариант. Лучше избегать его.
2. зачем os.walk? логи могут быть в поддиректориях?
3. лучше всего - дайте пример лога
lomach
s0rg
1. readlines - не самый оптимальный вариант. Лучше избегать его.
Избегать в пользу чего?

s0rg
2. зачем os.walk? логи могут быть в поддиректориях?
Да, могут.

s0rg
3. лучше всего - дайте пример лога
Date: 29.01.2012 10:16

java.lang.NullPointerException
hirondelle.electricity.main.home.Spending.validateState(Spending.java:93)
hirondelle.electricity.main.home.Spending.<init>(Spending.java:37)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at
hirondelle.web4j.model.ModelCtorUtil.buildModelObject(Unknown Source)
at hirondelle.web4j.model.ModelFromRequest.build(Unknown
Source)
at
hirondelle.electricity.main.home.SpendingAction.validateUserInput(SpendingAc
tion.java:45)
at
hirondelle.web4j.action.ActionTemplateListAndEdit.execute(Unknown Source)
at
hirondelle.web4j.Controller.checkOwnershipThenExecuteAction(Unknown Source)
at hirondelle.web4j.Controller.processRequest(Unknown
Source)
at hirondelle.web4j.Controller.doPost(Unknown Source)
at
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
Допустим в этом стек-трейсе мы получаем ошибку “Spending.java:93”.
Мне нужно вывести этот трейс (или хотя бы только строку) НО с датой и временем, когда это произошло, которые расположены на несколько строк выше. (Дополнительно в качестве параметра скрипту планирую указывать временные диапазоны с … по …).
doza_and
гораздо быстрее будет просто read
и поиск нужного вам места в полученной строке регулярным выражением. Если надо более аккуратно делать - то выкусить потом кусок вокруг найденного места и распарсить его по человечески например с использованием pyparsing или регулярками.

Это будет хорошо работать если логи маленькие (те лезут в оперативку), но судя по всему у вас они такие.

Если таких действий в дальнейшем будет много логичнее засосать все в базу данных, например в mongodb http://www.slideshare.net/WombatNation/logging-app-behavior-to-mongo-db
py.user.next
lomach
python 2.4 (обновить python не проблема)
license()
    2.4             2.3         2004        PSF         yes
2012 - 2004 = 8
lomach
doza_and
гораздо быстрее будет просто read
и поиск нужного вам места в полученной строке регулярным выражением. Если надо более аккуратно делать - то выкусить потом кусок вокруг найденного места и распарсить его по человечески например с использованием pyparsing или регулярками.

Это будет хорошо работать если логи маленькие (те лезут в оперативку), но судя по всему у вас они такие.

Если таких действий в дальнейшем будет много логичнее засосать все в базу данных, например в mongodb http://www.slideshare.net/WombatNation/logging-app-behavior-to-mongo-db
У меня логи как раз не маленькие с различными уровнями вложенности.
Располагаются на десятках распределенных серверов и пишутся очень интенсивно. Именно поэтому и хочется автоматизировать поиск ошибки, потому что пока смотришь на одном сервере, другой уже завалился.
По поводу mongodb и запись логов в БД. Я думаю, один сервер mongodb не выдержит, а городить целый кластер совершенно не хочет по экономическим и административным причинам.
s0rg
lomach
пишутся очень интенсивно.
Вам тогда нужно посмотреть в сторону inotify (он точно есть в Twisted)

По поводу вашего лога, самый оптимальный вариант, как мне кажется - это парсинг с накоплением:
#!/usr/bin/env python
#coding: utf8

LOG_EXAMPLE='''Date: 29.01.2012 10:16

java.lang.NullPointerException
hirondelle.electricity.main.home.Spending.validateState(Spending.java:93)
hirondelle.electricity.main.home.Spending.<init>(Spending.java:37)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at hirondelle.web4j.model.ModelCtorUtil.buildModelObject(Unknown Source)
at hirondelle.web4j.model.ModelFromRequest.build(Unknown Source)
at hirondelle.electricity.main.home.SpendingAction.validateUserInput(SpendingAction.java:45)
at hirondelle.web4j.action.ActionTemplateListAndEdit.execute(Unknown Source)
at hirondelle.web4j.Controller.checkOwnershipThenExecuteAction(Unknown Source)
at hirondelle.web4j.Controller.processRequest(Unknown Source)
at hirondelle.web4j.Controller.doPost(Unknown Source)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
'''.splitlines()

def simple_parser(log, needle):
last_date = None

for line in log:
line = line.strip()
if line:
if line.startswith('Date:'):
last_date = line
elif (needle in line) and (last_date is not None):
return (last_date, line)
return (None, None)

print simple_parser(LOG_EXAMPLE, 'Spending.java:93')
#output: ('Date: 29.01.2012 10:16', 'hirondelle.electricity.main.home.Spending.validateState(Spending.java:93)')
lomach
py.user.next
Вы меня пристыдили. Обновил python до версии 2.7.2.

Проблему решили с использованием “grep -B -A”.
Не знаю, насколько это грязный хак, но работает.

Всем спасибо за помощь.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB