Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / logger.py @ 828bbf06

History | View | Annotate | Download (15.3 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 ee89df69 Ilias Tsitsimpis
                 in_parallel=False, log_level=0, curr_time=None):
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 ee89df69 Ilias Tsitsimpis
        @type log_level: int
233 ee89df69 Ilias Tsitsimpis
        @param log_level: logging level
234 ee89df69 Ilias Tsitsimpis
            0: log to console and file
235 ee89df69 Ilias Tsitsimpis
            1: log to file only and output the results to console
236 ee89df69 Ilias Tsitsimpis
            2: don't log
237 ee89df69 Ilias Tsitsimpis
        @type curr_time: datetime.datetime()
238 ee89df69 Ilias Tsitsimpis
        @param curr_time: The current time (used as burnin's run id)
239 4c52d5bf Ilias Tsitsimpis

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

308 4c52d5bf Ilias Tsitsimpis
        We show debug messages only to stdout. The message will be formatted
309 4c52d5bf Ilias Tsitsimpis
        using the args.
310 4c52d5bf Ilias Tsitsimpis

311 4c52d5bf Ilias Tsitsimpis
        """
312 4c52d5bf Ilias Tsitsimpis
        msg = "  (DD) " + _list_to_string(msg, append="       ")
313 4c52d5bf Ilias Tsitsimpis
        if self.verbose >= 2:
314 4c52d5bf Ilias Tsitsimpis
            colored_msg = self._color_message(None, msg, *args)
315 4c52d5bf Ilias Tsitsimpis
            self._write_to_stdout(section, colored_msg)
316 4c52d5bf Ilias Tsitsimpis
317 4c52d5bf Ilias Tsitsimpis
    def log(self, section, msg, *args):
318 4c52d5bf Ilias Tsitsimpis
        """Normal messages (verbose 0)"""
319 4c52d5bf Ilias Tsitsimpis
        assert section, "Section can not be empty"
320 4c52d5bf Ilias Tsitsimpis
321 4c52d5bf Ilias Tsitsimpis
        msg = _list_to_string(msg)
322 4c52d5bf Ilias Tsitsimpis
323 4c52d5bf Ilias Tsitsimpis
        colored_msg = self._color_message(None, msg, *args)
324 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(section, colored_msg)
325 4c52d5bf Ilias Tsitsimpis
326 4c52d5bf Ilias Tsitsimpis
        plain_msg = _format_message(msg, *args)
327 4c52d5bf Ilias Tsitsimpis
        self._write_to_file(section, plain_msg)
328 4c52d5bf Ilias Tsitsimpis
329 4c52d5bf Ilias Tsitsimpis
    def info(self, section, msg, *args):
330 4c52d5bf Ilias Tsitsimpis
        """Info messages (verbose 1)
331 4c52d5bf Ilias Tsitsimpis

332 4c52d5bf Ilias Tsitsimpis
        Prepare message and write it to file logger and stdout logger
333 4c52d5bf Ilias Tsitsimpis

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

398 4c52d5bf Ilias Tsitsimpis
        Add a new section in the logging file
399 4c52d5bf Ilias Tsitsimpis

400 4c52d5bf Ilias Tsitsimpis
        """
401 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
402 4c52d5bf Ilias Tsitsimpis
403 4c52d5bf Ilias Tsitsimpis
        # Add a new section in the logging file
404 4c52d5bf Ilias Tsitsimpis
        test_runned = "  * " + testsuite + "\n"
405 ee89df69 Ilias Tsitsimpis
        self._write_to_file(SECTION_RUNNED, test_runned)
406 4c52d5bf Ilias Tsitsimpis
407 4c52d5bf Ilias Tsitsimpis
        new_section_entry = \
408 4c52d5bf Ilias Tsitsimpis
            SECTION_SEPARATOR + "\n" + SECTION_PREFIX + testsuite + "\n\n\n\n"
409 ee89df69 Ilias Tsitsimpis
        self._write_to_file(SECTION_NEW, new_section_entry)
410 4c52d5bf Ilias Tsitsimpis
411 4c52d5bf Ilias Tsitsimpis
        # Add new section to the stdout
412 4c52d5bf Ilias Tsitsimpis
        msg = "Starting testsuite %s" % testsuite
413 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_magenta, msg)
414 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
415 4c52d5bf Ilias Tsitsimpis
416 4c52d5bf Ilias Tsitsimpis
    def testsuite_success(self, testsuite):
417 4c52d5bf Ilias Tsitsimpis
        """A testsuite has successfully finished
418 4c52d5bf Ilias Tsitsimpis

419 4c52d5bf Ilias Tsitsimpis
        Update Results
420 4c52d5bf Ilias Tsitsimpis

421 4c52d5bf Ilias Tsitsimpis
        """
422 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
423 4c52d5bf Ilias Tsitsimpis
424 4c52d5bf Ilias Tsitsimpis
        # Add our testsuite to Results
425 ee89df69 Ilias Tsitsimpis
        self._write_to_file(SECTION_PASSED, testsuite)
426 4c52d5bf Ilias Tsitsimpis
427 4c52d5bf Ilias Tsitsimpis
        # Add success to stdout
428 4c52d5bf Ilias Tsitsimpis
        msg = "Testsuite %s passed" % testsuite
429 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_green, msg)
430 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
431 4c52d5bf Ilias Tsitsimpis
432 4c52d5bf Ilias Tsitsimpis
    def testsuite_failure(self, testsuite):
433 4c52d5bf Ilias Tsitsimpis
        """A testsuite has failed
434 4c52d5bf Ilias Tsitsimpis

435 4c52d5bf Ilias Tsitsimpis
        Update Results
436 4c52d5bf Ilias Tsitsimpis

437 4c52d5bf Ilias Tsitsimpis
        """
438 4c52d5bf Ilias Tsitsimpis
        assert testsuite, "Testsuite name can not be emtpy"
439 4c52d5bf Ilias Tsitsimpis
440 4c52d5bf Ilias Tsitsimpis
        # Add our testsuite to Results
441 ee89df69 Ilias Tsitsimpis
        self._write_to_file(SECTION_FAILED, testsuite)
442 4c52d5bf Ilias Tsitsimpis
443 4c52d5bf Ilias Tsitsimpis
        # Add success to stdout
444 4c52d5bf Ilias Tsitsimpis
        msg = "Testsuite %s failed" % testsuite
445 12ef696f Ilias Tsitsimpis
        colored_msg = self._color_message(_red, msg)
446 4c52d5bf Ilias Tsitsimpis
        self._write_to_stdout(None, colored_msg)
447 4c52d5bf Ilias Tsitsimpis
448 4c52d5bf Ilias Tsitsimpis
    # ----------------------------------
449 4c52d5bf Ilias Tsitsimpis
    # Colors
450 4c52d5bf Ilias Tsitsimpis
    def _color_message(self, color_fun, msg, *args):
451 4c52d5bf Ilias Tsitsimpis
        """Color a message before printing it
452 4c52d5bf Ilias Tsitsimpis

453 4c52d5bf Ilias Tsitsimpis
        The color_fun parameter is used when we want the whole message to be
454 4c52d5bf Ilias Tsitsimpis
        colored.
455 4c52d5bf Ilias Tsitsimpis

456 4c52d5bf Ilias Tsitsimpis
        """
457 4c52d5bf Ilias Tsitsimpis
        if self.use_colors:
458 4c52d5bf Ilias Tsitsimpis
            if callable(color_fun):
459 6c78720b Ilias Tsitsimpis
                if args:
460 6c78720b Ilias Tsitsimpis
                    return color_fun((msg % args)) + "\n"
461 6c78720b Ilias Tsitsimpis
                else:
462 6c78720b Ilias Tsitsimpis
                    return color_fun(msg) + "\n"
463 4c52d5bf Ilias Tsitsimpis
            else:
464 4c52d5bf Ilias Tsitsimpis
                args = tuple([_blue(arg) for arg in args])
465 4c52d5bf Ilias Tsitsimpis
                return _format_message(msg, *args)
466 4c52d5bf Ilias Tsitsimpis
        else:
467 4c52d5bf Ilias Tsitsimpis
            return _format_message(msg, *args)