]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/topolog.py
*: auto-convert to SPDX License IDs
[mirror_frr.git] / tests / topotests / lib / topolog.py
CommitLineData
acddc0ed 1# SPDX-License-Identifier: ISC
36d1dc45
RZ
2#
3# topolog.py
4# Library of helper functions for NetDEF Topology Tests
5#
6# Copyright (c) 2017 by
7# Network Device Education Foundation, Inc. ("NetDEF")
8#
36d1dc45
RZ
9
10"""
11Logging utilities for topology tests.
12
13This file defines our logging abstraction.
14"""
15
16import logging
49581587
CH
17import os
18import subprocess
19import sys
20
21if sys.version_info[0] > 2:
4953ca97 22 pass
49581587 23else:
4953ca97 24 pass
49581587
CH
25
26try:
27 from xdist import is_xdist_controller
28except ImportError:
a53c08bc 29
49581587
CH
30 def is_xdist_controller():
31 return False
32
a53c08bc 33
49581587 34BASENAME = "topolog"
36d1dc45
RZ
35
36# Helper dictionary to convert Topogen logging levels to Python's logging.
37DEBUG_TOPO2LOGGING = {
787e7624 38 "debug": logging.DEBUG,
39 "info": logging.INFO,
40 "output": logging.INFO,
41 "warning": logging.WARNING,
42 "error": logging.ERROR,
43 "critical": logging.CRITICAL,
36d1dc45 44}
49581587 45FORMAT = "%(asctime)s.%(msecs)03d %(levelname)s: %(name)s: %(message)s"
36d1dc45 46
49581587
CH
47handlers = {}
48logger = logging.getLogger("topolog")
787e7624 49
9427b78f 50
49581587
CH
51def set_handler(l, target=None):
52 if target is None:
53 h = logging.NullHandler()
54 else:
55 if isinstance(target, str):
56 h = logging.FileHandler(filename=target, mode="w")
57 else:
58 h = logging.StreamHandler(stream=target)
59 h.setFormatter(logging.Formatter(fmt=FORMAT))
60 # Don't filter anything at the handler level
61 h.setLevel(logging.DEBUG)
62 l.addHandler(h)
63 return h
787e7624 64
36d1dc45 65
49581587
CH
66def set_log_level(l, level):
67 "Set the logging level."
68 # Messages sent to this logger only are created if this level or above.
69 log_level = DEBUG_TOPO2LOGGING.get(level, level)
70 l.setLevel(log_level)
787e7624 71
77ebccac 72
49581587
CH
73def get_logger(name, log_level=None, target=None):
74 l = logging.getLogger("{}.{}".format(BASENAME, name))
36d1dc45 75
49581587
CH
76 if log_level is not None:
77 set_log_level(l, log_level)
78
79 if target is not None:
80 set_handler(l, target)
81
82 return l
83
84
85# nodeid: all_protocol_startup/test_all_protocol_startup.py::test_router_running
86
a53c08bc 87
49581587
CH
88def get_test_logdir(nodeid=None):
89 """Get log directory relative pathname."""
90 xdist_worker = os.getenv("PYTEST_XDIST_WORKER", "")
a53c08bc 91 mode = os.getenv("PYTEST_XDIST_MODE", "no")
49581587
CH
92
93 if not nodeid:
94 nodeid = os.environ["PYTEST_CURRENT_TEST"].split(" ")[0]
95
96 cur_test = nodeid.replace("[", "_").replace("]", "_")
97 path, testname = cur_test.split("::")
98 path = path[:-3].replace("/", ".")
99
100 # We use different logdir paths based on how xdist is running.
101 if mode == "each":
102 return os.path.join(path, testname, xdist_worker)
103 elif mode == "load":
104 return os.path.join(path, testname)
105 else:
106 assert (
a53c08bc 107 mode == "no" or mode == "loadfile" or mode == "loadscope"
49581587
CH
108 ), "Unknown dist mode {}".format(mode)
109
110 return path
111
112
113def logstart(nodeid, location, rundir):
114 """Called from pytest before module setup."""
115
a53c08bc 116 mode = os.getenv("PYTEST_XDIST_MODE", "no")
49581587
CH
117 worker = os.getenv("PYTEST_TOPOTEST_WORKER", "")
118
119 # We only per-test log in the workers (or non-dist)
120 if not worker and mode != "no":
121 return
122
123 handler_id = nodeid + worker
124 assert handler_id not in handlers
125
126 rel_log_dir = get_test_logdir(nodeid)
127 exec_log_dir = os.path.join(rundir, rel_log_dir)
a53c08bc
CH
128 subprocess.check_call(
129 "mkdir -p {0} && chmod 1777 {0}".format(exec_log_dir), shell=True
130 )
49581587
CH
131 exec_log_path = os.path.join(exec_log_dir, "exec.log")
132
133 # Add test based exec log handler
134 h = set_handler(logger, exec_log_path)
135 handlers[handler_id] = h
136
137 if worker:
a53c08bc
CH
138 logger.info(
139 "Logging on worker %s for %s into %s", worker, handler_id, exec_log_path
140 )
49581587
CH
141 else:
142 logger.info("Logging for %s into %s", handler_id, exec_log_path)
143
144
145def logfinish(nodeid, location):
146 """Called from pytest after module teardown."""
147 # This function may not be called if pytest is interrupted.
148
149 worker = os.getenv("PYTEST_TOPOTEST_WORKER", "")
150 handler_id = nodeid + worker
151
152 if handler_id in handlers:
153 # Remove test based exec log handler
154 if worker:
155 logger.info("Closing logs for %s", handler_id)
156
157 h = handlers[handler_id]
158 logger.removeHandler(handlers[handler_id])
159 h.flush()
160 h.close()
161 del handlers[handler_id]
787e7624 162
36d1dc45 163
49581587
CH
164console_handler = set_handler(logger, None)
165set_log_level(logger, "debug")