Скрипт Python, который выполняет сопоставление строк в устаревших файлах, генерирует несогласованный вывод

Я создал сценарий python для анализа файлов журналов почты (exim) и выполнения сопоставления с образцом, чтобы получить список 100 лучших доменов отправки на моих серверах smtp. Однако каждый раз, когда я выполняю сценарий, я получаю другой счет. Это устаревшие файлы журналов, и я не могу найти функциональную ошибку в своем коде.

Example output:
    1:
    70353 gmail.com
    68337 hotmail.com
    53657 yahoo.com
    2:
    70020 gmail.com
    67741 hotmail.com
    54397 yahoo.com
    3:
    70191 gmail.com
    67917 hotmail.com
    54438 yahoo.com

Code:

#!/usr/bin/env python

import os
import datetime
import re
from collections import defaultdict

class DomainCounter(object):
def __init__(self):
    self.base_path = '/opt/mail_log'
    self.tmp = []
    self.date = datetime.date.today() - datetime.timedelta(days=14)
    self.file_out = '/var/tmp/parsed_exim_files-'  + str(self.date.strftime('%Y%m%d')) + '.decompressed'

def parse_log_files(self):
    sub_dir = os.listdir(self.base_path)
    for directory in sub_dir:
        if re.search('smtp\d+', directory):
            fileInput = self.base_path + '/' + directory + '/maillog-' + str(self.date.strftime('%Y%m%d')) + '.bz2'
            if not os.path.isfile(self.file_out):
                 os.popen('touch ' + self.file_out)
            proccessFiles = os.popen('/bin/bunzip2 -cd ' + fileInput + ' > ' + self.file_out)
            accessFileHandle =  open(self.file_out, 'r')
            readFileHandle = accessFileHandle.readlines()
            print "Proccessing %s." % fileInput
            for line in readFileHandle:
                if '<=' in line and ' for ' in line and '<>' not in line:
                    distinctLine = line.split(' for ')
                    recipientAddresses = distinctLine[1].strip()
                    recipientAddressList = recipientAddresses.strip().split(' ')
                    if len(recipientAddressList) > 1:
                        for emailaddress in recipientAddressList:
                            # Since syslog messages are transmitted over UDP some messages are dropped and needs to be filtered out.
                            if '@' in emailaddress:
                                (login, domein) = emailaddress.split("@")
                                self.tmp.append(domein)
                                continue
    else:
        try:
                                (login, domein) = recipientAddressList[0].split("@")
                                self.tmp.append(domein)
        except Exception as e:
             print e, '<<No valid email address found, skipping line>>'

    accessFileHandle.close()
    os.unlink(self.file_out)
return self.tmp


if __name__ == '__main__':
domainCounter = DomainCounter()
result = domainCounter.parse_log_files()
domainCounts = defaultdict(int)
top = 100
for domain in result:
    domainCounts[domain] += 1

sortedDict = dict(sorted(domainCounts.items(), key=lambda x: x[1], reverse=True)[:int(top)])
for w in sorted(sortedDict, key=sortedDict.get, reverse=True):
    print '%-3s %s' % (sortedDict[w], w)

person user.py    schedule 10.03.2014    source источник
comment
попробуйте просто запустить его в одном файле несколько раз и убедитесь, что вы получите тот же результат ... также запустите его с упрощенным файлом, чтобы убедиться, что результат соответствует вашим ожиданиям   -  person Joran Beasley    schedule 10.03.2014
comment
В вашем коде есть некоторые очевидные причуды. Например, в конце вы дважды звоните sorted(). Это почему? Еще одна нелогичная вещь: у вас есть for .... else конструкция, но break не используется. Разберитесь с этими вещами, прежде чем мы продолжим поиск этой ошибки.   -  person Dr. Jan-Philip Gehrcke    schedule 10.03.2014
comment
Похоже, вы делаете много акробатических трюков, чтобы разобрать файлы журнала. Есть ли шанс вставить снимок того, как выглядит один из этих файлов журнала?   -  person Joel Cornett    schedule 10.03.2014
comment
Не копаясь слишком глубоко в вашем коде, я предполагаю, что ваши разные результаты связаны с тем, что словарь не хранит и не гарантирует порядок элементов. Эта строка sortedDict = dict(sorted(domainCounts.items(), ...)) не имеет смысла, поскольку вы теряете порядок в момент создания словаря из упорядоченной последовательности двух кортежей.   -  person Dr. Jan-Philip Gehrcke    schedule 10.03.2014
comment
Я переформатировал код и исправил конструкцию for .... else. Кажется, проблема в моем механизме сортировки. Однако это решение (для меня) очень сложное. Есть идеи, как исправить сортировку словаря?   -  person user.py    schedule 11.03.2014


Ответы (1)


proccessFiles = os.popen('/bin/bunzip2 -cd ' + fileInput + ' > ' + self.file_out)

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

См. Также: Команда Python popen. Подождите, пока команда не будет завершена, поскольку os.popen устарел, начиная с python-2.6 (в зависимости от того, какую версию вы используете).

Примечание. То же самое происходит со строкой ниже. Файл может существовать, а может и не существовать после выполнения следующей строки:

os.popen('touch ' + self.file_out)
person Caramiriel    schedule 12.03.2014