From 76403bba8ef2b0fa2abb22be9961dea30f27129d Mon Sep 17 00:00:00 2001 From: Nat Morris Date: Sun, 3 Jan 2021 23:35:58 +0000 Subject: [PATCH] New stats module, refactor stats generation out of http module. StatsEmitter thread to send stats to MQTT every 60 seconds by default, optional stats_interval config value. New service stats attribute, containing uptime in seconds and version. --- frigate/app.py | 13 ++++++++- frigate/config.py | 9 +++++- frigate/http.py | 32 +++------------------- frigate/stats.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 frigate/stats.py diff --git a/frigate/app.py b/frigate/app.py index dc36fde5f..792358dd5 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -20,6 +20,7 @@ from frigate.models import Event from frigate.mqtt import create_mqtt_client from frigate.object_processing import TrackedObjectProcessor from frigate.record import RecordingMaintainer +from frigate.stats import StatsEmitter, stats_init from frigate.video import capture_camera, track_camera from frigate.watchdog import FrigateWatchdog from frigate.zeroconf import broadcast_zeroconf @@ -115,8 +116,11 @@ class FrigateApp(): self.db.bind(models) self.db.create_tables(models, safe=True) + def init_stats(self): + self.stats_tracking = stats_init(self.camera_metrics, self.detectors) + def init_web_server(self): - self.flask_app = create_app(self.config, self.db, self.camera_metrics, self.detectors, self.detected_frames_processor) + self.flask_app = create_app(self.config, self.db, self.stats_tracking, self.detected_frames_processor) def init_mqtt(self): self.mqtt_client = create_mqtt_client(self.config) @@ -173,6 +177,10 @@ class FrigateApp(): self.recording_maintainer = RecordingMaintainer(self.config, self.stop_event) self.recording_maintainer.start() + def start_stats_emitter(self): + self.stats_emitter = StatsEmitter(self.config, self.stats_tracking, self.mqtt_client, self.config.mqtt.topic_prefix, self.stop_event) + self.stats_emitter.start() + def start_watchdog(self): self.frigate_watchdog = FrigateWatchdog(self.detectors, self.stop_event) self.frigate_watchdog.start() @@ -200,10 +208,12 @@ class FrigateApp(): self.start_detected_frames_processor() self.start_camera_processors() self.start_camera_capture_processes() + self.init_stats() self.init_web_server() self.start_event_processor() self.start_event_cleanup() self.start_recording_maintainer() + self.start_stats_emitter() self.start_watchdog() # self.zeroconf = broadcast_zeroconf(self.config.mqtt.client_id) @@ -224,6 +234,7 @@ class FrigateApp(): self.event_processor.join() self.event_cleanup.join() self.recording_maintainer.join() + self.stats_emitter.join() self.frigate_watchdog.join() for detector in self.detectors.values(): diff --git a/frigate/config.py b/frigate/config.py index d455f2187..3d86f1a63 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -37,6 +37,7 @@ MQTT_SCHEMA = vol.Schema( vol.Optional('port', default=1883): int, vol.Optional('topic_prefix', default='frigate'): str, vol.Optional('client_id', default='frigate'): str, + vol.Optional('stats_interval', default=60): int, 'user': str, 'password': str } @@ -324,6 +325,7 @@ class MqttConfig(): self._client_id = config['client_id'] self._user = config.get('user') self._password = config.get('password') + self._stats_interval = config.get('stats_interval') @property def host(self): @@ -349,13 +351,18 @@ class MqttConfig(): def password(self): return self._password + @property + def stats_interval(self): + return self._stats_interval + def to_dict(self): return { 'host': self.host, 'port': self.port, 'topic_prefix': self.topic_prefix, 'client_id': self.client_id, - 'user': self.user + 'user': self.user, + 'stats_interval': self.stats_interval } class CameraInput(): diff --git a/frigate/http.py b/frigate/http.py index 4a25b59f6..94466920a 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -13,6 +13,7 @@ from peewee import SqliteDatabase, operator, fn, DoesNotExist from playhouse.shortcuts import model_to_dict from frigate.models import Event +from frigate.stats import stats_snapshot from frigate.util import calculate_region from frigate.version import VERSION @@ -20,7 +21,7 @@ logger = logging.getLogger(__name__) bp = Blueprint('frigate', __name__) -def create_app(frigate_config, database: SqliteDatabase, camera_metrics, detectors, detected_frames_processor): +def create_app(frigate_config, database: SqliteDatabase, stats_tracking, detected_frames_processor): app = Flask(__name__) @app.before_request @@ -33,8 +34,7 @@ def create_app(frigate_config, database: SqliteDatabase, camera_metrics, detecto database.close() app.frigate_config = frigate_config - app.camera_metrics = camera_metrics - app.detectors = detectors + app.stats_tracking = stats_tracking app.detected_frames_processor = detected_frames_processor app.register_blueprint(bp) @@ -152,31 +152,7 @@ def version(): @bp.route('/stats') def stats(): - camera_metrics = current_app.camera_metrics - stats = {} - - total_detection_fps = 0 - - for name, camera_stats in camera_metrics.items(): - total_detection_fps += camera_stats['detection_fps'].value - stats[name] = { - 'camera_fps': round(camera_stats['camera_fps'].value, 2), - 'process_fps': round(camera_stats['process_fps'].value, 2), - 'skipped_fps': round(camera_stats['skipped_fps'].value, 2), - 'detection_fps': round(camera_stats['detection_fps'].value, 2), - 'pid': camera_stats['process'].pid, - 'capture_pid': camera_stats['capture_process'].pid - } - - stats['detectors'] = {} - for name, detector in current_app.detectors.items(): - stats['detectors'][name] = { - 'inference_speed': round(detector.avg_inference_speed.value*1000, 2), - 'detection_start': detector.detection_start.value, - 'pid': detector.detect_process.pid - } - stats['detection_fps'] = round(total_detection_fps, 2) - + stats = stats_snapshot(current_app.stats_tracking) return jsonify(stats) @bp.route('//