"""
DMesgLineList - command ``dmesg``
=================================
DMesgLineList is a simple parser that is based on the ``LogFileOutput``
parser class.
It provides one additional helper method not included in ``LogFileOutput``:
* ``has_startswith`` - does the log contain any line that starts with the
given string?
Sample input::
[ 0.000000] Linux version 3.10.0-327.36.3.el7.x86_64 (mockbuild@x86-037.build.eng.bos.redhat.com) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC) ) #1 SMP Thu Oct 20 04:56:07 EDT 2016
[ 0.000000] Command line: BOOT_IMAGE=/vmlinuz-3.10.0-327.36.3.el7.x86_64 root=/dev/RHEL7CSB/Root ro rd.lvm.lv=RHEL7CSB/Root rd.luks.uuid=luks-96c66446-77fd-4431-9508-f6912bd84194 crashkernel=auto vconsole.keymap=us rd.lvm.lv=RHEL7CSB/Swap vconsole.font=latarcyrheb-sun16 rhgb quiet LANG=en_GB.utf8
[ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
[ 0.000000] x86/fpu: xstate_offset[2]: 0240, xstate_sizes[2]: 0100
[ 0.000000] xsave: enabled xstate_bv 0x7, cntxt size 0x340
[ 0.000000] AGP: Checking aperture...
[ 0.000000] AGP: No AGP bridge found
[ 0.000000] Memory: 15918544k/17274880k available (6444k kernel code, 820588k absent, 535748k reserved, 4265k data, 1632k init)
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
[ 0.000000] Hierarchical RCU implementation.
Examples:
>>> dmesg = shared[DmesgLineList]
>>> 'BOOT_IMAGE' in dmesg
True
>>> dmesg.get('AGP')
['[ 0.000000] AGP: Checking aperture...', '[ 0.000000] AGP: No AGP bridge found']
"""
from .. import LogFileOutput, parser, CommandParser
from ..specs import Specs
import re
[docs]
@parser(Specs.dmesg)
class DmesgLineList(CommandParser, LogFileOutput):
"""
Class for reading output of ``dmesg`` using the LogFileOutput parser class.
.. note::
Please refer to its super-class :class:`insights.core.LogFileOutput`
"""
_line_re = re.compile(r'^(?:\[\s*(?P<timestamp>\d+\.\d+)\]\s+)?(?P<message>.*)$')
[docs]
def has_startswith(self, prefix):
"""
Parameters:
prefix (str): The prefix of the line to look for. Ignores any
timestamp before the message body.
Returns:
(bool): Does any line start with the given prefix?
"""
return any(
self._line_re.search(line).group('message').startswith(prefix)
for line in self.lines
)
[docs]
def logs_startwith(self, prefix):
"""
Parameters:
prefix (str): The prefix of the line to look for. Ignores any timestamp.
Returns:
(list): All logs start with the given prefix without timestamp.
"""
msgs = list()
for line in self.lines:
match = self._line_re.search(line)
if match:
msg = match.group('message')
if msg.startswith(prefix):
msgs.append(msg)
return msgs
[docs]
def get_after(self, timestamp, s=None):
"""
Find all the (available) logs that are after the given time stamp.
If `s` is not supplied, then all lines are used. Otherwise, only the
lines contain the `s` are used. `s` can be either a single string or a
strings list. For list, all keywords in the list must be found in the
line.
.. note::
The time stamp is the floating point number of seconds
after the boot time, and is not related to an actual datetime. If
a time stamp is not found on the line between square brackets, then
it is treated as a continuation of the previous line and is only
included if the previous line's timestamp is greater than the
timestamp given. Because continuation lines are only included if a
previous line has matched, this means that searching in logs that do
not have a time stamp produces no lines.
Parameters:
timestamp(float): log lines after this time are returned.
s(str or list): one or more strings to search for.
If not supplied, all available lines are searched.
Yields:
Log lines with time stamps after the given time.
Raises:
TypeError: The ``timestamp`` should be in `float` type, otherwise a
`TypeError` will be raised.
"""
if not isinstance(timestamp, float):
raise TypeError(
"get_after needs a float type timestamp, but get '{c}'".format(
c=timestamp)
)
including_lines = False
search_by_expression = self._valid_search(s)
for line in self.lines:
# If `s` is not None, keywords must be found in the line
if s and not search_by_expression(line):
continue
# Otherwise, search all lines
match = self._line_re.search(line)
if match and match.group('timestamp'):
# Get logtimestamp and compare to given timestamp
logstamp = float(match.group('timestamp'))
if logstamp >= timestamp:
including_lines = True
yield self._parse_line(line)
else:
including_lines = False
else:
# If we're including lines, add this continuation line
if including_lines:
yield self._parse_line(line)