log.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. # adapted from https://medium.com/@jonathonbao/python3-logging-with-multiprocessing-f51f460b8778
  2. import logging
  3. import threading
  4. import os
  5. import signal
  6. import queue
  7. import multiprocessing as mp
  8. from logging import handlers
  9. from setproctitle import setproctitle
  10. from collections import deque
  11. def listener_configurer():
  12. root = logging.getLogger()
  13. console_handler = logging.StreamHandler()
  14. formatter = logging.Formatter('%(name)-30s %(levelname)-8s: %(message)s')
  15. console_handler.setFormatter(formatter)
  16. root.addHandler(console_handler)
  17. root.setLevel(logging.INFO)
  18. def root_configurer(queue):
  19. h = handlers.QueueHandler(queue)
  20. root = logging.getLogger()
  21. root.addHandler(h)
  22. root.setLevel(logging.INFO)
  23. def log_process(log_queue):
  24. stop_event = mp.Event()
  25. def receiveSignal(signalNumber, frame):
  26. stop_event.set()
  27. signal.signal(signal.SIGTERM, receiveSignal)
  28. signal.signal(signal.SIGINT, receiveSignal)
  29. threading.current_thread().name = f"logger"
  30. setproctitle("frigate.logger")
  31. listener_configurer()
  32. while True:
  33. if stop_event.is_set() and log_queue.empty():
  34. break
  35. try:
  36. record = log_queue.get(timeout=5)
  37. except queue.Empty:
  38. continue
  39. logger = logging.getLogger(record.name)
  40. logger.handle(record)
  41. # based on https://codereview.stackexchange.com/a/17959
  42. class LogPipe(threading.Thread):
  43. def __init__(self, log_name, level):
  44. """Setup the object with a logger and a loglevel
  45. and start the thread
  46. """
  47. threading.Thread.__init__(self)
  48. self.daemon = False
  49. self.logger = logging.getLogger(log_name)
  50. self.level = level
  51. self.deque = deque(maxlen=100)
  52. self.fdRead, self.fdWrite = os.pipe()
  53. self.pipeReader = os.fdopen(self.fdRead)
  54. self.start()
  55. def fileno(self):
  56. """Return the write file descriptor of the pipe
  57. """
  58. return self.fdWrite
  59. def run(self):
  60. """Run the thread, logging everything.
  61. """
  62. for line in iter(self.pipeReader.readline, ''):
  63. self.deque.append(line.strip('\n'))
  64. self.pipeReader.close()
  65. def dump(self):
  66. while len(self.deque) > 0:
  67. self.logger.log(self.level, self.deque.popleft())
  68. def close(self):
  69. """Close the write end of the pipe.
  70. """
  71. os.close(self.fdWrite)