1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-01-31 02:00:45 +00:00

collector/dmesg: Allow not raising on dmesg output parsing failure

Some drivers emit broken multiline dmesg output (with some Windows-style
newline ...) . In order to parse the rest of the content, allow not
raising on such input.
This commit is contained in:
Douglas Raillard 2024-09-25 14:46:25 +01:00 committed by Marc Bonnici
parent d4d9c92ae9
commit e927e2f2cd

View File

@ -16,6 +16,7 @@
import re import re
from itertools import takewhile from itertools import takewhile
from datetime import timedelta from datetime import timedelta
import logging
from devlib.collector import (CollectorBase, CollectorOutput, from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry) CollectorOutputEntry)
@ -23,6 +24,9 @@ from devlib.exception import TargetStableError
from devlib.utils.misc import memoized from devlib.utils.misc import memoized
_LOGGER = logging.getLogger('dmesg')
class KernelLogEntry(object): class KernelLogEntry(object):
""" """
Entry of the kernel ring buffer. Entry of the kernel ring buffer.
@ -112,17 +116,35 @@ class KernelLogEntry(object):
) )
@classmethod @classmethod
def from_dmesg_output(cls, dmesg_out): def from_dmesg_output(cls, dmesg_out, error=None):
""" """
Return a generator of :class:`KernelLogEntry` for each line of the Return a generator of :class:`KernelLogEntry` for each line of the
output of dmesg command. output of dmesg command.
:param error: If ``"raise"`` or ``None``, an exception will be raised
if a parsing error occurs. If ``"warn"``, it will be logged at
WARNING level. If ``"ignore"``, it will be ignored. If a callable
is passed, the exception will be passed to it.
:type error: str or None or typing.Callable[[BaseException], None]
.. note:: The same restrictions on the dmesg output format as for .. note:: The same restrictions on the dmesg output format as for
:meth:`from_str` apply. :meth:`from_str` apply.
""" """
for i, line in enumerate(dmesg_out.splitlines()): for i, line in enumerate(dmesg_out.splitlines()):
if line.strip(): if line.strip():
yield cls.from_str(line, line_nr=i) try:
yield cls.from_str(line, line_nr=i)
except Exception as e:
if error in (None, 'raise'):
raise e
elif error == 'warn':
_LOGGER.warn(f'error while parsing line "{line!r}": {e}')
elif error == 'ignore':
pass
elif callable(error):
error(e)
else:
raise ValueError(f'Unknown error handling strategy: {error}')
def __str__(self): def __str__(self):
facility = self.facility + ': ' if self.facility else '' facility = self.facility + ': ' if self.facility else ''
@ -167,7 +189,7 @@ class DmesgCollector(CollectorBase):
"debug", # debug-level messages "debug", # debug-level messages
] ]
def __init__(self, target, level=LOG_LEVELS[-1], facility='kern', empty_buffer=False): def __init__(self, target, level=LOG_LEVELS[-1], facility='kern', empty_buffer=False, parse_error=None):
super(DmesgCollector, self).__init__(target) super(DmesgCollector, self).__init__(target)
if not target.is_rooted: if not target.is_rooted:
@ -199,6 +221,7 @@ class DmesgCollector(CollectorBase):
self._begin_timestamp = None self._begin_timestamp = None
self.empty_buffer = empty_buffer self.empty_buffer = empty_buffer
self._dmesg_out = None self._dmesg_out = None
self._parse_error = parse_error
@property @property
def dmesg_out(self): def dmesg_out(self):
@ -216,11 +239,15 @@ class DmesgCollector(CollectorBase):
@property @property
def entries(self): def entries(self):
return self._get_entries(self._dmesg_out, self._begin_timestamp) return self._get_entries(
self._dmesg_out,
self._begin_timestamp,
error=self._parse_error,
)
@memoized @memoized
def _get_entries(self, dmesg_out, timestamp): def _get_entries(self, dmesg_out, timestamp, error):
entries = KernelLogEntry.from_dmesg_output(dmesg_out) entries = KernelLogEntry.from_dmesg_output(dmesg_out, error=error)
entries = list(entries) entries = list(entries)
if timestamp is None: if timestamp is None:
return entries return entries