Создание динамического «макета переменной» для split () в Python

1

У меня есть скрипт, который анализирует журналы IIS и в данный момент он выбирает строки журнала один за другим, используя split, чтобы поместить значения поля IIS в несколько переменных:

date, time, sitename, ip, uri_stem, whatever = log_line.split(" ")

И он отлично работает для настройки по умолчанию. Но, если кто-то другой использует другой макет поля журнала (разные порядки или разные поля журнала или оба), ему нужно будет найти эту строку в источнике и изменить ее. Этот человек также должен был бы знать, как изменить его, чтобы ничего не сломалось, поскольку, очевидно, эти переменные используются позже в коде.

Как я могу сделать это более общим для того, чтобы иметь какой-то список, который будет содержать макет поля журнала IIS, который пользователь мог бы изменить (переменная конфигурации или dict/list в начале скрипта), которая позже будет используется для хранения значений строки журнала? Это то, что я считаю - "динамическим". Я думал, что, возможно, использовать for-loop и словарь для этого, но я полагаю, что это сильно повлияло бы на производительность по сравнению с использованием split(), или не так ли? Есть ли у кого-нибудь предложение о том, как это сделать/должно быть сделано?

Это даже стоит того, что мне нужно, или я должен просто сделать заметку для тех, кто использует сценарий, где можно изменить строку кода, содержащую log_line.split(), как это сделать и на что обратить внимание?

Спасибо.

  • 0
    Я бы сделал замечание не менять макет журнала, а не заметку о вашем скрипте.
  • 0
    Да, но что, если у кого-то уже настроено ведение журнала нестандартным способом, который используется сценарием по умолчанию?
Показать ещё 1 комментарий
Теги:
dynamic
split

2 ответа

1
Лучший ответ

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

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

И общее условие состоит в том, что поля должны иметь "личности", достаточно сильные, чтобы легко различимы

Без более точной информации никто не может идти дальше, ИМО

Понедельник, 15 августа 9:39 GMT + 0: 00

Кажется, в spilp.py есть ошибка:
Это должно быть

with codecs.open(file_path, 'r', encoding='utf-8', errors='ignore') as log_lines:
не
with open(file_path, 'r', encoding='utf-8', errors='ignore') as log_lines:
Последний использует встроенный open(), который не имеет ключевых слов

Понедельник, 15 августа 16:10 GMT + 0: 00

В настоящее время в файле образца поля находятся в следующем порядке:

Дата
время
S-имя_сайт
глоток
CS-метод
CS-URI-стволовых
CS-URI-запрос
s-port cs-username
с-ф
CS (User-Agent)
SC-статус
SC-подсостояние
SC-win32-статус

,

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

с-порт
время
Дата
S-имя_сайт
глоток
CS (User-Agent)
SC-статус
SC-подсостояние
SC-win32-статус
с-ф
CS-имя пользователя
CS-метод
cs-uri-stem cs-uri-query

назначить их следующим идентификаторам в том же порядке:

s_port
время
Дата
s_sitename
глоток
cs_user_agent
sc_status
sc_substatus
sc_win32_status
c_ip
cs_username
cs_method
cs_uri_stem
cs_uri_query

дела

s_port,
time, date,
s_sitename, s_ip,
cs_user_agent, sc_status, sc_substatus, sc_win32_status,
c_ip,
cs_username,
cs_method, cs_uri_stem, cs_uri_query = line_spliter(line)

с функцией line_spliter()

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

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

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

В моем коде этот желаемый порядок задается с объектом ref_fields

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

import re


ref_fields = ['s-port',
              'time','date', 
              's-sitename', 's-ip',
              'cs(User-Agent)', 'sc-status', 
              'sc-substatus', 'sc-win32-status',
              'c-ip',
              'cs-username',
              'cs-method', 'cs-uri-stem', 'cs-uri-query']

print 'REF_FIELDS :\n------------\n%s\n' % '\n'.join(ref_fields)


############################################
file_path = 'I:\\sample[1].log'                  # Path to put here
############################################


with open(file_path, 'r') as log_lines:
    line = ''
    while line[0:8]!='#Fields:':
        line = next(log_lines)
    # At this point, line is the line containing the fields keywords
    print 'line of the fields keywords:\n----------------------------\n%r\n' % line

    found_fields = line.split()[1:]
    len_found_fields = len(found_fields)
    regex_extractor = re.compile('[ \t]+'.join(len_found_fields*['([^ \t]+)']))
    print 'list found_fields of keywords in the file:\n------------------------------------------\n%s\n' % found_fields

    print '\nfound_fields == ref_fields  is ',found_fields == ref_fields




    if found_fields == ref_fields:
        print '\nNORMAL ORDER\n------------'
        def line_spliter(line):
            return line.split()

    else:
        the_order = [ found_fields.index(fild) + 1 for fild in ref_fields]
        # the_order is the list of indexes localizing the elements of ref_fields 
        # in the order in which they succeed in the actual line of found fields keywords
        print '\nSPECIAL ORDER\n-------------\nthe_order == %s\n\n\n======================' % the_order
        def line_spliter(line):
            return regex_extractor.match(line).group(*the_order)



    for i in xrange(1):
        line = next(log_lines)
        (s_port,
        time, date,
        s_sitename, s_ip,
        cs_user_agent, sc_status, sc_substatus, sc_win32_status,
        c_ip,
        cs_username,
        cs_method, cs_uri_stem, cs_uri_query) = line_spliter(line)
        print ('LINE :\n------\n'
               '%s\n'
               'SPLIT LINE :\n--------------\n'
               '%s\n\n'
               'REORDERED SPLIT LINE :\n-------------------------\n'
               '%s\n\n'
               'EXAMPLE OF SOME CORRECT BINDINGS OBTAINED :\n-------------------------------------------\n'
               'date == %s\n'
               'time == %s\n'
               's_port == %s\n'
               'c_ip == %s\n\n'
               '======================') % (line,'\n'.join(line.split()),line_spliter(line),date,time,s_port,c_ip)




# ---- split each logline into multiple variables, populate dictionaries and db ---- #      
def splitLogline(log_line):
        # needs to be dynamic (for different logging setups)
        s_port,
        time, date,
        s_sitename, s_ip,
        cs_user_agent, sc_status, sc_substatus, sc_win32_status,
        c_ip,
        cs_username,
        cs_method, cs_uri_stem, cs_uri_query = line_spliter(line)

результат

REF_FIELDS :
------------
s-port
time
date
s-sitename
s-ip
cs(User-Agent)
sc-status
sc-substatus
sc-win32-status
c-ip
cs-username
cs-method
cs-uri-stem
cs-uri-query

line of the fields keywords:
----------------------------
'#Fields: date time s-sitename s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status \n'

list found_fields of keywords in the file:
------------------------------------------
['date', 'time', 's-sitename', 's-ip', 'cs-method', 'cs-uri-stem', 'cs-uri-query', 's-port', 'cs-username', 'c-ip', 'cs(User-Agent)', 'sc-status', 'sc-substatus', 'sc-win32-status']


found_fields == ref_fields  is  False

SPECIAL ORDER
-------------
the_order == [8, 2, 1, 3, 4, 11, 12, 13, 14, 10, 9, 5, 6, 7]


======================
LINE :
------
2010-01-01 00:00:03 SITENAME 192.168.1.1 GET /news-views.aspx - 80 - 66.249.72.135 Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html) 200 0 0

SPLIT LINE :
--------------
2010-01-01
00:00:03
SITENAME
192.168.1.1
GET
/news-views.aspx
-
80
-
66.249.72.135
Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)
200
0
0

REORDERED SPLIT LINE :
-------------------------
('80', '00:00:03', '2010-01-01', 'SITENAME', '192.168.1.1', 'Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)', '200', '0', '0\n', '66.249.72.135', '-', 'GET', '/news-views.aspx', '-')

EXAMPLE OF SOME CORRECT BINDINGS OBTAINED :
-------------------------------------------
date == 2010-01-01
time == 00:00:03
s_port == 80
c_ip == 66.249.72.135

======================

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

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

,

Я думаю, что у меня будет много замечаний по поводу кода, который я быстро прочитал в spilp.py. Я напишу их, когда у меня будет время.

  • 0
    Информация заголовка каждого файла журнала дает вам как порядок, так и имена полей, поэтому всегда известно, какая информация у вас есть. это в основном как таблица с именами столбцов, и все значения каждой строки (строки) разделены пробелом, поэтому информация является постоянной по всему файлу.
  • 0
    @pootzko Так что это "легко" сделать. Если вы дадите конкретные примеры, мы могли бы написать коды.
Показать ещё 3 комментария
1

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

Такие изменения происходят не каждый день; они должны быть довольно редкими. И когда вы добавили или удалили элементы в логлайн, вы все равно меняете код - в конце концов, новые поля должны быть обработаны каким-то образом, а код для обработки любых удаленных полей должен быть удален.

Да, писать надежный код - это хорошая вещь. Определение имен полей сопоставления схемы для их позиций в строке журнала может показаться отличной идеей, так как позволяет перетасовывать и добавлять без выкапывания в одну разделенную линию. Но стоит ли это менять схемы, которые происходят два раза в год? И стоит ли мешать изменению одной строки, когда так много других строк придется менять? Это вам решать.

Тем не менее, если вы хотите это сделать, рассмотрите возможность использования collection.namedtuple для обработки вашей строки в объект, подобный dict. Спецификация имен может быть выполнена в области конфигурации вашего кода. Вы сделаете так, чтобы добиться успеха, поэтому взвешивайте это с учетом гибкости....

Ещё вопросы

Сообщество Overcoder
Наверх
Меню