У меня есть файл журнала многопоточного процесса, который выглядит так:
<timestamp_in> <first_function_call_input> <thread:1>
input_parameter_1: value
input_parameter_2: value
<timestamp_in> <another_function_call_input> <thread:2>
input_parameters: values
<timestamp_out> <another_function_call_output> <thread:2>
output_parameters: values
<timestamp_out> <first_function_call_output> <thread:1>
output_parameters: values
В моей переменной результатов анализа я хотел бы иметь информацию о входе и выходе одного вызова функции вместе, например, например:
>>> print(parse_results.dump())
-[0]:
-function: first_function
-thread: 1
-timestamp_in: ...
-timestamp_out: ...
-input_parameters:
[0]:
-parameter_name: input_parameter_1
-parameter_value: value
[1]:
-parameter_name: input_parameter_2
-parameter_value: value
-output_parameters:
[0]: ...
...
-[1]:
-function: another_function
-thread: 2
...
Есть ли способ реструктурировать parse_results непосредственно во время разбора, поэтому мне не нужно реструктурировать результаты позже? Может быть, с некоторыми синтаксическими действиями? Или было бы проще просто разобрать части ввода и выходные части самостоятельно, а затем отсортировать их по потоку, временной отметке и функции и сшить части ввода и выходные части вместе в новом объекте?
Спасибо за вашу помощь!
Редактировать:
Я собираюсь выполнить сортировку входных частей и выходных частей после их разбора отдельно, что кажется проще. Тем не менее, мне все еще интересно, если и как можно реструктурировать экземпляр результатов синтаксического анализа. Скажем, у меня есть следующая грамматика и тестовая строка:
from pyparsing import *
ParserElement.inlineLiteralsUsing(Suppress)
key_val_lines = OneOrMore(Group(Word(alphas)('key') + ':' + Word(nums)('val')))('parameters')
special_key_val_lines = OneOrMore(Group(Word(printables)('key') + ':' + Word(alphas)('val')))('special_parameters')
log = OneOrMore(Group(key_val_lines | special_key_val_lines))('contents').setDebug()
test_string ='''
foo : 1
bar : 2
special_key1! : wow
another_special : abc
normalAgain : 3'''
parse_results = log.parseString(test_string).dump()
print(parse_results)
Это обеспечивает следующее:
- contents: [[['foo', '1'], ['bar', '2']], [['special_key1!', 'wow'], ['another_special', 'abc']], [['normalAgain', '3']]]
[0]:
[['foo', '1'], ['bar', '2']]
- parameters: [['foo', '1'], ['bar', '2']]
[0]:
['foo', '1']
- key: 'foo'
- val: '1'
[1]:
['bar', '2']
- key: 'bar'
- val: '2'
[1]:
[['special_key1!', 'wow'], ['another_special', 'abc']]
- special_parameters: [['special_key1!', 'wow'], ['another_special', 'abc']]
[0]:
['special_key1!', 'wow']
- key: 'special_key1!'
- val: 'wow'
[1]:
['another_special', 'abc']
- key: 'another_special'
- val: 'abc'
[2]:
[['normalAgain', '3']]
- parameters: [['normalAgain', '3']]
[0]:
['normalAgain', '3']
- key: 'normalAgain'
- val: '3'
Как изменить грамматику моего парсера таким образом, чтобы parse_results.contents[2].parameters[0]
вместо этого были parse_results.contents[0].parameters[3]
?
Чисто судить о том, где рисовать линию на этом, и я написал парсеров в обоих стилях.
В этом конкретном случае моя интуиция подсказывает мне, что он сделает более четкий код, если вы сосредоточите свой парсер и проанализируете действия по группировке, преобразованию и именованию частей отдельных записей журнала, а затем используйте отдельный метод для их реорганизации на основе ваши различные стратегии группировки. Мое рассуждение состоит в том, что структура сообщений журнала уже несколько сложна, и поэтому вашему парсеру будет достаточно работы, чтобы вытащить каждое сообщение в единую форму. Кроме того, ваши стратегии группировки могут немного развиться (необходимо собрать элементы, которые находятся в небольшом временном окне, а не только точное совпадение временных меток), и это в отдельном методе пост-обработки будет локализовать эти изменения.
С точки зрения тестирования это также позволит вам протестировать код реструктуризации отдельно от кода разбора, возможно, со списком dicts или namedtuples, который будет симулировать проанализированные результаты из отдельных записей журнала.
tl; dr - для этой ситуации я бы пошел с методом последующей обработки для окончательной сортировки/реорганизации анализируемых записей журнала.
EDIT: Чтобы изменить результаты синтаксического анализа на месте, определите действие синтаксического анализа, которое принимает один аргумент, который я обычно tokens
, и изменяю их с помощью типичных мутаторов списка или dict:
def rearrange(tokens):
# mutate tokens in place
tokens.contents[0].parameters.append(tokens.contents[2].parameters[0])
log.addParseAction(rearrange)
Если вы вернете None
(как в этом примере), то структура маркеров, которая была передана, сохраняется как возвращаемая структура маркера. Если вы вернете значение non- None
, то новое возвращаемое значение заменяет заданные токены в выводе парсера. Это как целое парсеров преобразовать анализируемую строку фактических чисел или дат/время парсеров преобразование разобранных строк в Python datetime
и datetime
с.