Files
scylladb/test/cluster/dtest/tools/log_utils.py
Evgeniy Naydanov e30e2345b7 test.py: dtest: rework wait_for_any_log()
Make `wait_for_any_log()` function to work closer to the original
dtest's version: use `ScyllaLogFile.grep()` method instead of
the usage of `ScyllaNode.wait_log_for()` with a small timeout to
have at least one try to find.

Also, add `max_count` argument to `.grep()` method for the
optimization purpose.
2025-06-30 10:16:36 +00:00

81 lines
2.7 KiB
Python

#
# Copyright (C) 2025-present ScyllaDB
#
# SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
#
from __future__ import annotations
import itertools
import logging
import re
import time
from datetime import datetime
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from test.cluster.dtest.ccmlib.scylla_node import ScyllaNode
control_chars = "".join(map(chr, itertools.chain(range(0x20), range(0x7F, 0xA0))))
control_char_re = re.compile("[%s]" % re.escape(control_chars))
def remove_control_chars(s):
return control_char_re.sub("", s)
class DisableLogger:
def __init__(self, logger_name):
self.logger_name = logger_name
self.level = 0
def __enter__(self):
self.level = logging.getLogger(self.logger_name).level
logging.getLogger(self.logger_name).setLevel(logging.WARNING)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
logging.getLogger(self.logger_name).setLevel(self.level)
def wait_for_any_log(nodes: list[ScyllaNode],
patterns: str | list[str],
timeout: int,
dispersed: bool = False) -> ScyllaNode | list[ScyllaNode]:
"""Look for a pattern in the system.log of any in a given list of nodes.
:param nodes: The list of nodes whose logs to scan
:param patterns: The target pattern (a string, or a list of strings)
:param timeout: How long to wait for the pattern. Note that
strictly speaking, timeout is not really a timeout,
but a maximum number of attempts. This implies that
the all the grepping takes no time at all, so it is
somewhat inaccurate, but probably close enough.
:return: The first node in whose log the pattern was found, if not dispersed.
Otherwise, if dispersed=True, return a list of all nodes with any of the patterns.
"""
if isinstance(patterns, str):
patterns = [patterns]
if dispersed:
patterns = patterns.copy()
ret = set()
for _ in range(timeout):
for node in nodes:
for p in patterns.copy():
if node.scylla_log_file.grep(expr=p, max_count=1):
patterns.remove(p)
ret.add(node)
if not patterns:
return list(ret)
time.sleep(1)
else:
for _ in range(timeout):
for node in nodes:
if all(node.scylla_log_file.grep(expr=p, max_count=1) for p in patterns):
return node
time.sleep(1)
raise TimeoutError(f"{datetime.now():%d %b %Y %H:%M:%S} Unable to find :{patterns} in any node log within {timeout}s")