Skip to content

Commit

Permalink
reporting diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan committed Sep 9, 2020
1 parent 791a73c commit f456331
Show file tree
Hide file tree
Showing 32 changed files with 1,287 additions and 253 deletions.
6 changes: 6 additions & 0 deletions docs/user/reporting/reporting-troubleshooting.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

Having trouble? Here are solutions to common problems you might encounter while using Reporting.

* <<reporting-diagnostics>>
* <<reporting-troubleshooting-system-dependencies>>
* <<reporting-troubleshooting-text-incorrect>>
* <<reporting-troubleshooting-missing-data>>
Expand All @@ -15,6 +16,11 @@ Having trouble? Here are solutions to common problems you might encounter while
* <<reporting-troubleshooting-puppeteer-debug-logs>>
* <<reporting-troubleshooting-system-requirements>>

[float]
[[reporting-diagnostics]]
=== Reporting Diagnostics
Reporting comes with a built-in utility to try to automatically find common issues. When Kibana is running, navigate to the Report Listing page, and click the "Run reporting diagnostics..." button. This will open up a diagnostic tool that checks various parts of the Kibana deployment to come up with any relevant recommendations.

[float]
[[reporting-troubleshooting-system-dependencies]]
=== System dependencies
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/reporting/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const API_BASE_URL_V1 = '/api/reporting/v1'; //
export const API_BASE_GENERATE_V1 = `${API_BASE_URL_V1}/generate`;
export const API_LIST_URL = '/api/reporting/jobs';
export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv/saved-object`;
export const API_DIAGNOSE_URL = `${API_BASE_URL}/diagnose`;

export const CONTENT_TYPE_CSV = 'text/csv';
export const CSV_REPORTING_ACTION = 'downloadCsvReport';
Expand Down
281 changes: 281 additions & 0 deletions x-pack/plugins/reporting/public/components/report_diagnostic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';
import React, { useState, Fragment } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiButton,
EuiButtonEmpty,
EuiCallOut,
EuiCodeBlock,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader,
EuiSpacer,
EuiSteps,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { ReportingAPIClient, DiagnoseResponse } from '../lib/reporting_api_client';

interface Props {
apiClient: ReportingAPIClient;
}

type ResultStatus = 'danger' | 'incomplete' | 'complete';

enum statuses {
configStatus = 'configStatus',
chromeStatus = 'chromeStatus',
screenshotStatus = 'screenshotStatus',
}

interface State {
isFlyoutVisible: boolean;
configStatus: ResultStatus;
chromeStatus: ResultStatus;
screenshotStatus: ResultStatus;
help: string[];
logs: string;
isBusy: boolean;
success: boolean;
}

const initialState: State = {
[statuses.configStatus]: 'incomplete',
[statuses.chromeStatus]: 'incomplete',
[statuses.screenshotStatus]: 'incomplete',
isFlyoutVisible: false,
help: [],
logs: '',
isBusy: false,
success: true,
};

export const ReportDiagnostic = ({ apiClient }: Props) => {
const [state, setStateBase] = useState(initialState);
const setState = (s: Partial<typeof state>) =>
setStateBase({
...state,
...s,
});
const {
configStatus,
isBusy,
screenshotStatus,
chromeStatus,
isFlyoutVisible,
help,
logs,
success,
} = state;

const closeFlyout = () => setState({ ...initialState, isFlyoutVisible: false });
const showFlyout = () => setState({ isFlyoutVisible: true });
const apiWrapper = (apiMethod: () => Promise<DiagnoseResponse>, statusProp: statuses) => () => {
setState({ isBusy: true, [statusProp]: 'incomplete' });
apiMethod()
.then((response) => {
setState({
isBusy: false,
help: response.help,
logs: response.logs,
success: response.success,
[statusProp]: response.success ? 'complete' : 'danger',
});
})
.catch((error) => {
setState({
isBusy: false,
help: [
i18n.translate('xpack.reporting.listing.diagnosticApiCallFailure', {
defaultMessage: `There was a problem running the diagnostic: {error}`,
values: { error },
}),
],
logs: `${error.message}`,
success: false,
[statusProp]: 'danger',
});
});
};

const steps = [
{
title: i18n.translate('xpack.reporting.listing.diagnosticConfigTitle', {
defaultMessage: 'Verify Kibana Configuration',
}),
children: (
<Fragment>
<FormattedMessage
id="xpack.reporting.listing.diagnosticConfigMessage"
defaultMessage="This check ensures your Kibana configuration is setup properly for reports."
/>
<EuiSpacer />
<EuiButton
disabled={isBusy || configStatus === 'complete'}
isLoading={isBusy && configStatus === 'incomplete'}
onClick={apiWrapper(apiClient.verifyConfig, statuses.configStatus)}
iconType={configStatus === 'complete' ? 'check' : undefined}
>
<FormattedMessage
id="xpack.reporting.listing.diagnosticConfigButton"
defaultMessage="Verify Configuration"
/>
</EuiButton>
</Fragment>
),
status: !success && configStatus !== 'complete' ? 'danger' : configStatus,
},
];

if (configStatus === 'complete') {
steps.push({
title: i18n.translate('xpack.reporting.listing.diagnosticBrowserTitle', {
defaultMessage: 'Check Browser',
}),
children: (
<Fragment>
<FormattedMessage
id="xpack.reporting.listing.diagnosticBrowserMessage"
defaultMessage="Reporting utilizes a headless browser to generate PDF and PNGS. This check validates
that the browser can launch successfully."
/>
<EuiSpacer />
<EuiButton
disabled={isBusy || chromeStatus === 'complete'}
onClick={apiWrapper(apiClient.verifyBrowser, statuses.chromeStatus)}
isLoading={isBusy && chromeStatus === 'incomplete'}
iconType={chromeStatus === 'complete' ? 'check' : undefined}
>
<FormattedMessage
id="xpack.reporting.listing.diagnosticBrowserButton"
defaultMessage="Check Browser"
/>
</EuiButton>
</Fragment>
),
status: !success && chromeStatus !== 'complete' ? 'danger' : chromeStatus,
});
}

if (chromeStatus === 'complete') {
steps.push({
title: i18n.translate('xpack.reporting.listing.diagnosticScreenshotTitle', {
defaultMessage: 'Check Screen Capture Capabilities',
}),
children: (
<Fragment>
<FormattedMessage
id="xpack.reporting.listing.diagnosticScreenshotMessage"
defaultMessage="This check ensures the headless browser can capture a screenshot of a page."
/>
<EuiSpacer />
<EuiButton
disabled={isBusy || screenshotStatus === 'complete'}
onClick={apiWrapper(apiClient.verifyScreenCapture, statuses.screenshotStatus)}
isLoading={isBusy && screenshotStatus === 'incomplete'}
iconType={screenshotStatus === 'complete' ? 'check' : undefined}
>
<FormattedMessage
id="xpack.reporting.listing.diagnosticScreenshotButton"
defaultMessage="Capture Screenshot"
/>
</EuiButton>
</Fragment>
),
status: !success && screenshotStatus !== 'complete' ? 'danger' : screenshotStatus,
});
}

if (screenshotStatus === 'complete') {
steps.push({
title: i18n.translate('xpack.reporting.listing.diagnosticSuccessTitle', {
defaultMessage: 'All set!',
}),
children: (
<Fragment>
<FormattedMessage
id="xpack.reporting.listing.diagnosticSuccessMessage"
defaultMessage="Excellent! Everything looks like shipshape for reporting to function!"
/>
</Fragment>
),
status: !success ? 'danger' : screenshotStatus,
});
}

if (!success) {
steps.push({
title: i18n.translate('xpack.reporting.listing.diagnosticFailureTitle', {
defaultMessage: "Whoops! Looks like something isn't working properly.",
}),
children: (
<Fragment>
{help.length ? (
<Fragment>
<EuiCallOut color="danger" iconType="alert">
<p>{help.join('\n')}</p>
</EuiCallOut>
</Fragment>
) : null}
{logs.length ? (
<Fragment>
<EuiSpacer />
<FormattedMessage
id="xpack.reporting.listing.diagnosticFailureDescription"
defaultMessage="Here are some more details about the issue:"
/>
<EuiSpacer />
<EuiCodeBlock>{logs}</EuiCodeBlock>
</Fragment>
) : null}
</Fragment>
),
status: 'danger',
});
}

let flyout;
if (isFlyoutVisible) {
flyout = (
<EuiFlyout onClose={closeFlyout} aria-labelledby="reportingHelperTitle" size="m">
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<h2>
<FormattedMessage
id="xpack.reporting.listing.diagnosticTitle"
defaultMessage="Reporting Diagnostics"
/>
</h2>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText color="subdued">
<FormattedMessage
id="xpack.reporting.listing.diagnosticDescription"
defaultMessage="Automatically run a series of diagnostics to troubleshoot common reporting problems."
/>
</EuiText>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiSteps steps={steps} />
</EuiFlyoutBody>
</EuiFlyout>
);
}
return (
<div>
{flyout}
<EuiButtonEmpty size="xs" flush="left" onClick={showFlyout}>
<FormattedMessage
id="xpack.reporting.listing.diagnosticButton"
defaultMessage="Run reporting diagnostics..."
/>
</EuiButtonEmpty>
</div>
);
};
52 changes: 35 additions & 17 deletions x-pack/plugins/reporting/public/components/report_listing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import {
EuiBasicTable,
EuiFlexItem,
EuiFlexGroup,
EuiPageContent,
EuiSpacer,
EuiText,
Expand All @@ -31,6 +33,7 @@ import {
ReportErrorButton,
ReportInfoButton,
} from './buttons';
import { ReportDiagnostic } from './report_diagnostic';

export interface Job {
id: string;
Expand Down Expand Up @@ -134,23 +137,38 @@ class ReportListingUi extends Component<Props, State> {

public render() {
return (
<EuiPageContent horizontalPosition="center" className="euiPageBody--restrictWidth-default">
<EuiTitle>
<h1>
<FormattedMessage id="xpack.reporting.listing.reportstitle" defaultMessage="Reports" />
</h1>
</EuiTitle>
<EuiText color="subdued" size="s">
<p>
<FormattedMessage
id="xpack.reporting.listing.reports.subtitle"
defaultMessage="Find reports generated in Kibana applications here"
/>
</p>
</EuiText>
<EuiSpacer />
{this.renderTable()}
</EuiPageContent>
<div>
<EuiPageContent horizontalPosition="center" className="euiPageBody--restrictWidth-default">
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiTitle>
<h1>
<FormattedMessage
id="xpack.reporting.listing.reportstitle"
defaultMessage="Reports"
/>
</h1>
</EuiTitle>
<EuiText color="subdued" size="s">
<p>
<FormattedMessage
id="xpack.reporting.listing.reports.subtitle"
defaultMessage="Find reports generated in Kibana applications here"
/>
</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
{this.renderTable()}
</EuiPageContent>
<EuiSpacer size="s" />
<EuiFlexGroup justifyContent="spaceBetween" direction="rowReverse">
<EuiFlexItem grow={false}>
<ReportDiagnostic apiClient={this.props.apiClient} />
</EuiFlexItem>
</EuiFlexGroup>
</div>
);
}

Expand Down
Loading

0 comments on commit f456331

Please sign in to comment.