1
0
mirror of https://github.com/ARM-software/devlib.git synced 2024-10-05 18:30:50 +01: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
from itertools import takewhile
from datetime import timedelta
import logging
from devlib.collector import (CollectorBase, CollectorOutput,
CollectorOutputEntry)
@ -23,6 +24,9 @@ from devlib.exception import TargetStableError
from devlib.utils.misc import memoized
_LOGGER = logging.getLogger('dmesg')
class KernelLogEntry(object):
"""
Entry of the kernel ring buffer.
@ -112,17 +116,35 @@ class KernelLogEntry(object):
)
@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
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
:meth:`from_str` apply.
"""
for i, line in enumerate(dmesg_out.splitlines()):
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):
facility = self.facility + ': ' if self.facility else ''
@ -167,7 +189,7 @@ class DmesgCollector(CollectorBase):
"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)
if not target.is_rooted:
@ -199,6 +221,7 @@ class DmesgCollector(CollectorBase):
self._begin_timestamp = None
self.empty_buffer = empty_buffer
self._dmesg_out = None
self._parse_error = parse_error
@property
def dmesg_out(self):
@ -216,11 +239,15 @@ class DmesgCollector(CollectorBase):
@property
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
def _get_entries(self, dmesg_out, timestamp):
entries = KernelLogEntry.from_dmesg_output(dmesg_out)
def _get_entries(self, dmesg_out, timestamp, error):
entries = KernelLogEntry.from_dmesg_output(dmesg_out, error=error)
entries = list(entries)
if timestamp is None:
return entries