|
32 | 32 |
|
33 | 33 | from classes import info
|
34 | 34 |
|
35 |
| -# Dictionary of logging handlers we create, keyed by type |
36 |
| -handlers = {} |
37 |
| -# Another dictionary of streams we've redirected (stdout, stderr) |
38 |
| -streams = {} |
39 |
| - |
40 | 35 |
|
41 | 36 | class StreamToLogger(object):
|
42 | 37 | """Custom class to log all stdout and stderr streams (from libopenshot / and other libraries)"""
|
43 |
| - def __init__(self, logger, log_level=logging.INFO): |
44 |
| - self.logger = logger |
| 38 | + def __init__(self, parent_stream, log_level=logging.INFO): |
| 39 | + self.parent = parent_stream or sys.__stderr__ |
| 40 | + self.logger = logging.LoggerAdapter( |
| 41 | + logging.getLogger('OpenShot.stderr'), {'source': 'stream'}) |
45 | 42 | self.log_level = log_level
|
46 |
| - self.linebuf = '' |
| 43 | + self.logbuf = '' |
47 | 44 |
|
48 |
| - def write(self, buf): |
49 |
| - for line in buf.rstrip().splitlines(): |
50 |
| - self.logger.log(self.log_level, line.rstrip()) |
| 45 | + def write(self, text): |
| 46 | + self.logbuf += str(text) or "" |
| 47 | + self.parent.write(text) |
51 | 48 |
|
52 | 49 | def flush(self):
|
53 |
| - pass |
| 50 | + if self.logbuf.rstrip(): |
| 51 | + self.logger.log(self.log_level, self.logbuf.rstrip()) |
| 52 | + self.logbuf = '' |
54 | 53 |
|
55 | 54 | def errors(self):
|
56 | 55 | pass
|
57 | 56 |
|
58 | 57 |
|
59 |
| -# Create logger instance |
60 |
| -log = logging.Logger('OpenShot') |
| 58 | +class StreamFilter(logging.Filter): |
| 59 | + """Filter out lines that originated on the output""" |
| 60 | + def filter(self, record): |
| 61 | + source = getattr(record, "source", "") |
| 62 | + return bool(source != "stream") |
| 63 | + |
61 | 64 |
|
62 | 65 | # Set up log formatters
|
63 | 66 | template = '%(levelname)s %(module)s: %(message)s'
|
64 | 67 | console_formatter = logging.Formatter(template)
|
65 | 68 | file_formatter = logging.Formatter('%(asctime)s ' + template, datefmt='%H:%M:%S')
|
66 | 69 |
|
67 |
| -# Add normal stderr stream handler |
68 |
| -sh = logging.StreamHandler() |
69 |
| -sh.setFormatter(console_formatter) |
70 |
| -sh.setLevel(info.LOG_LEVEL_CONSOLE) |
71 |
| -log.addHandler(sh) |
72 |
| -handlers['stream'] = sh |
| 70 | +# Configure root logger for minimal logging |
| 71 | +logging.basicConfig(level=logging.ERROR) |
| 72 | +root_log = logging.getLogger() |
| 73 | + |
| 74 | +# Set up our top-level logging context |
| 75 | +log = root_log.getChild('OpenShot') |
| 76 | +log.setLevel(info.LOG_LEVEL_FILE) |
| 77 | +# Don't pass messages on to root logger |
| 78 | +log.propagate = False |
73 | 79 |
|
74 |
| -# Add rotating file handler |
| 80 | +# |
| 81 | +# Create rotating file handler |
| 82 | +# |
75 | 83 | fh = logging.handlers.RotatingFileHandler(
|
76 |
| - os.path.join(info.USER_PATH, 'openshot-qt.log'), encoding="utf-8", maxBytes=25*1024*1024, backupCount=3) |
77 |
| -fh.setFormatter(file_formatter) |
| 84 | + os.path.join(info.USER_PATH, 'openshot-qt.log'), |
| 85 | + encoding="utf-8", |
| 86 | + maxBytes=25*1024*1024, backupCount=3) |
78 | 87 | fh.setLevel(info.LOG_LEVEL_FILE)
|
| 88 | +fh.setFormatter(file_formatter) |
| 89 | + |
79 | 90 | log.addHandler(fh)
|
80 |
| -handlers['file'] = fh |
| 91 | + |
| 92 | +# |
| 93 | +# Create typical stream handler which logs to stderr |
| 94 | +# |
| 95 | +sh = logging.StreamHandler(sys.stderr) |
| 96 | +sh.setLevel(info.LOG_LEVEL_CONSOLE) |
| 97 | +sh.setFormatter(console_formatter) |
| 98 | + |
| 99 | +# Filter out redirected output on console, to avoid duplicates |
| 100 | +filt = StreamFilter() |
| 101 | +sh.addFilter(filt) |
| 102 | + |
| 103 | +log.addHandler(sh) |
81 | 104 |
|
82 | 105 |
|
83 | 106 | def reroute_output():
|
84 | 107 | """Route stdout and stderr to logger (custom handler)"""
|
85 |
| - if not getattr(sys, 'frozen', False): |
86 |
| - # Hang on to the original objects |
87 |
| - streams.update({ |
88 |
| - 'stderr': sys.stderr, |
89 |
| - 'stdout': sys.stdout, |
90 |
| - }) |
91 |
| - # Re-route output streams |
92 |
| - handlers['stdout'] = StreamToLogger(log, logging.INFO) |
93 |
| - sys.stdout = handlers['stdout'] |
94 |
| - handlers['stderr'] = StreamToLogger(log, logging.ERROR) |
95 |
| - sys.stderr = handlers['stderr'] |
| 108 | + if (getattr(sys, 'frozen', False) |
| 109 | + or sys.stdout != sys.__stdout__): |
| 110 | + return |
| 111 | + sys.stdout = StreamToLogger(sys.stdout, logging.INFO) |
| 112 | + sys.stderr = StreamToLogger(sys.stderr, logging.WARNING) |
96 | 113 |
|
97 | 114 |
|
98 | 115 | def set_level_file(level=logging.INFO):
|
99 |
| - handlers['file'].setLevel(level) |
| 116 | + """Adjust the minimum log level written to our logfile""" |
| 117 | + fh.setLevel(level) |
100 | 118 |
|
101 | 119 |
|
102 | 120 | def set_level_console(level=logging.INFO):
|
103 |
| - handlers['stream'].setLevel(level) |
104 |
| - |
| 121 | + """Adjust the minimum log level for output to the terminal""" |
| 122 | + sh.setLevel(level) |
0 commit comments