Поиск по сайту:

Часы не показывают время, а символизируют его (Авессалом Подводный).

Проблемы с практикой Python. Приготовьтесь к следующему собеседованию. Анализатор журнала. Часть 38 мин для чтения

FavoriteLoadingДобавить в избранное
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...
5 октября 2020
Проблемы с практикой Python. Приготовьтесь к следующему собеседованию

Практическая задача Python 4: анализатор журнала

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

 

Описание проблемы

Для этой проблемы вам нужно проанализировать файл журнала в указанном формате и создать отчет:

# logparse.py
""" log parser
    Accepts a filename on the command line. The file is a Linux-like log file
    from a system you are debugging. Mixed in among the various statements are
    messages indicating the state of the device. They look like this:
        Jul 11 16:11:51:490 [139681125603136] dut: Device State: ON
    The device state message has many possible values, but this program cares
    about only three: ON, OFF, and ERR.

    Your program will parse the given log file and print out a report giving
    how long the device was ON and the timestamp of any ERR conditions.
"""

 

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

Прилагается файл test.log с примером. Решение, которое вы исследуете, дает следующий результат:

$./logparse.py test.log
Device was on for 7 seconds
Timestamps of error events:
   Jul 11 16:11:54:661
   Jul 11 16:11:56:067

 

Хотя этот формат генерируется решением Real Python, вы можете создать свой собственный формат для вывода. Образец входного файла должен генерировать эквивалентную информацию.

 

Решение проблемы

Полное решение

Поскольку это решение длиннее, чем то, что вы видели для целых сумм или задач с шифром Цезаря, давайте начнем с полной программы:

# logparse.py
""" log parser
    Accepts a filename on the command line. The file is a Linux-like log file
    from a system you are debugging. Mixed in among the various statements are
    messages indicating the state of the device. They look like this:
        Jul 11 16:11:51:490 [139681125603136] dut: Device State: ON
    The device state message has many possible values, but this program cares
    about only three: ON, OFF, and ERR.

    Your program will parse the given log file and print out a report giving
    how long the device was ON and the timestamp of any ERR conditions.
"""
import datetime
import sys

def get_next_event(filename):
    with open(filename, "r") as datafile:
        for line in datafile:
            if "dut: Device State: " in line:
                line = line.strip()
                # Parse out the action and timestamp
                action = line.split()[-1]
                timestamp = line[:19]
                yield (action, timestamp)

def compute_time_diff_seconds(start, end):
    format = "%b %d %H:%M:%S:%f"
    start_time = datetime.datetime.strptime(start, format)
    end_time = datetime.datetime.strptime(end, format)
    return (end_time - start_time).total_seconds()

def extract_data(filename):
    time_on_started = None
    errs = []
    total_time_on = 0

    for action, timestamp in get_next_event(filename):
        # First test for errs
        if "ERR" == action:
            errs.append(timestamp)
        elif ("ON" == action) and (not time_on_started):
            time_on_started = timestamp
        elif ("OFF" == action) and time_on_started:
            time_on = compute_time_diff_seconds(time_on_started, timestamp)
            total_time_on += time_on
            time_on_started = None
    return total_time_on, errs

if __name__ == "__main__":
    total_time_on, errs = extract_data(sys.argv[1])
    print(f"Device was on for {total_time_on} seconds")
    if errs:
        print("Timestamps of error events:")
        for err in errs:
            print(f"t{err}")
    else:
        print("No error events found.")

 

Это ваше полное решение. Вы можете видеть, что программа состоит из трех функций и основного раздела. Вы будете работать через них сверху.

 

Вспомогательная функция: get_next_event()

Во-первых, это get_next_event():

# logparse.py
def get_next_event(filename):
    with open(filename, "r") as datafile:
        for line in datafile:
            if "dut: Device State: " in line:
                line = line.strip()
                # Parse out the action and timestamp
                action = line.split()[-1]
                timestamp = line[:19]
                yield (action, timestamp)

 

Читать  4 совета по оптимизации производительности для более быстрого кода на Python

Потому что он содержит в себе оператор yield, эта функция является генератор. Это означает, что вы можете использовать его для создания одного события из файла журнала За один раз.

Вы могли бы просто использовать for line in datafile, но вместо этого вы добавляете немного фильтрации. Вызов рутины будет получать только те события, которые имеют dut: Device State: в них. Это позволяет сохранить весь специфичный для файла синтаксический анализ, содержащийся в одной функции.

Это может сделать get_next_event() немного сложнее, но это относительно небольшая функция, поэтому она остается достаточно короткой, чтобы читать и понимать. Он также сохраняет этот сложный код инкапсулированным в одном месте.

Вам может быть интересно, когда datafile закрывается. До тех пор, пока вы не вызовете генератор, пока все строки не будут прочитаны из datafile, for петля завершится, позволив вам покинуть with заблокируйте и выйдите из функции.

 

Вспомогательная функция: compute_time_diff_seconds()

Вторая функция – это compute_time_diff_seconds(), которая, как следует из названия, вычисляет количество секунд между двумя метками времени:

# logparse.py
def compute_time_diff_seconds(start, end):
    format = "%b %d %H:%M:%S:%f"
    start_time = datetime.datetime.strptime(start, format)
    end_time = datetime.datetime.strptime(end, format)
    return (end_time - start_time).total_seconds()

 

В этой функции есть несколько интересных моментов. Во-первых, это вычитание двух datetime объекты приводят к datetime.timedelta. Для этой проблемы вы сообщите общее количество секунд, так что возвращайтесь .total_seconds() из timedelta, это уместно.

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

Вот и все, datetime.datetime.strptime() это достойно упоминания. При передаче строки и определенного формата, .strptime() анализирует эту строку с заданным форматом и производит datetime объект.

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

 

Вспомогательная функция: extract_data()

Следующий шаг-это extract_data(), который выполняет основную часть работы в этой программе. Прежде чем вы погрузитесь в код, давайте вернемся назад и поговорим о государственных машинах.

Государственная машина являются ли программные (или аппаратные) устройства, которые переходят от одного государство к другому в зависимости от конкретных входных данных. Это действительно широкое определение, которое может быть трудно понять, поэтому давайте посмотрим на диаграмму государственной машины, которую вы будете использовать ниже:

Проблемы с практикой Python. Приготовьтесь к следующему собеседованию. Анализатор журнала. Часть 3

 

На этой диаграмме состояния представлены помеченными прямоугольниками. Здесь есть только два Device State: ON и OFF, которые соответствуют состоянию устройства. Есть также два входных сигнала, Device State: ON и Device State: OFF. Диаграмма использует стрелки, чтобы показать, что происходит, когда ввод происходит, пока машина находится в каждом состоянии.

Например, если машина находится в Device State: ON происходит ввод данных, после чего машина остается в ON. Никаких изменений не происходит. И наоборот, если машина получает Device State: OFF ввод, когда он находится в ON состояние, то оно будет переходить в OFF.

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

Давайте вернемся к extract_data():

# logparse.py
def extract_data(filename):
    time_on_started = None
    errs = []
    total_time_on = 0

    for action, timestamp in get_next_event(filename):
        # First test for errs
        if "ERR" == action:
            errs.append(timestamp)
        elif ("ON" == action) and (not time_on_started):
            time_on_started = timestamp
        elif ("OFF" == action) and time_on_started:
            time_on = compute_time_diff_seconds(time_on_started, timestamp)
            total_time_on += time_on
            time_on_started = None
    return total_time_on, errs

 

Читать  Как удалить файлы и каталоги в Python

Может быть, здесь трудно увидеть. Обычно машины состояний требуют переменной для хранения состояния. В этом случае вы используете time_on_started служить двум целям:

  1. Укажите состояние: time_on_started содержит состояние Вашей машины. Если это None, после этого машина находится в OFF. Если это так not None, тогда машина будет ON.
  2. Время начала работы: Если есть ON, затем time_on_started также содержит метку времени включения устройства. Вы используете эту метку времени для вызова compute_time_diff_seconds().

Верхняя часть extract_data() настройка переменной состояния, time_on_started, а также два выхода, которые вы хотите. errs это список меток времени, при которых ERR сообщение было найдено, и total_time_on это сумма всех периодов, когда устройство было включено.

Как только вы завершите начальную настройку, вы вызовете генератор get_next_event() для извлечения каждого события и метки времени. action. Он получает используется для управления машиной состояний, но прежде чем он проверяет наличие изменений состояния, он сначала использует if блок для отфильтровывания любых ERR условия и добавить их к errs.

После проверки ошибок, первая elif блок обрабатывает переходы к ON. Вы можете перейти к следующему ON только когда вы находитесь в OFF состояние, о котором сигнализирует time_on_started существование False. Если вы еще не находитесь в ON состояние и действие есть “ON”, то вы храните timestamp, кладя машину в ON State.

Второй elif обрабатывает переход к OFF State. Об этом переходе, extract_data() необходимо вычислить количество секунд, в течение которых устройство было включено. Он делает это с помощью compute_time_diff_seconds(), вы видели выше. Это добавляет это время к бегу total_time_on и наборы time_on_started вернуться к None, эффектно переводят машину назад в OFF State.

 

Основная функция

Наконец, вы можете перейти к следующему разделу __main__. Этот последний раздел проходит sys.argv[1], который является первым аргумент командной строки, extract_data() а затем представляет отчет о результатах:

# logparse.py
if __name__ == "__main__":
    total_time_on, errs = extract_data(sys.argv[1])
    print(f"Device was on for {total_time_on} seconds")
    if errs:
        print("Timestamps of error events:")
        for err in errs:
            print(f"t{err}")
    else:
        print("No error events found.")

 

Чтобы вызвать это решение, вы запускаете скрипт и передаете имя файла журнала. Запуск вашего примера кода приводит к такому результату:

$ python3 logparse.py test.log
Device was on for 7 seconds
Timestamps of error events:
   Jul 11 16:11:54:661
   Jul 11 16:11:56:067

 

Ваше решение может иметь различное форматирование, но информация должна быть одинаковой для примера файла журнала.

Есть много способов решить подобную проблему. Помните, что в ситуации интервью обсуждение проблемы и ваш мыслительный процесс могут быть более важными, чем решение, которое вы решите реализовать.

Это все, что касается решения для анализа журналов.

 

Предыдущие статьи:

 

Продолжение:

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Читайте также

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам:

Заполните форму и наш менеджер перезвонит Вам в самое ближайшее время!

badge
Обратный звонок 1
Отправить
galka

Спасибо! Ваша заявка принята

close
galka

Спасибо! Ваша заявка принята

close