Python 修剪大日志文件
我为一些java应用程序执行性能测试。在测试期间,应用程序会生成非常大的日志文件(可能是7-10GB)。我需要在特定日期和时间之间修剪这些日志文件。目前,我使用python脚本,它解析datetime python对象中的日志时间戳,并只打印匹配的字符串。但这个解决方案非常缓慢。5 GB日志解析时间约为25分钟 显然,日志文件中的条目是按顺序的,我不需要逐行读取所有文件。 我考虑从头到尾读取文件,直到条件匹配,并在匹配的行数之间打印文件。但我不知道如何才能在不将文件下载到内存的情况下从后面读取文件 请问,你能给我推荐一个适合这个箱子的解决方案吗 以下是python脚本的一部分:Python 修剪大日志文件,python,performance,bash,sed,logging,Python,Performance,Bash,Sed,Logging,我为一些java应用程序执行性能测试。在测试期间,应用程序会生成非常大的日志文件(可能是7-10GB)。我需要在特定日期和时间之间修剪这些日志文件。目前,我使用python脚本,它解析datetime python对象中的日志时间戳,并只打印匹配的字符串。但这个解决方案非常缓慢。5 GB日志解析时间约为25分钟 显然,日志文件中的条目是按顺序的,我不需要逐行读取所有文件。 我考虑从头到尾读取文件,直到条件匹配,并在匹配的行数之间打印文件。但我不知道如何才能在不将文件下载到内存的情况下从后面读取文
lfmt = '%Y-%m-%d %H:%M:%S'
file = open(filename, 'rU')
normal_line = ''
for line in file:
if line[0] == '[':
ltimestamp = datetime.strptime(line[1:20], lfmt)
if ltimestamp >= str and ltimestamp <= end:
normal_line = 'True'
else:
normal_line = ''
if normal_line:
print line,
lfmt='%Y-%m-%d%H:%m:%S'
文件=打开(文件名为'rU')
法线=“”
对于文件中的行:
如果第[0]行=“[”:
ltimestamp=datetime.strtime(第[1:20]行,lfmt)
如果ltimestamp>=str且ltimestamp7到10 GB是大量数据。如果我必须分析此类数据,我会将应用程序记录到数据库或将日志文件上载到数据库。然后,您可以在数据库上高效地执行大量分析。如果您使用标准日志记录工具,如Log4J记录到数据库se应该很简单。只是建议一个替代解决方案
有关数据库日志记录的更多信息,请参阅以下文章:
由于数据是连续的,如果感兴趣区域的起点和终点靠近文件的起点,那么从文件的终点读取(以找到匹配的终点)仍然是一个糟糕的解决方案
我已经编写了一些代码,可以根据需要快速找到起点和终点,这种方法被称为,类似于clasic儿童的“高或低”猜测游戏
脚本在下界
和上界
(最初是SOF和EOF)之间的中间读取试验行,并检查匹配条件。如果搜索的行较早,则通过读取下界
和上一次读取试验之间的中间行,再次进行猜测(如果它更高,那么它在猜测和上界之间分裂)。因此,您在上界和下界之间不断迭代-这将产生最快的“平均”解
这应该是一个真正快速的解决方案(记录到行数的基数2!!)。例如,在最坏的情况下(从1000行中找到999行),使用二进制搜索只需要9行读取!(从10亿行读取只需要30…)
以下代码的假设:
- 每一行都以时间信息开始
- 时间是唯一的-如果不是,当找到匹配项时,您必须向后或向前检查,以包括或排除具有匹配时间的所有条目(如果需要)
- 有趣的是,这是一个递归函数,因此文件的行数限制为2**1000(幸运的是,这允许相当大的文件…)
进一步:
- 如J.F.Sebastian所建议的,如果愿意的话,可以将其调整为在任意块中读取,而不是按行读取
- 在我最初的回答中,我建议使用这种方法,但这可能不适用于大文件,因为它将整个文件读入内存(因此
file.seek()
更优越),感谢TerryE和J.F.Sebastian指出这一点
导入日期时间
def match(line):
lfmt = '%Y-%m-%d %H:%M:%S'
if line[0] == '[':
return datetime.datetime.strptime(line[1:20], lfmt)
def retrieve_test_line(position):
file.seek(position,0)
file.readline() # avoids reading partial line, which will mess up match attempt
new_position = file.tell() # gets start of line position
return file.readline(), new_position
def check_lower_bound(position):
file.seek(position,0)
new_position = file.tell() # gets start of line position
return file.readline(), new_position
def find_line(target, lower_bound, upper_bound):
trial = int((lower_bound + upper_bound) /2)
inspection_text, position = retrieve_test_line(trial)
if position == upper_bound:
text, position = check_lower_bound(lower_bound)
if match(text) == target:
return position
return # no match for target within range
matched_position = match(inspection_text)
if matched_position == target:
return position
elif matched_position < target:
return find_line(target, position, upper_bound)
elif matched_position > target:
return find_line(target, lower_bound, position)
else:
return # no match for target within range
lfmt = '%Y-%m-%d %H:%M:%S'
# start_target = # first line you are trying to find:
start_target = datetime.datetime.strptime("2012-02-01 13:10:00", lfmt)
# end_target = # last line you are trying to find:
end_target = datetime.datetime.strptime("2012-02-01 13:39:00", lfmt)
file = open("log_file.txt","r")
lower_bound = 0
file.seek(0,2) # find upper bound
upper_bound = file.tell()
sequence_start = find_line(start_target, lower_bound, upper_bound)
if sequence_start or sequence_start == 0: #allow for starting at zero - corner case
sequence_end = find_line(end_target, sequence_start, upper_bound)
if not sequence_end:
print "start_target match: ", sequence_start
print "end match is not present in the current file"
else:
print "start match is not present in the current file"
if (sequence_start or sequence_start == 0) and sequence_end:
print "start_target match: ", sequence_start
print "end_target match: ", sequence_end
print
print start_target, 'target'
file.seek(sequence_start,0)
print file.readline()
print end_target, 'target'
file.seek(sequence_end,0)
print file.readline()
def匹配(行):
lfmt=“%Y-%m-%d%H:%m:%S”
如果第[0]行=“[”:
return datetime.datetime.strtime(第[1:20]行,lfmt)
def检索测试线(位置):
file.seek(位置0)
file.readline()#避免读取部分行,这将破坏匹配尝试
new_position=file.tell()#获取行位置的开始
返回文件.readline(),新位置
def检查下限(位置):
file.seek(位置0)
new_position=file.tell()#获取行位置的开始
返回文件.readline(),新位置
def查找行(目标、下限、上限):
试用=整数((下限+上限)/2)
检验文本,位置=检索测试线(试验)
如果位置==上限:
文本,位置=检查下界(下界)
如果匹配(文本)=目标:
返回位置
返回#范围内目标不匹配
匹配位置=匹配(检查文本)
如果匹配_位置==目标:
返回位置
elif匹配位置<目标:
返回查找行(目标、位置、上限)
elif匹配位置>目标:
返回查找行(目标、下限、位置)
其他:
返回#范围内目标不匹配
lfmt=“%Y-%m-%d%H:%m:%S”
#start_target=#您试图查找的第一行:
start_target=datetime.datetime.strtime(“2012-02-01 13:10:00”,lfmt)
#end_target=#您试图查找的最后一行:
end_target=datetime.datetime.strtime(“2012-02-01 13:39:00”,lfmt)
文件=打开(“log_file.txt”、“r”)
下限=0
file.seek(0,2)#find上界
上限=file.tell()
顺序\u开始=查找\u行(开始\u目标、下限、上限)
如果sequence_start或sequence_start==0:#允许在零角情况下启动
序列\结束=查找\线(结束\目标,序列\开始,上限)
如果没有顺序结束:
打印“开始\目标匹配:”,顺序\开始
打印“当前文件中不存在结束匹配”
其他:
打印“当前文件中不存在开始匹配”
如果(序列开始或序列开始==0)和序列结束:
打印“开始\目标匹配:”,顺序\开始
打印“结束\目标匹配:”,序列\结束
打印
打印开始_目标,“目标”
seek(sequence\u start,0)
打印文件.readline()
打印结束_目标,“目标”
查找文件(序列结束,0)
打印文件.r
class Query(object):
def __init__(self, query):
self.query = query # e.g., '2012-01-01'
def __lt__(self, chunk):
# assume line starts with a date; find the start of line
i = chunk.find('\n')
# assert '\n' in chunk and len(chunk) > (len(self.query) + i)
# e.g., '2012-01-01' < '2012-03-01'
return self.query < chunk[i+1:i+1+len(self.query)]