mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Make logging code self-contained (#13785)
* Make logging code self-contained. Rewrite logging code to use python's builting QueueListener, effectively moving the logging process into a thread of the Frigate app. Also, wrap this behaviour in a easy-to-use context manager to encourage some consistency. * Fixed typing errors * Remove todo note from log filter Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com> * Do not access log record's msg directly * Clear all root handlers before starting app --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
parent
f7eaace7ae
commit
1c24f0054a
@ -1,17 +1,28 @@
|
|||||||
import faulthandler
|
import faulthandler
|
||||||
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from flask import cli
|
from flask import cli
|
||||||
|
|
||||||
from frigate.app import FrigateApp
|
from frigate.app import FrigateApp
|
||||||
|
|
||||||
faulthandler.enable()
|
|
||||||
|
|
||||||
threading.current_thread().name = "frigate"
|
def main() -> None:
|
||||||
|
faulthandler.enable()
|
||||||
|
|
||||||
|
# Clear all existing handlers.
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
handlers=[],
|
||||||
|
force=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
threading.current_thread().name = "frigate"
|
||||||
|
cli.show_server_banner = lambda *x: None
|
||||||
|
|
||||||
|
# Run the main application.
|
||||||
|
FrigateApp().start()
|
||||||
|
|
||||||
cli.show_server_banner = lambda *x: None
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
frigate_app = FrigateApp()
|
main()
|
||||||
|
|
||||||
frigate_app.start()
|
|
||||||
|
@ -43,7 +43,7 @@ from frigate.events.audio import listen_to_audio
|
|||||||
from frigate.events.cleanup import EventCleanup
|
from frigate.events.cleanup import EventCleanup
|
||||||
from frigate.events.external import ExternalEventProcessor
|
from frigate.events.external import ExternalEventProcessor
|
||||||
from frigate.events.maintainer import EventProcessor
|
from frigate.events.maintainer import EventProcessor
|
||||||
from frigate.log import log_process, root_configurer
|
from frigate.log import log_thread
|
||||||
from frigate.models import (
|
from frigate.models import (
|
||||||
Event,
|
Event,
|
||||||
Export,
|
Export,
|
||||||
@ -113,15 +113,6 @@ class FrigateApp:
|
|||||||
else:
|
else:
|
||||||
logger.debug(f"Skipping directory: {d}")
|
logger.debug(f"Skipping directory: {d}")
|
||||||
|
|
||||||
def init_logger(self) -> None:
|
|
||||||
self.log_process = mp.Process(
|
|
||||||
target=log_process, args=(self.log_queue,), name="log_process"
|
|
||||||
)
|
|
||||||
self.log_process.daemon = True
|
|
||||||
self.log_process.start()
|
|
||||||
self.processes["logger"] = self.log_process.pid or 0
|
|
||||||
root_configurer(self.log_queue)
|
|
||||||
|
|
||||||
def init_config(self) -> None:
|
def init_config(self) -> None:
|
||||||
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
|
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
|
||||||
|
|
||||||
@ -667,6 +658,7 @@ class FrigateApp:
|
|||||||
logger.info("********************************************************")
|
logger.info("********************************************************")
|
||||||
logger.info("********************************************************")
|
logger.info("********************************************************")
|
||||||
|
|
||||||
|
@log_thread()
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="Frigate",
|
prog="Frigate",
|
||||||
@ -675,7 +667,6 @@ class FrigateApp:
|
|||||||
parser.add_argument("--validate-config", action="store_true")
|
parser.add_argument("--validate-config", action="store_true")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
self.init_logger()
|
|
||||||
logger.info(f"Starting Frigate ({VERSION})")
|
logger.info(f"Starting Frigate ({VERSION})")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -702,13 +693,11 @@ class FrigateApp:
|
|||||||
print("*************************************************************")
|
print("*************************************************************")
|
||||||
print("*** End Config Validation Errors ***")
|
print("*** End Config Validation Errors ***")
|
||||||
print("*************************************************************")
|
print("*************************************************************")
|
||||||
self.log_process.terminate()
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if args.validate_config:
|
if args.validate_config:
|
||||||
print("*************************************************************")
|
print("*************************************************************")
|
||||||
print("*** Your config file is valid. ***")
|
print("*** Your config file is valid. ***")
|
||||||
print("*************************************************************")
|
print("*************************************************************")
|
||||||
self.log_process.terminate()
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
self.set_environment_vars()
|
self.set_environment_vars()
|
||||||
self.set_log_levels()
|
self.set_log_levels()
|
||||||
@ -725,7 +714,6 @@ class FrigateApp:
|
|||||||
self.init_dispatcher()
|
self.init_dispatcher()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
self.log_process.terminate()
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self.start_detectors()
|
self.start_detectors()
|
||||||
self.start_video_output_processor()
|
self.start_video_output_processor()
|
||||||
@ -848,7 +836,4 @@ class FrigateApp:
|
|||||||
shm.close()
|
shm.close()
|
||||||
shm.unlink()
|
shm.unlink()
|
||||||
|
|
||||||
self.log_process.terminate()
|
|
||||||
self.log_process.join()
|
|
||||||
|
|
||||||
os._exit(os.EX_OK)
|
os._exit(os.EX_OK)
|
||||||
|
@ -1,71 +1,71 @@
|
|||||||
# adapted from https://medium.com/@jonathonbao/python3-logging-with-multiprocessing-f51f460b8778
|
import atexit
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import os
|
import os
|
||||||
import queue
|
|
||||||
import signal
|
|
||||||
import threading
|
import threading
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from logging import handlers
|
from contextlib import AbstractContextManager, ContextDecorator
|
||||||
from multiprocessing import Queue
|
from logging.handlers import QueueHandler, QueueListener
|
||||||
from types import FrameType
|
from types import TracebackType
|
||||||
from typing import Deque, Optional
|
from typing import Deque, Optional
|
||||||
|
|
||||||
from setproctitle import setproctitle
|
from typing_extensions import Self
|
||||||
|
|
||||||
from frigate.util.builtin import clean_camera_user_pass
|
from frigate.util.builtin import clean_camera_user_pass
|
||||||
|
|
||||||
|
LOG_HANDLER = logging.StreamHandler()
|
||||||
def listener_configurer() -> None:
|
LOG_HANDLER.setFormatter(
|
||||||
root = logging.getLogger()
|
logging.Formatter(
|
||||||
|
"[%(asctime)s] %(name)-30s %(levelname)-8s: %(message)s",
|
||||||
if root.hasHandlers():
|
"%Y-%m-%d %H:%M:%S",
|
||||||
root.handlers.clear()
|
|
||||||
|
|
||||||
console_handler = logging.StreamHandler()
|
|
||||||
formatter = logging.Formatter(
|
|
||||||
"[%(asctime)s] %(name)-30s %(levelname)-8s: %(message)s", "%Y-%m-%d %H:%M:%S"
|
|
||||||
)
|
)
|
||||||
console_handler.setFormatter(formatter)
|
)
|
||||||
root.addHandler(console_handler)
|
|
||||||
root.setLevel(logging.INFO)
|
LOG_HANDLER.addFilter(
|
||||||
|
lambda record: not record.getMessage().startswith(
|
||||||
|
"You are using a scalar distance function"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def root_configurer(queue: Queue) -> None:
|
class log_thread(AbstractContextManager, ContextDecorator):
|
||||||
h = handlers.QueueHandler(queue)
|
def __init__(self, *, handler: logging.Handler = LOG_HANDLER):
|
||||||
root = logging.getLogger()
|
super().__init__()
|
||||||
|
|
||||||
if root.hasHandlers():
|
self._handler = handler
|
||||||
root.handlers.clear()
|
|
||||||
|
|
||||||
root.addHandler(h)
|
log_queue: mp.Queue = mp.Queue()
|
||||||
root.setLevel(logging.INFO)
|
self._queue_handler = QueueHandler(log_queue)
|
||||||
|
|
||||||
|
self._log_listener = QueueListener(
|
||||||
|
log_queue, self._handler, respect_handler_level=True
|
||||||
|
)
|
||||||
|
|
||||||
def log_process(log_queue: Queue) -> None:
|
@property
|
||||||
threading.current_thread().name = "logger"
|
def handler(self) -> logging.Handler:
|
||||||
setproctitle("frigate.logger")
|
return self._handler
|
||||||
listener_configurer()
|
|
||||||
|
|
||||||
stop_event = mp.Event()
|
def _stop_thread(self) -> None:
|
||||||
|
self._log_listener.stop()
|
||||||
|
|
||||||
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
def __enter__(self) -> Self:
|
||||||
stop_event.set()
|
logging.getLogger().addHandler(self._queue_handler)
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
atexit.register(self._stop_thread)
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
self._log_listener.start()
|
||||||
|
|
||||||
while True:
|
return self
|
||||||
try:
|
|
||||||
record = log_queue.get(block=True, timeout=1.0)
|
def __exit__(
|
||||||
except queue.Empty:
|
self,
|
||||||
if stop_event.is_set():
|
exc_type: Optional[type[BaseException]],
|
||||||
break
|
exc_info: Optional[BaseException],
|
||||||
continue
|
exc_tb: Optional[TracebackType],
|
||||||
if record.msg.startswith("You are using a scalar distance function"):
|
) -> None:
|
||||||
continue
|
logging.getLogger().removeHandler(self._queue_handler)
|
||||||
logger = logging.getLogger(record.name)
|
|
||||||
logger.handle(record)
|
atexit.unregister(self._stop_thread)
|
||||||
|
self._stop_thread()
|
||||||
|
|
||||||
|
|
||||||
# based on https://codereview.stackexchange.com/a/17959
|
# based on https://codereview.stackexchange.com/a/17959
|
||||||
|
@ -28,8 +28,7 @@ from frigate.video import ( # noqa: E402
|
|||||||
start_or_restart_ffmpeg,
|
start_or_restart_ffmpeg,
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.basicConfig()
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logging.root.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user