Add support for journalctl output

The lines in the "Mem-Info:" block start with spaces instead of date /
time / hostname. As a result, removing the needless columns no longer
works correctly.

Suggested-by: Mikko Rantalainen <mikko.rantalainen@gmail.com>
This commit is contained in:
Carsten Grohmann 2021-11-29 20:59:14 +01:00
parent 7038cced1f
commit a7e1e4cc64
3 changed files with 68 additions and 2 deletions

View File

@ -897,6 +897,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
<li>Add support for manually triggered OOM (suggested by Mikko Rantalainen)</li>
<li>Add support for systems w/o swap (suggested by Mikko Rantalainen)</li>
<li>Add support for newer kernels (suggested by Mikko Rantalainen)</li>
<li>Add support for journalctl output (suggested by Mikko Rantalainen)</li>
<li>...</li>
</ol>

View File

@ -525,6 +525,7 @@ class OOMEntity:
oom_lines = self._remove_non_oom_lines(oom_lines)
oom_lines = self._remove_kernel_colon(oom_lines)
cols_to_strip = self._number_of_columns_to_strip(oom_lines[self._get_CPU_index(oom_lines)])
oom_lines = self._journalctl_add_leading_columns_to_meminfo(oom_lines, cols_to_strip)
oom_lines = self._strip_needless_columns(oom_lines, cols_to_strip)
oom_lines = self._rsyslog_unescape_lf(oom_lines)
@ -536,6 +537,34 @@ class OOMEntity:
else:
self.state = OOMEntityState.started
def _journalctl_add_leading_columns_to_meminfo(self, oom_lines, cols_to_add):
"""
Add leading columns to handle line breaks in journalctl output correctly.
The output of the "Mem-Info:" block contains line breaks. journalctl breaks these lines accordingly, but
inserts at the beginning spaces instead of date and time. As a result, removing the needless columns no longer
works correctly.
This function adds columns back in the affected rows so that the removal works cleanly over all rows.
@see: _rsyslog_unescape_lf()
"""
pattern = r'^\s+ (active_file|unevictable|slab_reclaimable|mapped|free):.+$'
rec = re.compile(pattern)
add_cols = ""
for i in range(cols_to_add):
add_cols += "Col{} ".format(i)
expanded_lines = []
for line in oom_lines:
match = rec.search(line)
if match:
line = "{} {}".format(add_cols, line.strip())
expanded_lines.append(line)
return expanded_lines
def _get_CPU_index(self, lines):
"""
Return the index of the first line with "CPU: "
@ -605,12 +634,17 @@ class OOMEntity:
def _rsyslog_unescape_lf(self, oom_lines):
"""
Rsyslog replaces line breaks with their octal representation #012.
Split lines at '#012' (octal representation of LF).
The output of the "Mem-Info:" block contains line breaks. Rsyslog replaces these line breaks with their octal
representation #012. This breaks the removal of needless columns as well as the detection of the OOM values.
Splitting the lines (again) solves this issue.
This feature can be controlled inside the rsyslog configuration with the directives
$EscapeControlCharactersOnReceive, $Escape8BitCharactersOnReceive and $ControlCharactersEscapePrefix.
The replacement is only in second line (active_anon:....) of the Mem-Info block.
@see: _journalctl_add_leading_columns_to_meminfo()
"""
lines = []

31
test.py
View File

@ -304,6 +304,37 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
self.assertEqual(self.get_error_text(), "ERROR: Failed to extract kernel version from OOM text")
self.click_reset()
def test_035_leading_journalctl_input(self):
"""Test loading input from journalctl """
# prepare example
example_lines = OOMAnalyser.OOMDisplay.example_rhel7.split('\n')
res = []
# unescape #012 - see OOMAnalyser.OOMEntity._rsyslog_unescape_lf()
for line in example_lines:
if '#012' in line:
res.extend(line.split('#012'))
else:
res.append(line)
example_lines = res
res = []
# add date/time prefix except for "Mem-Info:" block
pattern = r'^ (active_file|unevictable|slab_reclaimable|mapped|free):.+$'
rec = re.compile(pattern)
for line in example_lines:
match = rec.search(line)
if match:
line = " {}".format(line)
else:
line = "Apr 01 14:13:32 mysrv <kern.warning> kernel: {}".format(line)
res.append(line)
example = "\n".join(res)
self.analyse_oom(example)
self.check_results_rhel7()
self.click_reset()
def test_040_trigger_proc_space(self):
"""Test trigger process name contains a space"""
example = OOMAnalyser.OOMDisplay.example_rhel7