Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs UI] Use the Super date picker in the log stream #54280

Merged
merged 123 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from 116 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
2d0f48b
Track `startDate` and `endDate` in LogPositionState
Jan 8, 2020
a282a1e
Add the SuperDatePicker and wire it up to the date state
Jan 8, 2020
11aaa5d
Use date range for the log summary buckets
Jan 8, 2020
b42df03
Track start and end dates in URL
Jan 8, 2020
ca8a7d3
Adjust minimap to start/end range
Jan 9, 2020
7640ba6
Remove drag&drop from the minimap
Jan 9, 2020
24ee94c
Add API client to fetch entries
Jan 9, 2020
e430397
Deduplicate log summary bucket types
Jan 9, 2020
eeb64d4
Extract datemath helpers into a module
Jan 9, 2020
4c3ee9d
Allow arbitrary values in field columns
Jan 10, 2020
1abb4b7
Deprecate old log response in the reducer
Jan 10, 2020
154dc3f
Load entries from HTTP API
Jan 10, 2020
50bc02c
Extract column types
Jan 13, 2020
9d190ac
Adapt components to new API response
Jan 13, 2020
e3733fe
Allow jumping to specific points in time
Jan 13, 2020
cc62bf8
Adjust logic to fetch new entries
Jan 13, 2020
e66215a
Clean state when fetching new entries
Jan 13, 2020
db1df11
Handle empty responses in entries API
Jan 13, 2020
f48cbfc
Expose start and end timestamps from LogPositionState
Jan 13, 2020
ba1fb9a
Ensure entries fetch when changing dates.
Jan 13, 2020
5ceaf05
Restore scroll pagination functionality
Jan 14, 2020
c4d2748
Tweak types
Jan 14, 2020
e1760b0
Scaffold new loading indicators
Jan 15, 2020
353c697
Add tests for datemath utils
Jan 15, 2020
d5eb7e5
Implement `extendDatemath()`
Jan 15, 2020
b1dece7
DRY conditions to increase/decrease date amounts
Jan 15, 2020
cd7de34
DRY implementation of `extendDatemath`
Jan 15, 2020
40903d1
Extend log range
Jan 16, 2020
8e0773d
Perform unit conversion when extending time too much
Jan 16, 2020
c544c46
Prettify messages to extend time
Jan 16, 2020
5554fb7
Adjust scale for highlight markers
Jan 30, 2020
d84e923
Extract bucket size calculation to its own hook
Jan 30, 2020
1806925
Use the date range to fetch summary highlights
Jan 30, 2020
96ebf11
Wire stream buttons in superdatepicker
Jan 31, 2020
69b5fdc
Update timestamps for streaming
Jan 31, 2020
1a1d2a4
Link `endTimestamp` to realtime `now`
Feb 4, 2020
555c08a
s/isAutoReloading/isStreaming/g
Feb 4, 2020
339d041
Fetch Highlights with new API
Feb 4, 2020
da0b2d3
Prevent re-fetches of summary info
Feb 4, 2020
817c19b
Tweak loading message for streaming
Feb 5, 2020
d8d8040
Tweak initialization logic for LogPositionState
Feb 5, 2020
2f44984
Normalize `*Date` and `*Timestamp` names in the APIs
Feb 5, 2020
d7d738b
WIP: cleanup
Feb 5, 2020
c2c8b8d
Fix `logSummary` tests
Feb 5, 2020
57b6eaa
Fix types
Feb 5, 2020
ae97e49
Remove deprecated functions/methods from domain and adapter
Feb 5, 2020
f734141
Cleanup GraphQL
Feb 5, 2020
1e653c0
Deduplicate I18n keys
Feb 6, 2020
c4ecb92
Load date range with data in the tests
Feb 7, 2020
92a1c5b
Remove unused translations
Feb 7, 2020
d3e4521
Remove outdated tests
Feb 7, 2020
cb67abc
Refine minimap dimensions
Feb 12, 2020
0d232bb
Label all ticks in the time ruler
Feb 12, 2020
46ac4ae
Tweak time ruler format for small ranges
Feb 12, 2020
f699073
Adjust initial start-end range for initial position
Feb 13, 2020
1c227f3
Fix rendering of visible range in the minimap
Feb 13, 2020
93cd714
Keep position when expanding the date range
Feb 13, 2020
f57ef37
Be stricter with log entries container
Feb 13, 2020
b9c6013
Round `endDate` up
Feb 14, 2020
d6acab1
Ensure timeRange falls within range
Feb 14, 2020
220e8d6
Correctly set the initial start and end date if there is no initial p…
Feb 14, 2020
393c7f1
Fix link-to test
Feb 14, 2020
3f53f55
Remove minimap scale configuration
Feb 17, 2020
929037b
Merge branch 'master' into 49154-logs-super-date-picker
Feb 20, 2020
b6fc19b
Properly pluralise the timeframe extension messages
Feb 21, 2020
10a4397
Fix density chart edges
Feb 26, 2020
a96579c
Tweak message part types
Feb 26, 2020
660eb5b
Align function name with Kibana standards
Feb 26, 2020
4dc15ae
Simplify positioning in minimap components
Feb 26, 2020
0dec6e3
Tweak "extend time frame" button labels
Feb 26, 2020
f0e1563
Remove outdated state field
Feb 28, 2020
45d032f
Update the timestamps when user clicks "refresh"
Mar 2, 2020
5a6dddc
Remove `*Date` range from useLogEntries hook
Mar 2, 2020
1d4b94e
Remove `*Date` range from useLogSummary hook
Mar 2, 2020
fe3a704
Remove `*Date` range from logSummaryHighlights
Mar 3, 2020
e6e00ce
Remove outdated function
Mar 3, 2020
1e42ffa
Rename `*Date` to `*DateExpression`
Mar 3, 2020
7ca1bb4
Cleanup unused variables
Mar 3, 2020
bf842fb
Redefine "Live streaming"
Mar 4, 2020
691ea8b
Extract datepicker into its own component
Mar 4, 2020
2538f2d
Cleanup unused code
Mar 4, 2020
0d8e0da
Tweak time markers on the edges
Mar 4, 2020
905da3a
Use relative time when streaming
Mar 4, 2020
adf5d14
Add missing component
Mar 4, 2020
bdc93a2
Merge branch 'master' into 49154-logs-super-date-picker
elasticmachine Mar 5, 2020
20a0558
Extract type
Mar 5, 2020
6c8abc8
Tweak dependency lists for summary hooks
Mar 5, 2020
a17e0b4
Extend absolute datemath expressions
Mar 5, 2020
6c6f10f
Fix test runner URL navigation
Mar 5, 2020
2f25ef2
Extract magic number to a constant
Mar 6, 2020
74ccb62
Remove outdated comment
Mar 6, 2020
a906bd7
Make `timestamp` mandatory in LogTextStreamLoadingItemView
Mar 6, 2020
d0de07a
Update doc comment
Mar 6, 2020
cb750bb
Merge branch 'master' into 49154-logs-super-date-picker
Mar 6, 2020
fe6f1a6
Prevent infinite reloads at bottom edge
Mar 6, 2020
67909c1
Tweak time markers for the range edges
Mar 6, 2020
0c738ea
Ensure `LoadingItemView` always have the same height
Mar 6, 2020
899b423
Fix entry loading if streaming is on
Mar 6, 2020
b8ae1e6
Prefix boolean flag
Mar 6, 2020
527ecf6
Extract test constants to shared location
Mar 6, 2020
e1f404d
Remove unused translations
Mar 6, 2020
5a1103b
Change default range behaviour if a log position is pre-set
Mar 9, 2020
7e1c228
Type `navigateTo` methods
Mar 9, 2020
adaca95
Clean type casts
Mar 10, 2020
b98afb2
Add miscellaneous tweaks
Mar 10, 2020
45c8d3f
Add miscelalneous tweaks
Mar 11, 2020
72c6818
Use standard `querystring` to set the tests url
Mar 11, 2020
de97635
Allow `null` in some parts of the API
Mar 11, 2020
db61f05
Tweak `updateDateRange` callback
Mar 11, 2020
81cf057
Restore test for default columns
Mar 12, 2020
4586cdb
Restore logs_without_millis test
Mar 12, 2020
4241e02
Merge branch 'master' into 49154-logs-super-date-picker
Mar 12, 2020
01aa571
Prevent overserializing
Mar 12, 2020
bb75f8f
Fix commit 01aa5716
Mar 12, 2020
2a85f3d
Fix type errors introduced when merging upstream
Mar 12, 2020
2737bb5
Tweak entry highlight fetching
Mar 16, 2020
18a9324
Remove unused imports
Mar 16, 2020
a146692
Refactor how `timestamps` are calculated
Mar 17, 2020
780c7fc
Merge branch 'master' into 49154-logs-super-date-picker
Mar 17, 2020
af41535
Fix typo
Mar 17, 2020
a806e3a
Tweak refresh of `endTimestamp`
Mar 18, 2020
5269c24
Expose `centerCursor` from `logEntriesState`
Mar 18, 2020
7afe86c
Merge branch 'master' into 49154-logs-super-date-picker
Mar 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 39 additions & 33 deletions x-pack/plugins/infra/common/http_api/log_entries/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export const LOG_ENTRIES_PATH = '/api/log_entries/entries';
export const logEntriesBaseRequestRT = rt.intersection([
rt.type({
sourceId: rt.string,
startDate: rt.number,
endDate: rt.number,
startTimestamp: rt.number,
endTimestamp: rt.number,
}),
rt.partial({
query: rt.string,
query: rt.union([rt.string, rt.null]),
size: rt.number,
}),
]);
Expand All @@ -31,7 +31,7 @@ export const logEntriesAfterRequestRT = rt.intersection([
rt.type({ after: rt.union([logEntriesCursorRT, rt.literal('first')]) }),
]);

export const logEntriesCenteredRT = rt.intersection([
export const logEntriesCenteredRequestRT = rt.intersection([
logEntriesBaseRequestRT,
rt.type({ center: logEntriesCursorRT }),
]);
Expand All @@ -40,54 +40,60 @@ export const logEntriesRequestRT = rt.union([
logEntriesBaseRequestRT,
logEntriesBeforeRequestRT,
logEntriesAfterRequestRT,
logEntriesCenteredRT,
logEntriesCenteredRequestRT,
]);

export type LogEntriesBaseRequest = rt.TypeOf<typeof logEntriesBaseRequestRT>;
export type LogEntriesBeforeRequest = rt.TypeOf<typeof logEntriesBeforeRequestRT>;
export type LogEntriesAfterRequest = rt.TypeOf<typeof logEntriesAfterRequestRT>;
export type LogEntriesCenteredRequest = rt.TypeOf<typeof logEntriesCenteredRequestRT>;
export type LogEntriesRequest = rt.TypeOf<typeof logEntriesRequestRT>;

// JSON value
const valueRT = rt.union([rt.string, rt.number, rt.boolean, rt.object, rt.null, rt.undefined]);
export const logMessageConstantPartRT = rt.type({
constant: rt.string,
});
export const logMessageFieldPartRT = rt.type({
field: rt.string,
value: rt.unknown,
highlights: rt.array(rt.string),
});

export const logMessagePartRT = rt.union([
rt.type({
constant: rt.string,
}),
rt.type({
field: rt.string,
value: valueRT,
highlights: rt.array(rt.string),
}),
]);
export const logMessagePartRT = rt.union([logMessageConstantPartRT, logMessageFieldPartRT]);

export const logColumnRT = rt.union([
rt.type({ columnId: rt.string, timestamp: rt.number }),
rt.type({
columnId: rt.string,
field: rt.string,
value: rt.union([rt.string, rt.undefined]),
highlights: rt.array(rt.string),
}),
rt.type({
columnId: rt.string,
message: rt.array(logMessagePartRT),
}),
]);
export const logTimestampColumnRT = rt.type({ columnId: rt.string, timestamp: rt.number });
export const logFieldColumnRT = rt.type({
columnId: rt.string,
field: rt.string,
value: rt.unknown,
highlights: rt.array(rt.string),
});
export const logMessageColumnRT = rt.type({
columnId: rt.string,
message: rt.array(logMessagePartRT),
});

export const logColumnRT = rt.union([logTimestampColumnRT, logFieldColumnRT, logMessageColumnRT]);

export const logEntryRT = rt.type({
id: rt.string,
cursor: logEntriesCursorRT,
columns: rt.array(logColumnRT),
});

export type LogMessagepart = rt.TypeOf<typeof logMessagePartRT>;
export type LogMessageConstantPart = rt.TypeOf<typeof logMessageConstantPartRT>;
export type LogMessageFieldPart = rt.TypeOf<typeof logMessageFieldPartRT>;
export type LogMessagePart = rt.TypeOf<typeof logMessagePartRT>;
export type LogTimestampColumn = rt.TypeOf<typeof logTimestampColumnRT>;
export type LogFieldColumn = rt.TypeOf<typeof logFieldColumnRT>;
export type LogMessageColumn = rt.TypeOf<typeof logMessageColumnRT>;
export type LogColumn = rt.TypeOf<typeof logColumnRT>;
export type LogEntry = rt.TypeOf<typeof logEntryRT>;

export const logEntriesResponseRT = rt.type({
data: rt.type({
entries: rt.array(logEntryRT),
topCursor: logEntriesCursorRT,
bottomCursor: logEntriesCursorRT,
topCursor: rt.union([logEntriesCursorRT, rt.null]),
bottomCursor: rt.union([logEntriesCursorRT, rt.null]),
}),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
logEntriesBaseRequestRT,
logEntriesBeforeRequestRT,
logEntriesAfterRequestRT,
logEntriesCenteredRT,
logEntriesCenteredRequestRT,
logEntryRT,
} from './entries';
import { logEntriesCursorRT } from './common';
Expand All @@ -36,7 +36,7 @@ export const logEntriesHighlightsAfterRequestRT = rt.intersection([
]);

export const logEntriesHighlightsCenteredRequestRT = rt.intersection([
logEntriesCenteredRT,
logEntriesCenteredRequestRT,
highlightsRT,
]);

Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/infra/common/http_api/log_entries/summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const LOG_ENTRIES_SUMMARY_PATH = '/api/log_entries/summary';

export const logEntriesSummaryRequestRT = rt.type({
sourceId: rt.string,
startDate: rt.number,
endDate: rt.number,
startTimestamp: rt.number,
endTimestamp: rt.number,
bucketSize: rt.number,
query: rt.union([rt.string, rt.undefined, rt.null]),
});
Expand Down
73 changes: 73 additions & 0 deletions x-pack/plugins/infra/public/components/logging/log_datepicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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 React, { useCallback } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker, EuiButtonEmpty } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

interface LogDatepickerProps {
startDateExpression: string;
endDateExpression: string;
isStreaming: boolean;
onUpdateDateRange?: (range: { startDateExpression: string; endDateExpression: string }) => void;
onStartStreaming?: () => void;
onStopStreaming?: () => void;
}

export const LogDatepicker: React.FC<LogDatepickerProps> = ({
afgomez marked this conversation as resolved.
Show resolved Hide resolved
startDateExpression,
endDateExpression,
isStreaming,
onUpdateDateRange,
onStartStreaming,
onStopStreaming,
}) => {
const handleTimeChange = useCallback(
({ start, end, isInvalid }) => {
if (onUpdateDateRange && !isInvalid) {
onUpdateDateRange({ startDateExpression: start, endDateExpression: end });
}
},
[onUpdateDateRange]
);

return (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiSuperDatePicker
start={startDateExpression}
end={endDateExpression}
onTimeChange={handleTimeChange}
showUpdateButton={false}
// @ts-ignore: EuiSuperDatePicker doesn't expose the `isDisabled` prop, although it exists.
isDisabled={isStreaming}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{isStreaming ? (
<EuiButtonEmpty
color="primary"
iconType="pause"
iconSide="left"
onClick={onStopStreaming}
>
<FormattedMessage
id="xpack.infra.logs.stopStreamingButtonLabel"
defaultMessage="Stop streaming"
/>
</EuiButtonEmpty>
) : (
<EuiButtonEmpty iconType="play" iconSide="left" onClick={onStartStreaming}>
<FormattedMessage
id="xpack.infra.logs.startStreamingButtonLabel"
defaultMessage="Stream live"
/>
</EuiButtonEmpty>
)}
</EuiFlexItem>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { max } from 'lodash';
import * as React from 'react';

import { euiStyled } from '../../../../../observability/public';
import { SummaryBucket } from './types';
import { LogEntriesSummaryBucket } from '../../../../common/http_api';

interface DensityChartProps {
buckets: SummaryBucket[];
buckets: LogEntriesSummaryBucket[];
end: number;
start: number;
width: number;
Expand All @@ -38,36 +38,36 @@ export const DensityChart: React.FC<DensityChartProps> = ({
const xMax = max(buckets.map(bucket => bucket.entriesCount)) || 0;
const xScale = scaleLinear()
.domain([0, xMax])
.range([0, width * (2 / 3)]);
.range([0, width]);

const path = area<SummaryBucket>()
const path = area<LogEntriesSummaryBucket>()
.x0(xScale(0))
.x1(bucket => xScale(bucket.entriesCount))
.y(bucket => yScale((bucket.start + bucket.end) / 2))
.y0(bucket => yScale(bucket.start))
.y1(bucket => yScale(bucket.end))
.curve(curveMonotoneY);
const pathData = path(buckets);

const highestPathCoord = String(pathData)
.replace(/[^.0-9,]/g, ' ')
.split(/[ ,]/)
.reduce((result, num) => (Number(num) > result ? Number(num) : result), 0);
const firstBucket = buckets[0];
const lastBucket = buckets[buckets.length - 1];
const pathBuckets = [
// Make sure the graph starts at the count of the first point
{ start, end: start, entriesCount: firstBucket.entriesCount },
...buckets,
// Make sure the line ends at the height of the last point
{ start: lastBucket.end, end: lastBucket.end, entriesCount: lastBucket.entriesCount },
// If the last point is not at the end of the minimap, make sure it doesn't extend indefinitely and goes to 0
{ start: end, end, entriesCount: 0 },
];
const pathData = path(pathBuckets);

return (
<g transform={`translate(${width / 3}, 0)`}>
<DensityChartNegativeBackground
transform={`translate(${-width / 3}, 0)`}
width={width / 2}
height={highestPathCoord}
/>
<DensityChartPositiveBackground width={width * (2 / 3)} height={highestPathCoord} />
<g>
<DensityChartPositiveBackground width={width} height={height} />
<PositiveAreaPath d={pathData || ''} />
</g>
);
};

const DensityChartNegativeBackground = euiStyled.rect`
fill: ${props => props.theme.eui.euiColorEmptyShade};
`;

const DensityChartPositiveBackground = euiStyled.rect`
fill: ${props =>
props.theme.darkMode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface HighlightedIntervalProps {
getPositionOfTime: (time: number) => number;
start: number;
end: number;
targetWidth: number;
width: number;
target: number | null;
}
Expand All @@ -22,6 +23,7 @@ export const HighlightedInterval: React.FC<HighlightedIntervalProps> = ({
end,
getPositionOfTime,
start,
targetWidth,
width,
target,
}) => {
Expand All @@ -35,14 +37,14 @@ export const HighlightedInterval: React.FC<HighlightedIntervalProps> = ({
<HighlightTargetMarker
className={className}
x1={0}
x2={width / 3}
x2={targetWidth}
y1={yTarget}
y2={yTarget}
/>
)}
<HighlightPolygon
className={className}
points={` ${width / 3},${yStart} ${width},${yStart} ${width},${yEnd} ${width / 3},${yEnd}`}
points={` ${targetWidth},${yStart} ${width},${yStart} ${width},${yEnd} ${targetWidth},${yEnd}`}
/>
</>
);
Expand Down
Loading