blob: fb8336d94ae2d1e9504c3a67e411cd295a796f7f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python -tt
2# vim: ai ts=4 sts=4 et sw=4
3#
4# Copyright (c) 2009, 2010, 2011 Intel, Inc.
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by the Free
8# Software Foundation; version 2 of the License
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13# for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc., 59
17# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19import os
20import sys
21import re
22import time
23
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024__ALL__ = ['get_loglevel',
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025 'set_loglevel',
26 'set_logfile',
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027 'debug',
28 'verbose',
29 'info',
30 'warning',
31 'error',
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032 ]
33
34# COLORs in ANSI
35INFO_COLOR = 32 # green
36WARN_COLOR = 33 # yellow
37ERR_COLOR = 31 # red
38ASK_COLOR = 34 # blue
39NO_COLOR = 0
40
41PREFIX_RE = re.compile('^<(.*?)>\s*(.*)', re.S)
42
43INTERACTIVE = True
44
45LOG_LEVEL = 1
46LOG_LEVELS = {
47 'quiet': 0,
48 'normal': 1,
49 'verbose': 2,
50 'debug': 3,
51 'never': 4,
52}
53
54LOG_FILE_FP = None
55LOG_CONTENT = ''
56CATCHERR_BUFFILE_FD = -1
57CATCHERR_BUFFILE_PATH = None
58CATCHERR_SAVED_2 = -1
59
60def _general_print(head, color, msg=None, stream=None, level='normal'):
61 global LOG_CONTENT
62 if not stream:
63 stream = sys.stdout
64
65 if LOG_LEVELS[level] > LOG_LEVEL:
66 # skip
67 return
68
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 errormsg = ''
70 if CATCHERR_BUFFILE_FD > 0:
71 size = os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_END)
72 os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_SET)
73 errormsg = os.read(CATCHERR_BUFFILE_FD, size)
74 os.ftruncate(CATCHERR_BUFFILE_FD, 0)
75
76 # append error msg to LOG
77 if errormsg:
78 LOG_CONTENT += errormsg
79
80 # append normal msg to LOG
81 save_msg = msg.strip() if msg else None
82 if save_msg:
83 timestr = time.strftime("[%m/%d %H:%M:%S %Z] ", time.localtime())
84 LOG_CONTENT += timestr + save_msg + '\n'
85
86 if errormsg:
87 _color_print('', NO_COLOR, errormsg, stream, level)
88
89 _color_print(head, color, msg, stream, level)
90
91def _color_print(head, color, msg, stream, level):
92 colored = True
93 if color == NO_COLOR or \
94 not stream.isatty() or \
95 os.getenv('ANSI_COLORS_DISABLED') is not None:
96 colored = False
97
98 if head.startswith('\r'):
99 # need not \n at last
100 newline = False
101 else:
102 newline = True
103
104 if colored:
105 head = '\033[%dm%s:\033[0m ' %(color, head)
106 if not newline:
107 # ESC cmd to clear line
108 head = '\033[2K' + head
109 else:
110 if head:
111 head += ': '
112 if head.startswith('\r'):
113 head = head.lstrip()
114 newline = True
115
116 if msg is not None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 stream.write('%s%s' % (head, msg))
118 if newline:
119 stream.write('\n')
120
121 stream.flush()
122
123def _color_perror(head, color, msg, level='normal'):
124 if CATCHERR_BUFFILE_FD > 0:
125 _general_print(head, color, msg, sys.stdout, level)
126 else:
127 _general_print(head, color, msg, sys.stderr, level)
128
129def _split_msg(head, msg):
130 if isinstance(msg, list):
131 msg = '\n'.join(map(str, msg))
132
133 if msg.startswith('\n'):
134 # means print \n at first
135 msg = msg.lstrip()
136 head = '\n' + head
137
138 elif msg.startswith('\r'):
139 # means print \r at first
140 msg = msg.lstrip()
141 head = '\r' + head
142
143 match = PREFIX_RE.match(msg)
144 if match:
145 head += ' <%s>' % match.group(1)
146 msg = match.group(2)
147
148 return head, msg
149
150def get_loglevel():
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600151 return next((k for k, v in LOG_LEVELS.items() if v == LOG_LEVEL))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
153def set_loglevel(level):
154 global LOG_LEVEL
155 if level not in LOG_LEVELS:
156 # no effect
157 return
158
159 LOG_LEVEL = LOG_LEVELS[level]
160
161def set_interactive(mode=True):
162 global INTERACTIVE
163 if mode:
164 INTERACTIVE = True
165 else:
166 INTERACTIVE = False
167
168def log(msg=''):
169 # log msg to LOG_CONTENT then save to logfile
170 global LOG_CONTENT
171 if msg:
172 LOG_CONTENT += msg
173
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174def info(msg):
175 head, msg = _split_msg('Info', msg)
176 _general_print(head, INFO_COLOR, msg)
177
178def verbose(msg):
179 head, msg = _split_msg('Verbose', msg)
180 _general_print(head, INFO_COLOR, msg, level='verbose')
181
182def warning(msg):
183 head, msg = _split_msg('Warning', msg)
184 _color_perror(head, WARN_COLOR, msg)
185
186def debug(msg):
187 head, msg = _split_msg('Debug', msg)
188 _color_perror(head, ERR_COLOR, msg, level='debug')
189
190def error(msg):
191 head, msg = _split_msg('Error', msg)
192 _color_perror(head, ERR_COLOR, msg)
193 sys.exit(1)
194
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500195def set_logfile(fpath):
196 global LOG_FILE_FP
197
198 def _savelogf():
199 if LOG_FILE_FP:
200 with open(LOG_FILE_FP, 'w') as log:
201 log.write(LOG_CONTENT)
202
203 if LOG_FILE_FP is not None:
204 warning('duplicate log file configuration')
205
206 LOG_FILE_FP = fpath
207
208 import atexit
209 atexit.register(_savelogf)
210
211def enable_logstderr(fpath):
212 global CATCHERR_BUFFILE_FD
213 global CATCHERR_BUFFILE_PATH
214 global CATCHERR_SAVED_2
215
216 if os.path.exists(fpath):
217 os.remove(fpath)
218 CATCHERR_BUFFILE_PATH = fpath
219 CATCHERR_BUFFILE_FD = os.open(CATCHERR_BUFFILE_PATH, os.O_RDWR|os.O_CREAT)
220 CATCHERR_SAVED_2 = os.dup(2)
221 os.dup2(CATCHERR_BUFFILE_FD, 2)
222
223def disable_logstderr():
224 global CATCHERR_BUFFILE_FD
225 global CATCHERR_BUFFILE_PATH
226 global CATCHERR_SAVED_2
227
228 raw(msg=None) # flush message buffer and print it.
229 os.dup2(CATCHERR_SAVED_2, 2)
230 os.close(CATCHERR_SAVED_2)
231 os.close(CATCHERR_BUFFILE_FD)
232 os.unlink(CATCHERR_BUFFILE_PATH)
233 CATCHERR_BUFFILE_FD = -1
234 CATCHERR_BUFFILE_PATH = None
235 CATCHERR_SAVED_2 = -1