Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #-*- coding: utf-8 -*-
  2. import copy
  3. import logging, logging.handlers
  4. import os.path
  5. # Variables & constants definitions
  6. default_format = '%(asctime)-15s %(levelname)s %(_pathname)s:%(_lineno)s:%(_funcName)s() : %(message)s'
  7. simple_format = '%(asctime)-15s %(levelname)s : %(message)s'
  8. SECURITY_LOGLEVEL = 35
  9. logging.addLevelName(SECURITY_LOGLEVEL, 'SECURITY')
  10. handlers = dict() # Handlers list (generated from settings)
  11. ##@brief Stores sent messages until module is able to be initialized
  12. msg_buffer = []
  13. # Fetching logger for current context
  14. from lodel.context import LodelContext
  15. logger = logging.getLogger(LodelContext.get_name())
  16. ##@brief Module initialisation from settings
  17. #@return True if inited else False
  18. def __init_from_settings():
  19. from lodel.settings import Settings
  20. from lodel.settings.settings import Settings, Lodel2Settings
  21. if not Lodel2Settings.started():
  22. return False
  23. # capture warning disabled, because the custom format raises error (unable
  24. # to give the _ preffixed arguments to logger resulting into a KeyError
  25. # exception )
  26. #logging.captureWarnings(True) # Log warnings
  27. logger.setLevel(logging.DEBUG)
  28. for name in Settings.logging._fields:
  29. add_handler(name, getattr(Settings.logging, name))
  30. return True
  31. ##@brief Add an handler, identified by a name, to a given logger
  32. #
  33. # logging_opt is a dict with logger option. Allowed keys are :
  34. # - filename : take a filepath as value and cause the use of a logging.handlers.RotatingFileHandler
  35. # - level : the minimum logging level for a logger, takes values [ 'DEBUG', 'INFO', 'WARNING', 'SECURITY', 'ERROR', 'CRITICAL' ]
  36. # - format : DONT USE THIS OPTION (or if you use it be sure to includes %(_pathname)s %(_lineno)s %(_funcName)s format variables in format string
  37. # - context : boolean, if True include the context (module:lineno:function_name) in the log format
  38. # @todo Move the logging_opt documentation somewhere related with settings
  39. #
  40. # @param name str : The handler name
  41. # @param logging_opt dict : dict containing options ( see above )
  42. def add_handler(name, logging_opt):
  43. logger = logging.getLogger(LodelContext.get_name())
  44. if name in handlers:
  45. raise KeyError("A handler named '%s' allready exists")
  46. logging_opt = logging_opt._asdict()
  47. if 'filename' in logging_opt and logging_opt['filename'] is not None:
  48. maxBytes = (1024 * 10) if 'maxbytes' not in logging_opt else logging_opt['maxbytes']
  49. backupCount = 10 if 'backupcount' not in logging_opt else logging_opt['backupcount']
  50. handler = logging.handlers.RotatingFileHandler(
  51. logging_opt['filename'],
  52. maxBytes = maxBytes,
  53. backupCount = backupCount,
  54. encoding = 'utf-8')
  55. else:
  56. handler = logging.StreamHandler()
  57. if 'level' in logging_opt:
  58. handler.setLevel(getattr(logging, logging_opt['level'].upper()))
  59. if 'format' in logging_opt:
  60. formatter = logging.Formatter(logging_opt['format'])
  61. else:
  62. if 'context' in logging_opt and not logging_opt['context']:
  63. formatter = logging.Formatter(simple_format)
  64. else:
  65. formatter = logging.Formatter(default_format)
  66. handler.setFormatter(formatter)
  67. handlers[name] = handler
  68. logger.addHandler(handler)
  69. ##@brief Remove an handler generated from configuration (runtime logger configuration)
  70. # @param name str : handler name
  71. def remove_handler(name):
  72. if name in handlers:
  73. logger.removeHandler(handlers[name])
  74. # else: can we do anything ?
  75. ##@brief Utility function that disable unconditionnaly handlers that implies console output
  76. # @note In fact, this function disables handlers generated from settings wich are instances of logging.StreamHandler
  77. def remove_console_handlers():
  78. for name, handler in handlers.items():
  79. if isinstance(handler, logging.StreamHandler):
  80. remove_handler(name)
  81. #####################
  82. # Utility functions #
  83. #####################
  84. ##@brief Generic logging function
  85. # @param lvl int : Log severity
  86. # @param msg str : log message
  87. # @param *args : additional positionnal arguments
  88. # @param **kwargs : additional named arguments
  89. def log(lvl, msg, *args, **kwargs):
  90. if len(handlers) == 0: #late initialisation
  91. if not __init_from_settings():
  92. s_kwargs = copy.copy(kwargs)
  93. s_kwargs.update({'lvl': lvl, 'msg':msg})
  94. msg_buffer.append((s_kwargs, args))
  95. return
  96. else:
  97. for s_kwargs, args in msg_buffer:
  98. log(*args, **s_kwargs)
  99. from lodel.context import LodelContext
  100. if LodelContext.multisite():
  101. msg = "CTX(%s) %s" % (LodelContext.get_name(), msg)
  102. caller = logger.findCaller() # Opti warning : small overhead
  103. extra = {
  104. '_pathname': os.path.abspath(caller[0]),
  105. '_lineno': caller[1],
  106. '_funcName': caller[2],
  107. }
  108. logger.log(lvl, msg, extra = extra, *args, **kwargs)
  109. def debug(msg, *args, **kwargs): log(logging.DEBUG, msg, *args, **kwargs)
  110. def info(msg, *args, **kwargs): log(logging.INFO, msg, *args, **kwargs)
  111. def warning(msg, *args, **kwargs): log(logging.WARNING, msg, *args, **kwargs)
  112. def security(msg, *args, **kwargs): log(SECURITY_LOGLEVEL, msg, *args, **kwargs)
  113. def error(msg, *args, **kwargs): log(logging.ERROR, msg, *args, **kwargs)
  114. def critical(msg, *args, **kwargs): log(logging.CRITICAL, msg, *args, **kwargs)