Анализ пользовательского файла журнала на python

#python #logparser

#python #logparser

Вопрос:

У меня есть файл журнала с символом новой строки

Пример файла:

 2019-02-12T00:01:03.428 01:00 [Error] ErrorCode {My error: "A"} -  -  - 00000000-0000-0000-6936-008007000000 
2019-02-12T00:01:03.428 01:00 [Error] ErrorCode {My error: "A"} -  -  - 00000000-0000-0000-6936-008007000000 
2019-02-12T00:03:23.944 01:00 [Information] A validation warning occurred: [[]] while running a file,
--- End of stack trace ---
    FileNotFoundError
--- End of stack trace from previous location where exception was thrown ---
    System Error
  

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

Для этого я использовал функцию разделения:

 currentDict = {"date":line.split("] ")[0].split(" [")[0],
                   "type":line.split("] ")[0].split(" [")[1],"text":line.split(" ]")[0].split("] ")[1]}
  

Чтобы разделить данные в заданных столбцах, он работает нормально, но выдает ошибку, если у меня есть запись, показанная ниже

 2019-02-12T00:03:23.944 01:00 [Information] A validation warning occurred: [[]] while running a file,
--- End of stack trace ---
    FileNotFoundError
--- End of stack trace from previous location where exception was thrown ---
    System Error
  

и второй подход заключается в использовании регулярных выражений

 with open(name, "r") as f:
         for lines in f:
             data_matcher = re.findall("^\d{4}[-]?\d{1,2}[-]?\d{1,2}T\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}[ ]?\d{1,2}:\d{1,2}",
                              lines)
  

Ожидаемый результат

используя это, я могу извлечь только временную метку, но застрял в том, как извлечь поля next to.

Комментарии:

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

Ответ №1:

Хороший совет при разборе — перестать пытаться делать все за один раз (даже если это весело). Например, написание большого регулярного выражения для разбора всего:

 re.findall("...", TEXT)
  

Или извлечение значения из фрагмента текста в одной (иногда связанной) строке кода:

 LINE.split("...")[...].split("...")[...]
  

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

 time, rest = line.split(' [', 1)
line_type, msg = rest.split('] ', 1)
  

И в реальном мире беспорядочных данных иногда требуется добавить логику обработки ошибок или проверки работоспособности между небольшими шагами.

Ответ №2:

Вам не нужно быть настолько точным с вашим регулярным выражением:

 import re

log_pattern = re.compile(r"([0-9-]*)T([0-9-:. ]*)s*[([^]]*)](.*)")

with open(name, "r") as f:
  for line in f:
      match = log_pattern.match(line)
      if not match:
        continue
      grps = match.groups()
      print("Log line:")
      print(f"  date:{grps[0]},n  time:{grps[1]},n  type:{grps[2]},n  text:{grps[3]}")
  

Вы могли бы даже представить, что это менее точно, чем это, например, r"(.*)T([^s]*)s*[([^]]*)](.*)" тоже работает. Вот хороший инструмент для тестирования регулярных выражений: regex101.