Add analytics opt-in setting, prompt notice kind, and notice watermarks

This commit is contained in:
Josh Hawkins
2026-09-22 08:08:23 -05:00
parent af0ba19196
commit aa72e555f5
5 changed files with 61 additions and 0 deletions
+5
View File
@@ -29,6 +29,11 @@ class StatsConfig(FrigateBaseModel):
class TelemetryConfig(FrigateBaseModel):
analytics: bool = Field(
default=False,
title="Share anonymous analytics",
description="Send one anonymous usage report a day to help the Frigate maintainers decide what to support. Nothing is sent until this is on.",
)
network_interfaces: list[str] = Field(
default=[],
title="Network interfaces",
+13
View File
@@ -319,6 +319,19 @@ class NoticeRegistry:
if row.kind in NOTICE_KINDS
]
def mark_reported(self, snapshot: list[dict[str, Any]]) -> None:
"""Move the analytics watermarks to the counts a sent report was built from.
Using the snapshot rather than the current counts sends anything raised
while the report was in flight with the next one.
"""
with self._lock:
for row in snapshot:
NoticeStats.update(
reported_occurrences=row["occurrences"],
reported_dismissals=row["dismissals"],
).where(NoticeStats.kind == row["kind"]).execute()
def _write_repeats(
self,
row: Notice,
+10
View File
@@ -86,6 +86,16 @@ _KINDS = (
link="https://github.com/blakeblackshear/frigate/releases/tag/v{version}",
counts_repeats=False,
keep_latest=1,
reportable=False,
),
# raised while analytics is off; the row keeps a dismissal across restarts
NoticeKind(
"analytics_prompt",
NoticeSeverity.info,
"system",
link="/settings?page=systemTelemetry",
counts_repeats=False,
reportable=False,
),
)
+5
View File
@@ -17,6 +17,11 @@ from frigate.util.builtin import deep_merge
class TestConfig(unittest.TestCase):
def test_analytics_is_off_by_default(self):
frigate_config = FrigateConfig(**self.minimal)
self.assertFalse(frigate_config.telemetry.analytics)
def setUp(self):
self.minimal = {
"mqtt": {"host": "mqtt"},
+28
View File
@@ -48,6 +48,16 @@ class TestNoticeKinds(unittest.TestCase):
self.assertIsNone(kind.link_for({"version": "0.19.1"}))
def test_analytics_prompt_links_to_telemetry_settings(self):
kind = NOTICE_KINDS["analytics_prompt"]
self.assertEqual(kind.link_for({}), "/settings?page=systemTelemetry")
self.assertFalse(kind.counts_repeats)
self.assertFalse(kind.reportable)
def test_update_available_is_not_reported(self):
self.assertFalse(NOTICE_KINDS["update_available"].reportable)
class RegistryTestCase(unittest.TestCase):
def setUp(self):
@@ -278,6 +288,24 @@ class TestNoticeRegistry(RegistryTestCase):
self.assertEqual(dismissals["detector_stuck"], 1)
class TestMarkReported(RegistryTestCase):
def test_moves_watermarks_to_the_snapshot_not_the_current_count(self):
self.registry.raise_notice(
"detector_stuck", scope="ov", params={"detector": "ov"}
)
snapshot = self.registry.stats()
self.registry.raise_notice(
"detector_stuck", scope="ov", params={"detector": "ov"}
)
self.registry.mark_reported(snapshot)
row = self.registry.stats()[0]
self.assertEqual(row["occurrences"], 2)
self.assertEqual(row["reported_occurrences"], 1)
self.assertEqual(row["reported_dismissals"], 0)
class TestApply(RegistryTestCase):
def test_each_action_reaches_its_method(self):
self.registry.apply(