mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-13 12:16:29 +00:00
Add diagnostics support (#1870)
* Add diagnostics support Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch> * add aditional data * Fix handling * Better states * Fix opt * Update supervisor/bootstrap.py Co-authored-by: Paulus Schoutsen <balloob@gmail.com> * Only events on supported systems Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
6599ae0ee0
commit
ad988f2a24
1
API.md
1
API.md
@ -47,6 +47,7 @@ The addons from `addons` are only installed one.
|
|||||||
"wait_boot": "int",
|
"wait_boot": "int",
|
||||||
"debug": "bool",
|
"debug": "bool",
|
||||||
"debug_block": "bool",
|
"debug_block": "bool",
|
||||||
|
"diagnostics": "None|bool",
|
||||||
"addons": [
|
"addons": [
|
||||||
{
|
{
|
||||||
"name": "xy bla",
|
"name": "xy bla",
|
||||||
|
@ -14,5 +14,6 @@ pulsectl==20.5.1
|
|||||||
pytz==2020.1
|
pytz==2020.1
|
||||||
pyudev==0.22.0
|
pyudev==0.22.0
|
||||||
ruamel.yaml==0.15.100
|
ruamel.yaml==0.15.100
|
||||||
|
sentry-sdk==0.16.3
|
||||||
uvloop==0.14.0
|
uvloop==0.14.0
|
||||||
voluptuous==0.11.7
|
voluptuous==0.11.7
|
||||||
|
@ -17,6 +17,7 @@ from ..const import (
|
|||||||
ATTR_DEBUG,
|
ATTR_DEBUG,
|
||||||
ATTR_DEBUG_BLOCK,
|
ATTR_DEBUG_BLOCK,
|
||||||
ATTR_DESCRIPTON,
|
ATTR_DESCRIPTON,
|
||||||
|
ATTR_DIAGNOSTICS,
|
||||||
ATTR_ICON,
|
ATTR_ICON,
|
||||||
ATTR_INSTALLED,
|
ATTR_INSTALLED,
|
||||||
ATTR_IP_ADDRESS,
|
ATTR_IP_ADDRESS,
|
||||||
@ -58,6 +59,7 @@ SCHEMA_OPTIONS = vol.Schema(
|
|||||||
vol.Optional(ATTR_LOGGING): vol.Coerce(LogLevel),
|
vol.Optional(ATTR_LOGGING): vol.Coerce(LogLevel),
|
||||||
vol.Optional(ATTR_DEBUG): vol.Boolean(),
|
vol.Optional(ATTR_DEBUG): vol.Boolean(),
|
||||||
vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(),
|
vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(),
|
||||||
|
vol.Optional(ATTR_DIAGNOSTICS): vol.Boolean(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -102,6 +104,7 @@ class APISupervisor(CoreSysAttributes):
|
|||||||
ATTR_LOGGING: self.sys_config.logging,
|
ATTR_LOGGING: self.sys_config.logging,
|
||||||
ATTR_DEBUG: self.sys_config.debug,
|
ATTR_DEBUG: self.sys_config.debug,
|
||||||
ATTR_DEBUG_BLOCK: self.sys_config.debug_block,
|
ATTR_DEBUG_BLOCK: self.sys_config.debug_block,
|
||||||
|
ATTR_DIAGNOSTICS: self.sys_config.diagnostics,
|
||||||
ATTR_ADDONS: list_addons,
|
ATTR_ADDONS: list_addons,
|
||||||
ATTR_ADDONS_REPOSITORIES: self.sys_config.addons_repositories,
|
ATTR_ADDONS_REPOSITORIES: self.sys_config.addons_repositories,
|
||||||
}
|
}
|
||||||
@ -126,6 +129,9 @@ class APISupervisor(CoreSysAttributes):
|
|||||||
if ATTR_DEBUG_BLOCK in body:
|
if ATTR_DEBUG_BLOCK in body:
|
||||||
self.sys_config.debug_block = body[ATTR_DEBUG_BLOCK]
|
self.sys_config.debug_block = body[ATTR_DEBUG_BLOCK]
|
||||||
|
|
||||||
|
if ATTR_DIAGNOSTICS in body:
|
||||||
|
self.sys_config.diagnostics = body[ATTR_DIAGNOSTICS]
|
||||||
|
|
||||||
if ATTR_LOGGING in body:
|
if ATTR_LOGGING in body:
|
||||||
self.sys_config.logging = body[ATTR_LOGGING]
|
self.sys_config.logging = body[ATTR_LOGGING]
|
||||||
|
|
||||||
|
@ -6,6 +6,13 @@ import shutil
|
|||||||
import signal
|
import signal
|
||||||
|
|
||||||
from colorlog import ColoredFormatter
|
from colorlog import ColoredFormatter
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
|
||||||
|
from sentry_sdk.integrations.atexit import AtexitIntegration
|
||||||
|
from sentry_sdk.integrations.dedupe import DedupeIntegration
|
||||||
|
from sentry_sdk.integrations.excepthook import ExcepthookIntegration
|
||||||
|
from sentry_sdk.integrations.stdlib import StdlibIntegration
|
||||||
|
from sentry_sdk.integrations.threading import ThreadingIntegration
|
||||||
|
|
||||||
from .addons import AddonManager
|
from .addons import AddonManager
|
||||||
from .api import RestAPI
|
from .api import RestAPI
|
||||||
@ -17,6 +24,8 @@ from .const import (
|
|||||||
ENV_SUPERVISOR_NAME,
|
ENV_SUPERVISOR_NAME,
|
||||||
ENV_SUPERVISOR_SHARE,
|
ENV_SUPERVISOR_SHARE,
|
||||||
SOCKET_DOCKER,
|
SOCKET_DOCKER,
|
||||||
|
SUPERVISOR_VERSION,
|
||||||
|
CoreStates,
|
||||||
LogLevel,
|
LogLevel,
|
||||||
UpdateChannels,
|
UpdateChannels,
|
||||||
)
|
)
|
||||||
@ -73,6 +82,9 @@ async def initialize_coresys() -> CoreSys:
|
|||||||
coresys.secrets = SecretsManager(coresys)
|
coresys.secrets = SecretsManager(coresys)
|
||||||
coresys.scheduler = Scheduler(coresys)
|
coresys.scheduler = Scheduler(coresys)
|
||||||
|
|
||||||
|
# diagnostics
|
||||||
|
setup_diagnostics(coresys)
|
||||||
|
|
||||||
# bootstrap config
|
# bootstrap config
|
||||||
initialize_system_data(coresys)
|
initialize_system_data(coresys)
|
||||||
|
|
||||||
@ -270,3 +282,54 @@ def supervisor_debugger(coresys: CoreSys) -> None:
|
|||||||
if coresys.config.debug_block:
|
if coresys.config.debug_block:
|
||||||
_LOGGER.info("Wait until debugger is attached")
|
_LOGGER.info("Wait until debugger is attached")
|
||||||
ptvsd.wait_for_attach()
|
ptvsd.wait_for_attach()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_diagnostics(coresys: CoreSys) -> None:
|
||||||
|
"""Sentry diagnostic backend."""
|
||||||
|
|
||||||
|
def filter_data(event, hint):
|
||||||
|
# Ignore issue if system is not supported or diagnostics is disabled
|
||||||
|
if not coresys.config.diagnostics or not coresys.core.healthy:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Not full startup - missing information
|
||||||
|
if coresys.core.state in (CoreStates.INITIALIZE, CoreStates.SETUP):
|
||||||
|
return event
|
||||||
|
|
||||||
|
# Update information
|
||||||
|
with sentry_sdk.configure_scope() as scope:
|
||||||
|
scope.set_context(
|
||||||
|
"supervisor",
|
||||||
|
{
|
||||||
|
"machine": coresys.machine,
|
||||||
|
"arch": coresys.arch.default,
|
||||||
|
"docker": coresys.docker.info.version,
|
||||||
|
"channel": coresys.updater.channel,
|
||||||
|
"supervisor": coresys.supervisor.version,
|
||||||
|
"os": coresys.hassos.version,
|
||||||
|
"core": coresys.homeassistant.version,
|
||||||
|
"audio": coresys.plugins.audio.version,
|
||||||
|
"dns": coresys.plugins.dns.version,
|
||||||
|
"multicast": coresys.plugins.multicast.version,
|
||||||
|
"cli": coresys.plugins.cli.version,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return event
|
||||||
|
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn="https://9c6ea70f49234442b4746e447b24747e@o427061.ingest.sentry.io/5370612",
|
||||||
|
before_send=filter_data,
|
||||||
|
default_integrations=False,
|
||||||
|
integrations=[
|
||||||
|
AioHttpIntegration(),
|
||||||
|
AtexitIntegration(),
|
||||||
|
ExcepthookIntegration(),
|
||||||
|
DedupeIntegration(),
|
||||||
|
StdlibIntegration(),
|
||||||
|
ThreadingIntegration(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
with sentry_sdk.configure_scope() as scope:
|
||||||
|
scope.set_tag("version", SUPERVISOR_VERSION)
|
||||||
|
@ -3,12 +3,13 @@ from datetime import datetime
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
from typing import List
|
from typing import List, Optional
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_ADDONS_CUSTOM_LIST,
|
ATTR_ADDONS_CUSTOM_LIST,
|
||||||
ATTR_DEBUG,
|
ATTR_DEBUG,
|
||||||
ATTR_DEBUG_BLOCK,
|
ATTR_DEBUG_BLOCK,
|
||||||
|
ATTR_DIAGNOSTICS,
|
||||||
ATTR_LAST_BOOT,
|
ATTR_LAST_BOOT,
|
||||||
ATTR_LOGGING,
|
ATTR_LOGGING,
|
||||||
ATTR_TIMEZONE,
|
ATTR_TIMEZONE,
|
||||||
@ -101,6 +102,16 @@ class CoreConfig(JsonConfig):
|
|||||||
"""Set debug wait mode."""
|
"""Set debug wait mode."""
|
||||||
self._data[ATTR_DEBUG_BLOCK] = value
|
self._data[ATTR_DEBUG_BLOCK] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def diagnostics(self) -> Optional[bool]:
|
||||||
|
"""Return bool if diagnostics is set otherwise None."""
|
||||||
|
return self._data[ATTR_DIAGNOSTICS]
|
||||||
|
|
||||||
|
@diagnostics.setter
|
||||||
|
def diagnostics(self, value: bool) -> None:
|
||||||
|
"""Set diagnostics settings."""
|
||||||
|
self._data[ATTR_DIAGNOSTICS] = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def logging(self) -> LogLevel:
|
def logging(self) -> LogLevel:
|
||||||
"""Return log level of system."""
|
"""Return log level of system."""
|
||||||
|
@ -240,6 +240,7 @@ ATTR_INDEX = "index"
|
|||||||
ATTR_ACTIVE = "active"
|
ATTR_ACTIVE = "active"
|
||||||
ATTR_APPLICATION = "application"
|
ATTR_APPLICATION = "application"
|
||||||
ATTR_INIT = "init"
|
ATTR_INIT = "init"
|
||||||
|
ATTR_DIAGNOSTICS = "diagnostics"
|
||||||
|
|
||||||
PROVIDE_SERVICE = "provide"
|
PROVIDE_SERVICE = "provide"
|
||||||
NEED_SERVICE = "need"
|
NEED_SERVICE = "need"
|
||||||
@ -355,6 +356,7 @@ class CoreStates(str, Enum):
|
|||||||
"""Represent current loading state."""
|
"""Represent current loading state."""
|
||||||
|
|
||||||
INITIALIZE = "initialize"
|
INITIALIZE = "initialize"
|
||||||
|
SETUP = "setup"
|
||||||
STARTUP = "startup"
|
STARTUP = "startup"
|
||||||
RUNNING = "running"
|
RUNNING = "running"
|
||||||
FREEZE = "freeze"
|
FREEZE = "freeze"
|
||||||
|
@ -55,7 +55,7 @@ class Core(CoreSysAttributes):
|
|||||||
|
|
||||||
async def setup(self):
|
async def setup(self):
|
||||||
"""Start setting up supervisor orchestration."""
|
"""Start setting up supervisor orchestration."""
|
||||||
self.state = CoreStates.STARTUP
|
self.state = CoreStates.SETUP
|
||||||
|
|
||||||
# Load DBus
|
# Load DBus
|
||||||
await self.sys_dbus.load()
|
await self.sys_dbus.load()
|
||||||
@ -104,6 +104,7 @@ class Core(CoreSysAttributes):
|
|||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
"""Start Supervisor orchestration."""
|
"""Start Supervisor orchestration."""
|
||||||
|
self.state = CoreStates.STARTUP
|
||||||
await self.sys_api.start()
|
await self.sys_api.start()
|
||||||
|
|
||||||
# Mark booted partition as healthy
|
# Mark booted partition as healthy
|
||||||
|
@ -18,6 +18,7 @@ from .const import (
|
|||||||
ATTR_CLI,
|
ATTR_CLI,
|
||||||
ATTR_DEBUG,
|
ATTR_DEBUG,
|
||||||
ATTR_DEBUG_BLOCK,
|
ATTR_DEBUG_BLOCK,
|
||||||
|
ATTR_DIAGNOSTICS,
|
||||||
ATTR_DNS,
|
ATTR_DNS,
|
||||||
ATTR_HASSOS,
|
ATTR_HASSOS,
|
||||||
ATTR_HOMEASSISTANT,
|
ATTR_HOMEASSISTANT,
|
||||||
@ -176,6 +177,7 @@ SCHEMA_SUPERVISOR_CONFIG = vol.Schema(
|
|||||||
vol.Optional(ATTR_LOGGING, default=LogLevel.INFO): vol.Coerce(LogLevel),
|
vol.Optional(ATTR_LOGGING, default=LogLevel.INFO): vol.Coerce(LogLevel),
|
||||||
vol.Optional(ATTR_DEBUG, default=False): vol.Boolean(),
|
vol.Optional(ATTR_DEBUG, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_DEBUG_BLOCK, default=False): vol.Boolean(),
|
vol.Optional(ATTR_DEBUG_BLOCK, default=False): vol.Boolean(),
|
||||||
|
vol.Optional(ATTR_DIAGNOSTICS, default=None): vol.Maybe(vol.Boolean()),
|
||||||
},
|
},
|
||||||
extra=vol.REMOVE_EXTRA,
|
extra=vol.REMOVE_EXTRA,
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,8 @@ def docker():
|
|||||||
async def coresys(loop, docker):
|
async def coresys(loop, docker):
|
||||||
"""Create a CoreSys Mock."""
|
"""Create a CoreSys Mock."""
|
||||||
with patch("supervisor.bootstrap.initialize_system_data"), patch(
|
with patch("supervisor.bootstrap.initialize_system_data"), patch(
|
||||||
|
"supervisor.bootstrap.setup_diagnostics"
|
||||||
|
), patch(
|
||||||
"supervisor.bootstrap.fetch_timezone", return_value="Europe/Zurich",
|
"supervisor.bootstrap.fetch_timezone", return_value="Europe/Zurich",
|
||||||
):
|
):
|
||||||
coresys_obj = await initialize_coresys()
|
coresys_obj = await initialize_coresys()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user