Add the ability to enable debug logs in the config entry overflow (#14319)

This commit is contained in:
J. Nick Koston 2022-12-01 05:53:41 -10:00 committed by GitHub
parent b97a9ef311
commit 44502d2c8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 156 additions and 2 deletions

View File

@ -1,5 +1,7 @@
import { Connection, createCollection } from "home-assistant-js-websocket";
import { LocalizeFunc } from "../common/translations/localize";
import { HomeAssistant } from "../types";
import { debounce } from "../common/util/debounce";
export type IntegrationType =
| "device"
@ -23,6 +25,7 @@ export interface IntegrationManifest {
zeroconf?: string[];
homekit?: { models: string[] };
integration_type?: IntegrationType;
loggers?: string[];
quality_scale?: "gold" | "internal" | "platinum" | "silver";
iot_class:
| "assumed_state"
@ -36,6 +39,24 @@ export interface IntegrationSetup {
seconds?: number;
}
export interface IntegrationLogInfo {
domain: string;
level?: number;
}
export enum LogSeverity {
CRITICAL = 50,
FATAL = 50,
ERROR = 40,
WARNING = 30,
WARN = 30,
INFO = 20,
DEBUG = 10,
NOTSET = 0,
}
export type IntegrationLogPersistance = "none" | "once" | "permanent";
export const integrationIssuesUrl = (
domain: string,
manifest: IntegrationManifest
@ -69,3 +90,46 @@ export const fetchIntegrationManifest = (
export const fetchIntegrationSetups = (hass: HomeAssistant) =>
hass.callWS<IntegrationSetup[]>({ type: "integration/setup_info" });
export const fetchIntegrationLogInfo = (conn) =>
conn.sendMessagePromise({
type: "logger/log_info",
});
export const setIntegrationLogLevel = (
hass: HomeAssistant,
integration: string,
level: string,
persistence: IntegrationLogPersistance
) =>
hass.callWS({
type: "logger/integration_log_level",
integration,
level,
persistence,
});
const subscribeLogInfoUpdates = (conn, store) =>
conn.subscribeEvents(
debounce(
() =>
fetchIntegrationLogInfo(conn).then((log_infos) =>
store.setState(log_infos, true)
),
200,
true
),
"logging_changed"
);
export const subscribeLogInfo = (
conn: Connection,
onChange: (devices: IntegrationLogInfo[]) => void
) =>
createCollection<IntegrationLogInfo[]>(
"_integration_log_info",
fetchIntegrationLogInfo,
subscribeLogInfoUpdates,
conn,
onChange
);

View File

@ -51,6 +51,8 @@ import {
fetchIntegrationManifest,
fetchIntegrationManifests,
IntegrationManifest,
IntegrationLogInfo,
subscribeLogInfo,
} from "../../../data/integration";
import {
getIntegrationDescriptions,
@ -154,6 +156,10 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
@state() private _diagnosticHandlers?: Record<string, boolean>;
@state() private _logInfos?: {
[integration: string]: IntegrationLogInfo;
};
public hassSubscribe(): Array<UnsubscribeFunc | Promise<UnsubscribeFunc>> {
return [
subscribeEntityRegistry(this.hass.connection, (entries) => {
@ -230,6 +236,13 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
},
{ type: ["device", "hub", "service"] }
),
subscribeLogInfo(this.hass.connection, (log_infos) => {
const logInfoLookup: { [integration: string]: IntegrationLogInfo } = {};
for (const log_info of log_infos) {
logInfoLookup[log_info.domain] = log_info;
}
this._logInfos = logInfoLookup;
}),
];
}
@ -514,6 +527,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
.supportsDiagnostics=${this._diagnosticHandlers
? this._diagnosticHandlers[domain]
: false}
.logInfo=${this._logInfos ? this._logInfos[domain] : null}
></ha-integration-card>`
)
: this._filter &&

View File

@ -5,6 +5,8 @@ import {
mdiAlertCircle,
mdiBookshelf,
mdiBug,
mdiBugPlay,
mdiBugStop,
mdiChevronLeft,
mdiCog,
mdiDelete,
@ -47,11 +49,17 @@ import {
ERROR_STATES,
RECOVERABLE_STATES,
} from "../../../data/config_entries";
import { getErrorLogDownloadUrl } from "../../../data/error_log";
import type { DeviceRegistryEntry } from "../../../data/device_registry";
import { getConfigEntryDiagnosticsDownloadUrl } from "../../../data/diagnostics";
import type { EntityRegistryEntry } from "../../../data/entity_registry";
import type { IntegrationManifest } from "../../../data/integration";
import { integrationIssuesUrl } from "../../../data/integration";
import {
integrationIssuesUrl,
IntegrationLogInfo,
LogSeverity,
setIntegrationLogLevel,
} from "../../../data/integration";
import { showConfigEntrySystemOptionsDialog } from "../../../dialogs/config-entry-system-options/show-dialog-config-entry-system-options";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
import {
@ -95,6 +103,8 @@ export class HaIntegrationCard extends LitElement {
@property({ type: Boolean }) public supportsDiagnostics = false;
@property() public logInfo?: IntegrationLogInfo;
protected render(): TemplateResult {
let item = this._selectededConfigEntry;
@ -137,6 +147,8 @@ export class HaIntegrationCard extends LitElement {
.localizedDomainName=${item ? item.localized_domain_name : undefined}
.manifest=${this.manifest}
.configEntry=${item}
.debugLoggingEnabled=${this.logInfo &&
this.logInfo.level === LogSeverity.DEBUG}
>
${this.items.length > 1
? html`
@ -398,6 +410,28 @@ export class HaIntegrationCard extends LitElement {
</mwc-list-item>
</a>`
: ""}
${this.logInfo
? html`<mwc-list-item
@request-selected=${this.logInfo.level === LogSeverity.DEBUG
? this._handleDisableDebugLogging
: this._handleEnableDebugLogging}
graphic="icon"
>
${this.logInfo.level === LogSeverity.DEBUG
? this.hass.localize(
"ui.panel.config.integrations.config_entry.disable_debug_logging"
)
: this.hass.localize(
"ui.panel.config.integrations.config_entry.enable_debug_logging"
)}
<ha-svg-icon
slot="graphic"
.path=${this.logInfo.level === LogSeverity.DEBUG
? mdiBugStop
: mdiBugPlay}
></ha-svg-icon>
</mwc-list-item>`
: ""}
${this.manifest &&
(this.manifest.is_built_in ||
this.manifest.issue_tracker ||
@ -501,6 +535,34 @@ export class HaIntegrationCard extends LitElement {
`;
}
private async _handleEnableDebugLogging(ev: MouseEvent) {
const configEntry = ((ev.target as HTMLElement).closest("ha-card") as any)
.configEntry;
const integration = configEntry.domain;
await setIntegrationLogLevel(
this.hass,
integration,
LogSeverity[LogSeverity.DEBUG],
"once"
);
}
private async _handleDisableDebugLogging(ev: MouseEvent) {
const configEntry = ((ev.target as HTMLElement).closest("ha-card") as any)
.configEntry;
const integration = configEntry.domain;
await setIntegrationLogLevel(
this.hass,
integration,
LogSeverity[LogSeverity.NOTSET],
"once"
);
const timeString = new Date().toISOString().replace(/:/g, "-");
const logFileName = `home-assistant_${integration}_${timeString}.log`;
const signedUrl = await getSignedPath(this.hass, getErrorLogDownloadUrl);
fileDownload(signedUrl.path, logFileName);
}
private get _selectededConfigEntry(): ConfigEntryExtended | undefined {
return this.items.length === 1
? this.items[0]

View File

@ -1,4 +1,4 @@
import { mdiCloud, mdiPackageVariant, mdiSyncOff } from "@mdi/js";
import { mdiBugPlay, mdiCloud, mdiPackageVariant, mdiSyncOff } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
@ -24,6 +24,8 @@ export class HaIntegrationHeader extends LitElement {
@property({ attribute: false }) public configEntry?: ConfigEntry;
@property({ attribute: false }) public debugLoggingEnabled?: boolean;
protected render(): TemplateResult {
let primary: string;
let secondary: string | undefined;
@ -76,6 +78,15 @@ export class HaIntegrationHeader extends LitElement {
}
}
if (this.debugLoggingEnabled) {
icons.push([
mdiBugPlay,
this.hass.localize(
"ui.panel.config.integrations.config_entry.debug_logging_enabled"
),
]);
}
return html`
${!this.banner ? "" : html`<div class="banner">${this.banner}</div>`}
<slot name="above-header"></slot>

View File

@ -3011,10 +3011,12 @@
"system_options": "System options",
"documentation": "Documentation",
"download_diagnostics": "Download diagnostics",
"disable_debug_logging": "Disable debug logging",
"known_issues": "Known issues",
"delete": "Delete",
"delete_confirm_title": "Delete {title}?",
"delete_confirm_text": "Its devices and entities will be permanently deleted.",
"enable_debug_logging": "Enable debug logging",
"reload": "Reload",
"restart_confirm": "Restart Home Assistant to finish removing this integration",
"reload_confirm": "The integration was reloaded",
@ -3049,6 +3051,7 @@
"depends_on_cloud": "Depends on the cloud",
"yaml_only": "Needs manual configuration",
"disabled_polling": "Automatic polling for updated data disabled",
"debug_logging_enabled": "Debug logging enabled",
"state": {
"loaded": "Loaded",
"setup_error": "Failed to set up",