Skip to content

Commit

Permalink
Merge branch 'master' into kertal-pr-2020-06-08-improve-discover-hist…
Browse files Browse the repository at this point in the history
…ogram-test
  • Loading branch information
elasticmachine authored Jul 9, 2020
2 parents 526f10c + 58cdbf0 commit f61b21e
Show file tree
Hide file tree
Showing 414 changed files with 2,618 additions and 1,239 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const Header = ({
<p>
<FormattedMessage
id="indexPatternManagement.createIndexPattern.description"
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data souces, {star}."
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data sources, {star}."
values={{
multiple: <strong>multiple</strong>,
single: <EuiCode>filebeat-4-3-22</EuiCode>,
Expand Down
8 changes: 2 additions & 6 deletions x-pack/plugins/apm/common/utils/range_filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

export function rangeFilter(
start: number,
end: number,
timestampField = '@timestamp'
) {
export function rangeFilter(start: number, end: number) {
return {
[timestampField]: {
'@timestamp': {
gte: start,
lte: end,
format: 'epoch_millis',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function AgentConfigurations() {
(callApmApi) =>
callApmApi({ pathname: '/api/apm/settings/agent-configuration' }),
[],
{ preservePreviousData: false }
{ preservePreviousData: false, showToastOnError: false }
);

useTrackPageview({ app: 'apm', path: 'agent_configuration' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,29 @@ import { i18n } from '@kbn/i18n';
import { EuiPanel } from '@elastic/eui';
import { JobsList } from './jobs_list';
import { AddEnvironments } from './add_environments';
import { useFetcher, FETCH_STATUS } from '../../../../hooks/useFetcher';
import { useFetcher } from '../../../../hooks/useFetcher';
import { LicensePrompt } from '../../../shared/LicensePrompt';
import { useLicense } from '../../../../hooks/useLicense';
import { APIReturnType } from '../../../../services/rest/createCallApmApi';

const DEFAULT_VALUE: APIReturnType<'/api/apm/settings/anomaly-detection'> = {
jobs: [],
hasLegacyJobs: false,
};

export const AnomalyDetection = () => {
const license = useLicense();
const hasValidLicense = license?.isActive && license?.hasAtLeast('platinum');

const [viewAddEnvironments, setViewAddEnvironments] = useState(false);

const { refetch, data = [], status } = useFetcher(
const { refetch, data = DEFAULT_VALUE, status } = useFetcher(
(callApmApi) =>
callApmApi({ pathname: `/api/apm/settings/anomaly-detection` }),
[],
{ preservePreviousData: false }
{ preservePreviousData: false, showToastOnError: false }
);

const isLoading =
status === FETCH_STATUS.PENDING || status === FETCH_STATUS.LOADING;
const hasFetchFailure = status === FETCH_STATUS.FAILURE;

if (!hasValidLicense) {
return (
<EuiPanel>
Expand Down Expand Up @@ -66,7 +68,7 @@ export const AnomalyDetection = () => {
<EuiSpacer size="l" />
{viewAddEnvironments ? (
<AddEnvironments
currentEnvironments={data.map(({ environment }) => environment)}
currentEnvironments={data.jobs.map(({ environment }) => environment)}
onCreateJobSuccess={() => {
refetch();
setViewAddEnvironments(false);
Expand All @@ -77,9 +79,9 @@ export const AnomalyDetection = () => {
/>
) : (
<JobsList
isLoading={isLoading}
hasFetchFailure={hasFetchFailure}
anomalyDetectionJobsByEnv={data}
status={status}
anomalyDetectionJobsByEnv={data.jobs}
hasLegacyJobs={data.hasLegacyJobs}
onAddEnvironments={() => {
setViewAddEnvironments(true);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { FETCH_STATUS } from '../../../../hooks/useFetcher';
import { ITableColumn, ManagedTable } from '../../../shared/ManagedTable';
import { LoadingStatePrompt } from '../../../shared/LoadingStatePrompt';
import { AnomalyDetectionJobByEnv } from '../../../../../typings/anomaly_detection';
import { MLJobLink } from '../../../shared/Links/MachineLearningLinks/MLJobLink';
import { MLLink } from '../../../shared/Links/MachineLearningLinks/MLLink';
import { ENVIRONMENT_NOT_DEFINED } from '../../../../../common/environment_filter_values';
import { LegacyJobsCallout } from './legacy_jobs_callout';

const columns: Array<ITableColumn<AnomalyDetectionJobByEnv>> = [
{
Expand Down Expand Up @@ -60,17 +62,22 @@ const columns: Array<ITableColumn<AnomalyDetectionJobByEnv>> = [
];

interface Props {
isLoading: boolean;
hasFetchFailure: boolean;
status: FETCH_STATUS;
onAddEnvironments: () => void;
anomalyDetectionJobsByEnv: AnomalyDetectionJobByEnv[];
hasLegacyJobs: boolean;
}
export const JobsList = ({
isLoading,
hasFetchFailure,
status,
onAddEnvironments,
anomalyDetectionJobsByEnv,
hasLegacyJobs,
}: Props) => {
const isLoading =
status === FETCH_STATUS.PENDING || status === FETCH_STATUS.LOADING;

const hasFetchFailure = status === FETCH_STATUS.FAILURE;

return (
<EuiPanel>
<EuiFlexGroup>
Expand Down Expand Up @@ -131,6 +138,8 @@ export const JobsList = ({
items={isLoading || hasFetchFailure ? [] : anomalyDetectionJobsByEnv}
/>
<EuiSpacer size="l" />

{hasLegacyJobs && <LegacyJobsCallout />}
</EuiPanel>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 { EuiCallOut, EuiButton } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';

export function LegacyJobsCallout() {
const { core } = useApmPluginContext();
return (
<EuiCallOut
title={i18n.translate(
'xpack.apm.settings.anomaly_detection.legacy_jobs.title',
{ defaultMessage: 'Legacy ML jobs are no longer used in APM app' }
)}
iconType="iInCircle"
>
<p>
{i18n.translate(
'xpack.apm.settings.anomaly_detection.legacy_jobs.body',
{
defaultMessage:
'We have discovered legacy Machine Learning jobs from our previous integration which are no longer being used in the APM app',
}
)}
</p>
<EuiButton
href={core.http.basePath.prepend(
'/app/ml#/jobs?mlManagement=(jobId:high_mean_response_time)'
)}
>
{i18n.translate(
'xpack.apm.settings.anomaly_detection.legacy_jobs.button',
{ defaultMessage: 'Review jobs' }
)}
</EuiButton>
</EuiCallOut>
);
}
8 changes: 8 additions & 0 deletions x-pack/plugins/apm/server/lib/anomaly_detection/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export const ML_MODULE_ID_APM_TRANSACTION = 'apm_transaction';
export const APM_ML_JOB_GROUP = 'apm';
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ import {
PROCESSOR_EVENT,
} from '../../../common/elasticsearch_fieldnames';
import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values';

const ML_MODULE_ID_APM_TRANSACTION = 'apm_transaction';
export const ML_GROUP_NAME_APM = 'apm';
import { APM_ML_JOB_GROUP, ML_MODULE_ID_APM_TRANSACTION } from './constants';

export type CreateAnomalyDetectionJobsAPIResponse = PromiseReturnType<
typeof createAnomalyDetectionJobs
Expand Down Expand Up @@ -83,8 +81,8 @@ async function createAnomalyDetectionJob({

return ml.modules.setup({
moduleId: ML_MODULE_ID_APM_TRANSACTION,
prefix: `${ML_GROUP_NAME_APM}-${convertedEnvironmentName}-${randomToken}-`,
groups: [ML_GROUP_NAME_APM, convertedEnvironmentName],
prefix: `${APM_ML_JOB_GROUP}-${convertedEnvironmentName}-${randomToken}-`,
groups: [APM_ML_JOB_GROUP, convertedEnvironmentName],
indexPatternName,
query: {
bool: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,34 @@
*/

import { Logger } from 'kibana/server';
import { PromiseReturnType } from '../../../../observability/typings/common';
import { Setup } from '../helpers/setup_request';
import { AnomalyDetectionJobByEnv } from '../../../typings/anomaly_detection';
import { ML_GROUP_NAME_APM } from './create_anomaly_detection_jobs';
import { getMlJobsWithAPMGroup } from './get_ml_jobs_by_group';

export type AnomalyDetectionJobsAPIResponse = PromiseReturnType<
typeof getAnomalyDetectionJobs
>;
export async function getAnomalyDetectionJobs(
setup: Setup,
logger: Logger
): Promise<AnomalyDetectionJobByEnv[]> {
export async function getAnomalyDetectionJobs(setup: Setup, logger: Logger) {
const { ml } = setup;
if (!ml) {
return [];
}
try {
const mlCapabilities = await ml.mlSystem.mlCapabilities();
if (
!(
mlCapabilities.mlFeatureEnabledInSpace &&
mlCapabilities.isPlatinumOrTrialLicense
)
) {
logger.warn(
'Anomaly detection integration is not availble for this user.'
);
return [];
}
} catch (error) {
logger.warn('Unable to get ML capabilities.');
logger.error(error);
return [];
}
try {
const { jobs } = await ml.anomalyDetectors.jobs(ML_GROUP_NAME_APM);
return jobs
.map((job) => {
const environment = job.custom_settings?.job_tags?.environment ?? '';
return {
job_id: job.job_id,
environment,
};
})
.filter((job) => job.environment);
} catch (error) {
if (error.statusCode !== 404) {
logger.warn('Unable to get APM ML jobs.');
logger.error(error);
}

const mlCapabilities = await ml.mlSystem.mlCapabilities();
if (
!(
mlCapabilities.mlFeatureEnabledInSpace &&
mlCapabilities.isPlatinumOrTrialLicense
)
) {
logger.warn('Anomaly detection integration is not availble for this user.');
return [];
}

const response = await getMlJobsWithAPMGroup(ml);
return response.jobs
.map((job) => {
const environment = job.custom_settings?.job_tags?.environment ?? '';
return {
job_id: job.job_id,
environment,
};
})
.filter((job) => job.environment);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 { Setup } from '../helpers/setup_request';
import { APM_ML_JOB_GROUP } from './constants';

// returns ml jobs containing "apm" group
// workaround: the ML api returns 404 when no jobs are found. This is handled so instead of throwing an empty response is returned
export async function getMlJobsWithAPMGroup(ml: NonNullable<Setup['ml']>) {
try {
return await ml.anomalyDetectors.jobs(APM_ML_JOB_GROUP);
} catch (e) {
if (e.statusCode === 404) {
return { count: 0, jobs: [] };
}

throw e;
}
}
24 changes: 24 additions & 0 deletions x-pack/plugins/apm/server/lib/anomaly_detection/has_legacy_jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 { Setup } from '../helpers/setup_request';
import { getMlJobsWithAPMGroup } from './get_ml_jobs_by_group';

// Determine whether there are any legacy ml jobs.
// A legacy ML job has a job id that ends with "high_mean_response_time" and created_by=ml-module-apm-transaction
export async function hasLegacyJobs(setup: Setup) {
const { ml } = setup;

if (!ml) {
return false;
}

const response = await getMlJobsWithAPMGroup(ml);
return response.jobs.some(
(job) =>
job.job_id.endsWith('high_mean_response_time') &&
job.custom_settings?.created_by === 'ml-module-apm-transaction'
);
}
Loading

0 comments on commit f61b21e

Please sign in to comment.