[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;
|
||||
readOnly: boolean;
|
||||
podFieldProps: InputFieldProps;
|
||||
tiebreakerFieldProps: InputFieldProps;
|
||||
timestampFieldProps: InputFieldProps;
|
||||
displaySettings: 'metrics' | 'logs';
|
||||
}
|
||||
|
||||
export const FieldsConfigurationPanel = ({
|
||||
|
@ -38,15 +36,12 @@ export const FieldsConfigurationPanel = ({
|
|||
isLoading,
|
||||
readOnly,
|
||||
podFieldProps,
|
||||
tiebreakerFieldProps,
|
||||
timestampFieldProps,
|
||||
displaySettings,
|
||||
}: FieldsConfigurationPanelProps) => {
|
||||
const isHostValueDefault = hostFieldProps.value === 'host.name';
|
||||
const isContainerValueDefault = containerFieldProps.value === 'container.id';
|
||||
const isPodValueDefault = podFieldProps.value === 'kubernetes.pod.uid';
|
||||
const isTimestampValueDefault = timestampFieldProps.value === '@timestamp';
|
||||
const isTiebreakerValueDefault = tiebreakerFieldProps.value === '_doc';
|
||||
return (
|
||||
<EuiForm>
|
||||
<EuiTitle size="s">
|
||||
|
@ -139,57 +134,6 @@ export const FieldsConfigurationPanel = ({
|
|||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
{displaySettings === 'logs' && (
|
||||
<>
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldLabel"
|
||||
defaultMessage="Tiebreaker"
|
||||
/>
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldDescription"
|
||||
defaultMessage="Field used to break ties between two entries with the same timestamp"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFormRow
|
||||
error={tiebreakerFieldProps.error}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldRecommendedValue"
|
||||
defaultMessage="The recommended value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>_doc</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isInvalid={tiebreakerFieldProps.isInvalid}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.tiebreakerFieldLabel"
|
||||
defaultMessage="Tiebreaker"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
fullWidth
|
||||
disabled={isLoading || isTiebreakerValueDefault}
|
||||
readOnly={readOnly}
|
||||
isLoading={isLoading}
|
||||
{...tiebreakerFieldProps}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
)}
|
||||
{displaySettings === 'metrics' && (
|
||||
<>
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
|
@ -325,8 +269,6 @@ export const FieldsConfigurationPanel = ({
|
|||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
)}
|
||||
</EuiForm>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -21,17 +21,13 @@ import { InputFieldProps } from './input_fields';
|
|||
interface IndicesConfigurationPanelProps {
|
||||
isLoading: boolean;
|
||||
readOnly: boolean;
|
||||
logAliasFieldProps: InputFieldProps;
|
||||
metricAliasFieldProps: InputFieldProps;
|
||||
displaySettings: 'metrics' | 'logs';
|
||||
}
|
||||
|
||||
export const IndicesConfigurationPanel = ({
|
||||
isLoading,
|
||||
readOnly,
|
||||
logAliasFieldProps,
|
||||
metricAliasFieldProps,
|
||||
displaySettings,
|
||||
}: IndicesConfigurationPanelProps) => (
|
||||
<EuiForm>
|
||||
<EuiTitle size="s">
|
||||
|
@ -43,20 +39,19 @@ export const IndicesConfigurationPanel = ({
|
|||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
{displaySettings === 'metrics' && (
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.metricIndicesTitle"
|
||||
defaultMessage="Metric indices"
|
||||
defaultMessage="Metrics indices"
|
||||
/>
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.metricIndicesDescription"
|
||||
defaultMessage="Index pattern for matching indices that contain Metricbeat data"
|
||||
defaultMessage="Index pattern for matching indices that contain metrics data"
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
@ -68,7 +63,7 @@ export const IndicesConfigurationPanel = ({
|
|||
id="xpack.infra.sourceConfiguration.metricIndicesRecommendedValue"
|
||||
defaultMessage="The recommended value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>metricbeat-*</EuiCode>,
|
||||
defaultValue: <EuiCode>metrics-*,metricbeat-*</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
@ -76,7 +71,7 @@ export const IndicesConfigurationPanel = ({
|
|||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.infra.sourceConfiguration.metricIndicesLabel"
|
||||
defaultMessage="Metric indices"
|
||||
defaultMessage="Metrics indices"
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
@ -90,54 +85,5 @@ export const IndicesConfigurationPanel = ({
|
|||
/>
|
||||
</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>
|
||||
);
|
||||
|
|
|
@ -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 { IndicesConfigurationPanel } from './indices_configuration_panel';
|
||||
import { NameConfigurationPanel } from './name_configuration_panel';
|
||||
import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel';
|
||||
import { useSourceConfigurationFormState } from './source_configuration_form_state';
|
||||
import { SourceLoadingPage } from '../source_loading_page';
|
||||
import { Prompt } from '../../utils/navigation_warning_prompt';
|
||||
|
||||
interface SourceConfigurationSettingsProps {
|
||||
shouldAllowEdit: boolean;
|
||||
displaySettings: 'metrics' | 'logs';
|
||||
}
|
||||
|
||||
export const SourceConfigurationSettings = ({
|
||||
shouldAllowEdit,
|
||||
displaySettings,
|
||||
}: SourceConfigurationSettingsProps) => {
|
||||
const {
|
||||
createSourceConfiguration,
|
||||
|
@ -45,16 +42,8 @@ export const SourceConfigurationSettings = ({
|
|||
updateSourceConfiguration,
|
||||
} = useContext(Source.Context);
|
||||
|
||||
const availableFields = useMemo(
|
||||
() => (source && source.status ? source.status.indexFields.map((field) => field.name) : []),
|
||||
[source]
|
||||
);
|
||||
|
||||
const {
|
||||
addLogColumn,
|
||||
moveLogColumn,
|
||||
indicesConfigurationProps,
|
||||
logColumnConfigurationProps,
|
||||
errors,
|
||||
resetForm,
|
||||
isFormDirty,
|
||||
|
@ -119,10 +108,8 @@ export const SourceConfigurationSettings = ({
|
|||
<EuiPanel paddingSize="l">
|
||||
<IndicesConfigurationPanel
|
||||
isLoading={isLoading}
|
||||
logAliasFieldProps={indicesConfigurationProps.logAlias}
|
||||
metricAliasFieldProps={indicesConfigurationProps.metricAlias}
|
||||
readOnly={!isWriteable}
|
||||
displaySettings={displaySettings}
|
||||
/>
|
||||
</EuiPanel>
|
||||
<EuiSpacer />
|
||||
|
@ -133,23 +120,10 @@ export const SourceConfigurationSettings = ({
|
|||
isLoading={isLoading}
|
||||
podFieldProps={indicesConfigurationProps.podField}
|
||||
readOnly={!isWriteable}
|
||||
tiebreakerFieldProps={indicesConfigurationProps.tiebreakerField}
|
||||
timestampFieldProps={indicesConfigurationProps.timestampField}
|
||||
displaySettings={displaySettings}
|
||||
/>
|
||||
</EuiPanel>
|
||||
<EuiSpacer />
|
||||
{displaySettings === 'logs' && (
|
||||
<EuiPanel paddingSize="l">
|
||||
<LogColumnsConfigurationPanel
|
||||
addLogColumn={addLogColumn}
|
||||
moveLogColumn={moveLogColumn}
|
||||
availableFields={availableFields}
|
||||
isLoading={isLoading}
|
||||
logColumnConfiguration={logColumnConfigurationProps}
|
||||
/>
|
||||
</EuiPanel>
|
||||
)}
|
||||
{errors.length > 0 ? (
|
||||
<>
|
||||
<EuiCallOut color="danger">
|
||||
|
|
|
@ -62,7 +62,7 @@ export const IndicesConfigurationPanel = ({
|
|||
id="xpack.infra.sourceConfiguration.logIndicesRecommendedValue"
|
||||
defaultMessage="The recommended value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>filebeat-*</EuiCode>,
|
||||
defaultValue: <EuiCode>logs-*,filebeat-*</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ export const MetricsSettingsPage = () => {
|
|||
<EuiErrorBoundary>
|
||||
<SourceConfigurationSettings
|
||||
shouldAllowEdit={uiCapabilities?.infrastructure?.configureSource as boolean}
|
||||
displaySettings="metrics"
|
||||
/>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
|
|
|
@ -9,8 +9,8 @@ import { InfraSourceConfiguration } from '../../../common/http_api/source_api';
|
|||
export const defaultSourceConfiguration: InfraSourceConfiguration = {
|
||||
name: 'Default',
|
||||
description: '',
|
||||
metricAlias: 'metricbeat-*',
|
||||
logAlias: 'filebeat-*,kibana_sample_data_logs*',
|
||||
metricAlias: 'metrics-*,metricbeat-*',
|
||||
logAlias: 'logs-*,filebeat-*,kibana_sample_data_logs*',
|
||||
fields: {
|
||||
container: 'container.id',
|
||||
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.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
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';
|
||||
|
||||
|
@ -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(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.tiebreaker).to.be('_doc');
|
||||
expect(configuration.logColumns[0]).to.have.key('timestampColumn');
|
||||
|
@ -97,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
expect(configuration.name).to.be('Default');
|
||||
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.tiebreaker).to.be('_doc');
|
||||
expect(configuration.logColumns).to.have.length(3);
|
||||
|
@ -166,7 +166,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
expect(configuration.name).to.be('NAME');
|
||||
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.tiebreaker).to.be('_doc');
|
||||
expect(configuration.logColumns).to.have.length(3);
|
||||
|
|
|
@ -40,8 +40,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
// shipped default values
|
||||
expect(sourceConfiguration.name).to.be('Default');
|
||||
expect(sourceConfiguration.metricAlias).to.be('metricbeat-*');
|
||||
expect(sourceConfiguration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
||||
expect(sourceConfiguration.metricAlias).to.be('metrics-*,metricbeat-*');
|
||||
expect(sourceConfiguration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||
expect(sourceConfiguration.fields.container).to.be('container.id');
|
||||
expect(sourceConfiguration.fields.host).to.be('host.name');
|
||||
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(configuration.name).to.be('NAME');
|
||||
expect(configuration.description).to.be('');
|
||||
expect(configuration.metricAlias).to.be('metricbeat-*');
|
||||
expect(configuration.logAlias).to.be('filebeat-*,kibana_sample_data_logs*');
|
||||
expect(configuration.metricAlias).to.be('metrics-*,metricbeat-*');
|
||||
expect(configuration.logAlias).to.be('logs-*,filebeat-*,kibana_sample_data_logs*');
|
||||
expect(configuration.fields.container).to.be('container.id');
|
||||
expect(configuration.fields.host).to.be('host.name');
|
||||
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(updatedAt).to.be.greaterThan(createdAt);
|
||||
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.metricIndicesExist).to.be(true);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue