Skip to content

Commit

Permalink
Merge branch 'master' into apm-70440-anomaly-detection-setup-link
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Jul 13, 2020
2 parents 4bf17ee + 79df8e0 commit 68e666d
Show file tree
Hide file tree
Showing 116 changed files with 3,157 additions and 1,315 deletions.
2 changes: 1 addition & 1 deletion docs/apm/api.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ include::api.asciidoc[tag=using-the-APIs]
[%collapsible%open]
======
`version` :::
(required, string) Name of service.
(required, string) Version of service.
`environment` :::
(optional, string) Environment of service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n';
import { debounce } from 'lodash';
import { parse } from 'query-string';
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
import { useUIAceKeyboardMode } from '../../../../../../../es_ui_shared/public';
import { ace } from '../../../../../../../es_ui_shared/public';
// @ts-ignore
import { retrieveAutoCompleteInfo, clearSubscriptions } from '../../../../../lib/mappings/mappings';
import { ConsoleMenu } from '../../../../components';
Expand All @@ -38,6 +38,8 @@ import { subscribeResizeChecker } from '../subscribe_console_resize_checker';
import { applyCurrentSettings } from './apply_editor_settings';
import { registerCommands } from './keyboard_shortcuts';

const { useUIAceKeyboardMode } = ace;

export interface EditorProps {
initialTextValue: string;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.kbnUiAceKeyboardHint {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: transparentize($euiColorEmptyShade, 0.3);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
opacity: 0;

&:focus {
opacity: 1;
border: 2px solid $euiColorPrimary;
z-index: $euiZLevel1;
}

&.kbnUiAceKeyboardHint-isInactive {
display: none;
}
}
20 changes: 20 additions & 0 deletions src/plugins/es_ui_shared/__packages_do_not_import__/ace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { useUIAceKeyboardMode } from './use_ui_ace_keyboard_mode';
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/

import React, { useEffect, useRef } from 'react';
import * as ReactDOM from 'react-dom';
import { keys, EuiText } from '@elastic/eui';

import './_ui_ace_keyboard_mode.scss';

const OverlayText = () => (
// The point of this element is for accessibility purposes, so ignore eslint error
// in this case
Expand Down
20 changes: 20 additions & 0 deletions src/plugins/es_ui_shared/public/ace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { useUIAceKeyboardMode } from '../../__packages_do_not_import__/ace';
5 changes: 2 additions & 3 deletions src/plugins/es_ui_shared/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
import * as Forms from './forms';
import * as Monaco from './monaco';
import * as ace from './ace';

export { JsonEditor, OnJsonEditorUpdateHandler } from './components/json_editor';

Expand All @@ -41,8 +42,6 @@ export {

export { indices } from './indices';

export { useUIAceKeyboardMode } from './use_ui_ace_keyboard_mode';

export {
installXJsonMode,
XJsonMode,
Expand All @@ -66,7 +65,7 @@ export {
useAuthorizationContext,
} from './authorization';

export { Monaco, Forms };
export { Monaco, Forms, ace };

export { extractQueryParams } from './url';

Expand Down
32 changes: 20 additions & 12 deletions test/functional/apps/discover/_doc_navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }) {
const retry = getService('retry');

// Flaky: https://github.com/elastic/kibana/issues/71216
describe.skip('doc link in discover', function contextSize() {
describe('doc link in discover', function contextSize() {
beforeEach(async function () {
log.debug('load kibana index with default index pattern');
await esArchiver.loadIfNeeded('discover');
Expand Down Expand Up @@ -63,20 +63,28 @@ export default function ({ getService, getPageObjects }) {
await filterBar.addFilter('agent', 'is', 'Missing/Fields');
await PageObjects.discover.waitUntilSearchingHasFinished();

// navigate to the doc view
await docTable.clickRowToggle({ rowIndex: 0 });
await retry.try(async () => {
// navigate to the doc view
await docTable.clickRowToggle({ rowIndex: 0 });

const details = await docTable.getDetailsRow();
await docTable.addInclusiveFilter(details, 'referer');
await PageObjects.discover.waitUntilSearchingHasFinished();
const details = await docTable.getDetailsRow();
await docTable.addInclusiveFilter(details, 'referer');
await PageObjects.discover.waitUntilSearchingHasFinished();

const hasInclusiveFilter = await filterBar.hasFilter('referer', 'exists', true, false, true);
expect(hasInclusiveFilter).to.be(true);
const hasInclusiveFilter = await filterBar.hasFilter(
'referer',
'exists',
true,
false,
true
);
expect(hasInclusiveFilter).to.be(true);

await docTable.removeInclusiveFilter(details, 'referer');
await PageObjects.discover.waitUntilSearchingHasFinished();
const hasExcludeFilter = await filterBar.hasFilter('referer', 'exists', true, false, false);
expect(hasExcludeFilter).to.be(true);
await docTable.removeInclusiveFilter(details, 'referer');
await PageObjects.discover.waitUntilSearchingHasFinished();
const hasExcludeFilter = await filterBar.hasFilter('referer', 'exists', true, false, false);
expect(hasExcludeFilter).to.be(true);
});
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const AnomalyDetection = () => {
<EuiText>
{i18n.translate('xpack.apm.settings.anomalyDetection.descriptionText', {
defaultMessage:
'The Machine Learning anomaly detection integration enables application health status indicators in the Service map by identifying transaction duration anomalies.',
'The Machine Learning anomaly detection integration enables application health status indicators for each configured environment in the Service map by identifying transaction duration anomalies.',
})}
</EuiText>
<EuiSpacer size="l" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const JobsList = ({
{i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.addEnvironments',
{
defaultMessage: 'Add environments',
defaultMessage: 'Create ML Job',
}
)}
</EuiButton>
Expand All @@ -101,7 +101,7 @@ export const JobsList = ({
<EuiText>
<FormattedMessage
id="xpack.apm.settings.anomalyDetection.jobList.mlDescriptionText"
defaultMessage="Manage existing anomaly detection jobs in {mlJobsLink}."
defaultMessage="To add anomaly detection to a new environment, create a machine learning job. Existing machine learning jobs can be managed in {mlJobsLink}."
values={{
mlJobsLink: (
<MLLink path="jobs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface Aggregation {
buckets: Array<{
aggregatedValue: { value: number; values?: Array<{ key: number; value: number }> };
doc_count: number;
key_as_string: string;
}>;
};
}
Expand Down Expand Up @@ -57,17 +58,18 @@ export const evaluateAlert = (
);
const { threshold, comparator } = criterion;
const comparisonFunction = comparatorMap[comparator];
return mapValues(currentValues, (values: number | number[] | null) => {
if (isTooManyBucketsPreviewException(values)) throw values;
return mapValues(currentValues, (points: any[] | typeof NaN | null) => {
if (isTooManyBucketsPreviewException(points)) throw points;
return {
...criterion,
metric: criterion.metric ?? DOCUMENT_COUNT_I18N,
currentValue: Array.isArray(values) ? last(values) : NaN,
shouldFire: Array.isArray(values)
? values.map((value) => comparisonFunction(value, threshold))
currentValue: Array.isArray(points) ? last(points)?.value : NaN,
timestamp: Array.isArray(points) ? last(points)?.key : NaN,
shouldFire: Array.isArray(points)
? points.map((point) => comparisonFunction(point.value, threshold))
: [false],
isNoData: values === null,
isError: isNaN(values),
isNoData: points === null,
isError: isNaN(points),
};
});
})
Expand Down Expand Up @@ -157,17 +159,20 @@ const getValuesFromAggregations = (
const { buckets } = aggregations.aggregatedIntervals;
if (!buckets.length) return null; // No Data state
if (aggType === Aggregators.COUNT) {
return buckets.map((bucket) => bucket.doc_count);
return buckets.map((bucket) => ({ key: bucket.key_as_string, value: bucket.doc_count }));
}
if (aggType === Aggregators.P95 || aggType === Aggregators.P99) {
return buckets.map((bucket) => {
const values = bucket.aggregatedValue?.values || [];
const firstValue = first(values);
if (!firstValue) return null;
return firstValue.value;
return { key: bucket.key_as_string, value: firstValue.value };
});
}
return buckets.map((bucket) => bucket.aggregatedValue.value);
return buckets.map((bucket) => ({
key: bucket.key_as_string,
value: bucket.aggregatedValue.value,
}));
} catch (e) {
return NaN; // Error state
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,26 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
);
});
});

describe('handles time', () => {
const end = new Date('2020-07-08T22:07:27.235Z').valueOf();
const timerange = {
end,
start: end - 5 * 60 * 1000,
};
const searchBody = getElasticsearchMetricQuery(
expressionParams,
timefield,
undefined,
undefined,
timerange
);
test('by rounding timestamps to the nearest timeUnit', () => {
const rangeFilter = searchBody.query.bool.filter.find((filter) =>
filter.hasOwnProperty('range')
)?.range[timefield];
expect(rangeFilter?.lte).toBe(1594246020000);
expect(rangeFilter?.gte).toBe(1594245720000);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { networkTraffic } from '../../../../../common/inventory_models/shared/metrics/snapshot/network_traffic';
import { MetricExpressionParams, Aggregators } from '../types';
import { getIntervalInSeconds } from '../../../../utils/get_interval_in_seconds';
import { roundTimestamp } from '../../../../utils/round_timestamp';
import { getDateHistogramOffset } from '../../../snapshot/query_helpers';
import { createPercentileAggregation } from './create_percentile_aggregation';

Expand Down Expand Up @@ -34,12 +36,15 @@ export const getElasticsearchMetricQuery = (
const interval = `${timeSize}${timeUnit}`;
const intervalAsSeconds = getIntervalInSeconds(interval);

const to = timeframe ? timeframe.end : Date.now();
const to = roundTimestamp(timeframe ? timeframe.end : Date.now(), timeUnit);
// We need enough data for 5 buckets worth of data. We also need
// to convert the intervalAsSeconds to milliseconds.
const minimumFrom = to - intervalAsSeconds * 1000 * MINIMUM_BUCKETS;

const from = timeframe && timeframe.start <= minimumFrom ? timeframe.start : minimumFrom;
const from = roundTimestamp(
timeframe && timeframe.start <= minimumFrom ? timeframe.start : minimumFrom,
timeUnit
);

const offset = getDateHistogramOffset(from, interval);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,14 @@ describe('The metric threshold alert type', () => {
expect(getState(instanceID).alertState).toBe(AlertStates.OK);
});
test('reports expected values to the action context', async () => {
const now = 1577858400000;
await execute(Comparator.GT, [0.75]);
const { action } = mostRecentAction(instanceID);
expect(action.group).toBe('*');
expect(action.reason).toContain('current value is 1');
expect(action.reason).toContain('threshold of 0.75');
expect(action.reason).toContain('test.metric.1');
expect(action.timestamp).toBe(new Date(now).toISOString());
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: s
}
}
if (reason) {
const firstResult = first(alertResults);
const timestamp = (firstResult && firstResult[group].timestamp) ?? moment().toISOString();
alertInstance.scheduleActions(FIRED_ACTIONS.id, {
group,
alertState: stateToAlertMessage[nextState],
reason,
timestamp: moment().toISOString(),
timestamp,
value: mapToConditionsLookup(alertResults, (result) => result[group].currentValue),
threshold: mapToConditionsLookup(criteria, (c) => c.threshold),
metric: mapToConditionsLookup(criteria, (c) => c.metric),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const bucketsA = [
{
doc_count: 3,
aggregatedValue: { value: 1.0, values: [{ key: 95.0, value: 1.0 }] },
key_as_string: new Date(1577858400000).toISOString(),
},
];

Expand Down
15 changes: 15 additions & 0 deletions x-pack/plugins/infra/server/utils/round_timestamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 { Unit } from '@elastic/datemath';
import moment from 'moment';

export const roundTimestamp = (timestamp: number, unit: Unit) => {
const floor = moment(timestamp).startOf(unit).valueOf();
const ceil = moment(timestamp).add(1, unit).startOf(unit).valueOf();
if (Math.abs(timestamp - floor) <= Math.abs(timestamp - ceil)) return floor;
return ceil;
};
Loading

0 comments on commit 68e666d

Please sign in to comment.