2020-11-04 04:26:39 +01:00
|
|
|
# adapted from https://medium.com/@jonathonbao/python3-logging-with-multiprocessing-f51f460b8778
|
|
|
|
import logging
|
2023-05-29 12:31:17 +02:00
|
|
|
import multiprocessing as mp
|
2020-12-04 13:59:03 +01:00
|
|
|
import os
|
2020-11-30 02:29:32 +01:00
|
|
|
import queue
|
2023-05-29 12:31:17 +02:00
|
|
|
import signal
|
|
|
|
import threading
|
|
|
|
from collections import deque
|
2020-11-04 04:26:39 +01:00
|
|
|
from logging import handlers
|
2023-05-29 12:31:17 +02:00
|
|
|
from multiprocessing.queues import Queue
|
2023-02-04 03:15:47 +01:00
|
|
|
from types import FrameType
|
|
|
|
from typing import Deque, Optional
|
2023-05-29 12:31:17 +02:00
|
|
|
|
|
|
|
from setproctitle import setproctitle
|
2020-11-04 04:26:39 +01:00
|
|
|
|
2022-11-02 13:00:54 +01:00
|
|
|
from frigate.util import clean_camera_user_pass
|
|
|
|
|
2020-11-04 13:31:25 +01:00
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def listener_configurer() -> None:
|
2020-11-04 04:26:39 +01:00
|
|
|
root = logging.getLogger()
|
2023-04-26 13:08:53 +02:00
|
|
|
|
|
|
|
if root.hasHandlers():
|
|
|
|
root.handlers.clear()
|
|
|
|
|
2020-11-04 04:26:39 +01:00
|
|
|
console_handler = logging.StreamHandler()
|
2021-05-06 03:20:44 +02:00
|
|
|
formatter = logging.Formatter(
|
|
|
|
"[%(asctime)s] %(name)-30s %(levelname)-8s: %(message)s", "%Y-%m-%d %H:%M:%S"
|
|
|
|
)
|
2020-11-04 04:26:39 +01:00
|
|
|
console_handler.setFormatter(formatter)
|
|
|
|
root.addHandler(console_handler)
|
|
|
|
root.setLevel(logging.INFO)
|
|
|
|
|
2021-02-17 14:23:32 +01:00
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def root_configurer(queue: Queue) -> None:
|
2020-11-04 04:26:39 +01:00
|
|
|
h = handlers.QueueHandler(queue)
|
|
|
|
root = logging.getLogger()
|
2023-04-26 13:08:53 +02:00
|
|
|
|
|
|
|
if root.hasHandlers():
|
|
|
|
root.handlers.clear()
|
|
|
|
|
2020-11-04 04:26:39 +01:00
|
|
|
root.addHandler(h)
|
|
|
|
root.setLevel(logging.INFO)
|
|
|
|
|
2021-02-17 14:23:32 +01:00
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def log_process(log_queue: Queue) -> None:
|
2023-05-29 12:31:17 +02:00
|
|
|
threading.current_thread().name = "logger"
|
2021-01-03 20:41:02 +01:00
|
|
|
setproctitle("frigate.logger")
|
2020-11-04 04:26:39 +01:00
|
|
|
listener_configurer()
|
2023-02-04 03:15:47 +01:00
|
|
|
|
|
|
|
stop_event = mp.Event()
|
|
|
|
|
|
|
|
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
|
|
|
stop_event.set()
|
|
|
|
|
|
|
|
signal.signal(signal.SIGTERM, receiveSignal)
|
|
|
|
signal.signal(signal.SIGINT, receiveSignal)
|
|
|
|
|
2020-11-04 04:26:39 +01:00
|
|
|
while True:
|
2020-11-29 23:19:59 +01:00
|
|
|
try:
|
2023-02-04 03:15:47 +01:00
|
|
|
record = log_queue.get(timeout=1)
|
2021-05-18 07:52:08 +02:00
|
|
|
except (queue.Empty, KeyboardInterrupt):
|
2023-02-04 03:15:47 +01:00
|
|
|
if stop_event.is_set():
|
|
|
|
break
|
2020-11-29 23:19:59 +01:00
|
|
|
continue
|
2023-05-31 16:12:43 +02:00
|
|
|
if record.msg.startswith("You are using a scalar distance function"):
|
|
|
|
continue
|
2020-11-04 04:26:39 +01:00
|
|
|
logger = logging.getLogger(record.name)
|
|
|
|
logger.handle(record)
|
2020-12-04 13:59:03 +01:00
|
|
|
|
2021-02-17 14:23:32 +01:00
|
|
|
|
2020-12-04 13:59:03 +01:00
|
|
|
# based on https://codereview.stackexchange.com/a/17959
|
|
|
|
class LogPipe(threading.Thread):
|
2022-04-12 22:24:45 +02:00
|
|
|
def __init__(self, log_name: str):
|
|
|
|
"""Setup the object with a logger and start the thread"""
|
2020-12-04 13:59:03 +01:00
|
|
|
threading.Thread.__init__(self)
|
|
|
|
self.daemon = False
|
|
|
|
self.logger = logging.getLogger(log_name)
|
2022-04-12 22:24:45 +02:00
|
|
|
self.level = logging.ERROR
|
|
|
|
self.deque: Deque[str] = deque(maxlen=100)
|
2020-12-04 13:59:03 +01:00
|
|
|
self.fdRead, self.fdWrite = os.pipe()
|
|
|
|
self.pipeReader = os.fdopen(self.fdRead)
|
|
|
|
self.start()
|
|
|
|
|
2022-11-02 13:00:54 +01:00
|
|
|
def cleanup_log(self, log: str) -> str:
|
|
|
|
"""Cleanup the log line to remove sensitive info and string tokens."""
|
|
|
|
log = clean_camera_user_pass(log).strip("\n")
|
|
|
|
return log
|
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def fileno(self) -> int:
|
2021-02-17 14:23:32 +01:00
|
|
|
"""Return the write file descriptor of the pipe"""
|
2020-12-04 13:59:03 +01:00
|
|
|
return self.fdWrite
|
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def run(self) -> None:
|
2021-02-17 14:23:32 +01:00
|
|
|
"""Run the thread, logging everything."""
|
|
|
|
for line in iter(self.pipeReader.readline, ""):
|
2022-11-02 13:00:54 +01:00
|
|
|
self.deque.append(self.cleanup_log(line))
|
2020-12-04 13:59:03 +01:00
|
|
|
|
|
|
|
self.pipeReader.close()
|
2021-02-17 14:23:32 +01:00
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def dump(self) -> None:
|
2021-01-30 14:50:17 +01:00
|
|
|
while len(self.deque) > 0:
|
|
|
|
self.logger.log(self.level, self.deque.popleft())
|
2020-12-04 13:59:03 +01:00
|
|
|
|
2022-04-12 22:24:45 +02:00
|
|
|
def close(self) -> None:
|
2021-02-17 14:23:32 +01:00
|
|
|
"""Close the write end of the pipe."""
|
2021-01-03 20:41:02 +01:00
|
|
|
os.close(self.fdWrite)
|