add timestr prefix in logfile
[tools/mic.git] / mic / msger.py
1 #!/usr/bin/python -tt
2 # vim: ai ts=4 sts=4 et sw=4
3 #
4 # Copyright 2009, 2010, 2011 Intel, Inc.
5 #
6 # This copyrighted material is made available to anyone wishing to use, modify,
7 # copy, or redistribute it subject to the terms and conditions of the GNU
8 # General Public License v.2.  This program is distributed in the hope that it
9 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
10 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # See the GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 51
15 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  Any Red Hat
16 # trademarks that are incorporated in the source code or documentation are not
17 # subject to the GNU General Public License and may only be used or replicated
18 # with the express permission of Red Hat, Inc.
19 #
20
21 import os,sys
22 import re
23 from datetime import datetime
24
25 __ALL__ = ['set_mode',
26            'get_loglevel',
27            'set_loglevel',
28            'set_logfile',
29            'raw',
30            'debug',
31            'verbose',
32            'info',
33            'warning',
34            'error',
35            'ask',
36            'pause',
37           ]
38
39 # COLORs in ANSI
40 INFO_COLOR = 32 # green
41 WARN_COLOR = 33 # yellow
42 ERR_COLOR  = 31 # red
43 ASK_COLOR  = 34 # blue
44 NO_COLOR = 0
45
46 PREFIX_RE = re.compile('^<(.*?)>\s*(.*)')
47
48 INTERACTIVE = True
49
50 LOG_LEVEL = 1
51 LOG_LEVELS = {
52                 'quiet': 0,
53                 'normal': 1,
54                 'verbose': 2,
55                 'debug': 3,
56                 'never': 4,
57              }
58
59 LOG_FILE_FP = None
60 LOG_CONTENT = ''
61
62 def _general_print(head, color, msg = None, stream = sys.stdout, level = 'normal'):
63     global LOG_CONTENT
64     if LOG_LEVELS[level] > LOG_LEVEL:
65         # skip
66         return
67
68     if LOG_FILE_FP:
69         save_msg = msg.strip()
70         if save_msg:
71             timestr = datetime.now().strftime('[%m/%d %H:%M:%S] ')
72             LOG_CONTENT += timestr + save_msg + '\n'
73
74     _color_print(head, color, msg, stream, level)
75
76 def _color_print(head, color, msg, stream, level):
77     colored = True
78     if color == NO_COLOR or \
79        not stream.isatty() or \
80        os.getenv('ANSI_COLORS_DISABLED') is not None:
81         colored = False
82
83     if head.startswith('\r'):
84         # need not \n at last
85         newline = False
86     else:
87         newline = True
88
89     if colored:
90         head = '\033[%dm%s:\033[0m ' %(color, head)
91         if not newline:
92             # ESC cmd to clear line
93             head = '\033[2K' + head
94     else:
95         if head:
96             head += ': '
97             if head.startswith('\r'):
98                 head = head.lstrip()
99                 newline = True
100
101     if msg is not None:
102         stream.write('%s%s' % (head, msg))
103         if newline:
104             stream.write('\n')
105
106     stream.flush()
107
108 def _color_perror(head, color, msg, level = 'normal'):
109     _general_print(head, color, msg, sys.stderr, level)
110
111 def _split_msg(head, msg):
112     if isinstance(msg, list):
113         msg = '\n'.join(map(str, msg))
114
115     if msg.startswith('\n'):
116         # means print \n at first
117         msg = msg.lstrip()
118         head = '\n' + head
119
120     elif msg.startswith('\r'):
121         # means print \r at first
122         msg = msg.lstrip()
123         head = '\r' + head
124
125     m = PREFIX_RE.match(msg)
126     if m:
127         head += ' <%s>' % m.group(1)
128         msg = m.group(2)
129
130     return head, msg
131
132 def get_loglevel():
133     return (k for k,v in LOG_LEVELS.items() if v==LOG_LEVEL).next()
134
135 def set_loglevel(level):
136     global LOG_LEVEL
137     if level not in LOG_LEVELS:
138         # no effect
139         return
140
141     LOG_LEVEL = LOG_LEVELS[level]
142
143 def set_interactive(mode=True):
144     global INTERACTIVE
145     if mode:
146         INTERACTIVE = True
147     else:
148         INTERACTIVE = False
149
150 def raw(msg=''):
151     _general_print('', NO_COLOR, msg)
152
153 def info(msg):
154     head, msg = _split_msg('Info', msg)
155     _general_print(head, INFO_COLOR, msg)
156
157 def verbose(msg):
158     head, msg = _split_msg('Verbose', msg)
159     _general_print(head, INFO_COLOR, msg, level = 'verbose')
160
161 def warning(msg):
162     head, msg = _split_msg('Warning', msg)
163     _color_perror(head, WARN_COLOR, msg)
164
165 def debug(msg):
166     head, msg = _split_msg('Debug', msg)
167     _color_perror(head, ERR_COLOR, msg, level = 'debug')
168
169 def error(msg):
170     head, msg = _split_msg('Error', msg)
171     _color_perror(head, ERR_COLOR, msg)
172     sys.exit(1)
173
174 def ask(msg, default=True):
175     _general_print('\rQ', ASK_COLOR, '')
176     try:
177         if default:
178             msg += '(Y/n) '
179         else:
180             msg += '(y/N) '
181         if INTERACTIVE:
182             while True:
183                 repl = raw_input(msg)
184                 if repl.lower() == 'y':
185                     return True
186                 elif repl.lower() == 'n':
187                     return False
188                 elif not repl.strip():
189                     # <Enter>
190                     return default
191
192                 # else loop
193         else:
194             if default:
195                 msg += ' Y'
196             else:
197                 msg += ' N'
198             _general_print('', NO_COLOR, msg)
199
200             return default
201     except KeyboardInterrupt:
202         sys.stdout.write('\n')
203         sys.exit(2)
204
205 def pause(msg=None):
206     if INTERACTIVE:
207         _general_print('\rQ', ASK_COLOR, '')
208         if msg is None:
209             msg = 'press <ENTER> to continue ...'
210         raw_input(msg)
211
212 def set_logfile(fpath):
213     global LOG_FILE_FP 
214
215     def _savelogf():
216         if LOG_FILE_FP:
217             fp = open(LOG_FILE_FP, 'w')
218             fp.write(LOG_CONTENT)
219             fp.close()
220
221     if LOG_FILE_FP is not None:
222         warning('duplicate log file configuration')
223
224     LOG_FILE_FP = os.path.abspath(os.path.expanduser(fpath))
225
226     import atexit
227     atexit.register(_savelogf)