Как прочитать и обрезать файл журнала snmptrapd без перезапуска демона

я сделал скрипт python, который выполняет проверку nagios. Функциональность скрипта довольно проста, он просто анализирует журнал и сопоставляет некоторую информацию, которая используется для построения вывода проверки nagios. Журнал представляет собой журнал snmptrapd, который записывает ловушки с других серверов и регистрирует их /var/log/snmptrapd после того, как я просто анализирую их с помощью сценария. Чтобы иметь последние ловушки, я стираю журнал из python каждый раз после его чтения. Чтобы сохранить информацию, я сделал задание cron, которое копирует содержимое журнала в другой журнал с интервалом времени, немного меньшим, чем интервал проверки nagios. Я не понимаю, почему журнал так сильно растет (я имею в виду, что журнал сообщений, в котором, я думаю, в 1000 раз больше информации, меньше). Из того, что я видел в журнале, есть много специальных символов, таких как ^@, и я думаю, что это делается тем, как я манипулирую файлом из pyton, но, видя, что у меня есть только три недели опыта работы с ним, я не могу понять проблему.

Код скрипта следующий:

import sys, os, re

validstring = "OK"
filename = "/var/log/snmptrapd.log"

if os.stat(filename)[6] == 0:
        print validstring
        sys.exit()

else:
        f = open(filename,"r")
        sharestring = ""
        line1 = []
        patte0 = re.compile("[0-9]+-[0-9]+-[0-9]+")
        patte2 = re.compile("NG: [a-zA-Z\s=0-9]+.*")
        for line in f:
                line1 = line.split(" ")
                if re.search(patte0,line1[0]):
                        sharestring = sharestring + line1[1] + " "
                        continue
                result2 = re.search(patte2,line)
                if result2:
                        result22 = result2.group()
                        result22 = result22.replace("NG:","")
                        sharestring = sharestring + result22 + " "
        f.close()
        f1 = open(filename,"w")
        f1.close()
        print sharestring
        sys.exit(2)

~

Журнал выглядит так:

2012-07-11 04:17:16 Some IP(via UDP: [this is an ip]:port) TRAP, SNMP v1, community somestring
    SNMPv2-SMI::enterprises.OID Some info which is not necesarry
    SNMPv2-MIB::sysDescrOID = STRING: info which i'm matching

Я почти уверен, что это как-то связано с моим способом стирания файла, но я не могу этого понять. Если у вас есть идея, мне было бы очень интересно. Спасибо.

В качестве информации о размере у меня есть 93 строки (так говорит Vim), а журнал занимает 161 КБ, и это не нормально, потому что строки довольно короткие.

Хорошо, это не имеет ничего общего с тем, как я прочитал и стер файл. Что-то в демоне snmptrapd делает это, когда я стираю его файл журнала. Я изменил свой код, и теперь я отправляю SIGSTOP в snmptrapd прямо перед тем, как открыть файл, и я вношу свои изменения в файл, а затем отправляю SIGCONT после того, как я закончу, но, похоже, я испытываю такое же поведение. Новый код выглядит так (разные части):

else:
    command = "pidof snmptrapd"
    p=subprocess.Popen(shlex.split(command),stdout=subprocess.PIPE)
    pidstring = p.stdout.readline()
    patte1 = re.compile("[0-9]+")
    pidnr = re.search(patte1,pidstring)
    pid = pidnr.group()
    os.kill(int(pid), SIGSTOP)
    time.sleep(0.5)
    f = open(filename,"r+")
    sharestring = ""

и

                  sharestring = sharestring + result22 + " "
    f.truncate(0)
    f.close()
    time.sleep(0.5)
    os.kill(int(pid), SIGCONT)
    print sharestring

Я думаю о том, чтобы остановить демона, стирающего файл, а затем воссоздать его с соответствующими разрешениями и запустить демон.


person primero    schedule 11.07.2012    source источник
comment
@Jarrod Это заменит файл пустым   -  person GP89    schedule 11.07.2012
comment
Я получил идею отсюда mail.python.org/pipermail/tutor/ 2010-февраль/074323.html . Я не правильно выразился, мне нужно очистить содержимое файла, а не совсем удалить его, потому что, если я его удалю, мне придется перезапустить демон, и это довольно сложное решение, если есть способ сделать это без возможности удаления.   -  person primero    schedule 11.07.2012
comment
@primero, о чем daemon ты говоришь? мы не знаем, что вы знаете. предоставьте больше деталей, чем вы думаете, что вам нужно.   -  person    schedule 11.07.2012
comment
@Jarrod Извини за это. Мне нужно перезапустить демон snmptrapd, у которого есть опция для файла журнала. Из того, что я видел, когда я стираю файл snmpdtrapd.log, демон должен быть перезапущен, чтобы знать, в какой файл писать.   -  person primero    schedule 11.07.2012
comment
Если что-то пишется в файле, а вы перезаписываете его open(..., O_TRUNC), а затем close, я думаю, вы заставите писателей создать файл с дырками. Это могло бы объяснить ^@ (обычное представление нулевого байта), поскольку нулевые байты - это то, как дыры (нераспределенное хранилище) представляются пользовательскому пространству при чтении. Если это так, я боюсь, если другие процессы, которые пишут файл журнала, не будут сотрудничать (например, разрешив отправить им SIGHUP, чтобы повторно открыть файл журнала), вы не сможете избежать нехватки места.   -  person fork0    schedule 11.07.2012


Ответы (1)


Я не думаю, что вы можете, но вот некоторые вещи, чтобы попробовать

Усечение файла

f1 = open(filename, 'w')
f1.close()

является хакерским побочным эффектом удаления содержимого файлов и, вероятно, будет вызывать нежелательные побочные эффекты в зависимости от базовой ОС, если другие приложения откроют этот файл.

Использование метода truncate() файлового объекта

truncate([size])

Сократите размер файла. Если присутствует необязательный аргумент размера, файл усекается (максимум) до этого размера. Размер по умолчанию соответствует текущей позиции. Текущая позиция файла не изменяется. Обратите внимание, что если указанный размер превышает текущий размер файла, результат зависит от платформы: возможно, файл может остаться неизменным, увеличиться до указанного размера, как если бы он был заполнен нулями, или увеличиться до указанного размера с неопределенным новым содержимым. Доступность: Windows, множество вариантов Unix.

Вероятно, единственный детерминистский способ сделать это

остановите процесс snmptrapd в начале сценария, используйте соответствующую функцию os module remove, а затем заново создайте файл и перезапустите демон snmptrapd в конце сценария.

os.remove(path)

Удалить (удалить) путь к файлу. Если путь является каталогом, возникает ошибка OSError; см. rmdir() ниже, чтобы удалить каталог. Это идентично функции unlink(), описанной ниже. В Windows попытка удалить файл, который используется, приводит к возникновению исключения; в Unix запись каталога удаляется, но хранилище, выделенное для файла, не становится доступным до тех пор, пока исходный файл больше не используется.

Общая забота о ресурсах

У вас все еще могут быть проблемы с двумя процессами, пытающимися бороться за запись в один файл без какого-либо механизма блокировки и с недетерминированными вещами, происходящими с файлом. Бьюсь об заклад, вы можете отправить SIGINT или что-то подобное вашему процессу демона и заставить его перечитать файл или что-то в этом роде, проверьте свою документацию.

Манипулирование общими ресурсами, особенно файловыми ресурсами без монопольной блокировки, будет проблематичным, особенно при кэшировании файловой системы и кэшировании данных приложениями.

person Community    schedule 11.07.2012
comment
Удаление файла не представляется возможным. Вместо этого @primero хочет удалить только содержимое файла. - person Rodrigue; 11.07.2012
comment
Итак, я мог бы использовать f.truncate([0]), чтобы стереть содержимое файла, не удаляя его? - person primero; 11.07.2012
comment
Я тестировал интерпретатор командной строки, и f.truncate(0), кажется, помогает. Я попробую это в сценарии и дам вам знать, как это работает. Спасибо за информацию. - person primero; 11.07.2012
comment
Это то же самое. У меня есть первая строка, которая занимает два монитора, заполненных символами ^@, и они занимают 40 КБ пространства. - person primero; 11.07.2012
comment
Я думаю сделать что-то вроде чтения каждой строки и для каждой строки, чтобы написать ответ - person primero; 11.07.2012
comment
Я не знаком с работой с сигналами процесса, но не попробовать ли мне отправить SIGSTOP, подождать совсем немного, а затем отправить SIGCONT, чтобы просто приостановить процесс, а затем возобновить его? - person primero; 11.07.2012
comment
@primero это зависит от того, отвечает ли snmptrapd на любой из этих сигналов и что он делает, если отвечает на них - person ; 11.07.2012
comment
@Jarrod демон не отвечал на сигналы, а скрипт запускается демоном nagios, поэтому он имеет разрешения nagios, поэтому такие вещи, как отправка сигналов или отключение демона, невозможны. Демон snmptrapd имеет доступ к порту udp:162, а это порт с ограниченным доступом, доступ к которому есть только у root. Я разработал другой метод, потому что это, кажется, был тупик. - person primero; 12.07.2012