Skip to content

Commit

Permalink
PR amendments
Browse files Browse the repository at this point in the history
- Fix typechecking
- Add an empty log example column header to account for the context menu
- Add anomaly start time to rows
  • Loading branch information
Kerry350 committed Jul 2, 2020
1 parent 5b06276 commit 390ecdd
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { AnomalyRecord } from '../../use_log_entry_rate_results';
import { useLogEntryRateModuleContext } from '../../use_log_entry_rate_module';
import { useLogEntryRateExamples } from '../../use_log_entry_rate_examples';
import { LogEntryExampleMessages } from '../../../../../components/logging/log_entry_examples/log_entry_examples';
import { bucketSpan } from '../../../../../../common/log_analysis/job_parameters';
import { LogEntryRateExampleMessage, LogEntryRateExampleMessageHeaders } from './log_entry_example';
import { euiStyled } from '../../../../../../../observability/public';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@ export const LogEntryRateExampleMessage: React.FunctionComponent<Props> = ({
return [
{
label: VIEW_IN_STREAM_LABEL,
...viewInStreamLinkProps,
onClick: viewInStreamLinkProps.onClick,
href: viewInStreamLinkProps.href,
},
{
label: VIEW_ANOMALY_IN_ML_LABEL,
...viewAnomalyInMachineLearningLinkProps,
onClick: viewAnomalyInMachineLearningLinkProps.onClick,
href: viewAnomalyInMachineLearningLinkProps.href,
},
];
}, [viewInStreamLinkProps, viewAnomalyInMachineLearningLinkProps]);
Expand Down Expand Up @@ -236,44 +238,54 @@ export const LogEntryRateExampleMessageHeaders: React.FunctionComponent<{
}> = ({ dateTime }) => {
return (
<LogEntryRateExampleMessageHeadersWrapper>
{exampleMessageColumnConfigurations.map((columnConfiguration) => {
if (isTimestampLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
key={columnConfiguration.timestampColumn.id}
columnWidth={columnWidths[columnConfiguration.timestampColumn.id]}
data-test-subj="logColumnHeader timestampLogColumnHeader"
>
{localizedDate(dateTime)}
</LogColumnHeader>
);
} else if (isMessageLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
columnWidth={columnWidths[columnConfiguration.messageColumn.id]}
data-test-subj="logColumnHeader messageLogColumnHeader"
key={columnConfiguration.messageColumn.id}
>
Message
</LogColumnHeader>
);
} else if (isFieldLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
columnWidth={columnWidths[columnConfiguration.fieldColumn.id]}
data-test-subj="logColumnHeader fieldLogColumnHeader"
key={columnConfiguration.fieldColumn.id}
>
{columnConfiguration.fieldColumn.field}
</LogColumnHeader>
);
}
})}
<>
{exampleMessageColumnConfigurations.map((columnConfiguration) => {
if (isTimestampLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
key={columnConfiguration.timestampColumn.id}
columnWidth={columnWidths[columnConfiguration.timestampColumn.id]}
data-test-subj="logColumnHeader timestampLogColumnHeader"
>
{localizedDate(dateTime)}
</LogColumnHeader>
);
} else if (isMessageLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
columnWidth={columnWidths[columnConfiguration.messageColumn.id]}
data-test-subj="logColumnHeader messageLogColumnHeader"
key={columnConfiguration.messageColumn.id}
>
Message
</LogColumnHeader>
);
} else if (isFieldLogColumnConfiguration(columnConfiguration)) {
return (
<LogColumnHeader
columnWidth={columnWidths[columnConfiguration.fieldColumn.id]}
data-test-subj="logColumnHeader fieldLogColumnHeader"
key={columnConfiguration.fieldColumn.id}
>
{columnConfiguration.fieldColumn.field}
</LogColumnHeader>
);
}
})}
<LogColumnHeader
columnWidth={columnWidths[iconColumnId]}
data-test-subj="logColumnHeader contextMenuLogColumnHeader"
key={'icon-column-header'}
>
{null}
</LogColumnHeader>
</>
</LogEntryRateExampleMessageHeadersWrapper>
);
};

const LogEntryRateExampleMessageHeadersWrapper = euiStyled(LogColumnHeadersWrapper)`
border-bottom: none;
box-shadow: none;
padding-right: 0;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui';
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
import moment from 'moment';
import { i18n } from '@kbn/i18n';
import React, { useCallback, useMemo, useState } from 'react';
import { useSet } from 'react-use';
Expand All @@ -18,13 +19,15 @@ import { RowExpansionButton } from '../../../../../components/basic_table';
import { LogEntryRateResults } from '../../use_log_entry_rate_results';
import { AnomaliesTableExpandedRow } from './expanded_row';
import { AnomalySeverityIndicator } from '../../../../../components/logging/log_analysis_results/anomaly_severity_indicator';
import { useKibanaUiSetting } from '../../../../../utils/use_kibana_ui_setting';

interface TableItem {
id: string;
dataset: string;
datasetName: string;
anomalyScore: number;
anomalyMessage: string;
startTime: number;
}

interface SortingOptions {
Expand Down Expand Up @@ -56,6 +59,13 @@ const anomalyMessageColumnName = i18n.translate(
}
);

const anomalyStartTimeColumnName = i18n.translate(
'xpack.infra.logs.analysis.anomaliesTableAnomalyStartTime',
{
defaultMessage: 'Start time',
}
);

const datasetColumnName = i18n.translate(
'xpack.infra.logs.analysis.anomaliesTableAnomalyDatasetName',
{
Expand Down Expand Up @@ -89,6 +99,8 @@ export const AnomaliesTable: React.FunctionComponent<{
timeRange: TimeRange;
jobId: string;
}> = ({ results, timeRange, setTimeRange, jobId }) => {
const [dateFormat] = useKibanaUiSetting('dateFormat', 'Y-MM-DD HH:mm:ss');

const tableItems: TableItem[] = useMemo(() => {
return results.anomalies.map((anomaly) => {
return {
Expand All @@ -97,11 +109,12 @@ export const AnomaliesTable: React.FunctionComponent<{
datasetName: getFriendlyNameForPartitionId(anomaly.partitionId),
anomalyScore: formatAnomalyScore(anomaly.anomalyScore),
anomalyMessage: getAnomalyMessage(anomaly.actualLogEntryRate, anomaly.typicalLogEntryRate),
startTime: anomaly.startTime,
};
});
}, [results]);

const [expandedIds, { add: expandDataset, remove: collapseDataset }] = useSet<string>(new Set());
const [expandedIds, { add: expandId, remove: collapseId }] = useSet<string>(new Set());

const expandedDatasetRowContents = useMemo(
() =>
Expand Down Expand Up @@ -167,7 +180,10 @@ export const AnomaliesTable: React.FunctionComponent<{
sortedItems = tableItems.sort((a, b) => (a.datasetName > b.datasetName ? 1 : -1));
} else if (sorting.sort.field === 'anomalyScore') {
sortedItems = tableItems.sort((a, b) => a.anomalyScore - b.anomalyScore);
} else if (sorting.sort.field === 'startTime') {
sortedItems = tableItems.sort((a, b) => a.startTime - b.startTime);
}

return sorting.sort.direction === 'asc' ? sortedItems : sortedItems.reverse();
}, [tableItems, sorting]);

Expand All @@ -193,6 +209,14 @@ export const AnomaliesTable: React.FunctionComponent<{
sortable: false,
truncateText: true,
},
{
field: 'startTime',
name: anomalyStartTimeColumnName,
sortable: true,
truncateText: true,
width: '230px',
render: (startTime: number) => moment(startTime).format(dateFormat),
},
{
field: 'datasetName',
name: datasetColumnName,
Expand All @@ -208,13 +232,13 @@ export const AnomaliesTable: React.FunctionComponent<{
<RowExpansionButton
isExpanded={expandedIds.has(item.id)}
item={item.id}
onExpand={expandDataset}
onCollapse={collapseDataset}
onExpand={expandId}
onCollapse={collapseId}
/>
),
},
],
[collapseDataset, expandDataset, expandedIds]
[collapseId, expandId, expandedIds, dateFormat]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { schema } from '@kbn/config-schema';
import Boom from 'boom';
import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';

import { throwErrors } from '../../../../common/runtime_types';
import { createValidationFunction } from '../../../../common/runtime_types';
import { InfraBackendLibs } from '../../../lib/infra_types';
import { NoLogAnalysisResultsIndexError, getLogEntryRateExamples } from '../../../lib/log_analysis';
import { assertHasInfraMlPlugins } from '../../../utils/request_context';
Expand All @@ -20,8 +15,6 @@ import {
LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH,
} from '../../../../common/http_api/log_analysis';

const anyObject = schema.object({}, { unknowns: 'allow' });

export const initGetLogEntryRateExamplesRoute = ({ framework, sources }: InfraBackendLibs) => {
framework.registerRoute(
{
Expand Down

0 comments on commit 390ecdd

Please sign in to comment.