mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add the ability to enable debug logs in the config entry overflow (#14319)
This commit is contained in:
parent
b97a9ef311
commit
44502d2c8d
@ -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
|
||||
);
|
||||
|
@ -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 &&
|
||||
|
@ -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]
|
||||
|
@ -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>
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user