Repository: bitcoin/bitcoin
File: test/functional/combine_logs.py (Python)

Code before:

    log_events = read_logs(testdir)

    if args.html:
        print_logs_html(log_events)
    else:
        print_logs_plain(log_events, colors)
        print_node_warnings(testdir, colors)


def read_logs(tmp_dir):
    """Reads log files.

    Delegates to generator function get_log_events() to provide individual log events
    for each of the input log files."""

    # Find out what the folder is called that holds node 0's debug.log file
    debug_logs = list(pathlib.Path(tmp_dir).glob('node0/**/debug.log'))
    if len(debug_logs) > 0:
        assert len(debug_logs) < 2, 'Max one debug.log is supported, ' \
            'found several:\n\t' + '\n\t'.join([str(f) for f in debug_logs])
        path = debug_logs[0]
        chain = re.search(r'node0/(.+?)/debug\.log$', path.as_posix()).group(1)  # extract the chain name
    else:
        chain = 'regtest'  # fallback to regtest (should only happen when none exists)

    files = [("test", "%s/test_framework.log" % tmp_dir)]
    for i in itertools.count():
        logfile = "{}/node{}/{}/debug.log".format(tmp_dir, i, chain)
        if not os.path.isfile(logfile):
            break
        files.append(("node%d" % i, logfile))

    return heapq.merge(*[get_log_events(source, f) for source, f in files])


def print_node_warnings(tmp_dir, colors):
    """Print nodes' errors and warnings"""

    warnings = []
    for stream in ['stdout', 'stderr']:
        for i in itertools.count():
            folder = "{}/node{}/{}".format(tmp_dir, i, stream)
            if not os.path.isdir(folder):
                break
            for (_, _, fns) in os.walk(folder):
                for fn in fns:
                    warning = pathlib.Path('{}/{}'.format(folder, fn)).read_text().strip()
                    if warning:
                        warnings.append(("node{} {}".format(i, stream), warning))


Review comment (bug):
nit:
```suggestion
                               '\n\t'.join(str(f) for f in debug_logs))
```
or
```suggestion
                               '\n\t'.join(map(str, debug_logs)))
```


Code after:

    log_events = read_logs(testdir)

    if args.html:
        print_logs_html(log_events)
    else:
        print_logs_plain(log_events, colors)
        print_node_warnings(testdir, colors)


def read_logs(tmp_dir):
    """Reads log files.

    Delegates to generator function get_log_events() to provide individual log events
    for each of the input log files."""

    # Find out what the folder is called that holds node 0's debug.log file
    debug_logs = list(pathlib.Path(tmp_dir).glob('node0/**/debug.log'))
    match len(debug_logs):
        case 0:
            chain = 'regtest'  # fallback to regtest
        case 1:
            chain = re.search(r'node0/(.+?)/debug\.log$', debug_logs[0].as_posix()).group(1)
        case _:
            raise RuntimeError('Max one debug.log is supported, found several:\n\t' +
                               '\n\t'.join(map(str, debug_logs)))

    files = [("test", "%s/test_framework.log" % tmp_dir)]
    for i in itertools.count():
        logfile = "{}/node{}/{}/debug.log".format(tmp_dir, i, chain)
        if not os.path.isfile(logfile):
            break
        files.append(("node%d" % i, logfile))

    return heapq.merge(*[get_log_events(source, f) for source, f in files])


def print_node_warnings(tmp_dir, colors):
    """Print nodes' errors and warnings"""

    warnings = []
    for stream in ['stdout', 'stderr']:
        for i in itertools.count():
            folder = "{}/node{}/{}".format(tmp_dir, i, stream)
            if not os.path.isdir(folder):
                break
            for (_, _, fns) in os.walk(folder):
                for fn in fns:
                    warning = pathlib.Path('{}/{}'.format(folder, fn)).read_text().strip()
                    if warning:
                        warnings.append(("node{} {}".format(i, stream), warning))