Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / logger.py @ 6c78720b

History | View | Annotate | Download (14.9 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 4c52d5bf Ilias Tsitsimpis
import datetime
56 4c52d5bf Ilias Tsitsimpis
57 12ef696f Ilias Tsitsimpis
from synnefo_tools.burnin import filelocker
58 4c52d5bf Ilias Tsitsimpis
59 4c52d5bf Ilias Tsitsimpis
60 4c52d5bf Ilias Tsitsimpis
# --------------------------------------------------------------------
61 4c52d5bf Ilias Tsitsimpis
# Constant variables
62 4c52d5bf Ilias Tsitsimpis
LOCK_EXT = ".lock"
63 4c52d5bf Ilias Tsitsimpis
SECTION_SEPARATOR = \
64 4c52d5bf Ilias Tsitsimpis
    "-- -------------------------------------------------------------------"
65 4c52d5bf Ilias Tsitsimpis
SECTION_PREFIX = "-- "
66 4c52d5bf Ilias Tsitsimpis
SECTION_RUNNED = "Tests Runned"
67 4c52d5bf Ilias Tsitsimpis
SECTION_RESULTS = "Results"
68 4c52d5bf Ilias Tsitsimpis
SECTION_NEW = "__ADD_NEW_SECTION__"
69 4c52d5bf Ilias Tsitsimpis
SECTION_PASSED = "  * Passed:"
70 4c52d5bf Ilias Tsitsimpis
SECTION_FAILED = "  * Failed:"
71 4c52d5bf Ilias Tsitsimpis
72 4c52d5bf Ilias Tsitsimpis
73 4c52d5bf Ilias Tsitsimpis
# --------------------------------------------------------------------
74 4c52d5bf Ilias Tsitsimpis
# Helper functions
75 4c52d5bf Ilias Tsitsimpis
def _blue(msg):
76 4c52d5bf Ilias Tsitsimpis
    """Blue color"""
77 4c52d5bf Ilias Tsitsimpis
    return "\x1b[1;34m" + str(msg) + "\x1b[0m"
78 4c52d5bf Ilias Tsitsimpis
79 4c52d5bf Ilias Tsitsimpis
80 4c52d5bf Ilias Tsitsimpis
def _yellow(msg):
81 4c52d5bf Ilias Tsitsimpis
    """Yellow color"""
82 4c52d5bf Ilias Tsitsimpis
    return "\x1b[33m" + str(msg) + "\x1b[0m"
83 4c52d5bf Ilias Tsitsimpis
84 4c52d5bf Ilias Tsitsimpis
85 4c52d5bf Ilias Tsitsimpis
def _red(msg):
86 4c52d5bf Ilias Tsitsimpis
    """Yellow color"""
87 4c52d5bf Ilias Tsitsimpis
    return "\x1b[31m" + str(msg) + "\x1b[0m"
88 4c52d5bf Ilias Tsitsimpis
89 4c52d5bf Ilias Tsitsimpis
90 12ef696f Ilias Tsitsimpis
def _magenta(msg):
91 12ef696f Ilias Tsitsimpis
    """Magenta color"""
92 4c52d5bf Ilias Tsitsimpis
    return "\x1b[35m" + str(msg) + "\x1b[0m"
93 4c52d5bf Ilias Tsitsimpis
94 4c52d5bf Ilias Tsitsimpis
95 12ef696f Ilias Tsitsimpis
def _green(msg):
96 12ef696f Ilias Tsitsimpis
    """Green color"""
97 12ef696f Ilias Tsitsimpis
    return "\x1b[32m" + str(msg) + "\x1b[0m"
98 4c52d5bf Ilias Tsitsimpis
99 4c52d5bf Ilias Tsitsimpis
100 4c52d5bf Ilias Tsitsimpis
def _format_message(msg, *args):
101 4c52d5bf Ilias Tsitsimpis
    """Format the message using the args"""
102 6c78720b Ilias Tsitsimpis
    if args:
103 6c78720b Ilias Tsitsimpis
        return (msg % args) + "\n"
104 6c78720b Ilias Tsitsimpis
    else:
105 6c78720b Ilias Tsitsimpis
        return msg + "\n"
106 4c52d5bf Ilias Tsitsimpis
107 4c52d5bf Ilias Tsitsimpis
108 4c52d5bf Ilias Tsitsimpis
def _list_to_string(lst, append=""):
109 4c52d5bf Ilias Tsitsimpis
    """Convert a list of strings to string
110 4c52d5bf Ilias Tsitsimpis

111 4c52d5bf Ilias Tsitsimpis
    Append the value given in L{append} in front of all lines
112 4c52d5bf Ilias Tsitsimpis
    (except of the first line).
113 4c52d5bf Ilias Tsitsimpis

114 4c52d5bf Ilias Tsitsimpis
    """
115 4c52d5bf Ilias Tsitsimpis
    if isinstance(lst, list):
116 4c52d5bf Ilias Tsitsimpis
        return append.join(lst).rstrip('\n')
117 4c52d5bf Ilias Tsitsimpis
    else:
118 4c52d5bf Ilias Tsitsimpis
        return lst.rstrip('\n')
119 4c52d5bf Ilias Tsitsimpis
120 4c52d5bf Ilias Tsitsimpis
121 4c52d5bf Ilias Tsitsimpis
# --------------------------------------
122 4c52d5bf Ilias Tsitsimpis
def _locate_sections(contents):
123 4c52d5bf Ilias Tsitsimpis
    """Locate the sections inside the logging file"""
124 4c52d5bf Ilias Tsitsimpis
    i = 0
125 4c52d5bf Ilias Tsitsimpis
    res = []
126 4c52d5bf Ilias Tsitsimpis
    for cnt in contents:
127 4c52d5bf Ilias Tsitsimpis
        if SECTION_SEPARATOR in cnt:
128 4c52d5bf Ilias Tsitsimpis
            res.append(i+1)
129 4c52d5bf Ilias Tsitsimpis
        i += 1
130 4c52d5bf Ilias Tsitsimpis
    return res
131 4c52d5bf Ilias Tsitsimpis
132 4c52d5bf Ilias Tsitsimpis
133 4c52d5bf Ilias Tsitsimpis
def _locate_input(contents, section):
134 4c52d5bf Ilias Tsitsimpis
    """Locate position to insert text
135 4c52d5bf Ilias Tsitsimpis

136 4c52d5bf Ilias Tsitsimpis
    Given a section location the next possition to insert text inside that
137 4c52d5bf Ilias Tsitsimpis
    section.
138 4c52d5bf Ilias Tsitsimpis

139 4c52d5bf Ilias Tsitsimpis
    """
140 4c52d5bf Ilias Tsitsimpis
    sect_locs = _locate_sections(contents)
141 4c52d5bf Ilias Tsitsimpis
    if section == SECTION_NEW:
142 4c52d5bf Ilias Tsitsimpis
        # We want to add a new section
143 4c52d5bf Ilias Tsitsimpis
        # Just return the position of SECTION_RESULTS
144 4c52d5bf Ilias Tsitsimpis
        for obj in sect_locs:
145 4c52d5bf Ilias Tsitsimpis
            if SECTION_RESULTS in contents[obj]:
146 4c52d5bf Ilias Tsitsimpis
                return obj - 1
147 4c52d5bf Ilias Tsitsimpis
    else:
148 4c52d5bf Ilias Tsitsimpis
        # We will add our message in this location
149 4c52d5bf Ilias Tsitsimpis
        for (index, obj) in enumerate(sect_locs):
150 4c52d5bf Ilias Tsitsimpis
            if section in contents[obj]:
151 4c52d5bf Ilias Tsitsimpis
                return sect_locs[index+1] - 3
152 4c52d5bf Ilias Tsitsimpis
153 4c52d5bf Ilias Tsitsimpis
    # We didn't find our section??
154 4c52d5bf Ilias Tsitsimpis
    sys.stderr.write("Section %s could not be found in logging file\n"
155 4c52d5bf Ilias Tsitsimpis
                     % section)
156 12ef696f Ilias Tsitsimpis
    sys.exit("Error in logger._locate_input")
157 4c52d5bf Ilias Tsitsimpis
158 4c52d5bf Ilias Tsitsimpis
159 4c52d5bf Ilias Tsitsimpis
def _add_testsuite_results(contents, section, testsuite):
160 4c52d5bf Ilias Tsitsimpis
    """Add the given testsuite to results
161 4c52d5bf Ilias Tsitsimpis

162 4c52d5bf Ilias Tsitsimpis
    Well we know that SECTION_FAILED is the last line and SECTION_PASSED is the
163 4c52d5bf Ilias Tsitsimpis
    line before, so we are going to cheat here and use this information.
164 4c52d5bf Ilias Tsitsimpis

165 4c52d5bf Ilias Tsitsimpis
    """
166 4c52d5bf Ilias Tsitsimpis
    if section == SECTION_PASSED:
167 4c52d5bf Ilias Tsitsimpis
        line = contents[-2]
168 4c52d5bf Ilias Tsitsimpis
        new_line = line.rstrip() + " " + testsuite + ",\n"
169 4c52d5bf Ilias Tsitsimpis
        contents[-2] = new_line
170 4c52d5bf Ilias Tsitsimpis
    elif section == SECTION_FAILED:
171 4c52d5bf Ilias Tsitsimpis
        line = contents[-1]
172 4c52d5bf Ilias Tsitsimpis
        new_line = line.rstrip() + " " + testsuite + ",\n"
173 4c52d5bf Ilias Tsitsimpis
        contents[-1] = new_line
174 4c52d5bf Ilias Tsitsimpis
    else:
175 4c52d5bf Ilias Tsitsimpis
        sys.stderr.write("Unknown section %s in _add_testsuite_results\n"
176 4c52d5bf Ilias Tsitsimpis
                         % section)
177 12ef696f Ilias Tsitsimpis
        sys.exit("Error in logger._add_testsuite_results")
178 4c52d5bf Ilias Tsitsimpis
    return contents
179 4c52d5bf Ilias Tsitsimpis
180 4c52d5bf Ilias Tsitsimpis
181 4c52d5bf Ilias Tsitsimpis
def _write_log_file(file_location, section, message):
182 4c52d5bf Ilias Tsitsimpis
    """Write something to our log file
183 4c52d5bf Ilias Tsitsimpis

184 4c52d5bf Ilias Tsitsimpis
    For this we have to get the lock, read and parse the file add the new
185 4c52d5bf Ilias Tsitsimpis
    message and re-write the file.
186 4c52d5bf Ilias Tsitsimpis

187 4c52d5bf Ilias Tsitsimpis
    """
188 4c52d5bf Ilias Tsitsimpis
    # Get the lock
189 4c52d5bf Ilias Tsitsimpis
    file_lock = os.path.splitext(file_location)[0] + LOCK_EXT
190 4c52d5bf Ilias Tsitsimpis
    with filelocker.lock(file_lock, filelocker.LOCK_EX):
191 4c52d5bf Ilias Tsitsimpis
        with open(file_location, "r+") as log_file:
192 4c52d5bf Ilias Tsitsimpis
            contents = log_file.readlines()
193 4c52d5bf Ilias Tsitsimpis
            if section == SECTION_PASSED or section == SECTION_FAILED:
194 4c52d5bf Ilias Tsitsimpis
                # Add testsuite to results
195 4c52d5bf Ilias Tsitsimpis
                new_contents = \
196 4c52d5bf Ilias Tsitsimpis
                    _add_testsuite_results(contents, section, message)
197 4c52d5bf Ilias Tsitsimpis
            else:
198 4c52d5bf Ilias Tsitsimpis
                # Add message to its line
199 4c52d5bf Ilias Tsitsimpis
                input_loc = _locate_input(contents, section)
200 4c52d5bf Ilias Tsitsimpis
                new_contents = \
201 4c52d5bf Ilias Tsitsimpis
                    contents[:input_loc] + [message] + contents[input_loc:]
202 4c52d5bf Ilias Tsitsimpis
            log_file.seek(0)
203 4c52d5bf Ilias Tsitsimpis
            log_file.write("".join(new_contents))
204 4c52d5bf Ilias Tsitsimpis
205 4c52d5bf Ilias Tsitsimpis
206 4c52d5bf Ilias Tsitsimpis
# --------------------------------------------------------------------
207 4c52d5bf Ilias Tsitsimpis
# The Log class
208 4c52d5bf Ilias Tsitsimpis
class Log(object):
209 4c52d5bf Ilias Tsitsimpis
    """Burnin logger
210 4c52d5bf Ilias Tsitsimpis

211 4c52d5bf Ilias Tsitsimpis
    """
212 4c52d5bf Ilias Tsitsimpis
    # ----------------------------------
213 0c1833c8 Ilias Tsitsimpis
    # Too many arguments. pylint: disable-msg=R0913
214 4c52d5bf Ilias Tsitsimpis
    def __init__(self, output_dir, verbose=1, use_colors=True,
215 0c1833c8 Ilias Tsitsimpis
                 in_parallel=False, quiet=False):
216 4c52d5bf Ilias Tsitsimpis
        """Initialize our loggers
217 4c52d5bf Ilias Tsitsimpis

218 4c52d5bf Ilias Tsitsimpis
        The file to be used by our file logger will be created inside
219 4c52d5bf Ilias Tsitsimpis
        the L{output_dir} with name the current timestamp.
220 4c52d5bf Ilias Tsitsimpis

221 4c52d5bf Ilias Tsitsimpis
        @type output_dir: string
222 4c52d5bf Ilias Tsitsimpis
        @param output_dir: the directory to save the output file
223 4c52d5bf Ilias Tsitsimpis
        @type verbose: int
224 4c52d5bf Ilias Tsitsimpis
        @param verbose: the verbose level to use for stdout/stderr logger
225 4c52d5bf Ilias Tsitsimpis
            0: verbose at minimum level (only which test we are running now)
226 4c52d5bf Ilias Tsitsimpis
            1: verbose at info level (information about our running test)
227 4c52d5bf Ilias Tsitsimpis
            2: verbose at debug level
228 4c52d5bf Ilias Tsitsimpis
        @type use_colors: boolean
229 4c52d5bf Ilias Tsitsimpis
        @param use_colors: use colors for out stdout/stderr logger
230 4c52d5bf Ilias Tsitsimpis
        @type in_parallel: boolean
231 4c52d5bf Ilias Tsitsimpis
        @param in_parallel: this signifies that burnin is running in parallel
232 0c1833c8 Ilias Tsitsimpis
        @type quiet: boolean
233 0c1833c8 Ilias Tsitsimpis
        @type quiet: do not print logs to stdout/stderr
234 4c52d5bf Ilias Tsitsimpis

235 4c52d5bf Ilias Tsitsimpis
        """
236 4c52d5bf Ilias Tsitsimpis
        self.verbose = verbose
237 4c52d5bf Ilias Tsitsimpis
        self.use_colors = use_colors
238 4c52d5bf Ilias Tsitsimpis
        self.in_parallel = in_parallel
239 0c1833c8 Ilias Tsitsimpis
        self.quiet = quiet
240 4c52d5bf Ilias Tsitsimpis
241 12ef696f Ilias Tsitsimpis
        assert output_dir
242 12ef696f Ilias Tsitsimpis
243 4c52d5bf Ilias Tsitsimpis
        # Create file for logging
244 4c52d5bf Ilias Tsitsimpis
        output_dir = os.path.expanduser(output_dir)
245 4c52d5bf Ilias Tsitsimpis
        if not os.path.exists(output_dir):
246 4c52d5bf Ilias Tsitsimpis
            self.debug(None, "Creating directory %s", output_dir)
247 12ef696f Ilias Tsitsimpis
            try:
248 12ef696f Ilias Tsitsimpis
                os.makedirs(output_dir)
249 12ef696f Ilias Tsitsimpis
            except OSError as err:
250 12ef696f Ilias Tsitsimpis
                msg = ("Failed to create folder \"%s\" with error: %s\n"
251 12ef696f Ilias Tsitsimpis
                       % (output_dir, err))
252 12ef696f Ilias Tsitsimpis
                sys.stderr.write(msg)
253 12ef696f Ilias Tsitsimpis
                sys.exit("Failed to create log folder")
254 12ef696f Ilias Tsitsimpis
255 4c52d5bf Ilias Tsitsimpis
        timestamp = datetime.datetime.strftime(
256 4c52d5bf Ilias Tsitsimpis
            datetime.datetime.now(), "%Y%m%d%H%M%S (%a %b %d %Y %H:%M)")
257 4c52d5bf Ilias Tsitsimpis
        file_name = timestamp + ".log"
258 4c52d5bf Ilias Tsitsimpis
        self.file_location = os.path.join(output_dir, file_name)
259 4c52d5bf Ilias Tsitsimpis
260 4c52d5bf Ilias Tsitsimpis
        timestamp = datetime.datetime.strftime(
261 4c52d5bf Ilias Tsitsimpis
            datetime.datetime.now(), "%a %b %d %Y %H:%M")
262 0c1833c8 Ilias Tsitsimpis
        self._write_to_stdout(None, "Starting burnin (%s)\n" % timestamp)
263 4c52d5bf Ilias Tsitsimpis
264 4c52d5bf Ilias Tsitsimpis
        # Create the logging file
265 4c52d5bf Ilias Tsitsimpis
        self._create_logging_file(timestamp)
266 4c52d5bf Ilias Tsitsimpis
267 4c52d5bf Ilias Tsitsimpis
    def _create_logging_file(self, timestamp):
268 4c52d5bf Ilias Tsitsimpis
        """Create the logging file"""
269 4c52d5bf Ilias Tsitsimpis
        self.debug(None, "Using \"%s\" file for logging", self.file_location)
270 4c52d5bf Ilias Tsitsimpis
        with open(self.file_location, 'w') as out_file:
271 4c52d5bf Ilias Tsitsimpis
            out_file.write(SECTION_SEPARATOR + "\n")
272 4c52d5bf Ilias Tsitsimpis
            out_file.write("%s%s (%s):\n\n\n\n" %
273 4c52d5bf Ilias Tsitsimpis
                           (SECTION_PREFIX, SECTION_RUNNED, timestamp))
274 4c52d5bf Ilias Tsitsimpis
            out_file.write(SECTION_SEPARATOR + "\n")
275 4c52d5bf Ilias Tsitsimpis
            out_file.write("%s%s:\n\n" % (SECTION_PREFIX, SECTION_RESULTS))
276 4c52d5bf Ilias Tsitsimpis
            out_file.write(SECTION_PASSED + "\n" + SECTION_FAILED + "\n")
277 4c52d5bf Ilias Tsitsimpis
278 4c52d5bf Ilias Tsitsimpis
    def __del__(self):
279 4c52d5bf Ilias Tsitsimpis
        """Delete the Log object"""
280 4c52d5bf Ilias Tsitsimpis
        # Remove the lock file
281 12ef696f Ilias Tsitsimpis
        if hasattr(self, "file_location"):
282 12ef696f Ilias Tsitsimpis
            file_lock = os.path.splitext(self.file_location)[0] + LOCK_EXT
283 12ef696f Ilias Tsitsimpis
            try:
284 12ef696f Ilias Tsitsimpis
                os.remove(file_lock)
285 12ef696f Ilias Tsitsimpis
            except OSError:
286 12ef696f Ilias Tsitsimpis
                self.debug(None, "Couldn't delete lock file")
287 4c52d5bf Ilias Tsitsimpis
288 0c1833c8 Ilias Tsitsimpis
    def print_logfile_to_stdout(self):
289 0c1833c8 Ilias Tsitsimpis
        """Print the contents of our log file to stdout"""
290 0c1833c8 Ilias Tsitsimpis
        with open(self.file_location, 'r') as fin:
291 0c1833c8 Ilias Tsitsimpis
            sys.stdout.write(fin.read())
292 0c1833c8 Ilias Tsitsimpis
293 4c52d5bf Ilias Tsitsimpis
    # ----------------------------------
294 4c52d5bf Ilias Tsitsimpis
    # Logging methods
295 4c52d5bf Ilias Tsitsimpis
    def debug(self, section, msg, *args):
296 4c52d5bf Ilias Tsitsimpis
        """Debug messages (verbose 2)
297 4c52d5bf Ilias Tsitsimpis

298 4c52d5bf Ilias Tsitsimpis
        We show debug messages only to stdout. The message will be formatted
299 4c52d5bf Ilias Tsitsimpis
        using the args.
300 4c52d5bf Ilias Tsitsimpis

301 4c52d5bf Ilias Tsitsimpis
        """
302 4c52d5bf Ilias Tsitsimpis
        msg = "  (DD) " + _list_to_string(msg, append="       ")
303 4c52d5bf Ilias Tsitsimpis
        if self.verbose >= 2:
304 4c52d5bf Ilias Tsitsimpis
            colored_msg = self._color_message(None, msg, *args)
305 4c52d5bf Ilias Tsitsimpis
            self._write_to_stdout(section, colored_msg)
306 4c52d5bf Ilias Tsitsimpis
307 4c52d5bf Ilias Tsitsimpis
    def log(self, section, msg, *args):
308 4c52d5bf Ilias Tsitsimpis
        """Normal messages (verbose 0)"""
309 4c52d5bf Ilias Tsitsimpis
        assert section, "Section can not be empty"
310 4c52d5bf Ilias Tsitsimpis
311 4c52d5bf Ilias Tsitsimpis
        msg = _list_to_string(msg)
312 4c52d5bf Ilias Tsitsimpis
313 4c52d5bf Ilias Tsitsimpis
        colored_msg = self._color_message(None, msg, *args)
314 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(section, colored_msg)
315 4c52d5bf Ilias Tsitsimpis
316 4c52d5bf Ilias Tsitsimpis
        plain_msg = _format_message(msg, *args)
317 4c52d5bf Ilias Tsitsimpis
        self._write_to_file(section, plain_msg)
318 4c52d5bf Ilias Tsitsimpis
319 4c52d5bf Ilias Tsitsimpis
    def info(self, section, msg, *args):
320 4c52d5bf Ilias Tsitsimpis
        """Info messages (verbose 1)
321 4c52d5bf Ilias Tsitsimpis

322 4c52d5bf Ilias Tsitsimpis
        Prepare message and write it to file logger and stdout logger
323 4c52d5bf Ilias Tsitsimpis

324 4c52d5bf Ilias Tsitsimpis
        """
325 4c52d5bf Ilias Tsitsimpis
        assert section, "Section can not be empty"
326 4c52d5bf Ilias Tsitsimpis
327 4c52d5bf Ilias Tsitsimpis
        msg = "  " + _list_to_string(msg, "  ")
328 4c52d5bf Ilias Tsitsimpis
        if self.verbose >= 1:
329 4c52d5bf Ilias Tsitsimpis
            colored_msg = self._color_message(None, msg, *args)
330 4c52d5bf Ilias Tsitsimpis
            self._write_to_stdout(section, colored_msg)
331 4c52d5bf Ilias Tsitsimpis
332 4c52d5bf Ilias Tsitsimpis
        plain_msg = _format_message(msg, *args)
333 4c52d5bf Ilias Tsitsimpis
        self._write_to_file(section, plain_msg)
334 4c52d5bf Ilias Tsitsimpis
335 4c52d5bf Ilias Tsitsimpis
    def warning(self, section, msg, *args):
336 4c52d5bf Ilias Tsitsimpis
        """Warning messages"""
337 4c52d5bf Ilias Tsitsimpis
        assert section, "Section can not be empty"
338 4c52d5bf Ilias Tsitsimpis
339 4c52d5bf Ilias Tsitsimpis
        msg = "  (WW) " + _list_to_string(msg, "       ")
340 4c52d5bf Ilias Tsitsimpis
341 4c52d5bf Ilias Tsitsimpis
        colored_msg = self._color_message(_yellow, msg, *args)
342 4c52d5bf Ilias Tsitsimpis
        self._write_to_stderr(section, colored_msg)
343 4c52d5bf Ilias Tsitsimpis
344 4c52d5bf Ilias Tsitsimpis
        plain_msg = _format_message(msg, *args)
345 4c52d5bf Ilias Tsitsimpis
        self._write_to_file(section, plain_msg)
346 4c52d5bf Ilias Tsitsimpis
347 4c52d5bf Ilias Tsitsimpis
    def error(self, section, msg, *args):
348 4c52d5bf Ilias Tsitsimpis
        """Error messages"""
349 4c52d5bf Ilias Tsitsimpis
        assert section, "Section can not be empty"
350 4c52d5bf Ilias Tsitsimpis
351 4c52d5bf Ilias Tsitsimpis
        msg = "  (EE) " + _list_to_string(msg, "       ")
352 4c52d5bf Ilias Tsitsimpis
353 4c52d5bf Ilias Tsitsimpis
        colored_msg = self._color_message(_red, msg, *args)
354 4c52d5bf Ilias Tsitsimpis
        self._write_to_stderr(section, colored_msg)
355 4c52d5bf Ilias Tsitsimpis
356 4c52d5bf Ilias Tsitsimpis
        plain_msg = _format_message(msg, *args)
357 4c52d5bf Ilias Tsitsimpis
        self._write_to_file(section, plain_msg)
358 4c52d5bf Ilias Tsitsimpis
359 4c52d5bf Ilias Tsitsimpis
    def _write_to_stdout(self, section, msg):
360 4c52d5bf Ilias Tsitsimpis
        """Write to stdout"""
361 0c1833c8 Ilias Tsitsimpis
        if not self.quiet:
362 0c1833c8 Ilias Tsitsimpis
            if section is not None and self.in_parallel:
363 0c1833c8 Ilias Tsitsimpis
                sys.stdout.write(section + ": " + msg)
364 0c1833c8 Ilias Tsitsimpis
            else:
365 0c1833c8 Ilias Tsitsimpis
                sys.stdout.write(msg)
366 4c52d5bf Ilias Tsitsimpis
367 4c52d5bf Ilias Tsitsimpis
    def _write_to_stderr(self, section, msg):
368 4c52d5bf Ilias Tsitsimpis
        """Write to stderr"""
369 0c1833c8 Ilias Tsitsimpis
        if not self.quiet:
370 0c1833c8 Ilias Tsitsimpis
            if section is not None and self.in_parallel:
371 0c1833c8 Ilias Tsitsimpis
                sys.stderr.write(section + ": " + msg)
372 0c1833c8 Ilias Tsitsimpis
            else:
373 0c1833c8 Ilias Tsitsimpis
                sys.stderr.write(msg)
374 4c52d5bf Ilias Tsitsimpis
375 4c52d5bf Ilias Tsitsimpis
    def _write_to_file(self, section, msg):
376 4c52d5bf Ilias Tsitsimpis
        """Write to file"""
377 4c52d5bf Ilias Tsitsimpis
        _write_log_file(self.file_location, section, msg)
378 4c52d5bf Ilias Tsitsimpis
379 4c52d5bf Ilias Tsitsimpis
    # ----------------------------------
380 4c52d5bf Ilias Tsitsimpis
    # Handle testsuites
381 4c52d5bf Ilias Tsitsimpis
    def testsuite_start(self, testsuite):
382 4c52d5bf Ilias Tsitsimpis
        """Start a new testsuite
383 4c52d5bf Ilias Tsitsimpis

384 4c52d5bf Ilias Tsitsimpis
        Add a new section in the logging file
385 4c52d5bf Ilias Tsitsimpis

386 4c52d5bf Ilias Tsitsimpis
        """
387 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
388 4c52d5bf Ilias Tsitsimpis
389 4c52d5bf Ilias Tsitsimpis
        # Add a new section in the logging file
390 4c52d5bf Ilias Tsitsimpis
        test_runned = "  * " + testsuite + "\n"
391 4c52d5bf Ilias Tsitsimpis
        _write_log_file(self.file_location, SECTION_RUNNED, test_runned)
392 4c52d5bf Ilias Tsitsimpis
393 4c52d5bf Ilias Tsitsimpis
        new_section_entry = \
394 4c52d5bf Ilias Tsitsimpis
            SECTION_SEPARATOR + "\n" + SECTION_PREFIX + testsuite + "\n\n\n\n"
395 4c52d5bf Ilias Tsitsimpis
        _write_log_file(self.file_location, SECTION_NEW, new_section_entry)
396 4c52d5bf Ilias Tsitsimpis
397 4c52d5bf Ilias Tsitsimpis
        # Add new section to the stdout
398 4c52d5bf Ilias Tsitsimpis
        msg = "Starting testsuite %s" % testsuite
399 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_magenta, msg)
400 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
401 4c52d5bf Ilias Tsitsimpis
402 4c52d5bf Ilias Tsitsimpis
    def testsuite_success(self, testsuite):
403 4c52d5bf Ilias Tsitsimpis
        """A testsuite has successfully finished
404 4c52d5bf Ilias Tsitsimpis

405 4c52d5bf Ilias Tsitsimpis
        Update Results
406 4c52d5bf Ilias Tsitsimpis

407 4c52d5bf Ilias Tsitsimpis
        """
408 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
409 4c52d5bf Ilias Tsitsimpis
410 4c52d5bf Ilias Tsitsimpis
        # Add our testsuite to Results
411 4c52d5bf Ilias Tsitsimpis
        _write_log_file(self.file_location, SECTION_PASSED, testsuite)
412 4c52d5bf Ilias Tsitsimpis
413 4c52d5bf Ilias Tsitsimpis
        # Add success to stdout
414 4c52d5bf Ilias Tsitsimpis
        msg = "Testsuite %s passed" % testsuite
415 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_green, msg)
416 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
417 4c52d5bf Ilias Tsitsimpis
418 4c52d5bf Ilias Tsitsimpis
    def testsuite_failure(self, testsuite):
419 4c52d5bf Ilias Tsitsimpis
        """A testsuite has failed
420 4c52d5bf Ilias Tsitsimpis

421 4c52d5bf Ilias Tsitsimpis
        Update Results
422 4c52d5bf Ilias Tsitsimpis

423 4c52d5bf Ilias Tsitsimpis
        """
424 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
425 4c52d5bf Ilias Tsitsimpis
426 4c52d5bf Ilias Tsitsimpis
        # Add our testsuite to Results
427 4c52d5bf Ilias Tsitsimpis
        _write_log_file(self.file_location, SECTION_FAILED, testsuite)
428 4c52d5bf Ilias Tsitsimpis
429 4c52d5bf Ilias Tsitsimpis
        # Add success to stdout
430 4c52d5bf Ilias Tsitsimpis
        msg = "Testsuite %s failed" % testsuite
431 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_red, msg)
432 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
433 4c52d5bf Ilias Tsitsimpis
434 4c52d5bf Ilias Tsitsimpis
    # ----------------------------------
435 4c52d5bf Ilias Tsitsimpis
    # Colors
436 4c52d5bf Ilias Tsitsimpis
    def _color_message(self, color_fun, msg, *args):
437 4c52d5bf Ilias Tsitsimpis
        """Color a message before printing it
438 4c52d5bf Ilias Tsitsimpis

439 4c52d5bf Ilias Tsitsimpis
        The color_fun parameter is used when we want the whole message to be
440 4c52d5bf Ilias Tsitsimpis
        colored.
441 4c52d5bf Ilias Tsitsimpis

442 4c52d5bf Ilias Tsitsimpis
        """
443 4c52d5bf Ilias Tsitsimpis
        if self.use_colors:
444 4c52d5bf Ilias Tsitsimpis
            if callable(color_fun):
445 6c78720b Ilias Tsitsimpis
                if args:
446 6c78720b Ilias Tsitsimpis
                    return color_fun((msg % args)) + "\n"
447 6c78720b Ilias Tsitsimpis
                else:
448 6c78720b Ilias Tsitsimpis
                    return color_fun(msg) + "\n"
449 4c52d5bf Ilias Tsitsimpis
            else:
450 4c52d5bf Ilias Tsitsimpis
                args = tuple([_blue(arg) for arg in args])
451 4c52d5bf Ilias Tsitsimpis
                return _format_message(msg, *args)
452 4c52d5bf Ilias Tsitsimpis
        else:
453 4c52d5bf Ilias Tsitsimpis
            return _format_message(msg, *args)