source: rtems-tools/rtemstoolkit/log.py @ 606c08c

4.10
Last change on this file since 606c08c was 606c08c, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 8, 2016 at 6:44:52 AM

rtemstoolkit: msys2 compatibility

  • Property mode set to 100755
File size: 6.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-testing'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# Log output to stdout and/or a file.
33#
34
35import os
36import sys
37import threading
38
39from . import error
40
41#
42# A global log.
43#
44default = None
45
46#
47# Global parameters.
48#
49tracing = False
50quiet = False
51
52#
53# Global output lock to keep output together when working with threads
54#
55lock = threading.Lock()
56
57def set_default_once(log):
58    if default is None:
59        default = log
60
61def _output(text = os.linesep, log = None):
62    """Output the text to a log if provided else send it to stdout."""
63    if text is None:
64        text = os.linesep
65    if type(text) is list:
66        _text = ''
67        for l in text:
68            _text += l + os.linesep
69        text = _text
70    if log:
71        log.output(text)
72    elif default is not None:
73        default.output(text)
74    else:
75        lock.acquire()
76        for l in text.replace(chr(13), '').splitlines():
77            print(l)
78        lock.release()
79
80def stderr(text = os.linesep, log = None):
81    lock.acquire()
82    for l in text.replace(chr(13), '').splitlines():
83        print >> sys.stderr, l
84    lock.release()
85
86def output(text = os.linesep, log = None):
87    if not quiet:
88        _output(text, log)
89
90def notice(text = os.linesep, log = None, stdout_only = False):
91    if not quiet and \
92            (default is not None and not default.has_stdout() or stdout_only):
93        lock.acquire()
94        for l in text.replace(chr(13), '').splitlines():
95            print(l)
96        lock.release()
97    if not stdout_only:
98        _output(text, log)
99
100def trace(text = os.linesep, log = None):
101    if tracing:
102        _output(text, log)
103
104def warning(text = os.linesep, log = None):
105    for l in text.replace(chr(13), '').splitlines():
106        _output('warning: %s' % (l), log)
107
108def flush(log = None):
109    if log:
110        log.flush()
111    elif default is not None:
112        default.flush()
113
114class log:
115    """Log output to stdout or a file."""
116    def __init__(self, streams = None, tail_size = 100):
117        self.lock = threading.Lock()
118        self.tail = []
119        self.tail_size = tail_size
120        self.fhs = [None, None]
121        if streams:
122            for s in streams:
123                if s == 'stdout':
124                    self.fhs[0] = sys.stdout
125                elif s == 'stderr':
126                    self.fhs[1] = sys.stderr
127                else:
128                    try:
129                        self.fhs.append(file(s, 'w'))
130                    except IOError as ioe:
131                         raise error.general("creating log file '" + s + \
132                                             "': " + str(ioe))
133
134    def __del__(self):
135        for f in range(2, len(self.fhs)):
136            self.fhs[f].close()
137
138    def __str__(self):
139        t = ''
140        for tl in self.tail:
141            t += tl + os.linesep
142        return t[:-len(os.linesep)]
143
144    def _tail(self, text):
145        if type(text) is not list:
146            text = text.splitlines()
147        self.tail += text
148        if len(self.tail) > self.tail_size:
149            self.tail = self.tail[-self.tail_size:]
150
151    def has_stdout(self):
152        return self.fhs[0] is not None
153
154    def has_stderr(self):
155        return self.fhs[1] is not None
156
157    def output(self, text):
158        """Output the text message to all the logs."""
159        # Reformat the text to have local line types.
160        text = text.replace(chr(13), '').splitlines()
161        self._tail(text)
162        out = ''
163        for l in text:
164            out += l + os.linesep
165        self.lock.acquire()
166        try:
167            for f in range(0, len(self.fhs)):
168                if self.fhs[f] is not None:
169                    self.fhs[f].write(out)
170            self.flush()
171        except:
172            raise
173        finally:
174            self.lock.release()
175
176    def flush(self):
177        """Flush the output."""
178        for f in range(0, len(self.fhs)):
179            if self.fhs[f] is not None:
180                self.fhs[f].flush()
181
182if __name__ == "__main__":
183    l = log(['stdout', 'log.txt'], tail_size = 20)
184    for i in range(0, 10):
185        l.output('log: hello world: %d\n' % (i))
186    l.output('log: hello world CRLF\r\n')
187    l.output('log: hello world NONE')
188    l.flush()
189    print('=-' * 40)
190    print('tail: %d' % (len(l.tail)))
191    print(l)
192    print('=-' * 40)
193    for i in range(0, 10):
194        l.output('log: hello world 2: %d\n' % (i))
195    l.flush()
196    print('=-' * 40)
197    print('tail: %d' % (len(l.tail)))
198    print(l)
199    print('=-' * 40)
200    for i in [0, 1]:
201        quiet = False
202        tracing = False
203        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
204        trace('trace with quiet and trace off')
205        notice('notice with quiet and trace off')
206        quiet = True
207        tracing = False
208        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
209        trace('trace with quiet on and trace off')
210        notice('notice with quiet on and trace off')
211        quiet = False
212        tracing = True
213        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
214        trace('trace with quiet off and trace on')
215        notice('notice with quiet off and trace on')
216        quiet = True
217        tracing = True
218        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
219        trace('trace with quiet on and trace on')
220        notice('notice with quiet on and trace on')
221        default = l
222    print('=-' * 40)
223    print('tail: %d' % (len(l.tail)))
224    print(l)
225    print('=-' * 40)
226    del l
Note: See TracBrowser for help on using the repository browser.