source: rtems-tools/rtemstoolkit/log.py

Last change on this file was 5dd75b0, checked in by Chris Johns <chrisj@…>, on 05/30/19 at 10:25:36

rtemstoolkit/log: Add info().

  • Property mode set to 100755
File size: 7.4 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2016 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
35from __future__ import print_function
36
37import os
38import sys
39import threading
40
41from rtemstoolkit import error
42
43#
44# A global log.
45#
46default = None
47
48#
49# A global capture handler.
50#
51capture = None
52
53#
54# Global parameters.
55#
56tracing = False
57quiet = False
58
59#
60# Global output lock to keep output together when working with threads
61#
62lock = threading.Lock()
63
64def info(args):
65    s = [' Command Line: %s' % (' '.join(args))]
66    if hasattr(os, 'uname'):
67        s += [' Host: %s' % (' '.join(os.uname()))]
68    else:
69        h = ' Host: win32-mingw'
70        if 'HOSTTYPE' in os.environ:
71            h += ' ' + os.environ['HOSTTYPE']
72        else:
73            h += ' i686'
74        s += [h]
75    s += [' Python: %s' % (sys.version.replace('\n', ''))]
76    return s
77
78def set_default_once(log):
79    if default is None:
80        default = log
81
82def _output(text = os.linesep, log = None):
83    """Output the text to a log if provided else send it to stdout."""
84    if text is None:
85        text = os.linesep
86    if type(text) is list:
87        text = os.linesep.join(text) + os.linesep
88    if isinstance(text, bytes):
89        text = text.decode('utf-8', 'ignore')
90    if log:
91        log.output(text)
92    elif default is not None:
93        default.output(text)
94    else:
95        lock.acquire()
96        for l in text.replace(chr(13), '').splitlines():
97            print(l)
98        lock.release()
99    if capture is not None:
100        lock.acquire()
101        capture(text)
102        lock.release()
103
104def stderr(text = os.linesep, log = None):
105    lock.acquire()
106    for l in text.replace(chr(13), '').splitlines():
107        print(l, file = sys.stderr)
108    lock.release()
109
110def output(text = os.linesep, log = None):
111    if not quiet:
112        _output(text, log)
113
114def notice(text = os.linesep, log = None, stdout_only = False):
115    if not quiet and \
116            (default is not None and not default.has_stdout() or stdout_only):
117        lock.acquire()
118        for l in text.replace(chr(13), '').splitlines():
119            print(l)
120        lock.release()
121    if not stdout_only:
122        _output(text, log)
123
124def trace(text = os.linesep, log = None):
125    if tracing:
126        _output(text, log)
127
128def warning(text = os.linesep, log = None):
129    for l in text.replace(chr(13), '').splitlines():
130        _output('warning: %s' % (l), log)
131
132def flush(log = None):
133    if log:
134        log.flush()
135    elif default is not None:
136        default.flush()
137
138class log:
139    """Log output to stdout or a file."""
140    def __init__(self, streams = None, tail_size = 100):
141        self.lock = threading.Lock()
142        self.tail = []
143        self.tail_size = tail_size
144        self.fhs = [None, None]
145        if streams:
146            for s in streams:
147                if s == 'stdout':
148                    self.fhs[0] = sys.stdout
149                elif s == 'stderr':
150                    self.fhs[1] = sys.stderr
151                else:
152                    try:
153                        self.fhs.append(open(s, 'w'))
154                    except IOError as ioe:
155                         raise error.general("creating log file '" + s + \
156                                             "': " + str(ioe))
157
158    def __del__(self):
159        for f in range(2, len(self.fhs)):
160            self.fhs[f].close()
161
162    def __str__(self):
163        t = ''
164        for tl in self.tail:
165            t += tl + os.linesep
166        return t[:-len(os.linesep)]
167
168    def _tail(self, text):
169        if type(text) is not list:
170            text = text.splitlines()
171        self.tail += text
172        if len(self.tail) > self.tail_size:
173            self.tail = self.tail[-self.tail_size:]
174
175    def has_stdout(self):
176        return self.fhs[0] is not None
177
178    def has_stderr(self):
179        return self.fhs[1] is not None
180
181    def output(self, text):
182        """Output the text message to all the logs."""
183        # Reformat the text to have local line types.
184        text = text.replace(chr(13), '').splitlines()
185        self._tail(text)
186        out = os.linesep.join(text) + os.linesep
187        if isinstance(out, bytes):
188            out = out.decode('utf-8', 'ignore')
189        self.lock.acquire()
190        try:
191            for f in range(0, len(self.fhs)):
192                if self.fhs[f] is not None:
193                    self.fhs[f].write(out)
194            self.flush()
195        except:
196            raise
197        finally:
198            self.lock.release()
199
200    def flush(self):
201        """Flush the output."""
202        for f in range(0, len(self.fhs)):
203            if self.fhs[f] is not None:
204                self.fhs[f].flush()
205
206if __name__ == "__main__":
207    l = log(['stdout', 'log.txt'], tail_size = 20)
208    for i in range(0, 10):
209        l.output('log: hello world: %d\n' % (i))
210    l.output('log: hello world CRLF\r\n')
211    l.output('log: hello world NONE')
212    l.flush()
213    print('=-' * 40)
214    print('tail: %d' % (len(l.tail)))
215    print(l)
216    print('=-' * 40)
217    for i in range(0, 10):
218        l.output('log: hello world 2: %d\n' % (i))
219    l.flush()
220    print('=-' * 40)
221    print('tail: %d' % (len(l.tail)))
222    print(l)
223    print('=-' * 40)
224    for i in [0, 1]:
225        quiet = False
226        tracing = False
227        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
228        trace('trace with quiet and trace off')
229        notice('notice with quiet and trace off')
230        quiet = True
231        tracing = False
232        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
233        trace('trace with quiet on and trace off')
234        notice('notice with quiet on and trace off')
235        quiet = False
236        tracing = True
237        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
238        trace('trace with quiet off and trace on')
239        notice('notice with quiet off and trace on')
240        quiet = True
241        tracing = True
242        print('- quiet:%s - trace:%s %s' % (str(quiet), str(tracing), '-' * 30))
243        trace('trace with quiet on and trace on')
244        notice('notice with quiet on and trace on')
245        default = l
246    print('=-' * 40)
247    print('tail: %d' % (len(l.tail)))
248    print(l)
249    print('=-' * 40)
250    del l
Note: See TracBrowser for help on using the repository browser.