root / snf-tools / synnefo_tools / burnin / logger.py @ 9355a604
History | View | Annotate | Download (15.6 kB)
1 | 4c52d5bf | Ilias Tsitsimpis | # Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 4c52d5bf | Ilias Tsitsimpis | #
|
3 | 4c52d5bf | Ilias Tsitsimpis | # Redistribution and use in source and binary forms, with or
|
4 | 4c52d5bf | Ilias Tsitsimpis | # without modification, are permitted provided that the following
|
5 | 4c52d5bf | Ilias Tsitsimpis | # conditions are met:
|
6 | 4c52d5bf | Ilias Tsitsimpis | #
|
7 | 4c52d5bf | Ilias Tsitsimpis | # 1. Redistributions of source code must retain the above
|
8 | 4c52d5bf | Ilias Tsitsimpis | # copyright notice, this list of conditions and the following
|
9 | 4c52d5bf | Ilias Tsitsimpis | # disclaimer.
|
10 | 4c52d5bf | Ilias Tsitsimpis | #
|
11 | 4c52d5bf | Ilias Tsitsimpis | # 2. Redistributions in binary form must reproduce the above
|
12 | 4c52d5bf | Ilias Tsitsimpis | # copyright notice, this list of conditions and the following
|
13 | 4c52d5bf | Ilias Tsitsimpis | # disclaimer in the documentation and/or other materials
|
14 | 4c52d5bf | Ilias Tsitsimpis | # provided with the distribution.
|
15 | 4c52d5bf | Ilias Tsitsimpis | #
|
16 | 4c52d5bf | Ilias Tsitsimpis | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | 4c52d5bf | Ilias Tsitsimpis | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | 4c52d5bf | Ilias Tsitsimpis | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | 4c52d5bf | Ilias Tsitsimpis | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | 4c52d5bf | Ilias Tsitsimpis | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | 4c52d5bf | Ilias Tsitsimpis | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | 4c52d5bf | Ilias Tsitsimpis | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | 4c52d5bf | Ilias Tsitsimpis | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | 4c52d5bf | Ilias Tsitsimpis | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | 4c52d5bf | Ilias Tsitsimpis | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | 4c52d5bf | Ilias Tsitsimpis | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | 4c52d5bf | Ilias Tsitsimpis | # POSSIBILITY OF SUCH DAMAGE.
|
28 | 4c52d5bf | Ilias Tsitsimpis | #
|
29 | 4c52d5bf | Ilias Tsitsimpis | # The views and conclusions contained in the software and
|
30 | 4c52d5bf | Ilias Tsitsimpis | # documentation are those of the authors and should not be
|
31 | 4c52d5bf | Ilias Tsitsimpis | # interpreted as representing official policies, either expressed
|
32 | 4c52d5bf | Ilias Tsitsimpis | # or implied, of GRNET S.A.
|
33 | 4c52d5bf | Ilias Tsitsimpis | |
34 | 4c52d5bf | Ilias Tsitsimpis | """
|
35 | 4c52d5bf | Ilias Tsitsimpis | This is the logging class for burnin
|
36 | 4c52d5bf | Ilias Tsitsimpis |
|
37 | 4c52d5bf | Ilias Tsitsimpis | It supports logging both for the stdout/stderr as well as file logging at the
|
38 | 4c52d5bf | Ilias Tsitsimpis | same time.
|
39 | 4c52d5bf | Ilias Tsitsimpis |
|
40 | 4c52d5bf | Ilias Tsitsimpis | The stdout/stderr logger supports verbose levels and colors but the file
|
41 | 4c52d5bf | Ilias Tsitsimpis | logging doesn't (we use the info verbose level for our file logger).
|
42 | 4c52d5bf | Ilias Tsitsimpis |
|
43 | 4c52d5bf | Ilias Tsitsimpis | Our loggers have primitive support for handling parallel execution (even though
|
44 | 4c52d5bf | Ilias Tsitsimpis | burnin doesn't support it yet). To do so the stdout/stderr logger prepends the
|
45 | 4c52d5bf | Ilias Tsitsimpis | name of the test under execution to every line it prints. On the other hand the
|
46 | 4c52d5bf | Ilias Tsitsimpis | file logger waits to lock the file, then reads it, prints the message to the
|
47 | 4c52d5bf | Ilias Tsitsimpis | corresponding line and closes the file.
|
48 | 4c52d5bf | Ilias Tsitsimpis |
|
49 | 4c52d5bf | Ilias Tsitsimpis |
|
50 | 4c52d5bf | Ilias Tsitsimpis | """
|
51 | 4c52d5bf | Ilias Tsitsimpis | |
52 | 4c52d5bf | Ilias Tsitsimpis | import os |
53 | 4c52d5bf | Ilias Tsitsimpis | import sys |
54 | 4c52d5bf | Ilias Tsitsimpis | import os.path |
55 | a64d8485 | Ilias Tsitsimpis | import logging |
56 | 4c52d5bf | Ilias Tsitsimpis | import datetime |
57 | 4c52d5bf | Ilias Tsitsimpis | |
58 | 12ef696f | Ilias Tsitsimpis | from synnefo_tools.burnin import filelocker |
59 | 4c52d5bf | Ilias Tsitsimpis | |
60 | 4c52d5bf | Ilias Tsitsimpis | |
61 | 4c52d5bf | Ilias Tsitsimpis | # --------------------------------------------------------------------
|
62 | 4c52d5bf | Ilias Tsitsimpis | # Constant variables
|
63 | 4c52d5bf | Ilias Tsitsimpis | LOCK_EXT = ".lock"
|
64 | 4c52d5bf | Ilias Tsitsimpis | SECTION_SEPARATOR = \ |
65 | 4c52d5bf | Ilias Tsitsimpis | "-- -------------------------------------------------------------------"
|
66 | 4c52d5bf | Ilias Tsitsimpis | SECTION_PREFIX = "-- "
|
67 | 06c9d4db | Ilias Tsitsimpis | SECTION_RUNNED = "Tests Run"
|
68 | 4c52d5bf | Ilias Tsitsimpis | SECTION_RESULTS = "Results"
|
69 | 4c52d5bf | Ilias Tsitsimpis | SECTION_NEW = "__ADD_NEW_SECTION__"
|
70 | 4c52d5bf | Ilias Tsitsimpis | SECTION_PASSED = " * Passed:"
|
71 | 4c52d5bf | Ilias Tsitsimpis | SECTION_FAILED = " * Failed:"
|
72 | 4c52d5bf | Ilias Tsitsimpis | |
73 | a64d8485 | Ilias Tsitsimpis | # Ignore `paramiko' logger
|
74 | a64d8485 | Ilias Tsitsimpis | logging.getLogger('paramiko').addHandler(logging.NullHandler())
|
75 | a64d8485 | Ilias Tsitsimpis | |
76 | 4c52d5bf | Ilias Tsitsimpis | |
77 | 4c52d5bf | Ilias Tsitsimpis | # --------------------------------------------------------------------
|
78 | 4c52d5bf | Ilias Tsitsimpis | # Helper functions
|
79 | 3e5bbd85 | Ilias Tsitsimpis | def _cyan(msg): |
80 | 3e5bbd85 | Ilias Tsitsimpis | """Bold High Intensity Cyan color"""
|
81 | 3e5bbd85 | Ilias Tsitsimpis | return "\x1b[1;96m" + str(msg) + "\x1b[0m" |
82 | 4c52d5bf | Ilias Tsitsimpis | |
83 | 4c52d5bf | Ilias Tsitsimpis | |
84 | 4c52d5bf | Ilias Tsitsimpis | def _yellow(msg): |
85 | 4c52d5bf | Ilias Tsitsimpis | """Yellow color"""
|
86 | 4c52d5bf | Ilias Tsitsimpis | return "\x1b[33m" + str(msg) + "\x1b[0m" |
87 | 4c52d5bf | Ilias Tsitsimpis | |
88 | 4c52d5bf | Ilias Tsitsimpis | |
89 | 4c52d5bf | Ilias Tsitsimpis | def _red(msg): |
90 | 4c52d5bf | Ilias Tsitsimpis | """Yellow color"""
|
91 | 4c52d5bf | Ilias Tsitsimpis | return "\x1b[31m" + str(msg) + "\x1b[0m" |
92 | 4c52d5bf | Ilias Tsitsimpis | |
93 | 4c52d5bf | Ilias Tsitsimpis | |
94 | 12ef696f | Ilias Tsitsimpis | def _magenta(msg): |
95 | 12ef696f | Ilias Tsitsimpis | """Magenta color"""
|
96 | 4c52d5bf | Ilias Tsitsimpis | return "\x1b[35m" + str(msg) + "\x1b[0m" |
97 | 4c52d5bf | Ilias Tsitsimpis | |
98 | 4c52d5bf | Ilias Tsitsimpis | |
99 | 12ef696f | Ilias Tsitsimpis | def _green(msg): |
100 | 12ef696f | Ilias Tsitsimpis | """Green color"""
|
101 | 12ef696f | Ilias Tsitsimpis | return "\x1b[32m" + str(msg) + "\x1b[0m" |
102 | 4c52d5bf | Ilias Tsitsimpis | |
103 | 4c52d5bf | Ilias Tsitsimpis | |
104 | 4c52d5bf | Ilias Tsitsimpis | def _format_message(msg, *args): |
105 | 4c52d5bf | Ilias Tsitsimpis | """Format the message using the args"""
|
106 | 6c78720b | Ilias Tsitsimpis | if args:
|
107 | 6c78720b | Ilias Tsitsimpis | return (msg % args) + "\n" |
108 | 6c78720b | Ilias Tsitsimpis | else:
|
109 | 6c78720b | Ilias Tsitsimpis | return msg + "\n" |
110 | 4c52d5bf | Ilias Tsitsimpis | |
111 | 4c52d5bf | Ilias Tsitsimpis | |
112 | 4c52d5bf | Ilias Tsitsimpis | def _list_to_string(lst, append=""): |
113 | 4c52d5bf | Ilias Tsitsimpis | """Convert a list of strings to string
|
114 | 4c52d5bf | Ilias Tsitsimpis |
|
115 | 4c52d5bf | Ilias Tsitsimpis | Append the value given in L{append} in front of all lines
|
116 | 4c52d5bf | Ilias Tsitsimpis | (except of the first line).
|
117 | 4c52d5bf | Ilias Tsitsimpis |
|
118 | 4c52d5bf | Ilias Tsitsimpis | """
|
119 | 4c52d5bf | Ilias Tsitsimpis | if isinstance(lst, list): |
120 | 4c52d5bf | Ilias Tsitsimpis | return append.join(lst).rstrip('\n') |
121 | 4c52d5bf | Ilias Tsitsimpis | else:
|
122 | 4c52d5bf | Ilias Tsitsimpis | return lst.rstrip('\n') |
123 | 4c52d5bf | Ilias Tsitsimpis | |
124 | 4c52d5bf | Ilias Tsitsimpis | |
125 | 4c52d5bf | Ilias Tsitsimpis | # --------------------------------------
|
126 | 4c52d5bf | Ilias Tsitsimpis | def _locate_sections(contents): |
127 | 4c52d5bf | Ilias Tsitsimpis | """Locate the sections inside the logging file"""
|
128 | 4c52d5bf | Ilias Tsitsimpis | i = 0
|
129 | 4c52d5bf | Ilias Tsitsimpis | res = [] |
130 | 4c52d5bf | Ilias Tsitsimpis | for cnt in contents: |
131 | 4c52d5bf | Ilias Tsitsimpis | if SECTION_SEPARATOR in cnt: |
132 | 4c52d5bf | Ilias Tsitsimpis | res.append(i+1)
|
133 | 4c52d5bf | Ilias Tsitsimpis | i += 1
|
134 | 4c52d5bf | Ilias Tsitsimpis | return res
|
135 | 4c52d5bf | Ilias Tsitsimpis | |
136 | 4c52d5bf | Ilias Tsitsimpis | |
137 | 4c52d5bf | Ilias Tsitsimpis | def _locate_input(contents, section): |
138 | 4c52d5bf | Ilias Tsitsimpis | """Locate position to insert text
|
139 | 4c52d5bf | Ilias Tsitsimpis |
|
140 | 4c52d5bf | Ilias Tsitsimpis | Given a section location the next possition to insert text inside that
|
141 | 4c52d5bf | Ilias Tsitsimpis | section.
|
142 | 4c52d5bf | Ilias Tsitsimpis |
|
143 | 4c52d5bf | Ilias Tsitsimpis | """
|
144 | 4c52d5bf | Ilias Tsitsimpis | sect_locs = _locate_sections(contents) |
145 | 4c52d5bf | Ilias Tsitsimpis | if section == SECTION_NEW:
|
146 | 4c52d5bf | Ilias Tsitsimpis | # We want to add a new section
|
147 | 4c52d5bf | Ilias Tsitsimpis | # Just return the position of SECTION_RESULTS
|
148 | 4c52d5bf | Ilias Tsitsimpis | for obj in sect_locs: |
149 | 4c52d5bf | Ilias Tsitsimpis | if SECTION_RESULTS in contents[obj]: |
150 | 4c52d5bf | Ilias Tsitsimpis | return obj - 1 |
151 | 4c52d5bf | Ilias Tsitsimpis | else:
|
152 | 4c52d5bf | Ilias Tsitsimpis | # We will add our message in this location
|
153 | 4c52d5bf | Ilias Tsitsimpis | for (index, obj) in enumerate(sect_locs): |
154 | 4c52d5bf | Ilias Tsitsimpis | if section in contents[obj]: |
155 | 4c52d5bf | Ilias Tsitsimpis | return sect_locs[index+1] - 3 |
156 | 4c52d5bf | Ilias Tsitsimpis | |
157 | 4c52d5bf | Ilias Tsitsimpis | # We didn't find our section??
|
158 | 4c52d5bf | Ilias Tsitsimpis | sys.stderr.write("Section %s could not be found in logging file\n"
|
159 | 4c52d5bf | Ilias Tsitsimpis | % section) |
160 | 12ef696f | Ilias Tsitsimpis | sys.exit("Error in logger._locate_input")
|
161 | 4c52d5bf | Ilias Tsitsimpis | |
162 | 4c52d5bf | Ilias Tsitsimpis | |
163 | 4c52d5bf | Ilias Tsitsimpis | def _add_testsuite_results(contents, section, testsuite): |
164 | 4c52d5bf | Ilias Tsitsimpis | """Add the given testsuite to results
|
165 | 4c52d5bf | Ilias Tsitsimpis |
|
166 | 4c52d5bf | Ilias Tsitsimpis | Well we know that SECTION_FAILED is the last line and SECTION_PASSED is the
|
167 | 4c52d5bf | Ilias Tsitsimpis | line before, so we are going to cheat here and use this information.
|
168 | 4c52d5bf | Ilias Tsitsimpis |
|
169 | 4c52d5bf | Ilias Tsitsimpis | """
|
170 | 4c52d5bf | Ilias Tsitsimpis | if section == SECTION_PASSED:
|
171 | 06c9d4db | Ilias Tsitsimpis | line = contents[-2].rstrip()
|
172 | 06c9d4db | Ilias Tsitsimpis | if line.endswith(":"): |
173 | 06c9d4db | Ilias Tsitsimpis | new_line = line + " " + testsuite + "\n" |
174 | 06c9d4db | Ilias Tsitsimpis | else:
|
175 | 06c9d4db | Ilias Tsitsimpis | new_line = line + ", " + testsuite + "\n" |
176 | 4c52d5bf | Ilias Tsitsimpis | contents[-2] = new_line
|
177 | 4c52d5bf | Ilias Tsitsimpis | elif section == SECTION_FAILED:
|
178 | 06c9d4db | Ilias Tsitsimpis | line = contents[-1].rstrip()
|
179 | 06c9d4db | Ilias Tsitsimpis | if line.endswith(":"): |
180 | 06c9d4db | Ilias Tsitsimpis | new_line = line.rstrip() + " " + testsuite + "\n" |
181 | 06c9d4db | Ilias Tsitsimpis | else:
|
182 | 06c9d4db | Ilias Tsitsimpis | new_line = line.rstrip() + ", " + testsuite + "\n" |
183 | 4c52d5bf | Ilias Tsitsimpis | contents[-1] = new_line
|
184 | 4c52d5bf | Ilias Tsitsimpis | else:
|
185 | 4c52d5bf | Ilias Tsitsimpis | sys.stderr.write("Unknown section %s in _add_testsuite_results\n"
|
186 | 4c52d5bf | Ilias Tsitsimpis | % section) |
187 | 12ef696f | Ilias Tsitsimpis | sys.exit("Error in logger._add_testsuite_results")
|
188 | 4c52d5bf | Ilias Tsitsimpis | return contents
|
189 | 4c52d5bf | Ilias Tsitsimpis | |
190 | 4c52d5bf | Ilias Tsitsimpis | |
191 | 4c52d5bf | Ilias Tsitsimpis | def _write_log_file(file_location, section, message): |
192 | 4c52d5bf | Ilias Tsitsimpis | """Write something to our log file
|
193 | 4c52d5bf | Ilias Tsitsimpis |
|
194 | 4c52d5bf | Ilias Tsitsimpis | For this we have to get the lock, read and parse the file add the new
|
195 | 4c52d5bf | Ilias Tsitsimpis | message and re-write the file.
|
196 | 4c52d5bf | Ilias Tsitsimpis |
|
197 | 4c52d5bf | Ilias Tsitsimpis | """
|
198 | 4c52d5bf | Ilias Tsitsimpis | # Get the lock
|
199 | 4c52d5bf | Ilias Tsitsimpis | file_lock = os.path.splitext(file_location)[0] + LOCK_EXT
|
200 | 4c52d5bf | Ilias Tsitsimpis | with filelocker.lock(file_lock, filelocker.LOCK_EX):
|
201 | 4c52d5bf | Ilias Tsitsimpis | with open(file_location, "r+") as log_file: |
202 | 4c52d5bf | Ilias Tsitsimpis | contents = log_file.readlines() |
203 | 4c52d5bf | Ilias Tsitsimpis | if section == SECTION_PASSED or section == SECTION_FAILED: |
204 | 4c52d5bf | Ilias Tsitsimpis | # Add testsuite to results
|
205 | 4c52d5bf | Ilias Tsitsimpis | new_contents = \ |
206 | 4c52d5bf | Ilias Tsitsimpis | _add_testsuite_results(contents, section, message) |
207 | 4c52d5bf | Ilias Tsitsimpis | else:
|
208 | 4c52d5bf | Ilias Tsitsimpis | # Add message to its line
|
209 | 4c52d5bf | Ilias Tsitsimpis | input_loc = _locate_input(contents, section) |
210 | 4c52d5bf | Ilias Tsitsimpis | new_contents = \ |
211 | 4c52d5bf | Ilias Tsitsimpis | contents[:input_loc] + [message] + contents[input_loc:] |
212 | 4c52d5bf | Ilias Tsitsimpis | log_file.seek(0)
|
213 | 4c52d5bf | Ilias Tsitsimpis | log_file.write("".join(new_contents))
|
214 | 4c52d5bf | Ilias Tsitsimpis | |
215 | 4c52d5bf | Ilias Tsitsimpis | |
216 | 4c52d5bf | Ilias Tsitsimpis | # --------------------------------------------------------------------
|
217 | 4c52d5bf | Ilias Tsitsimpis | # The Log class
|
218 | 4c52d5bf | Ilias Tsitsimpis | class Log(object): |
219 | 4c52d5bf | Ilias Tsitsimpis | """Burnin logger
|
220 | 4c52d5bf | Ilias Tsitsimpis |
|
221 | 4c52d5bf | Ilias Tsitsimpis | """
|
222 | 4c52d5bf | Ilias Tsitsimpis | # ----------------------------------
|
223 | 9355a604 | Ilias Tsitsimpis | # pylint: disable=too-many-arguments
|
224 | 4c52d5bf | Ilias Tsitsimpis | def __init__(self, output_dir, verbose=1, use_colors=True, |
225 | ee89df69 | Ilias Tsitsimpis | in_parallel=False, log_level=0, curr_time=None): |
226 | 4c52d5bf | Ilias Tsitsimpis | """Initialize our loggers
|
227 | 4c52d5bf | Ilias Tsitsimpis |
|
228 | 4c52d5bf | Ilias Tsitsimpis | The file to be used by our file logger will be created inside
|
229 | 4c52d5bf | Ilias Tsitsimpis | the L{output_dir} with name the current timestamp.
|
230 | 4c52d5bf | Ilias Tsitsimpis |
|
231 | 4c52d5bf | Ilias Tsitsimpis | @type output_dir: string
|
232 | 4c52d5bf | Ilias Tsitsimpis | @param output_dir: the directory to save the output file
|
233 | 4c52d5bf | Ilias Tsitsimpis | @type verbose: int
|
234 | 4c52d5bf | Ilias Tsitsimpis | @param verbose: the verbose level to use for stdout/stderr logger
|
235 | 4c52d5bf | Ilias Tsitsimpis | 0: verbose at minimum level (only which test we are running now)
|
236 | 4c52d5bf | Ilias Tsitsimpis | 1: verbose at info level (information about our running test)
|
237 | 4c52d5bf | Ilias Tsitsimpis | 2: verbose at debug level
|
238 | 4c52d5bf | Ilias Tsitsimpis | @type use_colors: boolean
|
239 | 4c52d5bf | Ilias Tsitsimpis | @param use_colors: use colors for out stdout/stderr logger
|
240 | 4c52d5bf | Ilias Tsitsimpis | @type in_parallel: boolean
|
241 | 4c52d5bf | Ilias Tsitsimpis | @param in_parallel: this signifies that burnin is running in parallel
|
242 | ee89df69 | Ilias Tsitsimpis | @type log_level: int
|
243 | ee89df69 | Ilias Tsitsimpis | @param log_level: logging level
|
244 | ee89df69 | Ilias Tsitsimpis | 0: log to console and file
|
245 | ee89df69 | Ilias Tsitsimpis | 1: log to file only and output the results to console
|
246 | ee89df69 | Ilias Tsitsimpis | 2: don't log
|
247 | ee89df69 | Ilias Tsitsimpis | @type curr_time: datetime.datetime()
|
248 | ee89df69 | Ilias Tsitsimpis | @param curr_time: The current time (used as burnin's run id)
|
249 | 4c52d5bf | Ilias Tsitsimpis |
|
250 | 4c52d5bf | Ilias Tsitsimpis | """
|
251 | 4c52d5bf | Ilias Tsitsimpis | self.verbose = verbose
|
252 | 4c52d5bf | Ilias Tsitsimpis | self.use_colors = use_colors
|
253 | 4c52d5bf | Ilias Tsitsimpis | self.in_parallel = in_parallel
|
254 | ee89df69 | Ilias Tsitsimpis | self.log_level = log_level
|
255 | 4c52d5bf | Ilias Tsitsimpis | |
256 | 12ef696f | Ilias Tsitsimpis | assert output_dir
|
257 | 12ef696f | Ilias Tsitsimpis | |
258 | 2afd10bf | Ilias Tsitsimpis | if curr_time is None: |
259 | 2afd10bf | Ilias Tsitsimpis | curr_time = datetime.datetime.now() |
260 | 4c52d5bf | Ilias Tsitsimpis | timestamp = datetime.datetime.strftime( |
261 | 2afd10bf | Ilias Tsitsimpis | curr_time, "%Y%m%d%H%M%S (%a %b %d %Y %H:%M)")
|
262 | 4c52d5bf | Ilias Tsitsimpis | file_name = timestamp + ".log"
|
263 | 4c52d5bf | Ilias Tsitsimpis | self.file_location = os.path.join(output_dir, file_name)
|
264 | 4c52d5bf | Ilias Tsitsimpis | |
265 | 2afd10bf | Ilias Tsitsimpis | self._write_to_stdout(None, "Starting burnin with id %s\n" % timestamp) |
266 | 4c52d5bf | Ilias Tsitsimpis | |
267 | 4c52d5bf | Ilias Tsitsimpis | # Create the logging file
|
268 | 828bbf06 | Ilias Tsitsimpis | self._create_logging_file(timestamp, output_dir)
|
269 | 4c52d5bf | Ilias Tsitsimpis | |
270 | 828bbf06 | Ilias Tsitsimpis | def _create_logging_file(self, timestamp, output_dir): |
271 | 4c52d5bf | Ilias Tsitsimpis | """Create the logging file"""
|
272 | ee89df69 | Ilias Tsitsimpis | if self.log_level > 1: |
273 | ee89df69 | Ilias Tsitsimpis | return
|
274 | 828bbf06 | Ilias Tsitsimpis | |
275 | 828bbf06 | Ilias Tsitsimpis | # Create file for logging
|
276 | 828bbf06 | Ilias Tsitsimpis | output_dir = os.path.expanduser(output_dir) |
277 | 828bbf06 | Ilias Tsitsimpis | if not os.path.exists(output_dir): |
278 | 828bbf06 | Ilias Tsitsimpis | self.debug(None, "Creating directory %s", output_dir) |
279 | 828bbf06 | Ilias Tsitsimpis | try:
|
280 | 828bbf06 | Ilias Tsitsimpis | os.makedirs(output_dir) |
281 | 828bbf06 | Ilias Tsitsimpis | except OSError as err: |
282 | 828bbf06 | Ilias Tsitsimpis | msg = ("Failed to create folder \"%s\" with error: %s\n"
|
283 | 828bbf06 | Ilias Tsitsimpis | % (output_dir, err)) |
284 | 828bbf06 | Ilias Tsitsimpis | sys.stderr.write(msg) |
285 | 828bbf06 | Ilias Tsitsimpis | sys.exit("Failed to create log folder")
|
286 | 828bbf06 | Ilias Tsitsimpis | |
287 | 4c52d5bf | Ilias Tsitsimpis | self.debug(None, "Using \"%s\" file for logging", self.file_location) |
288 | 4c52d5bf | Ilias Tsitsimpis | with open(self.file_location, 'w') as out_file: |
289 | 4c52d5bf | Ilias Tsitsimpis | out_file.write(SECTION_SEPARATOR + "\n")
|
290 | 828bbf06 | Ilias Tsitsimpis | out_file.write("%s%s with id %s:\n\n\n\n" %
|
291 | 4c52d5bf | Ilias Tsitsimpis | (SECTION_PREFIX, SECTION_RUNNED, timestamp)) |
292 | 4c52d5bf | Ilias Tsitsimpis | out_file.write(SECTION_SEPARATOR + "\n")
|
293 | 4c52d5bf | Ilias Tsitsimpis | out_file.write("%s%s:\n\n" % (SECTION_PREFIX, SECTION_RESULTS))
|
294 | 4c52d5bf | Ilias Tsitsimpis | out_file.write(SECTION_PASSED + "\n" + SECTION_FAILED + "\n") |
295 | 4c52d5bf | Ilias Tsitsimpis | |
296 | 4c52d5bf | Ilias Tsitsimpis | def __del__(self): |
297 | 4c52d5bf | Ilias Tsitsimpis | """Delete the Log object"""
|
298 | ee89df69 | Ilias Tsitsimpis | self.print_logfile_to_stdout()
|
299 | 4c52d5bf | Ilias Tsitsimpis | # Remove the lock file
|
300 | 12ef696f | Ilias Tsitsimpis | if hasattr(self, "file_location"): |
301 | 12ef696f | Ilias Tsitsimpis | file_lock = os.path.splitext(self.file_location)[0] + LOCK_EXT |
302 | 12ef696f | Ilias Tsitsimpis | try:
|
303 | 12ef696f | Ilias Tsitsimpis | os.remove(file_lock) |
304 | 12ef696f | Ilias Tsitsimpis | except OSError: |
305 | 12ef696f | Ilias Tsitsimpis | self.debug(None, "Couldn't delete lock file") |
306 | 4c52d5bf | Ilias Tsitsimpis | |
307 | 0c1833c8 | Ilias Tsitsimpis | def print_logfile_to_stdout(self): |
308 | 0c1833c8 | Ilias Tsitsimpis | """Print the contents of our log file to stdout"""
|
309 | ee89df69 | Ilias Tsitsimpis | if self.log_level == 1: |
310 | ee89df69 | Ilias Tsitsimpis | with open(self.file_location, 'r') as fin: |
311 | ee89df69 | Ilias Tsitsimpis | sys.stdout.write(fin.read()) |
312 | 0c1833c8 | Ilias Tsitsimpis | |
313 | 4c52d5bf | Ilias Tsitsimpis | # ----------------------------------
|
314 | 4c52d5bf | Ilias Tsitsimpis | # Logging methods
|
315 | 4c52d5bf | Ilias Tsitsimpis | def debug(self, section, msg, *args): |
316 | 4c52d5bf | Ilias Tsitsimpis | """Debug messages (verbose 2)
|
317 | 4c52d5bf | Ilias Tsitsimpis |
|
318 | 4c52d5bf | Ilias Tsitsimpis | We show debug messages only to stdout. The message will be formatted
|
319 | 4c52d5bf | Ilias Tsitsimpis | using the args.
|
320 | 4c52d5bf | Ilias Tsitsimpis |
|
321 | 4c52d5bf | Ilias Tsitsimpis | """
|
322 | 4c52d5bf | Ilias Tsitsimpis | msg = " (DD) " + _list_to_string(msg, append=" ") |
323 | 4c52d5bf | Ilias Tsitsimpis | if self.verbose >= 2: |
324 | 4c52d5bf | Ilias Tsitsimpis | colored_msg = self._color_message(None, msg, *args) |
325 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(section, colored_msg)
|
326 | 4c52d5bf | Ilias Tsitsimpis | |
327 | 4c52d5bf | Ilias Tsitsimpis | def log(self, section, msg, *args): |
328 | 4c52d5bf | Ilias Tsitsimpis | """Normal messages (verbose 0)"""
|
329 | 4c52d5bf | Ilias Tsitsimpis | assert section, "Section can not be empty" |
330 | 4c52d5bf | Ilias Tsitsimpis | |
331 | 4c52d5bf | Ilias Tsitsimpis | msg = _list_to_string(msg) |
332 | 4c52d5bf | Ilias Tsitsimpis | |
333 | 4c52d5bf | Ilias Tsitsimpis | colored_msg = self._color_message(None, msg, *args) |
334 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(section, colored_msg)
|
335 | 4c52d5bf | Ilias Tsitsimpis | |
336 | 4c52d5bf | Ilias Tsitsimpis | plain_msg = _format_message(msg, *args) |
337 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_file(section, plain_msg)
|
338 | 4c52d5bf | Ilias Tsitsimpis | |
339 | 4c52d5bf | Ilias Tsitsimpis | def info(self, section, msg, *args): |
340 | 4c52d5bf | Ilias Tsitsimpis | """Info messages (verbose 1)
|
341 | 4c52d5bf | Ilias Tsitsimpis |
|
342 | 4c52d5bf | Ilias Tsitsimpis | Prepare message and write it to file logger and stdout logger
|
343 | 4c52d5bf | Ilias Tsitsimpis |
|
344 | 4c52d5bf | Ilias Tsitsimpis | """
|
345 | 4c52d5bf | Ilias Tsitsimpis | assert section, "Section can not be empty" |
346 | 4c52d5bf | Ilias Tsitsimpis | |
347 | 4c52d5bf | Ilias Tsitsimpis | msg = " " + _list_to_string(msg, " ") |
348 | 4c52d5bf | Ilias Tsitsimpis | if self.verbose >= 1: |
349 | 4c52d5bf | Ilias Tsitsimpis | colored_msg = self._color_message(None, msg, *args) |
350 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(section, colored_msg)
|
351 | 4c52d5bf | Ilias Tsitsimpis | |
352 | 4c52d5bf | Ilias Tsitsimpis | plain_msg = _format_message(msg, *args) |
353 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_file(section, plain_msg)
|
354 | 4c52d5bf | Ilias Tsitsimpis | |
355 | 4c52d5bf | Ilias Tsitsimpis | def warning(self, section, msg, *args): |
356 | 4c52d5bf | Ilias Tsitsimpis | """Warning messages"""
|
357 | 4c52d5bf | Ilias Tsitsimpis | assert section, "Section can not be empty" |
358 | 4c52d5bf | Ilias Tsitsimpis | |
359 | 4c52d5bf | Ilias Tsitsimpis | msg = " (WW) " + _list_to_string(msg, " ") |
360 | 4c52d5bf | Ilias Tsitsimpis | |
361 | 4c52d5bf | Ilias Tsitsimpis | colored_msg = self._color_message(_yellow, msg, *args)
|
362 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stderr(section, colored_msg)
|
363 | 4c52d5bf | Ilias Tsitsimpis | |
364 | 4c52d5bf | Ilias Tsitsimpis | plain_msg = _format_message(msg, *args) |
365 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_file(section, plain_msg)
|
366 | 4c52d5bf | Ilias Tsitsimpis | |
367 | 4c52d5bf | Ilias Tsitsimpis | def error(self, section, msg, *args): |
368 | 4c52d5bf | Ilias Tsitsimpis | """Error messages"""
|
369 | 4c52d5bf | Ilias Tsitsimpis | assert section, "Section can not be empty" |
370 | 4c52d5bf | Ilias Tsitsimpis | |
371 | 4c52d5bf | Ilias Tsitsimpis | msg = " (EE) " + _list_to_string(msg, " ") |
372 | 4c52d5bf | Ilias Tsitsimpis | |
373 | 4c52d5bf | Ilias Tsitsimpis | colored_msg = self._color_message(_red, msg, *args)
|
374 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stderr(section, colored_msg)
|
375 | 4c52d5bf | Ilias Tsitsimpis | |
376 | 4c52d5bf | Ilias Tsitsimpis | plain_msg = _format_message(msg, *args) |
377 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_file(section, plain_msg)
|
378 | 4c52d5bf | Ilias Tsitsimpis | |
379 | 4c52d5bf | Ilias Tsitsimpis | def _write_to_stdout(self, section, msg): |
380 | 4c52d5bf | Ilias Tsitsimpis | """Write to stdout"""
|
381 | ee89df69 | Ilias Tsitsimpis | if self.log_level > 0: |
382 | ee89df69 | Ilias Tsitsimpis | return
|
383 | ee89df69 | Ilias Tsitsimpis | if section is not None and self.in_parallel: |
384 | ee89df69 | Ilias Tsitsimpis | sys.stdout.write(section + ": " + msg)
|
385 | ee89df69 | Ilias Tsitsimpis | else:
|
386 | ee89df69 | Ilias Tsitsimpis | sys.stdout.write(msg) |
387 | 4c52d5bf | Ilias Tsitsimpis | |
388 | 4c52d5bf | Ilias Tsitsimpis | def _write_to_stderr(self, section, msg): |
389 | 4c52d5bf | Ilias Tsitsimpis | """Write to stderr"""
|
390 | ee89df69 | Ilias Tsitsimpis | if self.log_level > 0: |
391 | ee89df69 | Ilias Tsitsimpis | return
|
392 | ee89df69 | Ilias Tsitsimpis | if section is not None and self.in_parallel: |
393 | ee89df69 | Ilias Tsitsimpis | sys.stderr.write(section + ": " + msg)
|
394 | ee89df69 | Ilias Tsitsimpis | else:
|
395 | ee89df69 | Ilias Tsitsimpis | sys.stderr.write(msg) |
396 | 4c52d5bf | Ilias Tsitsimpis | |
397 | 4c52d5bf | Ilias Tsitsimpis | def _write_to_file(self, section, msg): |
398 | 4c52d5bf | Ilias Tsitsimpis | """Write to file"""
|
399 | ee89df69 | Ilias Tsitsimpis | if self.log_level > 1: |
400 | ee89df69 | Ilias Tsitsimpis | return
|
401 | 4c52d5bf | Ilias Tsitsimpis | _write_log_file(self.file_location, section, msg)
|
402 | 4c52d5bf | Ilias Tsitsimpis | |
403 | 4c52d5bf | Ilias Tsitsimpis | # ----------------------------------
|
404 | 4c52d5bf | Ilias Tsitsimpis | # Handle testsuites
|
405 | 4c52d5bf | Ilias Tsitsimpis | def testsuite_start(self, testsuite): |
406 | 4c52d5bf | Ilias Tsitsimpis | """Start a new testsuite
|
407 | 4c52d5bf | Ilias Tsitsimpis |
|
408 | 4c52d5bf | Ilias Tsitsimpis | Add a new section in the logging file
|
409 | 4c52d5bf | Ilias Tsitsimpis |
|
410 | 4c52d5bf | Ilias Tsitsimpis | """
|
411 | 4c52d5bf | Ilias Tsitsimpis | assert testsuite, "Testsuite name can not be emtpy" |
412 | 4c52d5bf | Ilias Tsitsimpis | |
413 | 4c52d5bf | Ilias Tsitsimpis | # Add a new section in the logging file
|
414 | 4c52d5bf | Ilias Tsitsimpis | test_runned = " * " + testsuite + "\n" |
415 | ee89df69 | Ilias Tsitsimpis | self._write_to_file(SECTION_RUNNED, test_runned)
|
416 | 4c52d5bf | Ilias Tsitsimpis | |
417 | 4c52d5bf | Ilias Tsitsimpis | new_section_entry = \ |
418 | 4c52d5bf | Ilias Tsitsimpis | SECTION_SEPARATOR + "\n" + SECTION_PREFIX + testsuite + "\n\n\n\n" |
419 | ee89df69 | Ilias Tsitsimpis | self._write_to_file(SECTION_NEW, new_section_entry)
|
420 | 4c52d5bf | Ilias Tsitsimpis | |
421 | 4c52d5bf | Ilias Tsitsimpis | # Add new section to the stdout
|
422 | 4c52d5bf | Ilias Tsitsimpis | msg = "Starting testsuite %s" % testsuite
|
423 | 12ef696f | Ilias Tsitsimpis | colored_msg = self._color_message(_magenta, msg)
|
424 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(None, colored_msg) |
425 | 4c52d5bf | Ilias Tsitsimpis | |
426 | 4c52d5bf | Ilias Tsitsimpis | def testsuite_success(self, testsuite): |
427 | 4c52d5bf | Ilias Tsitsimpis | """A testsuite has successfully finished
|
428 | 4c52d5bf | Ilias Tsitsimpis |
|
429 | 4c52d5bf | Ilias Tsitsimpis | Update Results
|
430 | 4c52d5bf | Ilias Tsitsimpis |
|
431 | 4c52d5bf | Ilias Tsitsimpis | """
|
432 | 4c52d5bf | Ilias Tsitsimpis | assert testsuite, "Testsuite name can not be emtpy" |
433 | 4c52d5bf | Ilias Tsitsimpis | |
434 | 4c52d5bf | Ilias Tsitsimpis | # Add our testsuite to Results
|
435 | ee89df69 | Ilias Tsitsimpis | self._write_to_file(SECTION_PASSED, testsuite)
|
436 | 4c52d5bf | Ilias Tsitsimpis | |
437 | 4c52d5bf | Ilias Tsitsimpis | # Add success to stdout
|
438 | 4c52d5bf | Ilias Tsitsimpis | msg = "Testsuite %s passed" % testsuite
|
439 | 12ef696f | Ilias Tsitsimpis | colored_msg = self._color_message(_green, msg)
|
440 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(None, colored_msg) |
441 | 4c52d5bf | Ilias Tsitsimpis | |
442 | 4c52d5bf | Ilias Tsitsimpis | def testsuite_failure(self, testsuite): |
443 | 4c52d5bf | Ilias Tsitsimpis | """A testsuite has failed
|
444 | 4c52d5bf | Ilias Tsitsimpis |
|
445 | 4c52d5bf | Ilias Tsitsimpis | Update Results
|
446 | 4c52d5bf | Ilias Tsitsimpis |
|
447 | 4c52d5bf | Ilias Tsitsimpis | """
|
448 | 4c52d5bf | Ilias Tsitsimpis | assert testsuite, "Testsuite name can not be emtpy" |
449 | 4c52d5bf | Ilias Tsitsimpis | |
450 | 4c52d5bf | Ilias Tsitsimpis | # Add our testsuite to Results
|
451 | ee89df69 | Ilias Tsitsimpis | self._write_to_file(SECTION_FAILED, testsuite)
|
452 | 4c52d5bf | Ilias Tsitsimpis | |
453 | 4c52d5bf | Ilias Tsitsimpis | # Add success to stdout
|
454 | 4c52d5bf | Ilias Tsitsimpis | msg = "Testsuite %s failed" % testsuite
|
455 | 12ef696f | Ilias Tsitsimpis | colored_msg = self._color_message(_red, msg)
|
456 | 4c52d5bf | Ilias Tsitsimpis | self._write_to_stdout(None, colored_msg) |
457 | 4c52d5bf | Ilias Tsitsimpis | |
458 | 4c52d5bf | Ilias Tsitsimpis | # ----------------------------------
|
459 | 4c52d5bf | Ilias Tsitsimpis | # Colors
|
460 | 4c52d5bf | Ilias Tsitsimpis | def _color_message(self, color_fun, msg, *args): |
461 | 4c52d5bf | Ilias Tsitsimpis | """Color a message before printing it
|
462 | 4c52d5bf | Ilias Tsitsimpis |
|
463 | 4c52d5bf | Ilias Tsitsimpis | The color_fun parameter is used when we want the whole message to be
|
464 | 4c52d5bf | Ilias Tsitsimpis | colored.
|
465 | 4c52d5bf | Ilias Tsitsimpis |
|
466 | 4c52d5bf | Ilias Tsitsimpis | """
|
467 | 4c52d5bf | Ilias Tsitsimpis | if self.use_colors: |
468 | 4c52d5bf | Ilias Tsitsimpis | if callable(color_fun): |
469 | 6c78720b | Ilias Tsitsimpis | if args:
|
470 | 6c78720b | Ilias Tsitsimpis | return color_fun((msg % args)) + "\n" |
471 | 6c78720b | Ilias Tsitsimpis | else:
|
472 | 6c78720b | Ilias Tsitsimpis | return color_fun(msg) + "\n" |
473 | 4c52d5bf | Ilias Tsitsimpis | else:
|
474 | 3e5bbd85 | Ilias Tsitsimpis | args = tuple([_cyan(arg) for arg in args]) |
475 | 4c52d5bf | Ilias Tsitsimpis | return _format_message(msg, *args)
|
476 | 4c52d5bf | Ilias Tsitsimpis | else:
|
477 | 4c52d5bf | Ilias Tsitsimpis | return _format_message(msg, *args) |