From 3a1c3c846a3a073cc2597dd387679ad58e03ab29 Mon Sep 17 00:00:00 2001 From: Kev365 <48181394+kev365@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:22:35 -0500 Subject: [PATCH 1/5] Make the systemd journal parser resilient to corrupt and binary data Three robustness fixes that matter for damaged, rotated and unclean journals: - Continue past a corrupt journal entry instead of returning. The parser previously aborted extraction of the entire file after the first unparsable entry; systemd's own format guidance is to skip corruption and recover as much surrounding data as possible. - Decode journal field data at the byte level (split on the first "=" and decode with replacement) so a non-UTF-8 field value no longer raises an uncaught UnicodeDecodeError. Journal field values may contain arbitrary binary data. The split-and-decode is extracted into _SplitFieldData and covered by a unit test for both text and non-UTF-8 values. - Wrap XZ and LZ4 decompression in try/except (as ZSTD already is) so corrupt compressed data raises a ParseError instead of an uncaught library exception. Update the dirty-journal test: the parser now reports all 46 corrupt entries in the unclean tail (1 corrupt pointer + 45 unused objects) instead of only the first. Co-Authored-By: Claude Opus 4.8 (1M context) --- plaso/parsers/systemd_journal.py | 43 ++++++++++++++++++--- tests/parsers/systemd_journal.py | 66 +++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 7 deletions(-) diff --git a/plaso/parsers/systemd_journal.py b/plaso/parsers/systemd_journal.py index 75d03cec98..90d7079ab3 100644 --- a/plaso/parsers/systemd_journal.py +++ b/plaso/parsers/systemd_journal.py @@ -139,7 +139,13 @@ def _ParseDataObject(self, file_object, file_offset): data = file_object.read(data_size) if data_object.object_flags & self._OBJECT_COMPRESSED_FLAG_XZ: - data = lzma.decompress(data) + try: + data = lzma.decompress(data) + except (lzma.LZMAError, EOFError) as exception: + raise errors.ParseError( + f"Unable to decompress XZ at offset: 0x{data_offset:08x} with " + f"error: {exception!s}" + ) elif data_object.object_flags & self._OBJECT_COMPRESSED_FLAG_LZ4: uncompressed_size_map = self._GetDataTypeMap("uint32le") @@ -154,7 +160,15 @@ def _ParseDataObject(self, file_object, file_offset): f"0x{data_offset:08x} with error: {exception!s}" ) - data = lz4_block.decompress(data[8:], uncompressed_size=uncompressed_size) + try: + data = lz4_block.decompress( + data[8:], uncompressed_size=uncompressed_size + ) + except (lz4_block.LZ4BlockError, ValueError) as exception: + raise errors.ParseError( + f"Unable to decompress LZ4 at offset: 0x{data_offset:08x} with " + f"error: {exception!s}" + ) elif data_object.object_flags & self._OBJECT_COMPRESSED_FLAG_ZSTD: try: @@ -272,6 +286,24 @@ def _ParseEntryObjectOffsets(self, file_object, file_offset): return entry_object_offsets + @staticmethod + def _SplitFieldData(field_data): + """Splits journal field data into a key and value. + + Args: + field_data (bytes): journal field data, which is "key=value" where the + value can contain arbitrary binary (non-UTF-8) data. + + Returns: + tuple[str, str]: key and value decoded as UTF-8, with invalid bytes + replaced rather than raising. + """ + key, _, value = field_data.partition(b"=") + return ( + key.decode("utf-8", errors="replace"), + value.decode("utf-8", errors="replace"), + ) + def _ParseJournalEntry(self, file_object, file_offset): """Parses a journal entry. @@ -321,9 +353,8 @@ def _ParseJournalEntry(self, file_object, file_offset): f"{self._maximum_journal_file_offset:d})" ) - event_data = self._ParseDataObject(file_object, entry_item.object_offset) - event_string = event_data.decode("utf-8") - key, value = event_string.split("=", 1) + field_data = self._ParseDataObject(file_object, entry_item.object_offset) + key, value = self._SplitFieldData(field_data) fields[key] = value return fields @@ -391,7 +422,7 @@ def ParseFileObject(self, parser_mediator, file_object): f"Unable to parse journal entry at offset: " f"0x{entry_object_offset:08x} with error: {exception!s}" ) - return + continue date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( timestamp=fields["real_time"] diff --git a/tests/parsers/systemd_journal.py b/tests/parsers/systemd_journal.py index 4016dde94d..11c38727db 100644 --- a/tests/parsers/systemd_journal.py +++ b/tests/parsers/systemd_journal.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 """Tests for the Systemd Journal parser.""" +import io import unittest from plaso.containers import warnings +from plaso.lib import errors from plaso.parsers import systemd_journal from tests.parsers import test_lib @@ -12,6 +14,49 @@ class SystemdJournalParserTest(test_lib.ParserTestCase): """Tests for the Systemd Journal parser.""" + # pylint: disable=protected-access + + def testSplitFieldData(self): + """Tests the _SplitFieldData function with text and binary values.""" + parser = systemd_journal.SystemdJournalParser() + + key, value = parser._SplitFieldData(b"MESSAGE=hello world") + self.assertEqual(key, "MESSAGE") + self.assertEqual(value, "hello world") + + # A value with non-UTF-8 bytes must decode with replacement characters + # rather than raising a UnicodeDecodeError. + key, value = parser._SplitFieldData(b"MESSAGE=abc\xff\xfexyz") + self.assertEqual(key, "MESSAGE") + self.assertEqual(value, "abc" + chr(0xFFFD) * 2 + "xyz") + + def testParseDataObjectWithCorruptCompressedData(self): + """Tests _ParseDataObject raises ParseError on corrupt compressed data.""" + parser = systemd_journal.SystemdJournalParser() + + def _data_object(flags, payload): + # A 64-byte DATA object header (object_type=1, object_flags=flags, + # 6 reserved bytes, data_size, then 6 unused uint64 fields) followed + # by a corrupt compressed payload. + header = ( + bytes([1, flags]) + + b"\x00" * 6 + + (64 + len(payload)).to_bytes(8, "little") + + b"\x00" * 48 + ) + return io.BytesIO(header + payload) + + file_object = _data_object(parser._OBJECT_COMPRESSED_FLAG_XZ, b"corrupt-xz") + with self.assertRaises(errors.ParseError): + parser._ParseDataObject(file_object, 0) + + file_object = _data_object( + parser._OBJECT_COMPRESSED_FLAG_LZ4, + b"\x10\x00\x00\x00\x00\x00\x00\x00corrupt-lz4", + ) + with self.assertRaises(errors.ParseError): + parser._ParseDataObject(file_object, 0) + def testParse(self): """Tests the Parse function.""" parser = systemd_journal.SystemdJournalParser() @@ -175,10 +220,13 @@ def testParseDirty(self): ) self.assertEqual(number_of_event_data, 2211) + # The parser skips each corrupt entry and continues instead of aborting + # at the first one, so every corrupt entry in the unclean tail is + # reported rather than only the first. number_of_warnings = storage_writer.GetNumberOfAttributeContainers( "extraction_warning" ) - self.assertEqual(number_of_warnings, 1) + self.assertEqual(number_of_warnings, 46) number_of_warnings = storage_writer.GetNumberOfAttributeContainers( "recovery_warning" @@ -213,6 +261,22 @@ def testParseDirty(self): ) self.assertEqual(test_warning.message, expected_message) + # The 46 warnings are 1 corrupt entry pointer plus 45 unused/zeroed + # objects in the unclean tail; check the breakdown and the last warning + # so the count is documented rather than an opaque magic number. + unsupported_warnings = [ + warning + for warning in test_warnings + if "Unsupported object type: 0" in warning.message + ] + self.assertEqual(len(unsupported_warnings), 45) + + expected_message = ( + "Unable to parse journal entry at offset: 0x004287a0 with error: " + "Unsupported object type: 0" + ) + self.assertEqual(test_warnings[-1].message, expected_message) + if __name__ == "__main__": unittest.main() From 338b15370dbeca6fb5aa1189bc34ce62162ab440 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Tue, 16 Jun 2026 08:34:04 +0200 Subject: [PATCH 2/5] Update systemd_journal.py --- plaso/parsers/systemd_journal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plaso/parsers/systemd_journal.py b/plaso/parsers/systemd_journal.py index 90d7079ab3..07088ae09d 100644 --- a/plaso/parsers/systemd_journal.py +++ b/plaso/parsers/systemd_journal.py @@ -141,7 +141,7 @@ def _ParseDataObject(self, file_object, file_offset): if data_object.object_flags & self._OBJECT_COMPRESSED_FLAG_XZ: try: data = lzma.decompress(data) - except (lzma.LZMAError, EOFError) as exception: + except (EOFError, lzma.LZMAError) as exception: raise errors.ParseError( f"Unable to decompress XZ at offset: 0x{data_offset:08x} with " f"error: {exception!s}" @@ -164,7 +164,7 @@ def _ParseDataObject(self, file_object, file_offset): data = lz4_block.decompress( data[8:], uncompressed_size=uncompressed_size ) - except (lz4_block.LZ4BlockError, ValueError) as exception: + except (ValueError, lz4_block.LZ4BlockError) as exception: raise errors.ParseError( f"Unable to decompress LZ4 at offset: 0x{data_offset:08x} with " f"error: {exception!s}" From f605f940b0784b2ea6ef4ec18d93065393827c15 Mon Sep 17 00:00:00 2001 From: Kev365 <48181394+kev365@users.noreply.github.com> Date: Tue, 16 Jun 2026 06:29:18 -0500 Subject: [PATCH 3/5] Produce an extraction warning when journal field data contains invalid UTF-8 Decoding journal field data with errors="replace" silently substituted the Unicode replacement character for invalid UTF-8 bytes. The parser now produces an extraction warning when this happens, so lossy decoding is visible rather than silent. The parser mediator is threaded into the field decode (_ParseJournalEntry -> _SplitFieldData -> new _DecodeFieldData) to do so. Co-Authored-By: Claude Opus 4.8 --- plaso/parsers/systemd_journal.py | 39 ++++++++++++++++++++++++++------ tests/parsers/systemd_journal.py | 18 ++++++++++++--- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/plaso/parsers/systemd_journal.py b/plaso/parsers/systemd_journal.py index 07088ae09d..1c43e0ff39 100644 --- a/plaso/parsers/systemd_journal.py +++ b/plaso/parsers/systemd_journal.py @@ -286,11 +286,33 @@ def _ParseEntryObjectOffsets(self, file_object, file_offset): return entry_object_offsets - @staticmethod - def _SplitFieldData(field_data): + def _DecodeFieldData(self, parser_mediator, byte_data): + """Decodes journal field data as UTF-8. + + Produces an extraction warning when the data contains invalid UTF-8, + which is replaced rather than raising. + + Args: + parser_mediator (ParserMediator): parser mediator. + byte_data (bytes): journal field data to decode. + + Returns: + str: data decoded as UTF-8, with invalid bytes replaced. + """ + try: + return byte_data.decode("utf-8") + except UnicodeDecodeError: + parser_mediator.ProduceExtractionWarning( + "Unable to decode journal field data as UTF-8, replaced invalid " + "characters" + ) + return byte_data.decode("utf-8", errors="replace") + + def _SplitFieldData(self, parser_mediator, field_data): """Splits journal field data into a key and value. Args: + parser_mediator (ParserMediator): parser mediator. field_data (bytes): journal field data, which is "key=value" where the value can contain arbitrary binary (non-UTF-8) data. @@ -300,16 +322,17 @@ def _SplitFieldData(field_data): """ key, _, value = field_data.partition(b"=") return ( - key.decode("utf-8", errors="replace"), - value.decode("utf-8", errors="replace"), + self._DecodeFieldData(parser_mediator, key), + self._DecodeFieldData(parser_mediator, value), ) - def _ParseJournalEntry(self, file_object, file_offset): + def _ParseJournalEntry(self, parser_mediator, file_object, file_offset): """Parses a journal entry. This method will generate an event per ENTRY object. Args: + parser_mediator (ParserMediator): parser mediator. file_object (dfvfs.FileIO): a file-like object. file_offset (int): offset of the entry object relative to the start of the file-like object. @@ -354,7 +377,7 @@ def _ParseJournalEntry(self, file_object, file_offset): ) field_data = self._ParseDataObject(file_object, entry_item.object_offset) - key, value = self._SplitFieldData(field_data) + key, value = self._SplitFieldData(parser_mediator, field_data) fields[key] = value return fields @@ -416,7 +439,9 @@ def ParseFileObject(self, parser_mediator, file_object): continue try: - fields = self._ParseJournalEntry(file_object, entry_object_offset) + fields = self._ParseJournalEntry( + parser_mediator, file_object, entry_object_offset + ) except errors.ParseError as exception: parser_mediator.ProduceExtractionWarning( f"Unable to parse journal entry at offset: " diff --git a/tests/parsers/systemd_journal.py b/tests/parsers/systemd_journal.py index 11c38727db..b0bfde295e 100644 --- a/tests/parsers/systemd_journal.py +++ b/tests/parsers/systemd_journal.py @@ -19,17 +19,29 @@ class SystemdJournalParserTest(test_lib.ParserTestCase): def testSplitFieldData(self): """Tests the _SplitFieldData function with text and binary values.""" parser = systemd_journal.SystemdJournalParser() + storage_writer = self._CreateStorageWriter() + parser_mediator = self._CreateParserMediator(storage_writer) - key, value = parser._SplitFieldData(b"MESSAGE=hello world") + key, value = parser._SplitFieldData(parser_mediator, b"MESSAGE=hello world") self.assertEqual(key, "MESSAGE") self.assertEqual(value, "hello world") + number_of_warnings = storage_writer.GetNumberOfAttributeContainers( + "extraction_warning" + ) + self.assertEqual(number_of_warnings, 0) + # A value with non-UTF-8 bytes must decode with replacement characters - # rather than raising a UnicodeDecodeError. - key, value = parser._SplitFieldData(b"MESSAGE=abc\xff\xfexyz") + # and produce an extraction warning rather than silently replacing them. + key, value = parser._SplitFieldData(parser_mediator, b"MESSAGE=abc\xff\xfexyz") self.assertEqual(key, "MESSAGE") self.assertEqual(value, "abc" + chr(0xFFFD) * 2 + "xyz") + number_of_warnings = storage_writer.GetNumberOfAttributeContainers( + "extraction_warning" + ) + self.assertEqual(number_of_warnings, 1) + def testParseDataObjectWithCorruptCompressedData(self): """Tests _ParseDataObject raises ParseError on corrupt compressed data.""" parser = systemd_journal.SystemdJournalParser() From ee3608885a10c09d118ed80c1c54835b0e981b4e Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Wed, 1 Jul 2026 14:00:13 +0200 Subject: [PATCH 4/5] Changes after review --- plaso/parsers/systemd_journal.py | 54 ++++++++++++++------------------ tests/parsers/systemd_journal.py | 54 +++++++++++++++++--------------- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/plaso/parsers/systemd_journal.py b/plaso/parsers/systemd_journal.py index 1c43e0ff39..5d89fa7638 100644 --- a/plaso/parsers/systemd_journal.py +++ b/plaso/parsers/systemd_journal.py @@ -286,45 +286,39 @@ def _ParseEntryObjectOffsets(self, file_object, file_offset): return entry_object_offsets - def _DecodeFieldData(self, parser_mediator, byte_data): - """Decodes journal field data as UTF-8. - - Produces an extraction warning when the data contains invalid UTF-8, - which is replaced rather than raising. + def _ParseKeyValuePair(self, parser_mediator, field_data): + """Parses a key value pair. Args: parser_mediator (ParserMediator): parser mediator. - byte_data (bytes): journal field data to decode. + field_data (bytes): journal field data, which is "key=value" where the + value can contain arbitrary binary (non-UTF-8) data. Returns: - str: data decoded as UTF-8, with invalid bytes replaced. + tuple[str, str]: key and value decoded as UTF-8, with invalid bytes + replaced rather than raising. """ + key_data, _, value_data = field_data.partition(b"=") + try: - return byte_data.decode("utf-8") + key = key_data.decode("utf-8") except UnicodeDecodeError: parser_mediator.ProduceExtractionWarning( - "Unable to decode journal field data as UTF-8, replaced invalid " - "characters" + "Unable to decode journal field key as UTF-8. Unsupported code points " + "are escaped." ) - return byte_data.decode("utf-8", errors="replace") + key = key_data.decode("utf-8", errors="backslashreplace") - def _SplitFieldData(self, parser_mediator, field_data): - """Splits journal field data into a key and value. - - Args: - parser_mediator (ParserMediator): parser mediator. - field_data (bytes): journal field data, which is "key=value" where the - value can contain arbitrary binary (non-UTF-8) data. + try: + value = value_data.decode("utf-8") + except UnicodeDecodeError: + parser_mediator.ProduceExtractionWarning( + f"Unable to decode journal field with key: {key:s} value as UTF-8. " + f"Unsupported code points are escaped." + ) + value = value_data.decode("utf-8", errors="backslashreplace") - Returns: - tuple[str, str]: key and value decoded as UTF-8, with invalid bytes - replaced rather than raising. - """ - key, _, value = field_data.partition(b"=") - return ( - self._DecodeFieldData(parser_mediator, key), - self._DecodeFieldData(parser_mediator, value), - ) + return key, value def _ParseJournalEntry(self, parser_mediator, file_object, file_offset): """Parses a journal entry. @@ -363,8 +357,8 @@ def _ParseJournalEntry(self, parser_mediator, file_object, file_offset): ) except (ValueError, errors.ParseError) as exception: raise errors.ParseError( - f"Unable to parse entry item at offset: 0x{file_offset:08x} " - f"with error: {exception!s}" + f"Unable to parse entry item at offset: 0x{file_offset:08x} with " + f"error: {exception!s}" ) file_offset += entry_item_data_size @@ -377,7 +371,7 @@ def _ParseJournalEntry(self, parser_mediator, file_object, file_offset): ) field_data = self._ParseDataObject(file_object, entry_item.object_offset) - key, value = self._SplitFieldData(parser_mediator, field_data) + key, value = self._ParseKeyValuePair(parser_mediator, field_data) fields[key] = value return fields diff --git a/tests/parsers/systemd_journal.py b/tests/parsers/systemd_journal.py index b0bfde295e..4b207c90e1 100644 --- a/tests/parsers/systemd_journal.py +++ b/tests/parsers/systemd_journal.py @@ -16,32 +16,6 @@ class SystemdJournalParserTest(test_lib.ParserTestCase): # pylint: disable=protected-access - def testSplitFieldData(self): - """Tests the _SplitFieldData function with text and binary values.""" - parser = systemd_journal.SystemdJournalParser() - storage_writer = self._CreateStorageWriter() - parser_mediator = self._CreateParserMediator(storage_writer) - - key, value = parser._SplitFieldData(parser_mediator, b"MESSAGE=hello world") - self.assertEqual(key, "MESSAGE") - self.assertEqual(value, "hello world") - - number_of_warnings = storage_writer.GetNumberOfAttributeContainers( - "extraction_warning" - ) - self.assertEqual(number_of_warnings, 0) - - # A value with non-UTF-8 bytes must decode with replacement characters - # and produce an extraction warning rather than silently replacing them. - key, value = parser._SplitFieldData(parser_mediator, b"MESSAGE=abc\xff\xfexyz") - self.assertEqual(key, "MESSAGE") - self.assertEqual(value, "abc" + chr(0xFFFD) * 2 + "xyz") - - number_of_warnings = storage_writer.GetNumberOfAttributeContainers( - "extraction_warning" - ) - self.assertEqual(number_of_warnings, 1) - def testParseDataObjectWithCorruptCompressedData(self): """Tests _ParseDataObject raises ParseError on corrupt compressed data.""" parser = systemd_journal.SystemdJournalParser() @@ -69,6 +43,34 @@ def _data_object(flags, payload): with self.assertRaises(errors.ParseError): parser._ParseDataObject(file_object, 0) + def testParseKeyValuePair(self): + """Tests the _ParseKeyValuePair function with text and binary values.""" + parser = systemd_journal.SystemdJournalParser() + storage_writer = self._CreateStorageWriter() + parser_mediator = self._CreateParserMediator(storage_writer) + + key, value = parser._ParseKeyValuePair(parser_mediator, b"MESSAGE=hello world") + self.assertEqual(key, "MESSAGE") + self.assertEqual(value, "hello world") + + number_of_warnings = storage_writer.GetNumberOfAttributeContainers( + "extraction_warning" + ) + self.assertEqual(number_of_warnings, 0) + + # A value with non-UTF-8 code points must decode with replacement characters + # and produce an extraction warning rather than silently replacing them. + key, value = parser._ParseKeyValuePair( + parser_mediator, b"MESSAGE=abc\xff\xfexyz" + ) + self.assertEqual(key, "MESSAGE") + self.assertEqual(value, "abc\\xff\\xfexyz") + + number_of_warnings = storage_writer.GetNumberOfAttributeContainers( + "extraction_warning" + ) + self.assertEqual(number_of_warnings, 1) + def testParse(self): """Tests the Parse function.""" parser = systemd_journal.SystemdJournalParser() From 4257669fef3f47ba50ee1cab0e75ff3f537292bb Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Wed, 1 Jul 2026 14:16:42 +0200 Subject: [PATCH 5/5] Clean up --- tests/parsers/systemd_journal.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/tests/parsers/systemd_journal.py b/tests/parsers/systemd_journal.py index 4b207c90e1..bec6676fb9 100644 --- a/tests/parsers/systemd_journal.py +++ b/tests/parsers/systemd_journal.py @@ -58,8 +58,8 @@ def testParseKeyValuePair(self): ) self.assertEqual(number_of_warnings, 0) - # A value with non-UTF-8 code points must decode with replacement characters - # and produce an extraction warning rather than silently replacing them. + # A key value pair containing invalid UTF-8 code points must decode with them + # escaped and produce an extraction warning. key, value = parser._ParseKeyValuePair( parser_mediator, b"MESSAGE=abc\xff\xfexyz" ) @@ -77,7 +77,6 @@ def testParse(self): storage_writer = self._ParseFile( ["systemd", "journal", "system.journal"], parser ) - number_of_event_data = storage_writer.GetNumberOfAttributeContainers( "event_data" ) @@ -101,7 +100,6 @@ def testParse(self): "reporter": "systemd", "written_time": "2017-01-27T09:40:55.913258+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 0) self.CheckEventData(event_data, expected_event_values) @@ -114,7 +112,6 @@ def testParse(self): "reporter": "root", "written_time": "2017-02-06T16:24:32.564585+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 2098) self.CheckEventData(event_data, expected_event_values) @@ -124,7 +121,6 @@ def testParseLZ4(self): storage_writer = self._ParseFile( ["systemd", "journal", "system.journal.lz4"], parser ) - number_of_event_data = storage_writer.GetNumberOfAttributeContainers( "event_data" ) @@ -148,14 +144,13 @@ def testParseLZ4(self): "reporter": "systemd", "written_time": "2018-07-03T15:00:16.682340+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 0) self.CheckEventData(event_data, expected_event_values) # Test a LZ4 compressed data log entry. - # The text used in the test message was triplicated to make it long enough - # to trigger the LZ4 compression. - # Source: https://github.com/systemd/systemd/issues/6237 + # The text used in the test message was trippled to make it long enough to + # trigger the LZ4 compression. Also see: + # https://github.com/systemd/systemd/issues/6237 expected_body_parts = [" textual user names."] expected_body_parts.extend( ( @@ -176,7 +171,6 @@ def testParseLZ4(self): "reporter": "test", "written_time": "2018-07-03T15:19:04.667807+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 84) self.CheckEventData(event_data, expected_event_values) @@ -186,7 +180,6 @@ def testParseCompactZSTD(self): storage_writer = self._ParseFile( ["systemd", "journal", "user-1000.journal"], parser ) - number_of_event_data = storage_writer.GetNumberOfAttributeContainers( "event_data" ) @@ -212,7 +205,6 @@ def testParseCompactZSTD(self): "reporter": "testapp", "written_time": "2023-09-26T07:42:46.445209+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 0) self.CheckEventData(event_data, expected_event_values) @@ -228,15 +220,11 @@ def testParseDirty(self): ], parser, ) - number_of_event_data = storage_writer.GetNumberOfAttributeContainers( "event_data" ) self.assertEqual(number_of_event_data, 2211) - # The parser skips each corrupt entry and continues instead of aborting - # at the first one, so every corrupt entry in the unclean tail is - # reported rather than only the first. number_of_warnings = storage_writer.GetNumberOfAttributeContainers( "extraction_warning" ) @@ -257,14 +245,12 @@ def testParseDirty(self): "reporter": "systemd-journald", "written_time": "2016-10-24T13:20:01.063423+00:00", } - event_data = storage_writer.GetAttributeContainerByIndex("event_data", 0) self.CheckEventData(event_data, expected_event_values) generator = storage_writer.GetAttributeContainers( warnings.ExtractionWarning.CONTAINER_TYPE ) - test_warnings = list(generator) test_warning = test_warnings[0] self.assertIsNotNone(test_warning) @@ -275,9 +261,8 @@ def testParseDirty(self): ) self.assertEqual(test_warning.message, expected_message) - # The 46 warnings are 1 corrupt entry pointer plus 45 unused/zeroed - # objects in the unclean tail; check the breakdown and the last warning - # so the count is documented rather than an opaque magic number. + # The 46 warnings are 1 corrupt entry pointer plus 45 unused/zeroed objects in + # the unclean tail. unsupported_warnings = [ warning for warning in test_warnings