使用 Python 解析日志文件

Posted

技术标签:

【中文标题】使用 Python 解析日志文件【英文标题】:Parsing log file using Python 【发布时间】:2016-07-13 12:39:57 【问题描述】:

我有以下日志文​​件,我想使用 Python 3.4 将其拆分并放入有序数据结构(类似于列表的列表)中

文件遵循以下结构:

Month #1
1465465464555
345646546454
442343423433
724342342655
34324233454
24543534533
***Day # 1
5465465465465455
644654654654454
4435423534833
***Day #2
24876867655
74654654454
643876867433
***Day #3
445543534655
344876867854
64365465433
Month #2
7454353455
84756756454
64563453433
***Day # 1
44756756655
34453453454
243867867433
***Day #2
64465465455
74454353454
34878733
***Day #3
1449898955
643434354
843090909888433

我们的目标是能够按月数循环,并能够在每一天分别工作。 我应该能够做这样的事情:

for month in months:
 for day in days:
  for number in day:
   print(number)

我采用的从文件中提取月份的解决方案如下,但这不是一个聪明的解决方案。我需要更好的东西

lista = []

in_file = open("log.txt","r")
righe= in_file.readlines()
in_file.close()


for i in range(0,len(righe)):
    if "Month" in righe[i]:
        lista.append(i)


lista.append((len(righe)-1))
counter = 1
for i in range(0,len(lista)-1):
    out_file = open(str(counter)+".txt","w")
    for j in range(lista[i], lista[i+1]):
        out_file.write(righe[j])
    out_file.close()
    counter=counter+1



for i in range(1,counter):
    print("Month: ", i)
    mano = open(str(i)+".txt","r")
    righe= mano.readlines()
    print(righe)
    mano.close()

【问题讨论】:

【参考方案1】:

如果你想沿着嵌套的 dict 路线走:

month, day = 0, 0
log = 
with open("log.txt") as f:
    for line in f:
        if 'Month' in line:
            month += 1
            day = 0
            log[month] = 0:[]
        elif 'Day' in line:
            day += 1
            log[month][day] = []
        else:
            log[month][day].append(line.strip())

请注意,我假设紧跟一个月行的条目是第 0 天。结构现在看起来像:

>>> from pprint import pprint
>>> pprint(log)
1: 0: ['1465465464555',
         '345646546454',
         '442343423433',
         '724342342655',
         '34324233454',
         '24543534533'],
     1: ['5465465465465455', '644654654654454', '4435423534833'],
     2: ['24876867655', '74654654454', '643876867433'],
     3: ['445543534655', '344876867854', '64365465433'],
 2: 0: ['7454353455', '84756756454', '64563453433'],
     1: ['44756756655', '34453453454', '243867867433'],
     2: ['64465465455', '74454353454', '34878733'],
     3: ['1449898955', '643434354', '843090909888433']

您可以使用以下方法对其进行迭代:

for month_index in sorted(log):
    month = log[month_index]
    for day_index in sorted(month):
        day = month[day_index]
        for number in day:
            print(number)

【讨论】:

【参考方案2】:

好吧,我们对这个问题的答案很少。

这是我的贡献,我使用一些递归解决方案解决了这个问题。所以,换一种新的思维方式:

def loop(stopParam, startArr, resultArr=[]):
    if startArr == []:
        return (resultArr, startArr)
    elif stopParam in startArr[0]:
        return (resultArr, startArr)
    else:
        return loop(stopParam, startArr[1:], resultArr + [startArr[0]])

def buildList(arr, testVal=):
    if 'Month' in (arr[0] if arr != [] else ''):
        res = loop('Month', arr[1:])
        testVal[arr[0]] = res[0]
        return buildList(res[1], testVal)
    else:
        return testVal


in_file = open("test.txt","r")
righe= in_file.readlines()
in_file.close()

print buildList(righe)

这是一个解决方案。

【讨论】:

【参考方案3】:

标准库中的itertools.groupby 是此类工作的强大功能。下面的代码按月查找行组,然后逐月查找,构建嵌套数据结构。完成后,您可以按月迭代该结构,并在每个月内逐日迭代。

data = """\
Month #1
1465465464555
345646546454
442343423433
724342342655
34324233454
24543534533
***Day # 1
5465465465465455
644654654654454
4435423534833
***Day #2
24876867655
74654654454
643876867433
***Day #3
445543534655
344876867854
64365465433
Month #2
7454353455
84756756454
64563453433
***Day # 1
44756756655
34453453454
243867867433
***Day #2
64465465455
74454353454
34878733
***Day #3
1449898955
643434354
843090909888433""".splitlines()
# or data = open(data_file).read().splitlines()

from itertools import groupby

# some simple boolean functions to detect Month and Day marker lines
is_month_line = lambda s: s.startswith("Month")
is_day_line = lambda s: s.startswith("***Day")

grouped_data = []
for is_month, month_lines in groupby(data, key=is_month_line):
    if is_month:
        # detected a 'Month' marker - save it and create placeholder in grouping structure
        current_month = list(month_lines)[0]
        current_month_data = []
        grouped_data.append([current_month, current_month_data])

        # set up blank day for month-level data lines
        current_day = ''
        current_day_data = []
        current_month_data.append([current_day, current_day_data])
    else:
        # found group of non-'Month' lines, group by days
        for is_day, day_lines in groupby(month_lines, key=is_day_line):
            if is_day:
                # day marker detected, save it for storing day values
                current_day = list(day_lines)[0][3:]
                current_day_data = []
                current_month_data.append([current_day, current_day_data])
            else:
                # all non-day lines, add to current day's data
                current_day_data.extend(day_lines)

使用pprint 转储嵌套列表:

from pprint import pprint
pprint(grouped_data, width=120)

给予:

[['Month #1',
  [['', ['1465465464555', '345646546454', '442343423433', '724342342655', '34324233454', '24543534533']],
   ['Day # 1', ['5465465465465455', '644654654654454', '4435423534833']],
   ['Day #2', ['24876867655', '74654654454', '643876867433']],
   ['Day #3', ['445543534655', '344876867854', '64365465433']]]],
 ['Month #2',
  [['', ['7454353455', '84756756454', '64563453433']],
   ['Day # 1', ['44756756655', '34453453454', '243867867433']],
   ['Day #2', ['64465465455', '74454353454', '34878733']],
   ['Day #3', ['1449898955', '643434354', '843090909888433']]]]]

【讨论】:

另一种选择可能是使用ConfigParser 并重新格式化您的日志文件(如果这是可用的路由)。 感谢 Paul 的回复。这几乎正​​是我想要的。问题是创建的嵌套结构让我有点困惑。例如,我如何迭代访问一个月中的所有日子(考虑到一个月内可能没有一天)?

以上是关于使用 Python 解析日志文件的主要内容,如果未能解决你的问题,请参考以下文章

python解析基于xml格式的日志文件

python lmgrd日志文件解析器

Python 日志记录 - 不同的日志但相同的输出

使用正则表达式解析日志文件

Logstash——解析各类日志文件

python获取nginx子请求