logger.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. '''
  2. /*#############################################################################
  3. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. ############################################################################ */
  14. '''
  15. import logging
  16. import sys
  17. import time
  18. #from ..regression.regress import Regression
  19. try:
  20. import curses
  21. except:
  22. curses = None
  23. class Logger(object):
  24. class _LogFormatter(logging.Formatter):
  25. def __init__(self, color, *args, **kwargs):
  26. logging.Formatter.__init__(self, *args, **kwargs)
  27. self._color = color
  28. if color:
  29. fg_color = (curses.tigetstr("setaf")
  30. or curses.tigetstr("setf") or "")
  31. self._colors = {
  32. logging.ERROR: curses.tparm(fg_color, 1),
  33. logging.INFO: curses.tparm(fg_color, 2),
  34. logging.CRITICAL: curses.tparm(fg_color, 3),
  35. logging.WARNING: curses.tparm(fg_color, 5),
  36. logging.DEBUG: curses.tparm(fg_color, 4)
  37. }
  38. self._normal = curses.tigetstr("sgr0")
  39. def format(self, record):
  40. try:
  41. record.message = record.getMessage()
  42. except Exception, e:
  43. record.message = "Bad message (%r): %r" % (e, record.__dict__)
  44. record.asctime = time.strftime(
  45. "%y-%m-%d %H:%M:%S", self.converter(record.created))
  46. if record.__dict__['levelname'] == "ERROR":
  47. prefix = '[Failure]' % \
  48. record.__dict__
  49. elif record.__dict__['levelname'] == "CRITICAL":
  50. prefix = '[Error]' % \
  51. record.__dict__
  52. elif record.__dict__['levelname'] == "DEBUG":
  53. prefix = '[Debug]' % \
  54. record.__dict__
  55. elif record.__dict__['levelname'] == "INFO":
  56. prefix = '[Pass]' % \
  57. record.__dict__
  58. elif record.__dict__['levelname'] == "WARNING":
  59. prefix = '[Action]' % \
  60. record.__dict__
  61. if self._color:
  62. prefix = (self._colors.get(record.levelno, self._normal) +
  63. prefix + self._normal)
  64. formatted = prefix + " " + record.message
  65. if record.exc_info:
  66. if not record.exc_text:
  67. record.exc_text = self.formatException(record.exc_info)
  68. if record.exc_text:
  69. formatted = formatted.rstrip() + "\n" + record.exc_text
  70. return formatted.replace("\n", "\n ")
  71. class ProgressFileHandler(logging.FileHandler):
  72. terminator = '\n'
  73. isBuffer = False
  74. logBuffer=dict()
  75. taskId = 0
  76. taskIds = {}
  77. def close(self):
  78. if len(self.logBuffer):
  79. stream = self.stream
  80. for item in self.logBuffer:
  81. for line in self.logBuffer[item]:
  82. stream.write(line)
  83. stream.write(self.terminator)
  84. self.logBuffer.clear()
  85. self.taskIds = {}
  86. self.isBuffer = False
  87. self.flush()
  88. def addTaskId(self, taskId, threadId, timestamp):
  89. if not self.taskIds.has_key(threadId):
  90. self.taskIds[threadId] ={'taskId':taskId, 'timestamp':'timestamp'}
  91. elif self.taskIds[threadId]['timestamp'] != timestamp:
  92. self.taskIds[threadId] ={'taskId':taskId, 'timestamp':'timestamp'}
  93. def getTaskId(self, threadId):
  94. record = self.taskIds.get(threadId, {'taskId':0, 'timestamp':'-'})
  95. return record['taskId']
  96. def emit(self, record):
  97. try:
  98. msg = self.format(record)
  99. stream = self.stream
  100. isBuffer = hasattr(record, 'filebuffer')
  101. toSort = hasattr(record, 'filesort')
  102. taskId = 0
  103. if hasattr(record, 'taskId'):
  104. taskId = getattr(record, 'taskId')
  105. self.addTaskId(taskId, record.thread, record.asctime)
  106. else:
  107. if record.threadName == "MainThread":
  108. taskId = 0
  109. else:
  110. taskId = self.getTaskId(record.thread)
  111. if record.levelname == 'DEBUG':
  112. msg +=" [asctime:"+record.asctime+", process:"+str(record.process)+", processName:"+record.processName+", thread:"+str(record.thread)+", threadName:"+record.threadName+"]"
  113. msg = "{0:3d}".format(taskId) + ". Debug-[debug-"+record.asctime+"]: "+msg
  114. if record.levelname == 'ERROR':
  115. msg +=" [asctime:"+record.asctime+", process:"+str(record.process)+", processName:"+record.processName+", thread:"+str(record.thread)+", threadName:"+record.threadName+"]"
  116. msg = "{0:3d}".format(taskId) + ". Error-[error-"+record.asctime+"]: "+msg
  117. if record.levelname == 'CRITICAL':
  118. msg += " [level: "+record.levelname+" ]"
  119. msg = "{0:3d}".format(taskId) +". " + msg
  120. if isBuffer:
  121. #toggle buffer switch
  122. self.isBuffer = not self.isBuffer
  123. isBuffer = False
  124. if self.isBuffer or isBuffer:
  125. if len(msg):
  126. self.logBuffer.setdefault(taskId, []).append(msg)
  127. else:
  128. if len(self.logBuffer):
  129. for item in self.logBuffer:
  130. for line in self.logBuffer[item]:
  131. line = line.replace(". Debug-", ". ")
  132. stream.write(line)
  133. stream.write(self.terminator)
  134. self.logBuffer.clear()
  135. self.taskIds = {}
  136. self.isBuffer = False
  137. if len(msg):
  138. stream.write(msg)
  139. stream.write(self.terminator)
  140. self.flush()
  141. except (KeyboardInterrupt, SystemExit):
  142. raise
  143. except Exception as ex:
  144. self.handleError(record)
  145. def addHandler(self, fd, level='info'):
  146. root_logger = logging.getLogger()
  147. self.channel = self.ProgressFileHandler(fd)
  148. self.channel.setLevel(getattr(logging, level.upper()))
  149. root_logger.addHandler(self.channel)
  150. def removeHandler(self):
  151. root_logger = logging.getLogger()
  152. root_logger.removeHandler(self.channel)
  153. self.channel.flush()
  154. self.channel.close()
  155. def enable_pretty_logging(self):
  156. root_logger = logging.getLogger()
  157. color = False
  158. if curses and sys.stderr.isatty():
  159. try:
  160. curses.setupterm()
  161. if curses.tigetnum("colors") > 0:
  162. color = True
  163. except:
  164. pass
  165. channel = logging.StreamHandler()
  166. channel.setFormatter(Logger._LogFormatter(color=color))
  167. root_logger.addHandler(channel)
  168. def setLevel(self, level):
  169. logging.getLogger().setLevel(getattr(logging, level.upper()))
  170. def __init__(self, level='info'):
  171. self.setLevel(level)
  172. self.enable_pretty_logging()
  173. self.taskId = 0;