Skip to content

Commit 3162194

Browse files
authored
[Logs UI] Add "Analyze in ML" buttons (#48268)
1 parent 9f11d0d commit 3162194

File tree

7 files changed

+135
-15
lines changed

7 files changed

+135
-15
lines changed

x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_jobs.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import createContainer from 'constate-latest';
88
import { useMemo, useCallback, useEffect } from 'react';
99

1010
import { callGetMlModuleAPI } from './api/ml_get_module';
11-
import { bucketSpan } from '../../../../common/log_analysis';
11+
import { bucketSpan, getJobId } from '../../../../common/log_analysis';
1212
import { useTrackedPromise } from '../../../utils/use_tracked_promise';
1313
import { callJobsSummaryAPI } from './api/ml_get_jobs_summary_api';
1414
import { callSetupMlModuleAPI, SetupMlModuleResponsePayload } from './api/ml_setup_module_api';
@@ -138,6 +138,12 @@ export const useLogAnalysisJobs = ({
138138
fetchModuleDefinition();
139139
}, [fetchModuleDefinition]);
140140

141+
const jobIds = useMemo(() => {
142+
return {
143+
'log-entry-rate': getJobId(spaceId, sourceId, 'log-entry-rate'),
144+
};
145+
}, [sourceId, spaceId]);
146+
141147
return {
142148
fetchJobStatus,
143149
isLoadingSetupStatus,
@@ -149,6 +155,7 @@ export const useLogAnalysisJobs = ({
149155
viewSetupForReconfiguration,
150156
viewSetupForUpdate,
151157
viewResults,
158+
jobIds,
152159
};
153160
};
154161

x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import numeral from '@elastic/numeral';
1919
import { FormattedMessage } from '@kbn/i18n/react';
2020
import moment from 'moment';
2121
import React, { useCallback, useContext, useMemo, useState } from 'react';
22+
import euiStyled from '../../../../../../common/eui_styled_components';
2223
import { TimeRange } from '../../../../common/http_api/shared/time_range';
2324
import { bucketSpan } from '../../../../common/log_analysis';
24-
import euiStyled from '../../../../../../common/eui_styled_components';
2525
import { LoadingPage } from '../../../components/loading_page';
2626
import {
2727
LogAnalysisJobs,
@@ -134,6 +134,7 @@ export const AnalysisResultsContent = ({
134134
setupStatus,
135135
viewSetupForReconfiguration,
136136
viewSetupForUpdate,
137+
jobIds,
137138
} = useContext(LogAnalysisJobs.Context);
138139

139140
useInterval(() => {
@@ -214,6 +215,7 @@ export const AnalysisResultsContent = ({
214215
setTimeRange={handleChartTimeRangeChange}
215216
setupStatus={setupStatus}
216217
timeRange={queryTimeRange}
218+
jobId={jobIds['log-entry-rate']}
217219
/>
218220
</EuiPanel>
219221
</EuiFlexItem>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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 React from 'react';
8+
import url from 'url';
9+
import { EuiButton } from '@elastic/eui';
10+
import { FormattedMessage } from '@kbn/i18n/react';
11+
import chrome from 'ui/chrome';
12+
import { QueryString } from 'ui/utils/query_string';
13+
import { encode } from 'rison-node';
14+
import { TimeRange } from '../../../../../common/http_api/shared/time_range';
15+
16+
export const AnalyzeInMlButton: React.FunctionComponent<{
17+
jobId: string;
18+
partition?: string;
19+
timeRange: TimeRange;
20+
}> = ({ jobId, partition, timeRange }) => {
21+
const pathname = chrome.addBasePath('/app/ml');
22+
const buttonLabel = (
23+
<FormattedMessage
24+
id="xpack.infra.logs.analysis.analyzeInMlButtonLabel"
25+
defaultMessage="Analyze in ML"
26+
/>
27+
);
28+
return partition ? (
29+
<EuiButton
30+
fill={false}
31+
href={getPartitionSpecificSingleMetricViewerLink(pathname, jobId, partition, timeRange)}
32+
>
33+
{buttonLabel}
34+
</EuiButton>
35+
) : (
36+
<EuiButton fill={true} href={getOverallAnomalyExplorerLink(pathname, jobId, timeRange)}>
37+
{buttonLabel}
38+
</EuiButton>
39+
);
40+
};
41+
42+
const getOverallAnomalyExplorerLink = (pathname: string, jobId: string, timeRange: TimeRange) => {
43+
const { from, to } = convertTimeRangeToParams(timeRange);
44+
45+
const _g = encode({
46+
ml: {
47+
jobIds: [jobId],
48+
},
49+
time: {
50+
from,
51+
to,
52+
},
53+
});
54+
55+
const hash = `/explorer?${QueryString.encode({ _g })}`;
56+
57+
return url.format({
58+
pathname,
59+
hash,
60+
});
61+
};
62+
63+
const getPartitionSpecificSingleMetricViewerLink = (
64+
pathname: string,
65+
jobId: string,
66+
partition: string,
67+
timeRange: TimeRange
68+
) => {
69+
const { from, to } = convertTimeRangeToParams(timeRange);
70+
71+
const _g = encode({
72+
ml: {
73+
jobIds: [jobId],
74+
},
75+
time: {
76+
from,
77+
to,
78+
mode: 'absolute',
79+
},
80+
});
81+
82+
const _a = encode({
83+
mlTimeSeriesExplorer: {
84+
entities: { 'event.dataset': partition },
85+
},
86+
});
87+
88+
const hash = `/timeseriesexplorer?${QueryString.encode({ _g, _a })}`;
89+
90+
return url.format({
91+
pathname,
92+
hash,
93+
});
94+
};
95+
96+
const convertTimeRangeToParams = (timeRange: TimeRange): { from: string; to: string } => {
97+
return {
98+
from: new Date(timeRange.startTime).toISOString(),
99+
to: new Date(timeRange.endTime).toISOString(),
100+
};
101+
};

x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/expanded_row.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import React, { useMemo } from 'react';
88
import { i18n } from '@kbn/i18n';
99
import numeral from '@elastic/numeral';
10-
import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui';
10+
import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiSpacer } from '@elastic/eui';
1111
import { AnomaliesChart } from './chart';
1212
import { GetLogEntryRateSuccessResponsePayload } from '../../../../../../common/http_api/log_analysis/results/log_entry_rate';
1313
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';
@@ -17,14 +17,16 @@ import {
1717
formatAnomalyScore,
1818
getTotalNumberOfLogEntriesForPartition,
1919
} from '../helpers/data_formatters';
20+
import { AnalyzeInMlButton } from '../analyze_in_ml_button';
2021

2122
export const AnomaliesTableExpandedRow: React.FunctionComponent<{
2223
partitionId: string;
2324
topAnomalyScore: number;
2425
results: GetLogEntryRateSuccessResponsePayload['data'];
2526
setTimeRange: (timeRange: TimeRange) => void;
2627
timeRange: TimeRange;
27-
}> = ({ results, timeRange, setTimeRange, topAnomalyScore, partitionId }) => {
28+
jobId: string;
29+
}> = ({ results, timeRange, setTimeRange, topAnomalyScore, partitionId, jobId }) => {
2830
const logEntryRateSeries = useMemo(
2931
() =>
3032
results && results.histogramBuckets
@@ -83,6 +85,12 @@ export const AnomaliesTableExpandedRow: React.FunctionComponent<{
8385
)}
8486
reverse
8587
/>
88+
<EuiSpacer size="s" />
89+
<EuiFlexGroup>
90+
<EuiFlexItem grow={false}>
91+
<AnalyzeInMlButton jobId={jobId} timeRange={timeRange} partition={partitionId} />
92+
</EuiFlexItem>
93+
</EuiFlexGroup>
8694
</EuiFlexItem>
8795
</EuiFlexGroup>
8896
);

x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/index.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
import {
8-
EuiButton,
98
EuiEmptyPrompt,
109
EuiFlexGroup,
1110
EuiFlexItem,
@@ -16,7 +15,6 @@ import {
1615
} from '@elastic/eui';
1716
import numeral from '@elastic/numeral';
1817
import { i18n } from '@kbn/i18n';
19-
import { FormattedMessage } from '@kbn/i18n/react';
2018
import React, { useMemo } from 'react';
2119

2220
import euiStyled from '../../../../../../../../common/eui_styled_components';
@@ -32,6 +30,7 @@ import {
3230
import { AnomaliesChart } from './chart';
3331
import { AnomaliesTable } from './table';
3432
import { LogAnalysisJobProblemIndicator } from '../../../../../components/logging/log_analysis_job_status';
33+
import { AnalyzeInMlButton } from '../analyze_in_ml_button';
3534

3635
export const AnomaliesResults: React.FunctionComponent<{
3736
isLoading: boolean;
@@ -42,6 +41,7 @@ export const AnomaliesResults: React.FunctionComponent<{
4241
timeRange: TimeRange;
4342
viewSetupForReconfiguration: () => void;
4443
viewSetupForUpdate: () => void;
44+
jobId: string;
4545
}> = ({
4646
isLoading,
4747
jobStatus,
@@ -51,6 +51,7 @@ export const AnomaliesResults: React.FunctionComponent<{
5151
timeRange,
5252
viewSetupForReconfiguration,
5353
viewSetupForUpdate,
54+
jobId,
5455
}) => {
5556
const title = i18n.translate('xpack.infra.logs.analysis.anomaliesSectionTitle', {
5657
defaultMessage: 'Anomalies',
@@ -105,12 +106,7 @@ export const AnomaliesResults: React.FunctionComponent<{
105106
</EuiTitle>
106107
</EuiFlexItem>
107108
<EuiFlexItem grow={false}>
108-
<EuiButton fill>
109-
<FormattedMessage
110-
id="xpack.infra.logs.analysis.analyzeInMlButtonLabel"
111-
defaultMessage="Analyze in ML"
112-
/>
113-
</EuiButton>
109+
<AnalyzeInMlButton jobId={jobId} timeRange={timeRange} />
114110
</EuiFlexItem>
115111
</EuiFlexGroup>
116112
<EuiSpacer size="m" />
@@ -193,7 +189,12 @@ export const AnomaliesResults: React.FunctionComponent<{
193189
</EuiFlexItem>
194190
</EuiFlexGroup>
195191
<EuiSpacer size="l" />
196-
<AnomaliesTable results={results} setTimeRange={setTimeRange} timeRange={timeRange} />
192+
<AnomaliesTable
193+
results={results}
194+
setTimeRange={setTimeRange}
195+
timeRange={timeRange}
196+
jobId={jobId}
197+
/>
197198
</>
198199
)}
199200
</>

x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/table.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ export const AnomaliesTable: React.FunctionComponent<{
5252
results: GetLogEntryRateSuccessResponsePayload['data'];
5353
setTimeRange: (timeRange: TimeRange) => void;
5454
timeRange: TimeRange;
55-
}> = ({ results, timeRange, setTimeRange }) => {
55+
jobId: string;
56+
}> = ({ results, timeRange, setTimeRange, jobId }) => {
5657
const tableItems: TableItem[] = useMemo(() => {
5758
return Object.entries(getTopAnomalyScoresByPartition(results)).map(([key, value]) => {
5859
return {
@@ -112,6 +113,7 @@ export const AnomaliesTable: React.FunctionComponent<{
112113
topAnomalyScore={item.topAnomalyScore}
113114
setTimeRange={setTimeRange}
114115
timeRange={timeRange}
116+
jobId={jobId}
115117
/>
116118
),
117119
};

x-pack/legacy/plugins/infra/public/utils/use_kibana_injected_var.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,5 @@ import { npSetup } from 'ui/new_platform';
1414
*/
1515
export const useKibanaInjectedVar = (name: string, defaultValue?: unknown) => {
1616
const injectedMetadata = npSetup.core.injectedMetadata;
17-
1817
return injectedMetadata.getInjectedVar(name, defaultValue);
1918
};

0 commit comments

Comments
 (0)