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:
Pascal Vizeli 2020-08-05 14:54:03 +02:00 committed by GitHub
parent 6599ae0ee0
commit ad988f2a24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 2 deletions

1
API.md
View File

@ -47,6 +47,7 @@ The addons from `addons` are only installed one.
"wait_boot": "int",
"debug": "bool",
"debug_block": "bool",
"diagnostics": "None|bool",
"addons": [
{
"name": "xy bla",

View File

@ -14,5 +14,6 @@ pulsectl==20.5.1
pytz==2020.1
pyudev==0.22.0
ruamel.yaml==0.15.100
sentry-sdk==0.16.3
uvloop==0.14.0
voluptuous==0.11.7

View File

@ -17,6 +17,7 @@ from ..const import (
ATTR_DEBUG,
ATTR_DEBUG_BLOCK,
ATTR_DESCRIPTON,
ATTR_DIAGNOSTICS,
ATTR_ICON,
ATTR_INSTALLED,
ATTR_IP_ADDRESS,
@ -58,6 +59,7 @@ SCHEMA_OPTIONS = vol.Schema(
vol.Optional(ATTR_LOGGING): vol.Coerce(LogLevel),
vol.Optional(ATTR_DEBUG): 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_DEBUG: self.sys_config.debug,
ATTR_DEBUG_BLOCK: self.sys_config.debug_block,
ATTR_DIAGNOSTICS: self.sys_config.diagnostics,
ATTR_ADDONS: list_addons,
ATTR_ADDONS_REPOSITORIES: self.sys_config.addons_repositories,
}
@ -126,6 +129,9 @@ class APISupervisor(CoreSysAttributes):
if ATTR_DEBUG_BLOCK in body:
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:
self.sys_config.logging = body[ATTR_LOGGING]

View File

@ -6,6 +6,13 @@ import shutil
import signal
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 .api import RestAPI
@ -17,6 +24,8 @@ from .const import (
ENV_SUPERVISOR_NAME,
ENV_SUPERVISOR_SHARE,
SOCKET_DOCKER,
SUPERVISOR_VERSION,
CoreStates,
LogLevel,
UpdateChannels,
)
@ -73,6 +82,9 @@ async def initialize_coresys() -> CoreSys:
coresys.secrets = SecretsManager(coresys)
coresys.scheduler = Scheduler(coresys)
# diagnostics
setup_diagnostics(coresys)
# bootstrap config
initialize_system_data(coresys)
@ -270,3 +282,54 @@ def supervisor_debugger(coresys: CoreSys) -> None:
if coresys.config.debug_block:
_LOGGER.info("Wait until debugger is attached")
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)

View File

@ -3,12 +3,13 @@ from datetime import datetime
import logging
import os
from pathlib import Path, PurePath
from typing import List
from typing import List, Optional
from .const import (
ATTR_ADDONS_CUSTOM_LIST,
ATTR_DEBUG,
ATTR_DEBUG_BLOCK,
ATTR_DIAGNOSTICS,
ATTR_LAST_BOOT,
ATTR_LOGGING,
ATTR_TIMEZONE,
@ -101,6 +102,16 @@ class CoreConfig(JsonConfig):
"""Set debug wait mode."""
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
def logging(self) -> LogLevel:
"""Return log level of system."""

View File

@ -240,6 +240,7 @@ ATTR_INDEX = "index"
ATTR_ACTIVE = "active"
ATTR_APPLICATION = "application"
ATTR_INIT = "init"
ATTR_DIAGNOSTICS = "diagnostics"
PROVIDE_SERVICE = "provide"
NEED_SERVICE = "need"
@ -355,6 +356,7 @@ class CoreStates(str, Enum):
"""Represent current loading state."""
INITIALIZE = "initialize"
SETUP = "setup"
STARTUP = "startup"
RUNNING = "running"
FREEZE = "freeze"

View File

@ -55,7 +55,7 @@ class Core(CoreSysAttributes):
async def setup(self):
"""Start setting up supervisor orchestration."""
self.state = CoreStates.STARTUP
self.state = CoreStates.SETUP
# Load DBus
await self.sys_dbus.load()
@ -104,6 +104,7 @@ class Core(CoreSysAttributes):
async def start(self):
"""Start Supervisor orchestration."""
self.state = CoreStates.STARTUP
await self.sys_api.start()
# Mark booted partition as healthy

View File

@ -18,6 +18,7 @@ from .const import (
ATTR_CLI,
ATTR_DEBUG,
ATTR_DEBUG_BLOCK,
ATTR_DIAGNOSTICS,
ATTR_DNS,
ATTR_HASSOS,
ATTR_HOMEASSISTANT,
@ -176,6 +177,7 @@ SCHEMA_SUPERVISOR_CONFIG = vol.Schema(
vol.Optional(ATTR_LOGGING, default=LogLevel.INFO): vol.Coerce(LogLevel),
vol.Optional(ATTR_DEBUG, 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,
)

View File

@ -19,6 +19,8 @@ def docker():
async def coresys(loop, docker):
"""Create a CoreSys Mock."""
with patch("supervisor.bootstrap.initialize_system_data"), patch(
"supervisor.bootstrap.setup_diagnostics"
), patch(
"supervisor.bootstrap.fetch_timezone", return_value="Europe/Zurich",
):
coresys_obj = await initialize_coresys()