Skip to content

Commit 94c13f6

Browse files
Joel Griffithelasticmachine
andauthored
Reporting/diagnostics (#74314) (#77124)
* WIP: Adding in new reporting diag tool * WIP: chrome-binary test + log capturing/error handling * More wip on diagnostic tool * More work adding in diagnose routes * Alter link in description + minor rename of chrome => browser * Wiring UI to API + some polish on UI flow * WIP: Add in screenshot diag route * Adding in screenshot diag route, hooking up client to it * Add missing lib check + memory check * Working screenshot test + config check for RAM * Small test helper consolidation + screenshot diag test * Delete old i18n translations * PR feedback, browser tests, rename, re-organize import statements and lite fixes * Lite rename for consistency * Remove old validate check i18n * Add config check * i18n all the things! * Docs on diagnostics tool * Fixes, better readability, spelling and more for diagnostic tool * Translate a few error messages * Rename of test => start_logs for clarity. Move to observables * Gathering logs even during process exit or crash * Adds a test case for the browser exiting during the diag check * Tap into browser logs for checking output * Rename asciidoc diag id * Remove duplicate shared object message * Add better comment as to why we merge events + wait for a period of time * Cloning logger for mirroring browser stderr to kibana output Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent 9d69007 commit 94c13f6

32 files changed

+1295
-253
lines changed

docs/user/reporting/reporting-troubleshooting.asciidoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

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

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

19+
[float]
20+
[[reporting-diagnostics]]
21+
=== Reporting Diagnostics
22+
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.
23+
1824
[float]
1925
[[reporting-troubleshooting-system-dependencies]]
2026
=== System dependencies

x-pack/plugins/reporting/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const API_BASE_URL_V1 = '/api/reporting/v1'; //
1616
export const API_BASE_GENERATE_V1 = `${API_BASE_URL_V1}/generate`;
1717
export const API_LIST_URL = '/api/reporting/jobs';
1818
export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv/saved-object`;
19+
export const API_DIAGNOSE_URL = `${API_BASE_URL}/diagnose`;
1920

2021
export const CONTENT_TYPE_CSV = 'text/csv';
2122
export const CSV_REPORTING_ACTION = 'downloadCsvReport';
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { i18n } from '@kbn/i18n';
8+
import React, { useState, Fragment } from 'react';
9+
import { FormattedMessage } from '@kbn/i18n/react';
10+
import {
11+
EuiButton,
12+
EuiButtonEmpty,
13+
EuiCallOut,
14+
EuiCodeBlock,
15+
EuiFlyout,
16+
EuiFlyoutBody,
17+
EuiFlyoutHeader,
18+
EuiSpacer,
19+
EuiSteps,
20+
EuiText,
21+
EuiTitle,
22+
} from '@elastic/eui';
23+
import { ReportingAPIClient, DiagnoseResponse } from '../lib/reporting_api_client';
24+
25+
interface Props {
26+
apiClient: ReportingAPIClient;
27+
}
28+
29+
type ResultStatus = 'danger' | 'incomplete' | 'complete';
30+
31+
enum statuses {
32+
configStatus = 'configStatus',
33+
chromeStatus = 'chromeStatus',
34+
screenshotStatus = 'screenshotStatus',
35+
}
36+
37+
interface State {
38+
isFlyoutVisible: boolean;
39+
configStatus: ResultStatus;
40+
chromeStatus: ResultStatus;
41+
screenshotStatus: ResultStatus;
42+
help: string[];
43+
logs: string;
44+
isBusy: boolean;
45+
success: boolean;
46+
}
47+
48+
const initialState: State = {
49+
[statuses.configStatus]: 'incomplete',
50+
[statuses.chromeStatus]: 'incomplete',
51+
[statuses.screenshotStatus]: 'incomplete',
52+
isFlyoutVisible: false,
53+
help: [],
54+
logs: '',
55+
isBusy: false,
56+
success: true,
57+
};
58+
59+
export const ReportDiagnostic = ({ apiClient }: Props) => {
60+
const [state, setStateBase] = useState(initialState);
61+
const setState = (s: Partial<typeof state>) =>
62+
setStateBase({
63+
...state,
64+
...s,
65+
});
66+
const {
67+
configStatus,
68+
isBusy,
69+
screenshotStatus,
70+
chromeStatus,
71+
isFlyoutVisible,
72+
help,
73+
logs,
74+
success,
75+
} = state;
76+
77+
const closeFlyout = () => setState({ ...initialState, isFlyoutVisible: false });
78+
const showFlyout = () => setState({ isFlyoutVisible: true });
79+
const apiWrapper = (apiMethod: () => Promise<DiagnoseResponse>, statusProp: statuses) => () => {
80+
setState({ isBusy: true, [statusProp]: 'incomplete' });
81+
apiMethod()
82+
.then((response) => {
83+
setState({
84+
isBusy: false,
85+
help: response.help,
86+
logs: response.logs,
87+
success: response.success,
88+
[statusProp]: response.success ? 'complete' : 'danger',
89+
});
90+
})
91+
.catch((error) => {
92+
setState({
93+
isBusy: false,
94+
help: [
95+
i18n.translate('xpack.reporting.listing.diagnosticApiCallFailure', {
96+
defaultMessage: `There was a problem running the diagnostic: {error}`,
97+
values: { error },
98+
}),
99+
],
100+
logs: `${error.message}`,
101+
success: false,
102+
[statusProp]: 'danger',
103+
});
104+
});
105+
};
106+
107+
const steps = [
108+
{
109+
title: i18n.translate('xpack.reporting.listing.diagnosticConfigTitle', {
110+
defaultMessage: 'Verify Kibana Configuration',
111+
}),
112+
children: (
113+
<Fragment>
114+
<FormattedMessage
115+
id="xpack.reporting.listing.diagnosticConfigMessage"
116+
defaultMessage="This check ensures your Kibana configuration is setup properly for reports."
117+
/>
118+
<EuiSpacer />
119+
<EuiButton
120+
disabled={isBusy || configStatus === 'complete'}
121+
isLoading={isBusy && configStatus === 'incomplete'}
122+
onClick={apiWrapper(apiClient.verifyConfig, statuses.configStatus)}
123+
iconType={configStatus === 'complete' ? 'check' : undefined}
124+
>
125+
<FormattedMessage
126+
id="xpack.reporting.listing.diagnosticConfigButton"
127+
defaultMessage="Verify Configuration"
128+
/>
129+
</EuiButton>
130+
</Fragment>
131+
),
132+
status: !success && configStatus !== 'complete' ? 'danger' : configStatus,
133+
},
134+
];
135+
136+
if (configStatus === 'complete') {
137+
steps.push({
138+
title: i18n.translate('xpack.reporting.listing.diagnosticBrowserTitle', {
139+
defaultMessage: 'Check Browser',
140+
}),
141+
children: (
142+
<Fragment>
143+
<FormattedMessage
144+
id="xpack.reporting.listing.diagnosticBrowserMessage"
145+
defaultMessage="Reporting utilizes a headless browser to generate PDF and PNGS. This check validates
146+
that the browser can launch successfully."
147+
/>
148+
<EuiSpacer />
149+
<EuiButton
150+
disabled={isBusy || chromeStatus === 'complete'}
151+
onClick={apiWrapper(apiClient.verifyBrowser, statuses.chromeStatus)}
152+
isLoading={isBusy && chromeStatus === 'incomplete'}
153+
iconType={chromeStatus === 'complete' ? 'check' : undefined}
154+
>
155+
<FormattedMessage
156+
id="xpack.reporting.listing.diagnosticBrowserButton"
157+
defaultMessage="Check Browser"
158+
/>
159+
</EuiButton>
160+
</Fragment>
161+
),
162+
status: !success && chromeStatus !== 'complete' ? 'danger' : chromeStatus,
163+
});
164+
}
165+
166+
if (chromeStatus === 'complete') {
167+
steps.push({
168+
title: i18n.translate('xpack.reporting.listing.diagnosticScreenshotTitle', {
169+
defaultMessage: 'Check Screen Capture Capabilities',
170+
}),
171+
children: (
172+
<Fragment>
173+
<FormattedMessage
174+
id="xpack.reporting.listing.diagnosticScreenshotMessage"
175+
defaultMessage="This check ensures the headless browser can capture a screenshot of a page."
176+
/>
177+
<EuiSpacer />
178+
<EuiButton
179+
disabled={isBusy || screenshotStatus === 'complete'}
180+
onClick={apiWrapper(apiClient.verifyScreenCapture, statuses.screenshotStatus)}
181+
isLoading={isBusy && screenshotStatus === 'incomplete'}
182+
iconType={screenshotStatus === 'complete' ? 'check' : undefined}
183+
>
184+
<FormattedMessage
185+
id="xpack.reporting.listing.diagnosticScreenshotButton"
186+
defaultMessage="Capture Screenshot"
187+
/>
188+
</EuiButton>
189+
</Fragment>
190+
),
191+
status: !success && screenshotStatus !== 'complete' ? 'danger' : screenshotStatus,
192+
});
193+
}
194+
195+
if (screenshotStatus === 'complete') {
196+
steps.push({
197+
title: i18n.translate('xpack.reporting.listing.diagnosticSuccessTitle', {
198+
defaultMessage: 'All set!',
199+
}),
200+
children: (
201+
<Fragment>
202+
<FormattedMessage
203+
id="xpack.reporting.listing.diagnosticSuccessMessage"
204+
defaultMessage="Excellent! Everything looks like shipshape for reporting to function!"
205+
/>
206+
</Fragment>
207+
),
208+
status: !success ? 'danger' : screenshotStatus,
209+
});
210+
}
211+
212+
if (!success) {
213+
steps.push({
214+
title: i18n.translate('xpack.reporting.listing.diagnosticFailureTitle', {
215+
defaultMessage: "Whoops! Looks like something isn't working properly.",
216+
}),
217+
children: (
218+
<Fragment>
219+
{help.length ? (
220+
<Fragment>
221+
<EuiCallOut color="danger" iconType="alert">
222+
<p>{help.join('\n')}</p>
223+
</EuiCallOut>
224+
</Fragment>
225+
) : null}
226+
{logs.length ? (
227+
<Fragment>
228+
<EuiSpacer />
229+
<FormattedMessage
230+
id="xpack.reporting.listing.diagnosticFailureDescription"
231+
defaultMessage="Here are some more details about the issue:"
232+
/>
233+
<EuiSpacer />
234+
<EuiCodeBlock>{logs}</EuiCodeBlock>
235+
</Fragment>
236+
) : null}
237+
</Fragment>
238+
),
239+
status: 'danger',
240+
});
241+
}
242+
243+
let flyout;
244+
if (isFlyoutVisible) {
245+
flyout = (
246+
<EuiFlyout onClose={closeFlyout} aria-labelledby="reportingHelperTitle" size="m">
247+
<EuiFlyoutHeader hasBorder>
248+
<EuiTitle size="m">
249+
<h2>
250+
<FormattedMessage
251+
id="xpack.reporting.listing.diagnosticTitle"
252+
defaultMessage="Reporting Diagnostics"
253+
/>
254+
</h2>
255+
</EuiTitle>
256+
<EuiSpacer size="s" />
257+
<EuiText color="subdued">
258+
<FormattedMessage
259+
id="xpack.reporting.listing.diagnosticDescription"
260+
defaultMessage="Automatically run a series of diagnostics to troubleshoot common reporting problems."
261+
/>
262+
</EuiText>
263+
</EuiFlyoutHeader>
264+
<EuiFlyoutBody>
265+
<EuiSteps steps={steps} />
266+
</EuiFlyoutBody>
267+
</EuiFlyout>
268+
);
269+
}
270+
return (
271+
<div>
272+
{flyout}
273+
<EuiButtonEmpty size="xs" flush="left" onClick={showFlyout}>
274+
<FormattedMessage
275+
id="xpack.reporting.listing.diagnosticButton"
276+
defaultMessage="Run reporting diagnostics..."
277+
/>
278+
</EuiButtonEmpty>
279+
</div>
280+
);
281+
};

x-pack/plugins/reporting/public/components/report_listing.tsx

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import {
88
EuiBasicTable,
9+
EuiFlexItem,
10+
EuiFlexGroup,
911
EuiPageContent,
1012
EuiSpacer,
1113
EuiText,
@@ -31,6 +33,7 @@ import {
3133
ReportErrorButton,
3234
ReportInfoButton,
3335
} from './buttons';
36+
import { ReportDiagnostic } from './report_diagnostic';
3437

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

135138
public render() {
136139
return (
137-
<EuiPageContent horizontalPosition="center" className="euiPageBody--restrictWidth-default">
138-
<EuiTitle>
139-
<h1>
140-
<FormattedMessage id="xpack.reporting.listing.reportstitle" defaultMessage="Reports" />
141-
</h1>
142-
</EuiTitle>
143-
<EuiText color="subdued" size="s">
144-
<p>
145-
<FormattedMessage
146-
id="xpack.reporting.listing.reports.subtitle"
147-
defaultMessage="Find reports generated in Kibana applications here"
148-
/>
149-
</p>
150-
</EuiText>
151-
<EuiSpacer />
152-
{this.renderTable()}
153-
</EuiPageContent>
140+
<div>
141+
<EuiPageContent horizontalPosition="center" className="euiPageBody--restrictWidth-default">
142+
<EuiFlexGroup justifyContent="spaceBetween">
143+
<EuiFlexItem grow={false}>
144+
<EuiTitle>
145+
<h1>
146+
<FormattedMessage
147+
id="xpack.reporting.listing.reportstitle"
148+
defaultMessage="Reports"
149+
/>
150+
</h1>
151+
</EuiTitle>
152+
<EuiText color="subdued" size="s">
153+
<p>
154+
<FormattedMessage
155+
id="xpack.reporting.listing.reports.subtitle"
156+
defaultMessage="Find reports generated in Kibana applications here"
157+
/>
158+
</p>
159+
</EuiText>
160+
</EuiFlexItem>
161+
</EuiFlexGroup>
162+
<EuiSpacer />
163+
{this.renderTable()}
164+
</EuiPageContent>
165+
<EuiSpacer size="s" />
166+
<EuiFlexGroup justifyContent="spaceBetween" direction="rowReverse">
167+
<EuiFlexItem grow={false}>
168+
<ReportDiagnostic apiClient={this.props.apiClient} />
169+
</EuiFlexItem>
170+
</EuiFlexGroup>
171+
</div>
154172
);
155173
}
156174

0 commit comments

Comments
 (0)