Add dialect (database engine) and version to recorder system health data (#72339)

This commit is contained in:
J. Nick Koston 2022-05-22 23:29:30 -05:00 committed by GitHub
parent e9ffcad4d1
commit 4dbc1ed7a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 8 deletions

View File

@ -12,6 +12,7 @@ import threading
import time
from typing import Any, TypeVar, cast
from awesomeversion import AwesomeVersion
from lru import LRU # pylint: disable=no-name-in-module
from sqlalchemy import create_engine, event as sqlalchemy_event, exc, func, select
from sqlalchemy.engine import Engine
@ -159,6 +160,7 @@ class Recorder(threading.Thread):
self.db_url = uri
self.db_max_retries = db_max_retries
self.db_retry_wait = db_retry_wait
self.engine_version: AwesomeVersion | None = None
self.async_db_ready: asyncio.Future[bool] = asyncio.Future()
self.async_recorder_ready = asyncio.Event()
self._queue_watch = threading.Event()
@ -1009,12 +1011,13 @@ class Recorder(threading.Thread):
) -> None:
"""Dbapi specific connection settings."""
assert self.engine is not None
setup_connection_for_dialect(
if version := setup_connection_for_dialect(
self,
self.engine.dialect.name,
dbapi_connection,
not self._completed_first_database_setup,
)
):
self.engine_version = version
self._completed_first_database_setup = True
if self.db_url == SQLITE_URL_PREFIX or ":memory:" in self.db_url:

View File

@ -3,7 +3,9 @@
"info": {
"oldest_recorder_run": "Oldest Run Start Time",
"current_recorder_run": "Current Run Start Time",
"estimated_db_size": "Estimated Database Size (MiB)"
"estimated_db_size": "Estimated Database Size (MiB)",
"database_engine": "Database Engine",
"database_version": "Database Version"
}
}
}

View File

@ -44,17 +44,32 @@ def _get_db_stats(instance: Recorder, database_name: str) -> dict[str, Any]:
return db_stats
@callback
def _async_get_db_engine_info(instance: Recorder) -> dict[str, Any]:
"""Get database engine info."""
db_engine_info: dict[str, Any] = {}
if dialect_name := instance.dialect_name:
db_engine_info["database_engine"] = dialect_name.value
if engine_version := instance.engine_version:
db_engine_info["database_version"] = str(engine_version)
return db_engine_info
async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
"""Get info for the info page."""
instance = get_instance(hass)
run_history = instance.run_history
database_name = URL(instance.db_url).path.lstrip("/")
db_engine_info = _async_get_db_engine_info(instance)
db_stats: dict[str, Any] = {}
if instance.async_db_ready.done():
db_stats = await instance.async_add_executor_job(
_get_db_stats, instance, database_name
)
return {
"oldest_recorder_run": run_history.first.start,
"current_recorder_run": run_history.current.start,
} | db_stats
db_runs = {
"oldest_recorder_run": run_history.first.start,
"current_recorder_run": run_history.current.start,
}
return db_runs | db_stats | db_engine_info

View File

@ -2,6 +2,8 @@
"system_health": {
"info": {
"current_recorder_run": "Current Run Start Time",
"database_engine": "Database Engine",
"database_version": "Database Version",
"estimated_db_size": "Estimated Database Size (MiB)",
"oldest_recorder_run": "Oldest Run Start Time"
}

View File

@ -396,8 +396,9 @@ def setup_connection_for_dialect(
dialect_name: str,
dbapi_connection: Any,
first_connection: bool,
) -> None:
) -> AwesomeVersion | None:
"""Execute statements needed for dialect connection."""
version: AwesomeVersion | None = None
if dialect_name == SupportedDialect.SQLITE:
if first_connection:
old_isolation = dbapi_connection.isolation_level
@ -465,6 +466,8 @@ def setup_connection_for_dialect(
else:
_fail_unsupported_dialect(dialect_name)
return version
def end_incomplete_runs(session: Session, start_time: datetime) -> None:
"""End any incomplete recorder runs."""

View File

@ -24,6 +24,8 @@ async def test_recorder_system_health(hass, recorder_mock):
"current_recorder_run": instance.run_history.current.start,
"oldest_recorder_run": instance.run_history.first.start,
"estimated_db_size": ANY,
"database_engine": SupportedDialect.SQLITE.value,
"database_version": ANY,
}
@ -46,6 +48,8 @@ async def test_recorder_system_health_alternate_dbms(hass, recorder_mock, dialec
"current_recorder_run": instance.run_history.current.start,
"oldest_recorder_run": instance.run_history.first.start,
"estimated_db_size": "1.00 MiB",
"database_engine": dialect_name.value,
"database_version": ANY,
}
@ -62,4 +66,6 @@ async def test_recorder_system_health_crashed_recorder_runs_table(
"current_recorder_run": instance.run_history.current.start,
"oldest_recorder_run": instance.run_history.current.start,
"estimated_db_size": ANY,
"database_engine": SupportedDialect.SQLITE.value,
"database_version": ANY,
}