Advertisement
Uno-Dan

Logging Server

May 13th, 2019
231
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.27 KB | None | 0 0
  1.  
  2. from os import path, makedirs
  3. from socket import gethostname, gethostbyname
  4. from logging import config, Filter, getLogger, INFO, DEBUG, WARNING, ERROR, CRITICAL, FATAL, NOTSET
  5. from multiprocessing import Process
  6.  
  7. from zmq import Context
  8. from zmq.backend.cython.constants import SUB, SUBSCRIBE, PUSH, PULL
  9.  
  10. PATH = path.dirname(path.realpath(__file__))
  11. PATH_LOGS = path.join(PATH, '../logs')
  12. LOGGER_FORMAT = '%(levelname)s:%(asctime)s,%(msecs)d:%(process)d:%(name)s:%(filename)s:%(funcName)s:' \
  13.                 '%(lineno)d:%(message)s'
  14. LOG_FILE_BACKUP_COUNT = 3
  15. LOG_FILE_MAXIMUM_BYTES = 5242880  # 5MB
  16.  
  17. _nameToLevel = {
  18.     'CRITICAL': CRITICAL,
  19.     'FATAL': FATAL,
  20.     'ERROR': ERROR,
  21.     'WARN': WARNING,
  22.     'WARNING': WARNING,
  23.     'INFO': INFO,
  24.     'DEBUG': DEBUG,
  25.     'NOTSET': NOTSET,
  26. }
  27.  
  28.  
  29. def spawn(task, *args):
  30.     process = Process(target=task, args=args)
  31.     process.daemon = True
  32.     process.start()
  33.     return process
  34.  
  35.  
  36. class Logger:
  37.     def __init__(self, name, frontend, backend):
  38.         super().__init__()
  39.  
  40.         self.ctx = None
  41.         self.name = name
  42.         self.workers = []
  43.         self.backend = backend
  44.         self.frontend = frontend
  45.         self.hostname = gethostname()
  46.         self.ipaddr = gethostbyname(self.hostname)
  47.  
  48.         if not path.exists(PATH_LOGS):
  49.             makedirs(PATH_LOGS)
  50.  
  51.         config.dictConfig(log_config)
  52.  
  53.     def start(self, nbr_workers):
  54.         ctx = Context()
  55.  
  56.         # Clients connect to the frontend
  57.         front_socket = ctx.socket(SUB)
  58.         front_socket.setsockopt_string(SUBSCRIBE, '')
  59.         front_socket.bind(self.frontend)
  60.  
  61.         # Workers connect to the backend
  62.         back_socket = ctx.socket(PUSH)
  63.         back_socket.bind(self.backend)
  64.  
  65.         for idx in range(nbr_workers):
  66.             process = spawn(self.worker)
  67.             self.workers.append(process)
  68.  
  69.         while True:
  70.             request = front_socket.recv_multipart()
  71.             back_socket.send_multipart(request)
  72.  
  73.     def worker(self):
  74.         socket = Context().socket(PULL)
  75.         socket.connect(self.backend)
  76.  
  77.         remote_logger = getLogger('remote')  # Handles logs for remote clients
  78.         remote_logger.setLevel(DEBUG)
  79.  
  80.         while True:
  81.             errorlevel, message = socket.recv_multipart()
  82.             message = message.decode('utf-8')
  83.             errorlevel = errorlevel.decode('utf-8')
  84.             remote_logger.log(_nameToLevel[errorlevel], message)
  85.  
  86.  
  87. class Equals(Filter):
  88.     def __init__(self, param):
  89.         super().__init__()
  90.         self.errorlevel = param if param else NOTSET
  91.  
  92.     def filter(self, record):
  93.         return True if record.levelno == self.errorlevel else False
  94.  
  95.  
  96. class LessThan(Filter):
  97.     def __init__(self, param):
  98.         super().__init__()
  99.         self.errorlevel = param if param else WARNING
  100.  
  101.     def filter(self, record):
  102.         return True if record.levelno < self.errorlevel else False
  103.  
  104.  
  105. class GreaterThan(Filter):
  106.     def __init__(self, param):
  107.         super().__init__()
  108.         self.errorlevel = param if param else INFO
  109.  
  110.     def filter(self, record):
  111.         return True if record.levelno > self.errorlevel else False
  112.  
  113.  
  114. log_config = {
  115.     'version': 1,
  116.     'formatters': {
  117.         'remote': {'format': ''},
  118.     },
  119.     'loggers': {
  120.         'remote': {
  121.             'handlers': [
  122.                 'stdout',
  123.                 'stderr',
  124.                 'debug',
  125.                 'info',
  126.                 'warning',
  127.                 'error',
  128.                 'critical'
  129.             ]
  130.         },
  131.     },
  132.     'filters': {
  133.         'stdout': {
  134.             '()': LessThan,
  135.             'param': WARNING
  136.         },
  137.         'stderr': {
  138.             '()': GreaterThan,
  139.             'param': INFO
  140.         },
  141.         'info': {
  142.             '()': Equals,
  143.             'param': INFO
  144.         },
  145.         'warning': {
  146.             '()': Equals,
  147.             'param': WARNING
  148.         },
  149.         'error': {
  150.             '()': Equals,
  151.             'param': ERROR
  152.         },
  153.         'critical': {
  154.             '()': Equals,
  155.             'param': CRITICAL
  156.         },
  157.     },
  158.     'handlers': {
  159.         'stdout': {
  160.             'class': 'logging.StreamHandler',
  161.             'level': DEBUG,
  162.             'stream': 'ext://sys.stdout',
  163.             'formatter': 'remote',
  164.             'filters': ['stdout']
  165.         },
  166.         'stderr': {
  167.             'class': 'logging.StreamHandler',
  168.             'level': WARNING,
  169.             'stream': 'ext://sys.stderr',
  170.             'formatter': 'remote',
  171.             'filters': ['stderr']
  172.         },
  173.         'debug': {
  174.             'class': 'logging.handlers.RotatingFileHandler',
  175.             'filename': path.join(PATH_LOGS, 'debug.log'),
  176.             'level': DEBUG,
  177.             'maxBytes': LOG_FILE_MAXIMUM_BYTES,
  178.             'backupCount': LOG_FILE_BACKUP_COUNT,
  179.             'formatter': 'remote',
  180.         },
  181.         'info': {
  182.             'class': 'logging.handlers.RotatingFileHandler',
  183.             'filename': path.join(PATH_LOGS, 'info.log'),
  184.             'level': INFO,
  185.             'maxBytes': LOG_FILE_MAXIMUM_BYTES,
  186.             'backupCount': LOG_FILE_BACKUP_COUNT,
  187.             'formatter': 'remote',
  188.             'filters': ['info'],
  189.         },
  190.         'warning': {
  191.             'class': 'logging.handlers.RotatingFileHandler',
  192.             'filename': path.join(PATH_LOGS, 'warning.log'),
  193.             'level': WARNING,
  194.             'maxBytes': LOG_FILE_MAXIMUM_BYTES,
  195.             'backupCount': LOG_FILE_BACKUP_COUNT,
  196.             'formatter': 'remote',
  197.             'filters': ['warning'],
  198.         },
  199.         'error': {
  200.             'class': 'logging.handlers.RotatingFileHandler',
  201.             'filename': path.join(PATH_LOGS, 'error.log'),
  202.             'level': ERROR,
  203.             'maxBytes': LOG_FILE_MAXIMUM_BYTES,
  204.             'backupCount': LOG_FILE_BACKUP_COUNT,
  205.             'formatter': 'remote',
  206.             'filters': ['error'],
  207.         },
  208.         'critical': {
  209.             'class': 'logging.handlers.RotatingFileHandler',
  210.             'filename': path.join(PATH_LOGS, 'critical.log'),
  211.             'level': CRITICAL,
  212.             'maxBytes': LOG_FILE_MAXIMUM_BYTES,
  213.             'backupCount': LOG_FILE_BACKUP_COUNT,
  214.             'formatter': 'remote',
  215.             'filters': ['critical'],
  216.         },
  217.     },
  218. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement