[Logs + Metrics UI] Add index names for the new indexing strategy (#70245)
This add support for the new index name patterns `logs-*` and `metrics-*` of the new indexing strategy to the Logs and Metrics UI source configurations in the form of a migration and changed defaults.
This commit is contained in:
parent
3250816d02
commit
2399780d99
|
@ -1,161 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 { EuiBadge, EuiButton, EuiPopover, EuiPopoverTitle, EuiSelectable } from '@elastic/eui';
|
|
||||||
import { EuiSelectableOption } from '@elastic/eui';
|
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
|
||||||
import React, { useCallback, useMemo } from 'react';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
|
|
||||||
import { LogColumnConfiguration } from '../../utils/source_configuration';
|
|
||||||
import { useVisibilityState } from '../../utils/use_visibility_state';
|
|
||||||
import { euiStyled } from '../../../../observability/public';
|
|
||||||
|
|
||||||
interface SelectableColumnOption {
|
|
||||||
optionProps: EuiSelectableOption;
|
|
||||||
columnConfiguration: LogColumnConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AddLogColumnButtonAndPopover: React.FunctionComponent<{
|
|
||||||
addLogColumn: (logColumnConfiguration: LogColumnConfiguration) => void;
|
|
||||||
availableFields: string[];
|
|
||||||
isDisabled?: boolean;
|
|
||||||
}> = ({ addLogColumn, availableFields, isDisabled }) => {
|
|
||||||
const { isVisible: isOpen, show: openPopover, hide: closePopover } = useVisibilityState(false);
|
|
||||||
|
|
||||||
const availableColumnOptions = useMemo<SelectableColumnOption[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
optionProps: {
|
|
||||||
append: <SystemColumnBadge />,
|
|
||||||
'data-test-subj': 'addTimestampLogColumn',
|
|
||||||
// this key works around EuiSelectable using a lowercased label as
|
|
||||||
// key, which leads to conflicts with field names
|
|
||||||
key: 'timestamp',
|
|
||||||
label: 'Timestamp',
|
|
||||||
},
|
|
||||||
columnConfiguration: {
|
|
||||||
timestampColumn: {
|
|
||||||
id: uuidv4(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
optionProps: {
|
|
||||||
'data-test-subj': 'addMessageLogColumn',
|
|
||||||
append: <SystemColumnBadge />,
|
|
||||||
// this key works around EuiSelectable using a lowercased label as
|
|
||||||
// key, which leads to conflicts with field names
|
|
||||||
key: 'message',
|
|
||||||
label: 'Message',
|
|
||||||
},
|
|
||||||
columnConfiguration: {
|
|
||||||
messageColumn: {
|
|
||||||
id: uuidv4(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...availableFields.map<SelectableColumnOption>((field) => ({
|
|
||||||
optionProps: {
|
|
||||||
'data-test-subj': `addFieldLogColumn addFieldLogColumn:${field}`,
|
|
||||||
// this key works around EuiSelectable using a lowercased label as
|
|
||||||
// key, which leads to conflicts with fields that only differ in the
|
|
||||||
// case (e.g. the metricbeat mongodb module)
|
|
||||||
key: `field-${field}`,
|
|
||||||
label: field,
|
|
||||||
},
|
|
||||||
columnConfiguration: {
|
|
||||||
fieldColumn: {
|
|
||||||
id: uuidv4(),
|
|
||||||
field,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
],
|
|
||||||
[availableFields]
|
|
||||||
);
|
|
||||||
|
|
||||||
const availableOptions = useMemo<EuiSelectableOption[]>(
|
|
||||||
() => availableColumnOptions.map((availableColumnOption) => availableColumnOption.optionProps),
|
|
||||||
[availableColumnOptions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleColumnSelection = useCallback(
|
|
||||||
(selectedOptions: EuiSelectableOption[]) => {
|
|
||||||
closePopover();
|
|
||||||
|
|
||||||
const selectedOptionIndex = selectedOptions.findIndex(
|
|
||||||
(selectedOption) => selectedOption.checked === 'on'
|
|
||||||
);
|
|
||||||
const selectedOption = availableColumnOptions[selectedOptionIndex];
|
|
||||||
|
|
||||||
addLogColumn(selectedOption.columnConfiguration);
|
|
||||||
},
|
|
||||||
[addLogColumn, availableColumnOptions, closePopover]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EuiPopover
|
|
||||||
anchorPosition="downRight"
|
|
||||||
button={
|
|
||||||
<EuiButton
|
|
||||||
data-test-subj="addLogColumnButton"
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
iconType="plusInCircle"
|
|
||||||
onClick={openPopover}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.addLogColumnButtonLabel"
|
|
||||||
defaultMessage="Add column"
|
|
||||||
/>
|
|
||||||
</EuiButton>
|
|
||||||
}
|
|
||||||
closePopover={closePopover}
|
|
||||||
id="addLogColumn"
|
|
||||||
isOpen={isOpen}
|
|
||||||
ownFocus
|
|
||||||
panelPaddingSize="none"
|
|
||||||
>
|
|
||||||
<EuiSelectable
|
|
||||||
height={600}
|
|
||||||
listProps={selectableListProps}
|
|
||||||
onChange={handleColumnSelection}
|
|
||||||
options={availableOptions}
|
|
||||||
searchable
|
|
||||||
searchProps={searchProps}
|
|
||||||
singleSelection
|
|
||||||
>
|
|
||||||
{(list, search) => (
|
|
||||||
<SelectableContent data-test-subj="addLogColumnPopover">
|
|
||||||
<EuiPopoverTitle>{search}</EuiPopoverTitle>
|
|
||||||
{list}
|
|
||||||
</SelectableContent>
|
|
||||||
)}
|
|
||||||
</EuiSelectable>
|
|
||||||
</EuiPopover>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const searchProps = {
|
|
||||||
'data-test-subj': 'fieldSearchInput',
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectableListProps = {
|
|
||||||
showIcons: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const SystemColumnBadge: React.FunctionComponent = () => (
|
|
||||||
<EuiBadge>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.systemColumnBadgeLabel"
|
|
||||||
defaultMessage="System"
|
|
||||||
/>
|
|
||||||
</EuiBadge>
|
|
||||||
);
|
|
||||||
|
|
||||||
const SelectableContent = euiStyled.div`
|
|
||||||
width: 400px;
|
|
||||||
`;
|
|
|
@ -27,9 +27,7 @@ interface FieldsConfigurationPanelProps {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
podFieldProps: InputFieldProps;
|
podFieldProps: InputFieldProps;
|
||||||
tiebreakerFieldProps: InputFieldProps;
|
|
||||||
timestampFieldProps: InputFieldProps;
|
timestampFieldProps: InputFieldProps;
|
||||||
displaySettings: 'metrics' | 'logs';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FieldsConfigurationPanel = ({
|
export const FieldsConfigurationPanel = ({
|
||||||
|
@ -38,15 +36,12 @@ export const FieldsConfigurationPanel = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
readOnly,
|
readOnly,
|
||||||
podFieldProps,
|
podFieldProps,
|
||||||
tiebreakerFieldProps,
|
|
||||||
timestampFieldProps,
|
timestampFieldProps,
|
||||||
displaySettings,
|
|
||||||
}: FieldsConfigurationPanelProps) => {
|
}: FieldsConfigurationPanelProps) => {
|
||||||
const isHostValueDefault = hostFieldProps.value === 'host.name';
|
const isHostValueDefault = hostFieldProps.value === 'host.name';
|
||||||
const isContainerValueDefault = containerFieldProps.value === 'container.id';
|
const isContainerValueDefault = containerFieldProps.value === 'container.id';
|
||||||
const isPodValueDefault = podFieldProps.value === 'kubernetes.pod.uid';
|
const isPodValueDefault = podFieldProps.value === 'kubernetes.pod.uid';
|
||||||
const isTimestampValueDefault = timestampFieldProps.value === '@timestamp';
|
const isTimestampValueDefault = timestampFieldProps.value === '@timestamp';
|
||||||
const isTiebreakerValueDefault = tiebreakerFieldProps.value === '_doc';
|
|
||||||
return (
|
return (
|
||||||
<EuiForm>
|
<EuiForm>
|
||||||
<EuiTitle size="s">
|
<EuiTitle size="s">
|
||||||
|
@ -139,194 +134,141 @@ export const FieldsConfigurationPanel = ({
|
||||||
/>
|
/>
|
||||||
</EuiFormRow>
|
</EuiFormRow>
|
||||||
</EuiDescribedFormGroup>
|
</EuiDescribedFormGroup>
|
||||||
{displaySettings === 'logs' && (
|
<EuiDescribedFormGroup
|
||||||
<>
|
title={
|
||||||
<EuiDescribedFormGroup
|
<h4>
|
||||||
title={
|
<FormattedMessage
|
||||||
<h4>
|
id="xpack.infra.sourceConfiguration.containerFieldLabel"
|
||||||
<FormattedMessage
|
defaultMessage="Container ID"
|
||||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldLabel"
|
/>
|
||||||
defaultMessage="Tiebreaker"
|
</h4>
|
||||||
/>
|
}
|
||||||
</h4>
|
description={
|
||||||
}
|
<FormattedMessage
|
||||||
description={
|
id="xpack.infra.sourceConfiguration.containerFieldDescription"
|
||||||
<FormattedMessage
|
defaultMessage="Field used to identify Docker containers"
|
||||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldDescription"
|
/>
|
||||||
defaultMessage="Field used to break ties between two entries with the same timestamp"
|
}
|
||||||
/>
|
>
|
||||||
}
|
<EuiFormRow
|
||||||
>
|
error={containerFieldProps.error}
|
||||||
<EuiFormRow
|
fullWidth
|
||||||
error={tiebreakerFieldProps.error}
|
helpText={
|
||||||
fullWidth
|
<FormattedMessage
|
||||||
helpText={
|
id="xpack.infra.sourceConfiguration.containerFieldRecommendedValue"
|
||||||
<FormattedMessage
|
defaultMessage="The recommended value is {defaultValue}"
|
||||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldRecommendedValue"
|
values={{
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
defaultValue: <EuiCode>container.id</EuiCode>,
|
||||||
values={{
|
}}
|
||||||
defaultValue: <EuiCode>_doc</EuiCode>,
|
/>
|
||||||
}}
|
}
|
||||||
/>
|
isInvalid={containerFieldProps.isInvalid}
|
||||||
}
|
label={
|
||||||
isInvalid={tiebreakerFieldProps.isInvalid}
|
<FormattedMessage
|
||||||
label={
|
id="xpack.infra.sourceConfiguration.containerFieldLabel"
|
||||||
<FormattedMessage
|
defaultMessage="Container ID"
|
||||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldLabel"
|
/>
|
||||||
defaultMessage="Tiebreaker"
|
}
|
||||||
/>
|
>
|
||||||
}
|
<EuiFieldText
|
||||||
>
|
fullWidth
|
||||||
<EuiFieldText
|
disabled={isLoading || isContainerValueDefault}
|
||||||
fullWidth
|
readOnly={readOnly}
|
||||||
disabled={isLoading || isTiebreakerValueDefault}
|
isLoading={isLoading}
|
||||||
readOnly={readOnly}
|
{...containerFieldProps}
|
||||||
isLoading={isLoading}
|
/>
|
||||||
{...tiebreakerFieldProps}
|
</EuiFormRow>
|
||||||
/>
|
</EuiDescribedFormGroup>
|
||||||
</EuiFormRow>
|
<EuiDescribedFormGroup
|
||||||
</EuiDescribedFormGroup>
|
title={
|
||||||
</>
|
<h4>
|
||||||
)}
|
<FormattedMessage
|
||||||
{displaySettings === 'metrics' && (
|
id="xpack.infra.sourceConfiguration.hostNameFieldLabel"
|
||||||
<>
|
defaultMessage="Host name"
|
||||||
<EuiDescribedFormGroup
|
/>
|
||||||
title={
|
</h4>
|
||||||
<h4>
|
}
|
||||||
<FormattedMessage
|
description={
|
||||||
id="xpack.infra.sourceConfiguration.containerFieldLabel"
|
<FormattedMessage
|
||||||
defaultMessage="Container ID"
|
id="xpack.infra.sourceConfiguration.hostNameFieldDescription"
|
||||||
/>
|
defaultMessage="Field used to identify hosts"
|
||||||
</h4>
|
/>
|
||||||
}
|
}
|
||||||
description={
|
>
|
||||||
<FormattedMessage
|
<EuiFormRow
|
||||||
id="xpack.infra.sourceConfiguration.containerFieldDescription"
|
error={hostFieldProps.error}
|
||||||
defaultMessage="Field used to identify Docker containers"
|
fullWidth
|
||||||
/>
|
helpText={
|
||||||
}
|
<FormattedMessage
|
||||||
>
|
id="xpack.infra.sourceConfiguration.hostFieldDescription"
|
||||||
<EuiFormRow
|
defaultMessage="The recommended value is {defaultValue}"
|
||||||
error={containerFieldProps.error}
|
values={{
|
||||||
fullWidth
|
defaultValue: <EuiCode>host.name</EuiCode>,
|
||||||
helpText={
|
}}
|
||||||
<FormattedMessage
|
/>
|
||||||
id="xpack.infra.sourceConfiguration.containerFieldRecommendedValue"
|
}
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
isInvalid={hostFieldProps.isInvalid}
|
||||||
values={{
|
label={
|
||||||
defaultValue: <EuiCode>container.id</EuiCode>,
|
<FormattedMessage
|
||||||
}}
|
id="xpack.infra.sourceConfiguration.hostFieldLabel"
|
||||||
/>
|
defaultMessage="Host name"
|
||||||
}
|
/>
|
||||||
isInvalid={containerFieldProps.isInvalid}
|
}
|
||||||
label={
|
>
|
||||||
<FormattedMessage
|
<EuiFieldText
|
||||||
id="xpack.infra.sourceConfiguration.containerFieldLabel"
|
fullWidth
|
||||||
defaultMessage="Container ID"
|
disabled={isLoading || isHostValueDefault}
|
||||||
/>
|
readOnly={readOnly}
|
||||||
}
|
isLoading={isLoading}
|
||||||
>
|
{...hostFieldProps}
|
||||||
<EuiFieldText
|
/>
|
||||||
fullWidth
|
</EuiFormRow>
|
||||||
disabled={isLoading || isContainerValueDefault}
|
</EuiDescribedFormGroup>
|
||||||
readOnly={readOnly}
|
<EuiDescribedFormGroup
|
||||||
isLoading={isLoading}
|
title={
|
||||||
{...containerFieldProps}
|
<h4>
|
||||||
/>
|
<FormattedMessage
|
||||||
</EuiFormRow>
|
id="xpack.infra.sourceConfiguration.podFieldLabel"
|
||||||
</EuiDescribedFormGroup>
|
defaultMessage="Pod ID"
|
||||||
<EuiDescribedFormGroup
|
/>
|
||||||
title={
|
</h4>
|
||||||
<h4>
|
}
|
||||||
<FormattedMessage
|
description={
|
||||||
id="xpack.infra.sourceConfiguration.hostNameFieldLabel"
|
<FormattedMessage
|
||||||
defaultMessage="Host name"
|
id="xpack.infra.sourceConfiguration.podFieldDescription"
|
||||||
/>
|
defaultMessage="Field used to identify Kubernetes pods"
|
||||||
</h4>
|
/>
|
||||||
}
|
}
|
||||||
description={
|
>
|
||||||
<FormattedMessage
|
<EuiFormRow
|
||||||
id="xpack.infra.sourceConfiguration.hostNameFieldDescription"
|
error={podFieldProps.error}
|
||||||
defaultMessage="Field used to identify hosts"
|
fullWidth
|
||||||
/>
|
helpText={
|
||||||
}
|
<FormattedMessage
|
||||||
>
|
id="xpack.infra.sourceConfiguration.podFieldRecommendedValue"
|
||||||
<EuiFormRow
|
defaultMessage="The recommended value is {defaultValue}"
|
||||||
error={hostFieldProps.error}
|
values={{
|
||||||
fullWidth
|
defaultValue: <EuiCode>kubernetes.pod.uid</EuiCode>,
|
||||||
helpText={
|
}}
|
||||||
<FormattedMessage
|
/>
|
||||||
id="xpack.infra.sourceConfiguration.hostFieldDescription"
|
}
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
isInvalid={podFieldProps.isInvalid}
|
||||||
values={{
|
label={
|
||||||
defaultValue: <EuiCode>host.name</EuiCode>,
|
<FormattedMessage
|
||||||
}}
|
id="xpack.infra.sourceConfiguration.podFieldLabel"
|
||||||
/>
|
defaultMessage="Pod ID"
|
||||||
}
|
/>
|
||||||
isInvalid={hostFieldProps.isInvalid}
|
}
|
||||||
label={
|
>
|
||||||
<FormattedMessage
|
<EuiFieldText
|
||||||
id="xpack.infra.sourceConfiguration.hostFieldLabel"
|
fullWidth
|
||||||
defaultMessage="Host name"
|
disabled={isLoading || isPodValueDefault}
|
||||||
/>
|
readOnly={readOnly}
|
||||||
}
|
isLoading={isLoading}
|
||||||
>
|
{...podFieldProps}
|
||||||
<EuiFieldText
|
/>
|
||||||
fullWidth
|
</EuiFormRow>
|
||||||
disabled={isLoading || isHostValueDefault}
|
</EuiDescribedFormGroup>
|
||||||
readOnly={readOnly}
|
|
||||||
isLoading={isLoading}
|
|
||||||
{...hostFieldProps}
|
|
||||||
/>
|
|
||||||
</EuiFormRow>
|
|
||||||
</EuiDescribedFormGroup>
|
|
||||||
<EuiDescribedFormGroup
|
|
||||||
title={
|
|
||||||
<h4>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.podFieldLabel"
|
|
||||||
defaultMessage="Pod ID"
|
|
||||||
/>
|
|
||||||
</h4>
|
|
||||||
}
|
|
||||||
description={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.podFieldDescription"
|
|
||||||
defaultMessage="Field used to identify Kubernetes pods"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<EuiFormRow
|
|
||||||
error={podFieldProps.error}
|
|
||||||
fullWidth
|
|
||||||
helpText={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.podFieldRecommendedValue"
|
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
|
||||||
values={{
|
|
||||||
defaultValue: <EuiCode>kubernetes.pod.uid</EuiCode>,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
isInvalid={podFieldProps.isInvalid}
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.podFieldLabel"
|
|
||||||
defaultMessage="Pod ID"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<EuiFieldText
|
|
||||||
fullWidth
|
|
||||||
disabled={isLoading || isPodValueDefault}
|
|
||||||
readOnly={readOnly}
|
|
||||||
isLoading={isLoading}
|
|
||||||
{...podFieldProps}
|
|
||||||
/>
|
|
||||||
</EuiFormRow>
|
|
||||||
</EuiDescribedFormGroup>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</EuiForm>
|
</EuiForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,17 +21,13 @@ import { InputFieldProps } from './input_fields';
|
||||||
interface IndicesConfigurationPanelProps {
|
interface IndicesConfigurationPanelProps {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
logAliasFieldProps: InputFieldProps;
|
|
||||||
metricAliasFieldProps: InputFieldProps;
|
metricAliasFieldProps: InputFieldProps;
|
||||||
displaySettings: 'metrics' | 'logs';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IndicesConfigurationPanel = ({
|
export const IndicesConfigurationPanel = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
readOnly,
|
readOnly,
|
||||||
logAliasFieldProps,
|
|
||||||
metricAliasFieldProps,
|
metricAliasFieldProps,
|
||||||
displaySettings,
|
|
||||||
}: IndicesConfigurationPanelProps) => (
|
}: IndicesConfigurationPanelProps) => (
|
||||||
<EuiForm>
|
<EuiForm>
|
||||||
<EuiTitle size="s">
|
<EuiTitle size="s">
|
||||||
|
@ -43,101 +39,51 @@ export const IndicesConfigurationPanel = ({
|
||||||
</h3>
|
</h3>
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
<EuiSpacer size="m" />
|
<EuiSpacer size="m" />
|
||||||
{displaySettings === 'metrics' && (
|
<EuiDescribedFormGroup
|
||||||
<EuiDescribedFormGroup
|
title={
|
||||||
title={
|
<h4>
|
||||||
<h4>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.metricIndicesTitle"
|
|
||||||
defaultMessage="Metric indices"
|
|
||||||
/>
|
|
||||||
</h4>
|
|
||||||
}
|
|
||||||
description={
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="xpack.infra.sourceConfiguration.metricIndicesDescription"
|
id="xpack.infra.sourceConfiguration.metricIndicesTitle"
|
||||||
defaultMessage="Index pattern for matching indices that contain Metricbeat data"
|
defaultMessage="Metrics indices"
|
||||||
|
/>
|
||||||
|
</h4>
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.sourceConfiguration.metricIndicesDescription"
|
||||||
|
defaultMessage="Index pattern for matching indices that contain metrics data"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<EuiFormRow
|
||||||
|
error={metricAliasFieldProps.error}
|
||||||
|
fullWidth
|
||||||
|
helpText={
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.sourceConfiguration.metricIndicesRecommendedValue"
|
||||||
|
defaultMessage="The recommended value is {defaultValue}"
|
||||||
|
values={{
|
||||||
|
defaultValue: <EuiCode>metrics-*,metricbeat-*</EuiCode>,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
isInvalid={metricAliasFieldProps.isInvalid}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.sourceConfiguration.metricIndicesLabel"
|
||||||
|
defaultMessage="Metrics indices"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<EuiFormRow
|
<EuiFieldText
|
||||||
error={metricAliasFieldProps.error}
|
data-test-subj="metricIndicesInput"
|
||||||
fullWidth
|
fullWidth
|
||||||
helpText={
|
disabled={isLoading}
|
||||||
<FormattedMessage
|
readOnly={readOnly}
|
||||||
id="xpack.infra.sourceConfiguration.metricIndicesRecommendedValue"
|
isLoading={isLoading}
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
{...metricAliasFieldProps}
|
||||||
values={{
|
/>
|
||||||
defaultValue: <EuiCode>metricbeat-*</EuiCode>,
|
</EuiFormRow>
|
||||||
}}
|
</EuiDescribedFormGroup>
|
||||||
/>
|
|
||||||
}
|
|
||||||
isInvalid={metricAliasFieldProps.isInvalid}
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.metricIndicesLabel"
|
|
||||||
defaultMessage="Metric indices"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<EuiFieldText
|
|
||||||
data-test-subj="metricIndicesInput"
|
|
||||||
fullWidth
|
|
||||||
disabled={isLoading}
|
|
||||||
readOnly={readOnly}
|
|
||||||
isLoading={isLoading}
|
|
||||||
{...metricAliasFieldProps}
|
|
||||||
/>
|
|
||||||
</EuiFormRow>
|
|
||||||
</EuiDescribedFormGroup>
|
|
||||||
)}
|
|
||||||
{displaySettings === 'logs' && (
|
|
||||||
<EuiDescribedFormGroup
|
|
||||||
title={
|
|
||||||
<h4>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.logIndicesTitle"
|
|
||||||
defaultMessage="Log indices"
|
|
||||||
/>
|
|
||||||
</h4>
|
|
||||||
}
|
|
||||||
description={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.logIndicesDescription"
|
|
||||||
defaultMessage="Index pattern for matching indices that contain log data"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<EuiFormRow
|
|
||||||
error={logAliasFieldProps.error}
|
|
||||||
fullWidth
|
|
||||||
helpText={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.logIndicesRecommendedValue"
|
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
|
||||||
values={{
|
|
||||||
defaultValue: <EuiCode>filebeat-*</EuiCode>,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
isInvalid={logAliasFieldProps.isInvalid}
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.logIndicesLabel"
|
|
||||||
defaultMessage="Log indices"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<EuiFieldText
|
|
||||||
data-test-subj="logIndicesInput"
|
|
||||||
fullWidth
|
|
||||||
disabled={isLoading}
|
|
||||||
isLoading={isLoading}
|
|
||||||
readOnly={readOnly}
|
|
||||||
{...logAliasFieldProps}
|
|
||||||
/>
|
|
||||||
</EuiFormRow>
|
|
||||||
</EuiDescribedFormGroup>
|
|
||||||
)}
|
|
||||||
</EuiForm>
|
</EuiForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,279 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 {
|
|
||||||
EuiButtonIcon,
|
|
||||||
EuiEmptyPrompt,
|
|
||||||
EuiForm,
|
|
||||||
EuiPanel,
|
|
||||||
EuiSpacer,
|
|
||||||
EuiText,
|
|
||||||
EuiTitle,
|
|
||||||
EuiFlexGroup,
|
|
||||||
EuiFlexItem,
|
|
||||||
EuiDragDropContext,
|
|
||||||
EuiDraggable,
|
|
||||||
EuiDroppable,
|
|
||||||
EuiIcon,
|
|
||||||
} from '@elastic/eui';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
import { DragHandleProps, DropResult } from '../../../../observability/public';
|
|
||||||
|
|
||||||
import { AddLogColumnButtonAndPopover } from './add_log_column_popover';
|
|
||||||
import {
|
|
||||||
FieldLogColumnConfigurationProps,
|
|
||||||
LogColumnConfigurationProps,
|
|
||||||
} from './log_columns_configuration_form_state';
|
|
||||||
import { LogColumnConfiguration } from '../../utils/source_configuration';
|
|
||||||
|
|
||||||
interface LogColumnsConfigurationPanelProps {
|
|
||||||
availableFields: string[];
|
|
||||||
isLoading: boolean;
|
|
||||||
logColumnConfiguration: LogColumnConfigurationProps[];
|
|
||||||
addLogColumn: (logColumn: LogColumnConfiguration) => void;
|
|
||||||
moveLogColumn: (sourceIndex: number, destinationIndex: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LogColumnsConfigurationPanel: React.FunctionComponent<LogColumnsConfigurationPanelProps> = ({
|
|
||||||
addLogColumn,
|
|
||||||
moveLogColumn,
|
|
||||||
availableFields,
|
|
||||||
isLoading,
|
|
||||||
logColumnConfiguration,
|
|
||||||
}) => {
|
|
||||||
const onDragEnd = useCallback(
|
|
||||||
({ source, destination }: DropResult) =>
|
|
||||||
destination && moveLogColumn(source.index, destination.index),
|
|
||||||
[moveLogColumn]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EuiForm>
|
|
||||||
<EuiFlexGroup>
|
|
||||||
<EuiFlexItem>
|
|
||||||
<EuiTitle size="s" data-test-subj="sourceConfigurationLogColumnsSectionTitle">
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.logColumnsSectionTitle"
|
|
||||||
defaultMessage="Log Columns"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
</EuiTitle>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<AddLogColumnButtonAndPopover
|
|
||||||
addLogColumn={addLogColumn}
|
|
||||||
availableFields={availableFields}
|
|
||||||
isDisabled={isLoading}
|
|
||||||
/>
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
{logColumnConfiguration.length > 0 ? (
|
|
||||||
<EuiDragDropContext onDragEnd={onDragEnd}>
|
|
||||||
<EuiDroppable droppableId="COLUMN_CONFIG_DROPPABLE_AREA">
|
|
||||||
<>
|
|
||||||
{/* Fragment here necessary for typechecking */}
|
|
||||||
{logColumnConfiguration.map((column, index) => (
|
|
||||||
<EuiDraggable
|
|
||||||
key={`logColumnConfigurationPanel-${column.logColumnConfiguration.id}`}
|
|
||||||
index={index}
|
|
||||||
draggableId={column.logColumnConfiguration.id}
|
|
||||||
customDragHandle
|
|
||||||
>
|
|
||||||
{(provided) => (
|
|
||||||
<LogColumnConfigurationPanel
|
|
||||||
dragHandleProps={provided.dragHandleProps}
|
|
||||||
logColumnConfigurationProps={column}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</EuiDraggable>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
</EuiDroppable>
|
|
||||||
</EuiDragDropContext>
|
|
||||||
) : (
|
|
||||||
<LogColumnConfigurationEmptyPrompt />
|
|
||||||
)}
|
|
||||||
</EuiForm>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface LogColumnConfigurationPanelProps {
|
|
||||||
logColumnConfigurationProps: LogColumnConfigurationProps;
|
|
||||||
dragHandleProps: DragHandleProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LogColumnConfigurationPanel: React.FunctionComponent<LogColumnConfigurationPanelProps> = (
|
|
||||||
props
|
|
||||||
) => (
|
|
||||||
<>
|
|
||||||
<EuiSpacer size="m" />
|
|
||||||
{props.logColumnConfigurationProps.type === 'timestamp' ? (
|
|
||||||
<TimestampLogColumnConfigurationPanel {...props} />
|
|
||||||
) : props.logColumnConfigurationProps.type === 'message' ? (
|
|
||||||
<MessageLogColumnConfigurationPanel {...props} />
|
|
||||||
) : (
|
|
||||||
<FieldLogColumnConfigurationPanel
|
|
||||||
logColumnConfigurationProps={props.logColumnConfigurationProps}
|
|
||||||
dragHandleProps={props.dragHandleProps}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const TimestampLogColumnConfigurationPanel: React.FunctionComponent<LogColumnConfigurationPanelProps> = ({
|
|
||||||
logColumnConfigurationProps,
|
|
||||||
dragHandleProps,
|
|
||||||
}) => (
|
|
||||||
<ExplainedLogColumnConfigurationPanel
|
|
||||||
fieldName="Timestamp"
|
|
||||||
helpText={
|
|
||||||
<FormattedMessage
|
|
||||||
tagName="span"
|
|
||||||
id="xpack.infra.sourceConfiguration.timestampLogColumnDescription"
|
|
||||||
defaultMessage="This system field shows the log entry's time as determined by the {timestampSetting} field setting."
|
|
||||||
values={{
|
|
||||||
timestampSetting: <code>timestamp</code>,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
removeColumn={logColumnConfigurationProps.remove}
|
|
||||||
dragHandleProps={dragHandleProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const MessageLogColumnConfigurationPanel: React.FunctionComponent<LogColumnConfigurationPanelProps> = ({
|
|
||||||
logColumnConfigurationProps,
|
|
||||||
dragHandleProps,
|
|
||||||
}) => (
|
|
||||||
<ExplainedLogColumnConfigurationPanel
|
|
||||||
fieldName="Message"
|
|
||||||
helpText={
|
|
||||||
<FormattedMessage
|
|
||||||
tagName="span"
|
|
||||||
id="xpack.infra.sourceConfiguration.messageLogColumnDescription"
|
|
||||||
defaultMessage="This system field shows the log entry message as derived from the document fields."
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
removeColumn={logColumnConfigurationProps.remove}
|
|
||||||
dragHandleProps={dragHandleProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const FieldLogColumnConfigurationPanel: React.FunctionComponent<{
|
|
||||||
logColumnConfigurationProps: FieldLogColumnConfigurationProps;
|
|
||||||
dragHandleProps: DragHandleProps;
|
|
||||||
}> = ({
|
|
||||||
logColumnConfigurationProps: {
|
|
||||||
logColumnConfiguration: { field },
|
|
||||||
remove,
|
|
||||||
},
|
|
||||||
dragHandleProps,
|
|
||||||
}) => {
|
|
||||||
const fieldLogColumnTitle = i18n.translate(
|
|
||||||
'xpack.infra.sourceConfiguration.fieldLogColumnTitle',
|
|
||||||
{
|
|
||||||
defaultMessage: 'Field',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<EuiPanel data-test-subj={`logColumnPanel fieldLogColumnPanel fieldLogColumnPanel:${field}`}>
|
|
||||||
<EuiFlexGroup>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<div data-test-subj="moveLogColumnHandle" {...dragHandleProps}>
|
|
||||||
<EuiIcon type="grab" />
|
|
||||||
</div>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={1}>{fieldLogColumnTitle}</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={3}>
|
|
||||||
<code>{field}</code>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<RemoveLogColumnButton
|
|
||||||
onClick={remove}
|
|
||||||
columnDescription={`${fieldLogColumnTitle} - ${field}`}
|
|
||||||
/>
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</EuiPanel>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ExplainedLogColumnConfigurationPanel: React.FunctionComponent<{
|
|
||||||
fieldName: React.ReactNode;
|
|
||||||
helpText: React.ReactNode;
|
|
||||||
removeColumn: () => void;
|
|
||||||
dragHandleProps: DragHandleProps;
|
|
||||||
}> = ({ fieldName, helpText, removeColumn, dragHandleProps }) => (
|
|
||||||
<EuiPanel
|
|
||||||
data-test-subj={`logColumnPanel systemLogColumnPanel systemLogColumnPanel:${fieldName}`}
|
|
||||||
>
|
|
||||||
<EuiFlexGroup>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<div data-test-subj="moveLogColumnHandle" {...dragHandleProps}>
|
|
||||||
<EuiIcon type="grab" />
|
|
||||||
</div>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={1}>{fieldName}</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={3}>
|
|
||||||
<EuiText size="s" color="subdued">
|
|
||||||
{helpText}
|
|
||||||
</EuiText>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<RemoveLogColumnButton onClick={removeColumn} columnDescription={String(fieldName)} />
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</EuiPanel>
|
|
||||||
);
|
|
||||||
|
|
||||||
const RemoveLogColumnButton: React.FunctionComponent<{
|
|
||||||
onClick?: () => void;
|
|
||||||
columnDescription: string;
|
|
||||||
}> = ({ onClick, columnDescription }) => {
|
|
||||||
const removeColumnLabel = i18n.translate(
|
|
||||||
'xpack.infra.sourceConfiguration.removeLogColumnButtonLabel',
|
|
||||||
{
|
|
||||||
defaultMessage: 'Remove {columnDescription} column',
|
|
||||||
values: { columnDescription },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EuiButtonIcon
|
|
||||||
color="danger"
|
|
||||||
data-test-subj="removeLogColumnButton"
|
|
||||||
iconType="trash"
|
|
||||||
onClick={onClick}
|
|
||||||
title={removeColumnLabel}
|
|
||||||
aria-label={removeColumnLabel}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const LogColumnConfigurationEmptyPrompt: React.FunctionComponent = () => (
|
|
||||||
<EuiEmptyPrompt
|
|
||||||
iconType="list"
|
|
||||||
title={
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.noLogColumnsTitle"
|
|
||||||
defaultMessage="No columns"
|
|
||||||
/>
|
|
||||||
</h2>
|
|
||||||
}
|
|
||||||
body={
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.sourceConfiguration.noLogColumnsDescription"
|
|
||||||
defaultMessage="Add a column to this list using the button above."
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
|
@ -22,19 +22,16 @@ import { Source } from '../../containers/source';
|
||||||
import { FieldsConfigurationPanel } from './fields_configuration_panel';
|
import { FieldsConfigurationPanel } from './fields_configuration_panel';
|
||||||
import { IndicesConfigurationPanel } from './indices_configuration_panel';
|
import { IndicesConfigurationPanel } from './indices_configuration_panel';
|
||||||
import { NameConfigurationPanel } from './name_configuration_panel';
|
import { NameConfigurationPanel } from './name_configuration_panel';
|
||||||
import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel';
|
|
||||||
import { useSourceConfigurationFormState } from './source_configuration_form_state';
|
import { useSourceConfigurationFormState } from './source_configuration_form_state';
|
||||||
import { SourceLoadingPage } from '../source_loading_page';
|
import { SourceLoadingPage } from '../source_loading_page';
|
||||||
import { Prompt } from '../../utils/navigation_warning_prompt';
|
import { Prompt } from '../../utils/navigation_warning_prompt';
|
||||||
|
|
||||||
interface SourceConfigurationSettingsProps {
|
interface SourceConfigurationSettingsProps {
|
||||||
shouldAllowEdit: boolean;
|
shouldAllowEdit: boolean;
|
||||||
displaySettings: 'metrics' | 'logs';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SourceConfigurationSettings = ({
|
export const SourceConfigurationSettings = ({
|
||||||
shouldAllowEdit,
|
shouldAllowEdit,
|
||||||
displaySettings,
|
|
||||||
}: SourceConfigurationSettingsProps) => {
|
}: SourceConfigurationSettingsProps) => {
|
||||||
const {
|
const {
|
||||||
createSourceConfiguration,
|
createSourceConfiguration,
|
||||||
|
@ -45,16 +42,8 @@ export const SourceConfigurationSettings = ({
|
||||||
updateSourceConfiguration,
|
updateSourceConfiguration,
|
||||||
} = useContext(Source.Context);
|
} = useContext(Source.Context);
|
||||||
|
|
||||||
const availableFields = useMemo(
|
|
||||||
() => (source && source.status ? source.status.indexFields.map((field) => field.name) : []),
|
|
||||||
[source]
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
addLogColumn,
|
|
||||||
moveLogColumn,
|
|
||||||
indicesConfigurationProps,
|
indicesConfigurationProps,
|
||||||
logColumnConfigurationProps,
|
|
||||||
errors,
|
errors,
|
||||||
resetForm,
|
resetForm,
|
||||||
isFormDirty,
|
isFormDirty,
|
||||||
|
@ -119,10 +108,8 @@ export const SourceConfigurationSettings = ({
|
||||||
<EuiPanel paddingSize="l">
|
<EuiPanel paddingSize="l">
|
||||||
<IndicesConfigurationPanel
|
<IndicesConfigurationPanel
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
logAliasFieldProps={indicesConfigurationProps.logAlias}
|
|
||||||
metricAliasFieldProps={indicesConfigurationProps.metricAlias}
|
metricAliasFieldProps={indicesConfigurationProps.metricAlias}
|
||||||
readOnly={!isWriteable}
|
readOnly={!isWriteable}
|
||||||
displaySettings={displaySettings}
|
|
||||||
/>
|
/>
|
||||||
</EuiPanel>
|
</EuiPanel>
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
|
@ -133,23 +120,10 @@ export const SourceConfigurationSettings = ({
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
podFieldProps={indicesConfigurationProps.podField}
|
podFieldProps={indicesConfigurationProps.podField}
|
||||||
readOnly={!isWriteable}
|
readOnly={!isWriteable}
|
||||||
tiebreakerFieldProps={indicesConfigurationProps.tiebreakerField}
|
|
||||||
timestampFieldProps={indicesConfigurationProps.timestampField}
|
timestampFieldProps={indicesConfigurationProps.timestampField}
|
||||||
displaySettings={displaySettings}
|
|
||||||
/>
|
/>
|
||||||
</EuiPanel>
|
</EuiPanel>
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
{displaySettings === 'logs' && (
|
|
||||||
<EuiPanel paddingSize="l">
|
|
||||||
<LogColumnsConfigurationPanel
|
|
||||||
addLogColumn={addLogColumn}
|
|
||||||
moveLogColumn={moveLogColumn}
|
|
||||||
availableFields={availableFields}
|
|
||||||
isLoading={isLoading}
|
|
||||||
logColumnConfiguration={logColumnConfigurationProps}
|
|
||||||
/>
|
|
||||||
</EuiPanel>
|
|
||||||
)}
|
|
||||||
{errors.length > 0 ? (
|
{errors.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<EuiCallOut color="danger">
|
<EuiCallOut color="danger">
|
||||||
|
|
|
@ -62,7 +62,7 @@ export const IndicesConfigurationPanel = ({
|
||||||
id="xpack.infra.sourceConfiguration.logIndicesRecommendedValue"
|
id="xpack.infra.sourceConfiguration.logIndicesRecommendedValue"
|
||||||
defaultMessage="The recommended value is {defaultValue}"
|
defaultMessage="The recommended value is {defaultValue}"
|
||||||
values={{
|
values={{
|
||||||
defaultValue: <EuiCode>filebeat-*</EuiCode>,
|
defaultValue: <EuiCode>logs-*,filebeat-*</EuiCode>,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ export const MetricsSettingsPage = () => {
|
||||||
<EuiErrorBoundary>
|
<EuiErrorBoundary>
|
||||||
<SourceConfigurationSettings
|
<SourceConfigurationSettings
|
||||||
shouldAllowEdit={uiCapabilities?.infrastructure?.configureSource as boolean}
|
shouldAllowEdit={uiCapabilities?.infrastructure?.configureSource as boolean}
|
||||||
displaySettings="metrics"
|
|
||||||
/>
|
/>
|
||||||
</EuiErrorBoundary>
|
</EuiErrorBoundary>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { InfraSourceConfiguration } from '../../../common/http_api/source_api';
|
||||||
export const defaultSourceConfiguration: InfraSourceConfiguration = {
|
export const defaultSourceConfiguration: InfraSourceConfiguration = {
|
||||||
name: 'Default',
|
name: 'Default',
|
||||||
description: '',
|
description: '',
|
||||||
metricAlias: 'metricbeat-*',
|
metricAlias: 'metrics-*,metricbeat-*',
|
||||||
logAlias: 'filebeat-*,kibana_sample_data_logs*',
|
logAlias: 'logs-*,filebeat-*,kibana_sample_data_logs*',
|
||||||
fields: {
|
fields: {
|
||||||
container: 'container.id',
|
container: 'container.id',
|
||||||
host: 'host.name',
|
host: 'host.name',
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* 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 { migrationMocks } from 'src/core/server/mocks';
|
||||||
|
import { addNewIndexingStrategyIndexNames } from './7_9_0_add_new_indexing_strategy_index_names';
|
||||||
|
import { infraSourceConfigurationSavedObjectName } from '../saved_object_type';
|
||||||
|
|
||||||
|
describe('infra source configuration migration function for 7.9.0', () => {
|
||||||
|
test('adds "logs-*" when the logAlias contains "filebeat-*"', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'filebeat-*,custom-log-index-*',
|
||||||
|
'custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(
|
||||||
|
createTestSourceConfiguration('filebeat-*,custom-log-index-*,logs-*', 'custom-metric-index-*')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('doesn\'t add "logs-*" when the logAlias doesn\'t contain "filebeat-*"', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'custom-log-index-*',
|
||||||
|
'custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('doesn\'t add "logs-*" when the logAlias already contains it', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'filebeat-*,logs-*,custom-log-index-*',
|
||||||
|
'custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('adds "metrics-*" when the logAlias contains "metricbeat-*"', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'custom-log-index-*',
|
||||||
|
'metricbeat-*,custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(
|
||||||
|
createTestSourceConfiguration(
|
||||||
|
'custom-log-index-*',
|
||||||
|
'metricbeat-*,custom-metric-index-*,metrics-*'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('doesn\'t add "metrics-*" when the logAlias doesn\'t contain "metricbeat-*"', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'custom-log-index-*',
|
||||||
|
'custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('doesn\'t add "metrics-*" when the metricAlias already contains it', () => {
|
||||||
|
const unmigratedConfiguration = createTestSourceConfiguration(
|
||||||
|
'custom-log-index-*',
|
||||||
|
'metrics-*,metricbeat-*,custom-metric-index-*'
|
||||||
|
);
|
||||||
|
|
||||||
|
const migratedConfiguration = addNewIndexingStrategyIndexNames(
|
||||||
|
unmigratedConfiguration,
|
||||||
|
migrationMocks.createContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(migratedConfiguration).toStrictEqual(unmigratedConfiguration);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTestSourceConfiguration = (logAlias: string, metricAlias: string) => ({
|
||||||
|
attributes: {
|
||||||
|
name: 'TEST CONFIGURATION',
|
||||||
|
description: '',
|
||||||
|
fields: {
|
||||||
|
pod: 'TEST POD FIELD',
|
||||||
|
host: 'TEST HOST FIELD',
|
||||||
|
message: ['TEST MESSAGE FIELD'],
|
||||||
|
container: 'TEST CONTAINER FIELD',
|
||||||
|
timestamp: 'TEST TIMESTAMP FIELD',
|
||||||
|
tiebreaker: 'TEST TIEBREAKER FIELD',
|
||||||
|
},
|
||||||
|
inventoryDefaultView: '0',
|
||||||
|
metricsExplorerDefaultView: '0',
|
||||||
|
logColumns: [
|
||||||
|
{
|
||||||
|
fieldColumn: {
|
||||||
|
id: 'TEST FIELD COLUMN ID',
|
||||||
|
field: 'TEST FIELD COLUMN FIELD',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
logAlias,
|
||||||
|
metricAlias,
|
||||||
|
},
|
||||||
|
id: 'TEST_ID',
|
||||||
|
type: infraSourceConfigurationSavedObjectName,
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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 { SavedObjectMigrationFn } from 'src/core/server';
|
||||||
|
import { InfraSourceConfiguration } from '../../../../common/http_api/source_api';
|
||||||
|
|
||||||
|
export const addNewIndexingStrategyIndexNames: SavedObjectMigrationFn<
|
||||||
|
InfraSourceConfiguration,
|
||||||
|
InfraSourceConfiguration
|
||||||
|
> = (sourceConfigurationDocument) => {
|
||||||
|
const oldLogAliasSegments = sourceConfigurationDocument.attributes.logAlias.split(',');
|
||||||
|
const oldMetricAliasSegments = sourceConfigurationDocument.attributes.metricAlias.split(',');
|
||||||
|
|
||||||
|
const newLogAliasSegment = 'logs-*';
|
||||||
|
const newMetricAliasSegment = 'metrics-*';
|
||||||
|
|
||||||
|
return {
|
||||||
|
...sourceConfigurationDocument,
|
||||||
|
attributes: {
|
||||||
|
...sourceConfigurationDocument.attributes,
|
||||||
|
logAlias:
|
||||||
|
oldLogAliasSegments.includes('filebeat-*') &&
|
||||||
|
!oldLogAliasSegments.includes(newLogAliasSegment)
|
||||||
|
? [...oldLogAliasSegments, newLogAliasSegment].join(',')
|
||||||
|
: sourceConfigurationDocument.attributes.logAlias,
|
||||||
|
metricAlias:
|
||||||
|
oldMetricAliasSegments.includes('metricbeat-*') &&
|
||||||
|
!oldMetricAliasSegments.includes(newMetricAliasSegment)
|
||||||
|
? [...oldMetricAliasSegments, newMetricAliasSegment].join(',')
|
||||||
|
: sourceConfigurationDocument.attributes.metricAlias,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
|
@ -4,8 +4,8 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
|
||||||
import { SavedObjectsType } from 'src/core/server';
|
import { SavedObjectsType } from 'src/core/server';
|
||||||
|
import { addNewIndexingStrategyIndexNames } from './migrations/7_9_0_add_new_indexing_strategy_index_names';
|
||||||
|
|
||||||
export const infraSourceConfigurationSavedObjectName = 'infrastructure-ui-source';
|
export const infraSourceConfigurationSavedObjectName = 'infrastructure-ui-source';
|
||||||
|
|
||||||
|
@ -86,4 +86,7 @@ export const infraSourceConfigurationSavedObjectType: SavedObjectsType = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
migrations: {
|
||||||
|
'7.9.0': addNewIndexingStrategyIndexNames,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
expect(origin).to.be('fallback');
|
expect(origin).to.be('fallback');
|
||||||
expect(configuration.name).to.be('Default');
|
expect(configuration.name).to.be('Default');
|
||||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(configuration.fields.timestamp).to.be('@timestamp');
|
expect(configuration.fields.timestamp).to.be('@timestamp');
|
||||||
expect(configuration.fields.tiebreaker).to.be('_doc');
|
expect(configuration.fields.tiebreaker).to.be('_doc');
|
||||||
expect(configuration.logColumns[0]).to.have.key('timestampColumn');
|
expect(configuration.logColumns[0]).to.have.key('timestampColumn');
|
||||||
|
@ -97,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
expect(configuration.name).to.be('Default');
|
expect(configuration.name).to.be('Default');
|
||||||
expect(origin).to.be('stored');
|
expect(origin).to.be('stored');
|
||||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(configuration.fields.timestamp).to.be('@timestamp');
|
expect(configuration.fields.timestamp).to.be('@timestamp');
|
||||||
expect(configuration.fields.tiebreaker).to.be('_doc');
|
expect(configuration.fields.tiebreaker).to.be('_doc');
|
||||||
expect(configuration.logColumns).to.have.length(3);
|
expect(configuration.logColumns).to.have.length(3);
|
||||||
|
@ -166,7 +166,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
expect(configuration.name).to.be('NAME');
|
expect(configuration.name).to.be('NAME');
|
||||||
expect(origin).to.be('stored');
|
expect(origin).to.be('stored');
|
||||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(configuration.fields.timestamp).to.be('@timestamp');
|
expect(configuration.fields.timestamp).to.be('@timestamp');
|
||||||
expect(configuration.fields.tiebreaker).to.be('_doc');
|
expect(configuration.fields.tiebreaker).to.be('_doc');
|
||||||
expect(configuration.logColumns).to.have.length(3);
|
expect(configuration.logColumns).to.have.length(3);
|
||||||
|
|
|
@ -40,8 +40,8 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
// shipped default values
|
// shipped default values
|
||||||
expect(sourceConfiguration.name).to.be('Default');
|
expect(sourceConfiguration.name).to.be('Default');
|
||||||
expect(sourceConfiguration.metricAlias).to.be('metricbeat-*');
|
expect(sourceConfiguration.metricAlias).to.be('metrics-*,metricbeat-*');
|
||||||
expect(sourceConfiguration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(sourceConfiguration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(sourceConfiguration.fields.container).to.be('container.id');
|
expect(sourceConfiguration.fields.container).to.be('container.id');
|
||||||
expect(sourceConfiguration.fields.host).to.be('host.name');
|
expect(sourceConfiguration.fields.host).to.be('host.name');
|
||||||
expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid');
|
expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid');
|
||||||
|
@ -125,8 +125,8 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
expect(updatedAt).to.be.greaterThan(0);
|
expect(updatedAt).to.be.greaterThan(0);
|
||||||
expect(configuration.name).to.be('NAME');
|
expect(configuration.name).to.be('NAME');
|
||||||
expect(configuration.description).to.be('');
|
expect(configuration.description).to.be('');
|
||||||
expect(configuration.metricAlias).to.be('metricbeat-*');
|
expect(configuration.metricAlias).to.be('metrics-*,metricbeat-*');
|
||||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(configuration.fields.container).to.be('container.id');
|
expect(configuration.fields.container).to.be('container.id');
|
||||||
expect(configuration.fields.host).to.be('host.name');
|
expect(configuration.fields.host).to.be('host.name');
|
||||||
expect(configuration.fields.pod).to.be('kubernetes.pod.uid');
|
expect(configuration.fields.pod).to.be('kubernetes.pod.uid');
|
||||||
|
@ -283,7 +283,7 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
expect(version).to.not.be(initialVersion);
|
expect(version).to.not.be(initialVersion);
|
||||||
expect(updatedAt).to.be.greaterThan(createdAt);
|
expect(updatedAt).to.be.greaterThan(createdAt);
|
||||||
expect(configuration.metricAlias).to.be('metricbeat-**');
|
expect(configuration.metricAlias).to.be('metricbeat-**');
|
||||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||||
expect(status.logIndicesExist).to.be(true);
|
expect(status.logIndicesExist).to.be(true);
|
||||||
expect(status.metricIndicesExist).to.be(true);
|
expect(status.metricIndicesExist).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue