Tasks rework mostly done, replaygain now uses tasks. Start of style/docs cleanup.
[audiomangler.git] / audiomangler / logging.py
blob2a9d1e0d26493320468c0de7024440d2023c1d65
1 # -*- coding: utf-8 -*-
2 from twisted.python import log, failure
3 from audiomangler.config import Config
4 import os, sys, atexit
6 try:
7 from cStringIO import StringIO
8 except ImportError:
9 from StringIO import StringIO
11 loglevels = dict(ERROR=0, WARNING=1, INFO=2, DEBUG=3)
12 locals().update(loglevels)
13 loglevels.update(map(reversed, loglevels.items()))
15 class FilteredFileLogObserver(log.FileLogObserver):
16 def __init__(self, f, loglevel=INFO):
17 self.output = f
18 if isinstance(loglevel, basestring):
19 loglevel = loglevels[loglevel]
20 self.loglevel = loglevel
22 def emit(self, eventDict):
23 if '_noignore' not in eventDict and not eventDict['isError']: return
24 if eventDict.get('loglevel', DEBUG) > self.loglevel:
25 return
26 encoding = sys.stdout.encoding
27 if eventDict['isError'] and 'failure' in eventDict:
28 text = log.textFromEventDict(eventDict)
29 elif eventDict['message']:
30 text = ' '.join(s.encode(encoding, 'replace') if isinstance(s, unicode) else s for s in eventDict['message'])
31 elif 'format' in eventDict or 'consoleformat' in eventDict:
32 fmt = eventDict.get('format', eventDict.get('consoleformat'))
33 text = (fmt % eventDict).encode(encoding, 'replace')
34 else:
35 text = log.textFromEventDict(eventDict)
36 timeStr = self.formatTime(eventDict['time'])
37 self.output.write(timeStr + ' [' + loglevels[eventDict['loglevel']].ljust(7) + '] ' + text + '\n')
39 class FilteredConsoleLogObserver:
40 def __init__(self, loglevel=INFO):
41 self.loglevel = loglevel
43 def start(self):
44 log.addObserver(self.emit)
46 def stop(self):
47 log.removeObserver(self.emit)
49 def emit(self, eventDict):
50 if '_noignore' not in eventDict and not eventDict['isError']: return
51 if eventDict.get('loglevel', DEBUG) > self.loglevel:
52 return
53 encoding = sys.stdout.encoding
54 if eventDict['isError'] and 'failure' in eventDict:
55 text = log.textFromEventDict(eventDict)
56 elif eventDict['message']:
57 text = ''.join(s.encode(encoding, 'replace') if isinstance(s, unicode) else s for s in eventDict['message'])
58 elif 'format' in eventDict or 'consoleformat' in eventDict:
59 fmt = eventDict.get('consoleformat', eventDict.get('format'))
60 text = (fmt % eventDict).encode(encoding, 'replace')
61 else:
62 text = log.textFromEventDict(eventDict)
63 sys.stdout.write(text + '\n')
64 sys.stdout.flush()
66 collector = None
67 logfile = None
68 logout = None
70 def get_level(x, default=ERROR):
71 try:
72 return int(x)
73 except ValueError:
74 pass
75 try:
76 return loglevels[x]
77 except KeyError:
78 return default
80 def err(*msg, **kwargs):
81 global collector, logfile
82 if 'nologerror' not in kwargs:
83 if collector is None:
84 try:
85 collector = FilteredFileLogObserver(StringIO(), ERROR)
86 collector.start()
87 except: pass
88 if logfile is None:
89 try:
90 logfile = FilteredFileLogObserver(open(Config.get('logfile', 'audiomangler-%d.log' % os.getpid()), 'wb'), get_level(Config['loglevel']))
91 logfile.start()
92 except: pass
93 kwargs['loglevel'] = ERROR
94 if msg and isinstance(msg[0], (failure.Failure, Exception)):
95 log.err(_noignore=1, *msg, **kwargs)
96 else:
97 log.msg(_noignore=1, *msg, **kwargs)
99 def msg(*msg, **kwargs):
100 global logfile
101 kwargs.setdefault('loglevel', DEBUG)
102 if kwargs['loglevel'] == ERROR:
103 err(_noignore=1, *msg, **kwargs)
104 else:
105 if Config['logfile'] and logfile is None and kwargs['loglevel'] <= get_level(Config['loglevel']):
106 try:
107 logfile = FilteredFileLogObserver(open(Config['logfile'], 'wb'), Config['loglevel'])
108 logfile.start()
109 except: pass
110 log.msg(_noignore=1, *msg, **kwargs)
112 def fatal(*msg, **kwargs):
113 err(*msg, **kwargs)
114 sys.exit()
116 def cleanup():
117 if logout:
118 sys.stdout.flush()
119 logout.stop()
120 if collector:
121 collector.output.flush()
122 collector.stop()
123 text = collector.output.getvalue()
124 if text:
125 print "The following errors occurred:"
126 print text
127 print "The above errors may also have been reported during processing."
128 if logfile:
129 logfile.output.flush()
130 logfile.stop()
131 print "Errors are also recorded in the logfile '%s'." % os.path.abspath(logfile.output.name)
132 sys.stdout.flush()
134 try:
135 logout = FilteredConsoleLogObserver(Config['consolelevel'])
136 logout.start()
137 if log.defaultObserver:
138 log.defaultObserver.stop()
139 log.defaultObserver = None
140 except:
141 pass
143 atexit.register(cleanup)
145 __all__ = ['err', 'msg', 'fatal', 'ERROR', 'WARNING', 'INFO', 'DEBUG']