Strip columns left to the message automatically
Just count the columns leftside of the OOM message instead of defining their format/content and position. This is more flexible.
This commit is contained in:
parent
7e637aa3f8
commit
23b33e3763
109
OOMAnalyser.py
109
OOMAnalyser.py
@ -55,15 +55,6 @@ def warning(msg):
|
|||||||
class OOM(object):
|
class OOM(object):
|
||||||
"""Hold OOM object and provide access"""
|
"""Hold OOM object and provide access"""
|
||||||
|
|
||||||
REC_TIMESTAMP = re.compile(
|
|
||||||
r'^('
|
|
||||||
# pattern for date format: Jul 28 10:48:41
|
|
||||||
r'[A-Z]+[\w ]+ +\d{1,2} \d{2}:\d{2}:\d{2} \d{4}'
|
|
||||||
r'|'
|
|
||||||
# pattern for date format: 2019-10-30T08:13:31.896744+00:00
|
|
||||||
r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3,6}\+\d{2}:\d{2}'
|
|
||||||
r') ', re.ASCII)
|
|
||||||
|
|
||||||
current_line = 0
|
current_line = 0
|
||||||
"""Zero based index of the current line in self.lines"""
|
"""Zero based index of the current line in self.lines"""
|
||||||
|
|
||||||
@ -79,44 +70,94 @@ class OOM(object):
|
|||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
# use Unix LF only
|
# use Unix LF only
|
||||||
text = text.replace('\r\n', '\r')
|
text = text.replace('\r\n', '\r')
|
||||||
|
oom_lines = text.split('\n')
|
||||||
|
|
||||||
# Split into lines
|
self.current_line = 0
|
||||||
oom_lines = []
|
self.lines = oom_lines
|
||||||
begin_found = False
|
self.text = text
|
||||||
end_found = False
|
|
||||||
|
|
||||||
for line in text.split('\n'):
|
# don't do anything if the text does not contains the leading OOM message
|
||||||
|
if 'invoked oom-killer:' not in text:
|
||||||
|
self.state = "oom_invalid"
|
||||||
|
return
|
||||||
|
|
||||||
|
oom_lines = self._remove_non_oom_lines(oom_lines)
|
||||||
|
oom_lines = self._strip_needless_columns(oom_lines)
|
||||||
|
|
||||||
|
self.lines = oom_lines
|
||||||
|
self.text = '\n'.join(oom_lines)
|
||||||
|
|
||||||
|
if 'Killed process' in text:
|
||||||
|
self.state = "oom_complete"
|
||||||
|
else:
|
||||||
|
self.state = "oom_started"
|
||||||
|
|
||||||
|
def _number_of_columns_to_strip(self, first_line):
|
||||||
|
"""
|
||||||
|
Determinate number of columns left to the OOM message to strip.
|
||||||
|
|
||||||
|
Sometime timestamps, hostnames and or syslog tags are left to the OOM message. This columns will be count to
|
||||||
|
strip later.
|
||||||
|
"""
|
||||||
|
to_strip = 0
|
||||||
|
|
||||||
|
columns = first_line.split(" ")
|
||||||
|
try:
|
||||||
|
# strip all before "<program name> invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
|
||||||
|
to_strip = columns.index("invoked")
|
||||||
|
# decrease to include <program name>
|
||||||
|
to_strip -= 1
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return to_strip
|
||||||
|
|
||||||
|
def _remove_non_oom_lines(self, oom_lines):
|
||||||
|
"""Remove all lines before and after OOM message block"""
|
||||||
|
cleaned_lines = []
|
||||||
|
in_oom_lines = False
|
||||||
|
|
||||||
|
for line in oom_lines:
|
||||||
|
# first line of the oom message block
|
||||||
if "invoked oom-killer:" in line:
|
if "invoked oom-killer:" in line:
|
||||||
begin_found = True
|
in_oom_lines = True
|
||||||
elif not begin_found:
|
|
||||||
continue
|
if in_oom_lines:
|
||||||
|
cleaned_lines.append(line)
|
||||||
|
|
||||||
# Remove leading timestamps
|
# next line will not be part of the oom anymore
|
||||||
line = self.REC_TIMESTAMP.sub('', line)
|
if 'Killed process' in line:
|
||||||
|
break
|
||||||
|
|
||||||
|
return cleaned_lines
|
||||||
|
|
||||||
|
def _strip_needless_columns(self, oom_lines):
|
||||||
|
"""
|
||||||
|
Remove needless columns at the start of every line.
|
||||||
|
|
||||||
|
This function removes all leading items w/o any relation to the OOM message like, date and time, hostname,
|
||||||
|
syslog priority/facility.
|
||||||
|
"""
|
||||||
|
stripped_lines = []
|
||||||
|
cols_to_strip = self._number_of_columns_to_strip(oom_lines[0])
|
||||||
|
|
||||||
|
for line in oom_lines:
|
||||||
# remove empty lines
|
# remove empty lines
|
||||||
if not line.strip():
|
if not line.strip():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
oom_lines.append(line)
|
if cols_to_strip:
|
||||||
|
elements = line.split(" ", cols_to_strip)
|
||||||
|
line = elements.pop(-1)
|
||||||
|
|
||||||
# next line will not be part of the oom anymore
|
# OOMs logged to /var/log/messages / journalctl may contain
|
||||||
if "Killed process" in line:
|
# "kernel:" at the begin of the content
|
||||||
end_found = True
|
if line.startswith('kernel:'):
|
||||||
break
|
line = line[7:]
|
||||||
|
|
||||||
self.current_line = 0
|
stripped_lines.append(line)
|
||||||
|
|
||||||
if begin_found and end_found:
|
return stripped_lines
|
||||||
self.state = "oom_complete"
|
|
||||||
elif begin_found and not end_found:
|
|
||||||
self.state = "oom_started"
|
|
||||||
else:
|
|
||||||
self.state = "oom_invalid"
|
|
||||||
|
|
||||||
self.lines = oom_lines
|
|
||||||
self.text = '\n'.join(oom_lines)
|
|
||||||
|
|
||||||
def back(self):
|
def back(self):
|
||||||
"""Return the previous line"""
|
"""Return the previous line"""
|
||||||
|
Loading…
Reference in New Issue
Block a user