log.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. # Copyright (C) 2010 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """
  16. This module is to convert python logging module over
  17. to log4python.
  18. Copyright (C) 2010 Internet Systems Consortium.
  19. To use, simply 'import isc.log.log' and log away!
  20. """
  21. import os
  22. import syslog
  23. import logging
  24. import logging.handlers
  25. """
  26. LEVELS: logging levels mapping
  27. """
  28. LEVELS = {'debug' : logging.DEBUG,
  29. 'info' : logging.INFO,
  30. 'warning' : logging.WARNING,
  31. 'error' : logging.ERROR,
  32. 'critical' : logging.CRITICAL}
  33. formatter = logging.Formatter("%(name)s: %(levelname)s: %(message)s")
  34. time_formatter = logging.Formatter("%(asctime)s: %(name)s: %(levelname)s: %(message)s")
  35. class RotatingFileHandler(logging.handlers.RotatingFileHandler):
  36. """
  37. RotatingFileHandler: replace RotatingFileHandler with a custom handler
  38. """
  39. def shouldRollover(self, record):
  40. """
  41. Rewrite RotatingFileHandler.shouldRollover.
  42. If the log file is deleted at run-time, a new file will be created.
  43. """
  44. dfn = self.baseFilename
  45. if (self.stream) and (not os.path.exists(dfn)): #Is log file exist?
  46. self.stream.close()
  47. self.stream = self._open()
  48. super(RotatingFileHandler, self).shouldRollover(record)
  49. def update_config(self, file_name, backup_count, max_bytes):
  50. """
  51. Update RotatingFileHandler configuration.
  52. input:
  53. log file name
  54. max backup count
  55. predetermined log file size
  56. """
  57. try:
  58. self._open(file_name)
  59. except IOError:
  60. print("The file path is not exist!")
  61. return
  62. self.baseFilename = file_name
  63. self.maxBytes = max_bytes
  64. self.backupCount = backup_count
  65. class SLHandler(logging.Handler):
  66. """
  67. Replace SysLogHandler with a custom handler
  68. A handler class which sends formatted logging records to a syslog
  69. server.
  70. """
  71. def __init__(self, ident, logopt=0, facility=syslog.LOG_USER):
  72. """
  73. Initialize a handler.
  74. If facility is not specified, LOG_USER is used.
  75. """
  76. super(SLHandler, self).__init__(self)
  77. self.ident = ident
  78. self.logopt = logopt
  79. self.facility = facility
  80. self.mappings = {
  81. logging.DEBUG: syslog.LOG_DEBUG,
  82. logging.INFO: syslog.LOG_INFO,
  83. logging.WARNING: syslog.LOG_WARNING,
  84. logging.ERROR: syslog.LOG_ERR,
  85. logging.CRITICAL: syslog.LOG_CRIT,
  86. }
  87. def encodeLevel(self, level):
  88. """
  89. Encoding the priority.
  90. """
  91. return self.mappings.get(level, syslog.LOG_INFO)
  92. def emit(self, record):
  93. """
  94. Emit a record.
  95. The record is formatted, and then sent to the syslog server. If
  96. exception information is present, it is NOT sent to the server.
  97. """
  98. syslog.openlog(self.ident, self.logopt, self.facility)
  99. msg = self.format(record)
  100. prio = self.encodeLevel(record.levelno)
  101. syslog.syslog(prio, msg)
  102. syslog.closelog()
  103. class ModuleLogger(logging.getLoggerClass()):
  104. """
  105. Override logging.logger behaviour
  106. """
  107. def __init__(self, log_name, log_file,
  108. severity = 'debug', backup_count = 0, max_bytes = 0,
  109. log_to_console = True):
  110. """
  111. Initializes the logger with some specific parameters
  112. """
  113. logging.Logger.__init__(self, log_name)
  114. # Set up a specific logger with our desired output level
  115. logLevel = LEVELS.get(severity, logging.NOTSET)
  116. self.setLevel(logLevel)
  117. self.null_handler = None
  118. self.rotating_handler = None
  119. self.stream_handler = None
  120. self.syslog_handler = None
  121. self.add_null_handler()
  122. self.add_rotate_handler(log_file, max_bytes, backup_count)
  123. if log_to_console:
  124. self.add_stream_handler()
  125. else:
  126. self.add_syslog_handler()
  127. def add_null_handler(self):
  128. """
  129. Add a null handler.
  130. """
  131. self.null_handler = logging.NullHandler()
  132. self.addHandler(self.null_handler)
  133. def add_rotate_handler(self, log_file, max_bytes, backup_count):
  134. """
  135. Add a rotate file handler.
  136. input:
  137. log_file : the location of log file.Handler would't be created is log_file is empty
  138. max_bytes : limit log growth
  139. backup_count : max backup count
  140. """
  141. if(log_file != 0 and log_file != ''):
  142. try:
  143. self.rotating_handler = RotatingFileHandler(filename = log_file, maxBytes = max_bytes,
  144. backupCount = backup_count)
  145. except IOError:
  146. self.rotating_handler = None
  147. return
  148. self.rotating_handler.setFormatter(time_formatter)
  149. self.addHandler(self.rotating_handler)
  150. def add_stream_handler(self):
  151. """
  152. Add a stream handler.
  153. sys.stderr will be used for logging output.
  154. """
  155. self.stream_handler = logging.StreamHandler()
  156. self.stream_handler.setFormatter(time_formatter)
  157. self.addHandler(self.stream_handler)
  158. def add_syslog_handler(self):
  159. """
  160. Add a syslog handler.
  161. If facility is not specified, LOG_USER is used.
  162. The default severity level is INFO.
  163. """
  164. self.syslog_handler = SLHandler('BIND10', facility=syslog.LOG_USER)
  165. self.syslog_handler.setFormatter(formatter)
  166. #set syslog handler level info
  167. self.syslog_handler.setLevel(logging.INFO)
  168. self.addHandler(self.syslog_handler)
  169. def update_rotate_handler(self, log_file, max_bytes, backup_count):
  170. """
  171. If rotate handler has been added to the logger, update its configuration,
  172. else add it to logger.
  173. If log file is empty, the handler will be removed.
  174. """
  175. if (self.rotating_handler in self.handlers):
  176. if(log_file != 0 and log_file != ''):
  177. self.rotating_handler.update_config(log_file, max_bytes, backup_count)
  178. else:
  179. self.rotating_handler.flush()
  180. self.rotating_handler.close()
  181. self.removeHandler(self.rotating_handler)
  182. else:
  183. self.add_rotate_handler(log_file, max_bytes, backup_count)
  184. def update_config(self, file_name, level, max_bytes, backup_count):
  185. """
  186. Update logger's configuration.
  187. We can update logger's log level and its rotate file handler's configuration.
  188. """
  189. logLevel = LEVELS.get(level, logging.NOTSET)
  190. if(logLevel != self.getEffectiveLevel()):
  191. self.setLevel(logLevel)
  192. self.update_rotate_handler(file_name, backup_count, max_bytes)
  193. def log_message(self, level, msg, *args, **kwargs):
  194. """
  195. Log 'msg % args' with the integer severity 'level'.
  196. To pass exception information, use the keyword argument exc_info with
  197. a true value, e.g.
  198. logger.log_message('info', "We have a %s", "mysterious problem", exc_info=1)
  199. """
  200. logLevel = LEVELS.get(level, logging.NOTSET)
  201. self.log(logLevel, msg, *args, **kwargs)