ci: Handle carriage return characters in LAVA logs
This commit updates LogFollower class to handle carriage return characters in LAVA logs. LAVA treats carriage return characters as a line break, so each carriage return in an output console is mapped to a console line in LAVA. The updated LogFollower class now merges lines that end with a carriage return character into a single line, making the Gitlab sections work correctly. In addition, the `remove_trailing_whitespace` method has been updated to remove trailing `\r\n` characters from log lines. The `test_lava_log_merge_carriage_return_lines` test function has also been updated to test for carriage returns at the end of the previous line. Closes: #8242 Signed-off-by: Guilherme Gallo <guilherme.gallo@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21614>
This commit is contained in:

committed by
Marge Bot

parent
3174cfcaf2
commit
7600e2cca2
@@ -40,6 +40,7 @@ class LogFollower:
|
||||
_buffer: list[str] = field(default_factory=list, init=False)
|
||||
log_hints: LAVALogHints = field(init=False)
|
||||
lava_farm: LavaFarm = field(init=False, default=get_lava_farm())
|
||||
_merge_next_line: str = field(default_factory=str, init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
section_is_created = bool(self.current_section)
|
||||
@@ -127,15 +128,50 @@ class LogFollower:
|
||||
return False
|
||||
|
||||
def remove_trailing_whitespace(self, line: dict[str, str]) -> None:
|
||||
"""
|
||||
Removes trailing whitespace from the end of the `msg` value in the log line dictionary.
|
||||
|
||||
Args:
|
||||
line: A dictionary representing a single log line.
|
||||
|
||||
Note:
|
||||
LAVA treats carriage return characters as a line break, so each carriage return in an output console
|
||||
is mapped to a console line in LAVA. This method removes trailing `\r\n` characters from log lines.
|
||||
"""
|
||||
msg: Optional[str] = line.get("msg")
|
||||
if not msg:
|
||||
return
|
||||
return False
|
||||
|
||||
messages = [msg] if isinstance(msg, str) else msg
|
||||
|
||||
for message in messages:
|
||||
# LAVA logs brings raw messages, which includes newlines characters.
|
||||
line["msg"]: str = message.rstrip("\n")
|
||||
# LAVA logs brings raw messages, which includes newlines characters as \r\n.
|
||||
line["msg"]: str = re.sub(r"\r\n$", "", message)
|
||||
|
||||
def merge_carriage_return_lines(self, line: dict[str, str]) -> bool:
|
||||
"""
|
||||
Merges lines that end with a carriage return character into a single line.
|
||||
|
||||
Args:
|
||||
line: A dictionary representing a single log line.
|
||||
|
||||
Returns:
|
||||
A boolean indicating whether the current line has been merged with the next line.
|
||||
|
||||
Note:
|
||||
LAVA treats carriage return characters as a line break, so each carriage return in an output console
|
||||
is mapped to a console line in LAVA.
|
||||
"""
|
||||
if line["msg"].endswith("\r"):
|
||||
self._merge_next_line += line["msg"]
|
||||
return True
|
||||
|
||||
if self._merge_next_line:
|
||||
line["msg"] = self._merge_next_line + line["msg"]
|
||||
self._merge_next_line = ""
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def feed(self, new_lines: list[dict[str, str]]) -> bool:
|
||||
"""Input data to be processed by LogFollower instance
|
||||
@@ -153,6 +189,9 @@ class LogFollower:
|
||||
if self.detect_kernel_dump_line(line):
|
||||
continue
|
||||
|
||||
if self.merge_carriage_return_lines(line):
|
||||
continue
|
||||
|
||||
# At least we are fed with a non-kernel dump log, it seems that the
|
||||
# job is progressing
|
||||
is_job_healthy = True
|
||||
|
@@ -217,6 +217,36 @@ def test_lava_gitlab_section_log_collabora(expected_message, messages, monkeypat
|
||||
assert new_messages == expected_message
|
||||
|
||||
|
||||
CARRIAGE_RETURN_SCENARIOS = {
|
||||
"Carriage return at the end of the previous line": (
|
||||
(
|
||||
"\x1b[0Ksection_start:1677609903:test_setup[collapsed=true]\r\x1b[0K\x1b[0;36m[303:44] deqp: preparing test setup\x1b[0m",
|
||||
),
|
||||
(
|
||||
"\x1b[0Ksection_start:1677609903:test_setup[collapsed=true]\r",
|
||||
"\x1b[0K\x1b[0;36m[303:44] deqp: preparing test setup\x1b[0m\r\n",
|
||||
),
|
||||
),
|
||||
"Newline at the end of the line": (
|
||||
("\x1b[0K\x1b[0;36m[303:44] deqp: preparing test setup\x1b[0m", "log"),
|
||||
("\x1b[0K\x1b[0;36m[303:44] deqp: preparing test setup\x1b[0m\r\n", "log"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_message, messages",
|
||||
CARRIAGE_RETURN_SCENARIOS.values(),
|
||||
ids=CARRIAGE_RETURN_SCENARIOS.keys(),
|
||||
)
|
||||
def test_lava_log_merge_carriage_return_lines(expected_message, messages):
|
||||
lf = LogFollower()
|
||||
for message in messages:
|
||||
lf.feed([create_lava_yaml_msg(msg=message)])
|
||||
new_messages = tuple(lf.flush())
|
||||
assert new_messages == expected_message
|
||||
|
||||
|
||||
WATCHDOG_SCENARIOS = {
|
||||
"1 second before timeout": ({"seconds": -1}, does_not_raise()),
|
||||
"1 second after timeout": ({"seconds": 1}, pytest.raises(MesaCITimeoutError)),
|
||||
|
Reference in New Issue
Block a user