[Observability] Change appLink passing the date range (#71259)
* changing apm appLink * changing apm appLink * removing title from api * adding absolute and relative times * addressing pr comments * addressing pr comments * addressing pr comments * fixing TS issues * addressing pr comments Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
831e427682
commit
3374b2d3b0
|
@ -39,9 +39,9 @@ import { toggleAppLinkInNav } from './toggleAppLinkInNav';
|
||||||
import { setReadonlyBadge } from './updateBadge';
|
import { setReadonlyBadge } from './updateBadge';
|
||||||
import { createStaticIndexPattern } from './services/rest/index_pattern';
|
import { createStaticIndexPattern } from './services/rest/index_pattern';
|
||||||
import {
|
import {
|
||||||
fetchLandingPageData,
|
fetchOverviewPageData,
|
||||||
hasData,
|
hasData,
|
||||||
} from './services/rest/observability_dashboard';
|
} from './services/rest/apm_overview_fetchers';
|
||||||
|
|
||||||
export type ApmPluginSetup = void;
|
export type ApmPluginSetup = void;
|
||||||
export type ApmPluginStart = void;
|
export type ApmPluginStart = void;
|
||||||
|
@ -81,9 +81,7 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> {
|
||||||
if (plugins.observability) {
|
if (plugins.observability) {
|
||||||
plugins.observability.dashboard.register({
|
plugins.observability.dashboard.register({
|
||||||
appName: 'apm',
|
appName: 'apm',
|
||||||
fetchData: async (params) => {
|
fetchData: fetchOverviewPageData,
|
||||||
return fetchLandingPageData(params);
|
|
||||||
},
|
|
||||||
hasData,
|
hasData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,23 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fetchLandingPageData, hasData } from './observability_dashboard';
|
import moment from 'moment';
|
||||||
|
import { fetchOverviewPageData, hasData } from './apm_overview_fetchers';
|
||||||
import * as createCallApmApi from './createCallApmApi';
|
import * as createCallApmApi from './createCallApmApi';
|
||||||
|
|
||||||
describe('Observability dashboard data', () => {
|
describe('Observability dashboard data', () => {
|
||||||
const callApmApiMock = jest.spyOn(createCallApmApi, 'callApmApi');
|
const callApmApiMock = jest.spyOn(createCallApmApi, 'callApmApi');
|
||||||
|
const params = {
|
||||||
|
absoluteTime: {
|
||||||
|
start: moment('2020-07-02T13:25:11.629Z').valueOf(),
|
||||||
|
end: moment('2020-07-09T14:25:11.629Z').valueOf(),
|
||||||
|
},
|
||||||
|
relativeTime: {
|
||||||
|
start: 'now-15m',
|
||||||
|
end: 'now',
|
||||||
|
},
|
||||||
|
bucketSize: '600s',
|
||||||
|
};
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
callApmApiMock.mockClear();
|
callApmApiMock.mockClear();
|
||||||
});
|
});
|
||||||
|
@ -25,7 +37,7 @@ describe('Observability dashboard data', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fetchLandingPageData', () => {
|
describe('fetchOverviewPageData', () => {
|
||||||
it('returns APM data with series and stats', async () => {
|
it('returns APM data with series and stats', async () => {
|
||||||
callApmApiMock.mockImplementation(() =>
|
callApmApiMock.mockImplementation(() =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
@ -37,14 +49,9 @@ describe('Observability dashboard data', () => {
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const response = await fetchLandingPageData({
|
const response = await fetchOverviewPageData(params);
|
||||||
startTime: '1',
|
|
||||||
endTime: '2',
|
|
||||||
bucketSize: '3',
|
|
||||||
});
|
|
||||||
expect(response).toEqual({
|
expect(response).toEqual({
|
||||||
title: 'APM',
|
appLink: '/app/apm#/services?rangeFrom=now-15m&rangeTo=now',
|
||||||
appLink: '/app/apm',
|
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -73,14 +80,9 @@ describe('Observability dashboard data', () => {
|
||||||
transactionCoordinates: [],
|
transactionCoordinates: [],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const response = await fetchLandingPageData({
|
const response = await fetchOverviewPageData(params);
|
||||||
startTime: '1',
|
|
||||||
endTime: '2',
|
|
||||||
bucketSize: '3',
|
|
||||||
});
|
|
||||||
expect(response).toEqual({
|
expect(response).toEqual({
|
||||||
title: 'APM',
|
appLink: '/app/apm#/services?rangeFrom=now-15m&rangeTo=now',
|
||||||
appLink: '/app/apm',
|
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -105,14 +107,9 @@ describe('Observability dashboard data', () => {
|
||||||
transactionCoordinates: [{ x: 1 }, { x: 2 }, { x: 3 }],
|
transactionCoordinates: [{ x: 1 }, { x: 2 }, { x: 3 }],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const response = await fetchLandingPageData({
|
const response = await fetchOverviewPageData(params);
|
||||||
startTime: '1',
|
|
||||||
endTime: '2',
|
|
||||||
bucketSize: '3',
|
|
||||||
});
|
|
||||||
expect(response).toEqual({
|
expect(response).toEqual({
|
||||||
title: 'APM',
|
appLink: '/app/apm#/services?rangeFrom=now-15m&rangeTo=now',
|
||||||
appLink: '/app/apm',
|
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
type: 'number',
|
type: 'number',
|
|
@ -4,7 +4,6 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { mean } from 'lodash';
|
import { mean } from 'lodash';
|
||||||
import {
|
import {
|
||||||
ApmFetchDataResponse,
|
ApmFetchDataResponse,
|
||||||
|
@ -12,23 +11,26 @@ import {
|
||||||
} from '../../../../observability/public';
|
} from '../../../../observability/public';
|
||||||
import { callApmApi } from './createCallApmApi';
|
import { callApmApi } from './createCallApmApi';
|
||||||
|
|
||||||
export const fetchLandingPageData = async ({
|
export const fetchOverviewPageData = async ({
|
||||||
startTime,
|
absoluteTime,
|
||||||
endTime,
|
relativeTime,
|
||||||
bucketSize,
|
bucketSize,
|
||||||
}: FetchDataParams): Promise<ApmFetchDataResponse> => {
|
}: FetchDataParams): Promise<ApmFetchDataResponse> => {
|
||||||
const data = await callApmApi({
|
const data = await callApmApi({
|
||||||
pathname: '/api/apm/observability_dashboard',
|
pathname: '/api/apm/observability_overview',
|
||||||
params: { query: { start: startTime, end: endTime, bucketSize } },
|
params: {
|
||||||
|
query: {
|
||||||
|
start: new Date(absoluteTime.start).toISOString(),
|
||||||
|
end: new Date(absoluteTime.end).toISOString(),
|
||||||
|
bucketSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { serviceCount, transactionCoordinates } = data;
|
const { serviceCount, transactionCoordinates } = data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: i18n.translate('xpack.apm.observabilityDashboard.title', {
|
appLink: `/app/apm#/services?rangeFrom=${relativeTime.start}&rangeTo=${relativeTime.end}`,
|
||||||
defaultMessage: 'APM',
|
|
||||||
}),
|
|
||||||
appLink: '/app/apm',
|
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -54,6 +56,6 @@ export const fetchLandingPageData = async ({
|
||||||
|
|
||||||
export async function hasData() {
|
export async function hasData() {
|
||||||
return await callApmApi({
|
return await callApmApi({
|
||||||
pathname: '/api/apm/observability_dashboard/has_data',
|
pathname: '/api/apm/observability_overview/has_data',
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -79,9 +79,9 @@ import {
|
||||||
rumServicesRoute,
|
rumServicesRoute,
|
||||||
} from './rum_client';
|
} from './rum_client';
|
||||||
import {
|
import {
|
||||||
observabilityDashboardHasDataRoute,
|
observabilityOverviewHasDataRoute,
|
||||||
observabilityDashboardDataRoute,
|
observabilityOverviewRoute,
|
||||||
} from './observability_dashboard';
|
} from './observability_overview';
|
||||||
import {
|
import {
|
||||||
anomalyDetectionJobsRoute,
|
anomalyDetectionJobsRoute,
|
||||||
createAnomalyDetectionJobsRoute,
|
createAnomalyDetectionJobsRoute,
|
||||||
|
@ -176,8 +176,8 @@ const createApmApi = () => {
|
||||||
.add(rumServicesRoute)
|
.add(rumServicesRoute)
|
||||||
|
|
||||||
// Observability dashboard
|
// Observability dashboard
|
||||||
.add(observabilityDashboardHasDataRoute)
|
.add(observabilityOverviewHasDataRoute)
|
||||||
.add(observabilityDashboardDataRoute)
|
.add(observabilityOverviewRoute)
|
||||||
|
|
||||||
// Anomaly detection
|
// Anomaly detection
|
||||||
.add(anomalyDetectionJobsRoute)
|
.add(anomalyDetectionJobsRoute)
|
||||||
|
|
|
@ -5,22 +5,22 @@
|
||||||
*/
|
*/
|
||||||
import * as t from 'io-ts';
|
import * as t from 'io-ts';
|
||||||
import { setupRequest } from '../lib/helpers/setup_request';
|
import { setupRequest } from '../lib/helpers/setup_request';
|
||||||
import { hasData } from '../lib/observability_dashboard/has_data';
|
import { getServiceCount } from '../lib/observability_overview/get_service_count';
|
||||||
|
import { getTransactionCoordinates } from '../lib/observability_overview/get_transaction_coordinates';
|
||||||
|
import { hasData } from '../lib/observability_overview/has_data';
|
||||||
import { createRoute } from './create_route';
|
import { createRoute } from './create_route';
|
||||||
import { rangeRt } from './default_api_types';
|
import { rangeRt } from './default_api_types';
|
||||||
import { getServiceCount } from '../lib/observability_dashboard/get_service_count';
|
|
||||||
import { getTransactionCoordinates } from '../lib/observability_dashboard/get_transaction_coordinates';
|
|
||||||
|
|
||||||
export const observabilityDashboardHasDataRoute = createRoute(() => ({
|
export const observabilityOverviewHasDataRoute = createRoute(() => ({
|
||||||
path: '/api/apm/observability_dashboard/has_data',
|
path: '/api/apm/observability_overview/has_data',
|
||||||
handler: async ({ context, request }) => {
|
handler: async ({ context, request }) => {
|
||||||
const setup = await setupRequest(context, request);
|
const setup = await setupRequest(context, request);
|
||||||
return await hasData({ setup });
|
return await hasData({ setup });
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const observabilityDashboardDataRoute = createRoute(() => ({
|
export const observabilityOverviewRoute = createRoute(() => ({
|
||||||
path: '/api/apm/observability_dashboard',
|
path: '/api/apm/observability_overview',
|
||||||
params: {
|
params: {
|
||||||
query: t.intersection([rangeRt, t.type({ bucketSize: t.string })]),
|
query: t.intersection([rangeRt, t.type({ bucketSize: t.string })]),
|
||||||
},
|
},
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
exports[`Metrics UI Observability Homepage Functions createMetricsFetchData() should just work 1`] = `
|
exports[`Metrics UI Observability Homepage Functions createMetricsFetchData() should just work 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"appLink": "/app/metrics",
|
"appLink": "/app/metrics/inventory?waffleTime=(currentTime:1593696311629,isAutoReloading:!f)",
|
||||||
"series": Object {
|
"series": Object {
|
||||||
"inboundTraffic": Object {
|
"inboundTraffic": Object {
|
||||||
"coordinates": Array [
|
"coordinates": Array [
|
||||||
|
@ -203,6 +203,5 @@ Object {
|
||||||
"value": 3,
|
"value": 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"title": "Metrics",
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -53,12 +53,18 @@ describe('Metrics UI Observability Homepage Functions', () => {
|
||||||
const { core, mockedGetStartServices } = setup();
|
const { core, mockedGetStartServices } = setup();
|
||||||
core.http.post.mockResolvedValue(FAKE_SNAPSHOT_RESPONSE);
|
core.http.post.mockResolvedValue(FAKE_SNAPSHOT_RESPONSE);
|
||||||
const fetchData = createMetricsFetchData(mockedGetStartServices);
|
const fetchData = createMetricsFetchData(mockedGetStartServices);
|
||||||
const endTime = moment();
|
const endTime = moment('2020-07-02T13:25:11.629Z');
|
||||||
const startTime = endTime.clone().subtract(1, 'h');
|
const startTime = endTime.clone().subtract(1, 'h');
|
||||||
const bucketSize = '300s';
|
const bucketSize = '300s';
|
||||||
const response = await fetchData({
|
const response = await fetchData({
|
||||||
startTime: startTime.toISOString(),
|
absoluteTime: {
|
||||||
endTime: endTime.toISOString(),
|
start: startTime.valueOf(),
|
||||||
|
end: endTime.valueOf(),
|
||||||
|
},
|
||||||
|
relativeTime: {
|
||||||
|
start: 'now-15m',
|
||||||
|
end: 'now',
|
||||||
|
},
|
||||||
bucketSize,
|
bucketSize,
|
||||||
});
|
});
|
||||||
expect(core.http.post).toHaveBeenCalledTimes(1);
|
expect(core.http.post).toHaveBeenCalledTimes(1);
|
||||||
|
|
|
@ -4,15 +4,13 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import moment from 'moment';
|
import { isFinite, isNumber, sum } from 'lodash';
|
||||||
import { sum, isFinite, isNumber } from 'lodash';
|
import { FetchDataParams, MetricsFetchDataResponse } from '../../observability/public';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { MetricsFetchDataResponse, FetchDataParams } from '../../observability/public';
|
|
||||||
import {
|
import {
|
||||||
SnapshotRequest,
|
|
||||||
SnapshotMetricInput,
|
SnapshotMetricInput,
|
||||||
SnapshotNode,
|
SnapshotNode,
|
||||||
SnapshotNodeResponse,
|
SnapshotNodeResponse,
|
||||||
|
SnapshotRequest,
|
||||||
} from '../common/http_api/snapshot_api';
|
} from '../common/http_api/snapshot_api';
|
||||||
import { SnapshotMetricType } from '../common/inventory_models/types';
|
import { SnapshotMetricType } from '../common/inventory_models/types';
|
||||||
import { InfraClientCoreSetup } from './types';
|
import { InfraClientCoreSetup } from './types';
|
||||||
|
@ -77,13 +75,12 @@ export const combineNodeTimeseriesBy = (
|
||||||
|
|
||||||
export const createMetricsFetchData = (
|
export const createMetricsFetchData = (
|
||||||
getStartServices: InfraClientCoreSetup['getStartServices']
|
getStartServices: InfraClientCoreSetup['getStartServices']
|
||||||
) => async ({
|
) => async ({ absoluteTime, bucketSize }: FetchDataParams): Promise<MetricsFetchDataResponse> => {
|
||||||
startTime,
|
|
||||||
endTime,
|
|
||||||
bucketSize,
|
|
||||||
}: FetchDataParams): Promise<MetricsFetchDataResponse> => {
|
|
||||||
const [coreServices] = await getStartServices();
|
const [coreServices] = await getStartServices();
|
||||||
const { http } = coreServices;
|
const { http } = coreServices;
|
||||||
|
|
||||||
|
const { start, end } = absoluteTime;
|
||||||
|
|
||||||
const snapshotRequest: SnapshotRequest = {
|
const snapshotRequest: SnapshotRequest = {
|
||||||
sourceId: 'default',
|
sourceId: 'default',
|
||||||
metrics: ['cpu', 'memory', 'rx', 'tx'].map((type) => ({ type })) as SnapshotMetricInput[],
|
metrics: ['cpu', 'memory', 'rx', 'tx'].map((type) => ({ type })) as SnapshotMetricInput[],
|
||||||
|
@ -91,8 +88,8 @@ export const createMetricsFetchData = (
|
||||||
nodeType: 'host',
|
nodeType: 'host',
|
||||||
includeTimeseries: true,
|
includeTimeseries: true,
|
||||||
timerange: {
|
timerange: {
|
||||||
from: moment(startTime).valueOf(),
|
from: start,
|
||||||
to: moment(endTime).valueOf(),
|
to: end,
|
||||||
interval: bucketSize,
|
interval: bucketSize,
|
||||||
forceInterval: true,
|
forceInterval: true,
|
||||||
ignoreLookback: true,
|
ignoreLookback: true,
|
||||||
|
@ -102,12 +99,8 @@ export const createMetricsFetchData = (
|
||||||
const results = await http.post<SnapshotNodeResponse>('/api/metrics/snapshot', {
|
const results = await http.post<SnapshotNodeResponse>('/api/metrics/snapshot', {
|
||||||
body: JSON.stringify(snapshotRequest),
|
body: JSON.stringify(snapshotRequest),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: i18n.translate('xpack.infra.observabilityHomepage.metrics.title', {
|
appLink: `/app/metrics/inventory?waffleTime=(currentTime:${end},isAutoReloading:!f)`,
|
||||||
defaultMessage: 'Metrics',
|
|
||||||
}),
|
|
||||||
appLink: '/app/metrics',
|
|
||||||
stats: {
|
stats: {
|
||||||
hosts: {
|
hosts: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
|
|
@ -5,18 +5,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { encode } from 'rison-node';
|
import { encode } from 'rison-node';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { SearchResponse } from 'src/plugins/data/public';
|
import { SearchResponse } from 'src/plugins/data/public';
|
||||||
import { DEFAULT_SOURCE_ID } from '../../common/constants';
|
|
||||||
import { InfraClientCoreSetup, InfraClientStartDeps } from '../types';
|
|
||||||
import {
|
import {
|
||||||
FetchData,
|
FetchData,
|
||||||
LogsFetchDataResponse,
|
|
||||||
HasData,
|
|
||||||
FetchDataParams,
|
FetchDataParams,
|
||||||
|
HasData,
|
||||||
|
LogsFetchDataResponse,
|
||||||
} from '../../../observability/public';
|
} from '../../../observability/public';
|
||||||
|
import { DEFAULT_SOURCE_ID } from '../../common/constants';
|
||||||
import { callFetchLogSourceConfigurationAPI } from '../containers/logs/log_source/api/fetch_log_source_configuration';
|
import { callFetchLogSourceConfigurationAPI } from '../containers/logs/log_source/api/fetch_log_source_configuration';
|
||||||
import { callFetchLogSourceStatusAPI } from '../containers/logs/log_source/api/fetch_log_source_status';
|
import { callFetchLogSourceStatusAPI } from '../containers/logs/log_source/api/fetch_log_source_status';
|
||||||
|
import { InfraClientCoreSetup, InfraClientStartDeps } from '../types';
|
||||||
|
|
||||||
interface StatsAggregation {
|
interface StatsAggregation {
|
||||||
buckets: Array<{ key: string; doc_count: number }>;
|
buckets: Array<{ key: string; doc_count: number }>;
|
||||||
|
@ -69,15 +68,11 @@ export function getLogsOverviewDataFetcher(
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
|
||||||
const timeSpanInMinutes =
|
const timeSpanInMinutes = (params.absoluteTime.end - params.absoluteTime.start) / (1000 * 60);
|
||||||
(Date.parse(params.endTime).valueOf() - Date.parse(params.startTime).valueOf()) / (1000 * 60);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: i18n.translate('xpack.infra.logs.logOverview.logOverviewTitle', {
|
appLink: `/app/logs/stream?logPosition=(end:${encode(params.relativeTime.end)},start:${encode(
|
||||||
defaultMessage: 'Logs',
|
params.relativeTime.start
|
||||||
}),
|
|
||||||
appLink: `/app/logs/stream?logPosition=(end:${encode(params.endTime)},start:${encode(
|
|
||||||
params.startTime
|
|
||||||
)})`,
|
)})`,
|
||||||
stats: normalizeStats(stats, timeSpanInMinutes),
|
stats: normalizeStats(stats, timeSpanInMinutes),
|
||||||
series: normalizeSeries(series),
|
series: normalizeSeries(series),
|
||||||
|
@ -122,8 +117,8 @@ function buildLogOverviewQuery(logParams: LogParams, params: FetchDataParams) {
|
||||||
return {
|
return {
|
||||||
range: {
|
range: {
|
||||||
[logParams.timestampField]: {
|
[logParams.timestampField]: {
|
||||||
gt: params.startTime,
|
gt: new Date(params.absoluteTime.start).toISOString(),
|
||||||
lte: params.endTime,
|
lte: new Date(params.absoluteTime.end).toISOString(),
|
||||||
format: 'strict_date_optional_time',
|
format: 'strict_date_optional_time',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,12 +44,16 @@ export const AlertsSection = ({ alerts }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer
|
<SectionContainer
|
||||||
title="Alerts"
|
title={i18n.translate('xpack.observability.overview.alerts.title', {
|
||||||
appLink={'/app/management/insightsAndAlerting/triggersActions/alerts'}
|
defaultMessage: 'Alerts',
|
||||||
hasError={false}
|
|
||||||
appLinkName={i18n.translate('xpack.observability.overview.alert.appLink', {
|
|
||||||
defaultMessage: 'Manage alerts',
|
|
||||||
})}
|
})}
|
||||||
|
appLink={{
|
||||||
|
href: '/app/management/insightsAndAlerting/triggersActions/alerts',
|
||||||
|
label: i18n.translate('xpack.observability.overview.alert.appLink', {
|
||||||
|
defaultMessage: 'Manage alerts',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
hasError={false}
|
||||||
>
|
>
|
||||||
<EuiFlexGroup direction="column" gutterSize="none">
|
<EuiFlexGroup direction="column" gutterSize="none">
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as fetcherHook from '../../../../hooks/use_fetcher';
|
||||||
import { render } from '../../../../utils/test_helper';
|
import { render } from '../../../../utils/test_helper';
|
||||||
import { APMSection } from './';
|
import { APMSection } from './';
|
||||||
import { response } from './mock_data/apm.mock';
|
import { response } from './mock_data/apm.mock';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
describe('APMSection', () => {
|
describe('APMSection', () => {
|
||||||
it('renders with transaction series and stats', () => {
|
it('renders with transaction series and stats', () => {
|
||||||
|
@ -18,8 +19,11 @@ describe('APMSection', () => {
|
||||||
});
|
});
|
||||||
const { getByText, queryAllByTestId } = render(
|
const { getByText, queryAllByTestId } = render(
|
||||||
<APMSection
|
<APMSection
|
||||||
startTime="2020-06-29T11:38:23.747Z"
|
absoluteTime={{
|
||||||
endTime="2020-06-29T12:08:23.748Z"
|
start: moment('2020-06-29T11:38:23.747Z').valueOf(),
|
||||||
|
end: moment('2020-06-29T12:08:23.748Z').valueOf(),
|
||||||
|
}}
|
||||||
|
relativeTime={{ start: 'now-15m', end: 'now' }}
|
||||||
bucketSize="60s"
|
bucketSize="60s"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -38,8 +42,11 @@ describe('APMSection', () => {
|
||||||
});
|
});
|
||||||
const { getByText, queryAllByText, getByTestId } = render(
|
const { getByText, queryAllByText, getByTestId } = render(
|
||||||
<APMSection
|
<APMSection
|
||||||
startTime="2020-06-29T11:38:23.747Z"
|
absoluteTime={{
|
||||||
endTime="2020-06-29T12:08:23.748Z"
|
start: moment('2020-06-29T11:38:23.747Z').valueOf(),
|
||||||
|
end: moment('2020-06-29T12:08:23.748Z').valueOf(),
|
||||||
|
}}
|
||||||
|
relativeTime={{ start: 'now-15m', end: 'now' }}
|
||||||
bucketSize="60s"
|
bucketSize="60s"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,8 +21,8 @@ import { StyledStat } from '../../styled_stat';
|
||||||
import { onBrushEnd } from '../helper';
|
import { onBrushEnd } from '../helper';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
startTime?: string;
|
absoluteTime: { start?: number; end?: number };
|
||||||
endTime?: string;
|
relativeTime: { start: string; end: string };
|
||||||
bucketSize?: string;
|
bucketSize?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,20 +30,25 @@ function formatTpm(value?: number) {
|
||||||
return numeral(value).format('0.00a');
|
return numeral(value).format('0.00a');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const APMSection = ({ startTime, endTime, bucketSize }: Props) => {
|
export const APMSection = ({ absoluteTime, relativeTime, bucketSize }: Props) => {
|
||||||
const theme = useContext(ThemeContext);
|
const theme = useContext(ThemeContext);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
const { start, end } = absoluteTime;
|
||||||
const { data, status } = useFetcher(() => {
|
const { data, status } = useFetcher(() => {
|
||||||
if (startTime && endTime && bucketSize) {
|
if (start && end && bucketSize) {
|
||||||
return getDataHandler('apm')?.fetchData({ startTime, endTime, bucketSize });
|
return getDataHandler('apm')?.fetchData({
|
||||||
|
absoluteTime: { start, end },
|
||||||
|
relativeTime,
|
||||||
|
bucketSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [startTime, endTime, bucketSize]);
|
}, [start, end, bucketSize]);
|
||||||
|
|
||||||
const { title = 'APM', appLink, stats, series } = data || {};
|
const { appLink, stats, series } = data || {};
|
||||||
|
|
||||||
const min = moment.utc(startTime).valueOf();
|
const min = moment.utc(absoluteTime.start).valueOf();
|
||||||
const max = moment.utc(endTime).valueOf();
|
const max = moment.utc(absoluteTime.end).valueOf();
|
||||||
|
|
||||||
const formatter = niceTimeFormatter([min, max]);
|
const formatter = niceTimeFormatter([min, max]);
|
||||||
|
|
||||||
|
@ -53,8 +58,15 @@ export const APMSection = ({ startTime, endTime, bucketSize }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer
|
<SectionContainer
|
||||||
title={title || 'APM'}
|
title={i18n.translate('xpack.observability.overview.apm.title', {
|
||||||
appLink={appLink}
|
defaultMessage: 'APM',
|
||||||
|
})}
|
||||||
|
appLink={{
|
||||||
|
href: appLink,
|
||||||
|
label: i18n.translate('xpack.observability.overview.apm.appLink', {
|
||||||
|
defaultMessage: 'View in app',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
hasError={status === FETCH_STATUS.FAILURE}
|
hasError={status === FETCH_STATUS.FAILURE}
|
||||||
>
|
>
|
||||||
<EuiFlexGroup>
|
<EuiFlexGroup>
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
import { ApmFetchDataResponse } from '../../../../../typings';
|
import { ApmFetchDataResponse } from '../../../../../typings';
|
||||||
|
|
||||||
export const response: ApmFetchDataResponse = {
|
export const response: ApmFetchDataResponse = {
|
||||||
title: 'APM',
|
|
||||||
|
|
||||||
appLink: '/app/apm',
|
appLink: '/app/apm',
|
||||||
stats: {
|
stats: {
|
||||||
services: { value: 11, type: 'number' },
|
services: { value: 11, type: 'number' },
|
||||||
|
|
|
@ -20,13 +20,13 @@ describe('SectionContainer', () => {
|
||||||
});
|
});
|
||||||
it('renders section with app link', () => {
|
it('renders section with app link', () => {
|
||||||
const component = render(
|
const component = render(
|
||||||
<SectionContainer title="Foo" appLink="/foo/bar" hasError={false}>
|
<SectionContainer title="Foo" appLink={{ label: 'foo', href: '/foo/bar' }} hasError={false}>
|
||||||
<div>I am a very nice component</div>
|
<div>I am a very nice component</div>
|
||||||
</SectionContainer>
|
</SectionContainer>
|
||||||
);
|
);
|
||||||
expect(component.getByText('I am a very nice component')).toBeInTheDocument();
|
expect(component.getByText('I am a very nice component')).toBeInTheDocument();
|
||||||
expect(component.getByText('Foo')).toBeInTheDocument();
|
expect(component.getByText('Foo')).toBeInTheDocument();
|
||||||
expect(component.getByText('View in app')).toBeInTheDocument();
|
expect(component.getByText('foo')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
it('renders section with error', () => {
|
it('renders section with error', () => {
|
||||||
const component = render(
|
const component = render(
|
||||||
|
|
|
@ -4,21 +4,23 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
import { EuiAccordion, EuiLink, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
|
import { EuiAccordion, EuiLink, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ErrorPanel } from './error_panel';
|
import { ErrorPanel } from './error_panel';
|
||||||
import { usePluginContext } from '../../../hooks/use_plugin_context';
|
import { usePluginContext } from '../../../hooks/use_plugin_context';
|
||||||
|
|
||||||
|
interface AppLink {
|
||||||
|
label: string;
|
||||||
|
href?: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
hasError: boolean;
|
hasError: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
minHeight?: number;
|
appLink?: AppLink;
|
||||||
appLink?: string;
|
|
||||||
appLinkName?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SectionContainer = ({ title, appLink, children, hasError, appLinkName }: Props) => {
|
export const SectionContainer = ({ title, appLink, children, hasError }: Props) => {
|
||||||
const { core } = usePluginContext();
|
const { core } = usePluginContext();
|
||||||
return (
|
return (
|
||||||
<EuiAccordion
|
<EuiAccordion
|
||||||
|
@ -31,15 +33,9 @@ export const SectionContainer = ({ title, appLink, children, hasError, appLinkNa
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
}
|
}
|
||||||
extraAction={
|
extraAction={
|
||||||
appLink && (
|
appLink?.href && (
|
||||||
<EuiLink href={core.http.basePath.prepend(appLink)}>
|
<EuiLink href={core.http.basePath.prepend(appLink.href)}>
|
||||||
<EuiText size="s">
|
<EuiText size="s">{appLink.label}</EuiText>
|
||||||
{appLinkName
|
|
||||||
? appLinkName
|
|
||||||
: i18n.translate('xpack.observability.chart.viewInAppLabel', {
|
|
||||||
defaultMessage: 'View in app',
|
|
||||||
})}
|
|
||||||
</EuiText>
|
|
||||||
</EuiLink>
|
</EuiLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ import { StyledStat } from '../../styled_stat';
|
||||||
import { onBrushEnd } from '../helper';
|
import { onBrushEnd } from '../helper';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
startTime?: string;
|
absoluteTime: { start?: number; end?: number };
|
||||||
endTime?: string;
|
relativeTime: { start: string; end: string };
|
||||||
bucketSize?: string;
|
bucketSize?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,21 +45,26 @@ function getColorPerItem(series?: LogsFetchDataResponse['series']) {
|
||||||
return colorsPerItem;
|
return colorsPerItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LogsSection = ({ startTime, endTime, bucketSize }: Props) => {
|
export const LogsSection = ({ absoluteTime, relativeTime, bucketSize }: Props) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
const { start, end } = absoluteTime;
|
||||||
const { data, status } = useFetcher(() => {
|
const { data, status } = useFetcher(() => {
|
||||||
if (startTime && endTime && bucketSize) {
|
if (start && end && bucketSize) {
|
||||||
return getDataHandler('infra_logs')?.fetchData({ startTime, endTime, bucketSize });
|
return getDataHandler('infra_logs')?.fetchData({
|
||||||
|
absoluteTime: { start, end },
|
||||||
|
relativeTime,
|
||||||
|
bucketSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [startTime, endTime, bucketSize]);
|
}, [start, end, bucketSize]);
|
||||||
|
|
||||||
const min = moment.utc(startTime).valueOf();
|
const min = moment.utc(absoluteTime.start).valueOf();
|
||||||
const max = moment.utc(endTime).valueOf();
|
const max = moment.utc(absoluteTime.end).valueOf();
|
||||||
|
|
||||||
const formatter = niceTimeFormatter([min, max]);
|
const formatter = niceTimeFormatter([min, max]);
|
||||||
|
|
||||||
const { title, appLink, stats, series } = data || {};
|
const { appLink, stats, series } = data || {};
|
||||||
|
|
||||||
const colorsPerItem = getColorPerItem(series);
|
const colorsPerItem = getColorPerItem(series);
|
||||||
|
|
||||||
|
@ -67,8 +72,15 @@ export const LogsSection = ({ startTime, endTime, bucketSize }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer
|
<SectionContainer
|
||||||
title={title || 'Logs'}
|
title={i18n.translate('xpack.observability.overview.logs.title', {
|
||||||
appLink={appLink}
|
defaultMessage: 'Logs',
|
||||||
|
})}
|
||||||
|
appLink={{
|
||||||
|
href: appLink,
|
||||||
|
label: i18n.translate('xpack.observability.overview.logs.appLink', {
|
||||||
|
defaultMessage: 'View in app',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
hasError={status === FETCH_STATUS.FAILURE}
|
hasError={status === FETCH_STATUS.FAILURE}
|
||||||
>
|
>
|
||||||
<EuiTitle size="xs">
|
<EuiTitle size="xs">
|
||||||
|
|
|
@ -18,8 +18,8 @@ import { ChartContainer } from '../../chart_container';
|
||||||
import { StyledStat } from '../../styled_stat';
|
import { StyledStat } from '../../styled_stat';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
startTime?: string;
|
absoluteTime: { start?: number; end?: number };
|
||||||
endTime?: string;
|
relativeTime: { start: string; end: string };
|
||||||
bucketSize?: string;
|
bucketSize?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,17 +46,23 @@ const StyledProgress = styled.div<{ color?: string }>`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const MetricsSection = ({ startTime, endTime, bucketSize }: Props) => {
|
export const MetricsSection = ({ absoluteTime, relativeTime, bucketSize }: Props) => {
|
||||||
const theme = useContext(ThemeContext);
|
const theme = useContext(ThemeContext);
|
||||||
|
|
||||||
|
const { start, end } = absoluteTime;
|
||||||
const { data, status } = useFetcher(() => {
|
const { data, status } = useFetcher(() => {
|
||||||
if (startTime && endTime && bucketSize) {
|
if (start && end && bucketSize) {
|
||||||
return getDataHandler('infra_metrics')?.fetchData({ startTime, endTime, bucketSize });
|
return getDataHandler('infra_metrics')?.fetchData({
|
||||||
|
absoluteTime: { start, end },
|
||||||
|
relativeTime,
|
||||||
|
bucketSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [startTime, endTime, bucketSize]);
|
}, [start, end, bucketSize]);
|
||||||
|
|
||||||
const isLoading = status === FETCH_STATUS.LOADING;
|
const isLoading = status === FETCH_STATUS.LOADING;
|
||||||
|
|
||||||
const { title = 'Metrics', appLink, stats, series } = data || {};
|
const { appLink, stats, series } = data || {};
|
||||||
|
|
||||||
const cpuColor = theme.eui.euiColorVis7;
|
const cpuColor = theme.eui.euiColorVis7;
|
||||||
const memoryColor = theme.eui.euiColorVis0;
|
const memoryColor = theme.eui.euiColorVis0;
|
||||||
|
@ -65,9 +71,15 @@ export const MetricsSection = ({ startTime, endTime, bucketSize }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer
|
<SectionContainer
|
||||||
minHeight={135}
|
title={i18n.translate('xpack.observability.overview.metrics.title', {
|
||||||
title={title}
|
defaultMessage: 'Metrics',
|
||||||
appLink={appLink}
|
})}
|
||||||
|
appLink={{
|
||||||
|
href: appLink,
|
||||||
|
label: i18n.translate('xpack.observability.overview.metrics.appLink', {
|
||||||
|
defaultMessage: 'View in app',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
hasError={status === FETCH_STATUS.FAILURE}
|
hasError={status === FETCH_STATUS.FAILURE}
|
||||||
>
|
>
|
||||||
<EuiFlexGroup>
|
<EuiFlexGroup>
|
||||||
|
|
|
@ -30,37 +30,49 @@ import { StyledStat } from '../../styled_stat';
|
||||||
import { onBrushEnd } from '../helper';
|
import { onBrushEnd } from '../helper';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
startTime?: string;
|
absoluteTime: { start?: number; end?: number };
|
||||||
endTime?: string;
|
relativeTime: { start: string; end: string };
|
||||||
bucketSize?: string;
|
bucketSize?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UptimeSection = ({ startTime, endTime, bucketSize }: Props) => {
|
export const UptimeSection = ({ absoluteTime, relativeTime, bucketSize }: Props) => {
|
||||||
const theme = useContext(ThemeContext);
|
const theme = useContext(ThemeContext);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
const { start, end } = absoluteTime;
|
||||||
const { data, status } = useFetcher(() => {
|
const { data, status } = useFetcher(() => {
|
||||||
if (startTime && endTime && bucketSize) {
|
if (start && end && bucketSize) {
|
||||||
return getDataHandler('uptime')?.fetchData({ startTime, endTime, bucketSize });
|
return getDataHandler('uptime')?.fetchData({
|
||||||
|
absoluteTime: { start, end },
|
||||||
|
relativeTime,
|
||||||
|
bucketSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [startTime, endTime, bucketSize]);
|
}, [start, end, bucketSize]);
|
||||||
|
|
||||||
|
const min = moment.utc(absoluteTime.start).valueOf();
|
||||||
|
const max = moment.utc(absoluteTime.end).valueOf();
|
||||||
|
|
||||||
const min = moment.utc(startTime).valueOf();
|
|
||||||
const max = moment.utc(endTime).valueOf();
|
|
||||||
const formatter = niceTimeFormatter([min, max]);
|
const formatter = niceTimeFormatter([min, max]);
|
||||||
|
|
||||||
const isLoading = status === FETCH_STATUS.LOADING;
|
const isLoading = status === FETCH_STATUS.LOADING;
|
||||||
|
|
||||||
const { title = 'Uptime', appLink, stats, series } = data || {};
|
const { appLink, stats, series } = data || {};
|
||||||
|
|
||||||
const downColor = theme.eui.euiColorVis2;
|
const downColor = theme.eui.euiColorVis2;
|
||||||
const upColor = theme.eui.euiColorLightShade;
|
const upColor = theme.eui.euiColorLightShade;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer
|
<SectionContainer
|
||||||
minHeight={273}
|
title={i18n.translate('xpack.observability.overview.uptime.title', {
|
||||||
title={title}
|
defaultMessage: 'Uptime',
|
||||||
appLink={appLink}
|
})}
|
||||||
|
appLink={{
|
||||||
|
href: appLink,
|
||||||
|
label: i18n.translate('xpack.observability.overview.uptime.appLink', {
|
||||||
|
defaultMessage: 'View in app',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
hasError={status === FETCH_STATUS.FAILURE}
|
hasError={status === FETCH_STATUS.FAILURE}
|
||||||
>
|
>
|
||||||
<EuiFlexGroup>
|
<EuiFlexGroup>
|
||||||
|
|
|
@ -4,10 +4,17 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
import { registerDataHandler, getDataHandler } from './data_handler';
|
import { registerDataHandler, getDataHandler } from './data_handler';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
startTime: '0',
|
absoluteTime: {
|
||||||
endTime: '1',
|
start: moment('2020-07-02T13:25:11.629Z').valueOf(),
|
||||||
|
end: moment('2020-07-09T13:25:11.629Z').valueOf(),
|
||||||
|
},
|
||||||
|
relativeTime: {
|
||||||
|
start: 'now-15m',
|
||||||
|
end: 'now',
|
||||||
|
},
|
||||||
bucketSize: '10s',
|
bucketSize: '10s',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
|
import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
|
||||||
import moment from 'moment';
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { ThemeContext } from 'styled-components';
|
import { ThemeContext } from 'styled-components';
|
||||||
import { EmptySection } from '../../components/app/empty_section';
|
import { EmptySection } from '../../components/app/empty_section';
|
||||||
|
@ -23,7 +22,7 @@ import { UI_SETTINGS, useKibanaUISettings } from '../../hooks/use_kibana_ui_sett
|
||||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||||
import { RouteParams } from '../../routes';
|
import { RouteParams } from '../../routes';
|
||||||
import { getObservabilityAlerts } from '../../services/get_observability_alerts';
|
import { getObservabilityAlerts } from '../../services/get_observability_alerts';
|
||||||
import { getParsedDate } from '../../utils/date';
|
import { getAbsoluteTime } from '../../utils/date';
|
||||||
import { getBucketSize } from '../../utils/get_bucket_size';
|
import { getBucketSize } from '../../utils/get_bucket_size';
|
||||||
import { getEmptySections } from './empty_section';
|
import { getEmptySections } from './empty_section';
|
||||||
import { LoadingObservability } from './loading_observability';
|
import { LoadingObservability } from './loading_observability';
|
||||||
|
@ -33,13 +32,9 @@ interface Props {
|
||||||
routeParams: RouteParams<'/overview'>;
|
routeParams: RouteParams<'/overview'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculatetBucketSize({ startTime, endTime }: { startTime?: string; endTime?: string }) {
|
function calculatetBucketSize({ start, end }: { start?: number; end?: number }) {
|
||||||
if (startTime && endTime) {
|
if (start && end) {
|
||||||
return getBucketSize({
|
return getBucketSize({ start, end, minInterval: '60s' });
|
||||||
start: moment.utc(startTime).valueOf(),
|
|
||||||
end: moment.utc(endTime).valueOf(),
|
|
||||||
minInterval: '60s',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,16 +57,22 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
return <LoadingObservability />;
|
return <LoadingObservability />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { refreshInterval = 10000, refreshPaused = true } = routeParams.query;
|
||||||
rangeFrom = timePickerTime.from,
|
|
||||||
rangeTo = timePickerTime.to,
|
|
||||||
refreshInterval = 10000,
|
|
||||||
refreshPaused = true,
|
|
||||||
} = routeParams.query;
|
|
||||||
|
|
||||||
const startTime = getParsedDate(rangeFrom);
|
const relativeTime = {
|
||||||
const endTime = getParsedDate(rangeTo, { roundUp: true });
|
start: routeParams.query.rangeFrom ?? timePickerTime.from,
|
||||||
const bucketSize = calculatetBucketSize({ startTime, endTime });
|
end: routeParams.query.rangeTo ?? timePickerTime.to,
|
||||||
|
};
|
||||||
|
|
||||||
|
const absoluteTime = {
|
||||||
|
start: getAbsoluteTime(relativeTime.start),
|
||||||
|
end: getAbsoluteTime(relativeTime.end, { roundUp: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const bucketSize = calculatetBucketSize({
|
||||||
|
start: absoluteTime.start,
|
||||||
|
end: absoluteTime.end,
|
||||||
|
});
|
||||||
|
|
||||||
const appEmptySections = getEmptySections({ core }).filter(({ id }) => {
|
const appEmptySections = getEmptySections({ core }).filter(({ id }) => {
|
||||||
if (id === 'alert') {
|
if (id === 'alert') {
|
||||||
|
@ -93,8 +94,8 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
<EuiFlexGroup justifyContent="flexEnd">
|
<EuiFlexGroup justifyContent="flexEnd">
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
rangeFrom={rangeFrom}
|
rangeFrom={relativeTime.start}
|
||||||
rangeTo={rangeTo}
|
rangeTo={relativeTime.end}
|
||||||
refreshInterval={refreshInterval}
|
refreshInterval={refreshInterval}
|
||||||
refreshPaused={refreshPaused}
|
refreshPaused={refreshPaused}
|
||||||
/>
|
/>
|
||||||
|
@ -116,8 +117,8 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
{hasData.infra_logs && (
|
{hasData.infra_logs && (
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<LogsSection
|
<LogsSection
|
||||||
startTime={startTime}
|
absoluteTime={absoluteTime}
|
||||||
endTime={endTime}
|
relativeTime={relativeTime}
|
||||||
bucketSize={bucketSize?.intervalString}
|
bucketSize={bucketSize?.intervalString}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -125,8 +126,8 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
{hasData.infra_metrics && (
|
{hasData.infra_metrics && (
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<MetricsSection
|
<MetricsSection
|
||||||
startTime={startTime}
|
absoluteTime={absoluteTime}
|
||||||
endTime={endTime}
|
relativeTime={relativeTime}
|
||||||
bucketSize={bucketSize?.intervalString}
|
bucketSize={bucketSize?.intervalString}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -134,8 +135,8 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
{hasData.apm && (
|
{hasData.apm && (
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<APMSection
|
<APMSection
|
||||||
startTime={startTime}
|
absoluteTime={absoluteTime}
|
||||||
endTime={endTime}
|
relativeTime={relativeTime}
|
||||||
bucketSize={bucketSize?.intervalString}
|
bucketSize={bucketSize?.intervalString}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -143,8 +144,8 @@ export const OverviewPage = ({ routeParams }: Props) => {
|
||||||
{hasData.uptime && (
|
{hasData.uptime && (
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<UptimeSection
|
<UptimeSection
|
||||||
startTime={startTime}
|
absoluteTime={absoluteTime}
|
||||||
endTime={endTime}
|
relativeTime={relativeTime}
|
||||||
bucketSize={bucketSize?.intervalString}
|
bucketSize={bucketSize?.intervalString}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
|
|
@ -10,7 +10,6 @@ export const fetchApmData: FetchData<ApmFetchDataResponse> = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response: ApmFetchDataResponse = {
|
const response: ApmFetchDataResponse = {
|
||||||
title: 'APM',
|
|
||||||
appLink: '/app/apm',
|
appLink: '/app/apm',
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
|
@ -607,7 +606,6 @@ const response: ApmFetchDataResponse = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emptyResponse: ApmFetchDataResponse = {
|
export const emptyResponse: ApmFetchDataResponse = {
|
||||||
title: 'APM',
|
|
||||||
appLink: '/app/apm',
|
appLink: '/app/apm',
|
||||||
stats: {
|
stats: {
|
||||||
services: {
|
services: {
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const fetchLogsData: FetchData<LogsFetchDataResponse> = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response: LogsFetchDataResponse = {
|
const response: LogsFetchDataResponse = {
|
||||||
title: 'Logs',
|
|
||||||
appLink:
|
appLink:
|
||||||
"/app/logs/stream?logPosition=(end:'2020-06-30T21:30:00.000Z',start:'2020-06-27T22:00:00.000Z')",
|
"/app/logs/stream?logPosition=(end:'2020-06-30T21:30:00.000Z',start:'2020-06-27T22:00:00.000Z')",
|
||||||
stats: {
|
stats: {
|
||||||
|
@ -2319,7 +2318,6 @@ const response: LogsFetchDataResponse = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emptyResponse: LogsFetchDataResponse = {
|
export const emptyResponse: LogsFetchDataResponse = {
|
||||||
title: 'Logs',
|
|
||||||
appLink: '/app/logs',
|
appLink: '/app/logs',
|
||||||
stats: {},
|
stats: {},
|
||||||
series: {},
|
series: {},
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const fetchMetricsData: FetchData<MetricsFetchDataResponse> = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response: MetricsFetchDataResponse = {
|
const response: MetricsFetchDataResponse = {
|
||||||
title: 'Metrics',
|
|
||||||
appLink: '/app/apm',
|
appLink: '/app/apm',
|
||||||
stats: {
|
stats: {
|
||||||
hosts: { value: 11, type: 'number' },
|
hosts: { value: 11, type: 'number' },
|
||||||
|
@ -113,7 +112,6 @@ const response: MetricsFetchDataResponse = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emptyResponse: MetricsFetchDataResponse = {
|
export const emptyResponse: MetricsFetchDataResponse = {
|
||||||
title: 'Metrics',
|
|
||||||
appLink: '/app/apm',
|
appLink: '/app/apm',
|
||||||
stats: {
|
stats: {
|
||||||
hosts: { value: 0, type: 'number' },
|
hosts: { value: 0, type: 'number' },
|
||||||
|
|
|
@ -10,7 +10,6 @@ export const fetchUptimeData: FetchData<UptimeFetchDataResponse> = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response: UptimeFetchDataResponse = {
|
const response: UptimeFetchDataResponse = {
|
||||||
title: 'Uptime',
|
|
||||||
appLink: '/app/uptime#/',
|
appLink: '/app/uptime#/',
|
||||||
stats: {
|
stats: {
|
||||||
monitors: {
|
monitors: {
|
||||||
|
@ -1191,7 +1190,6 @@ const response: UptimeFetchDataResponse = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emptyResponse: UptimeFetchDataResponse = {
|
export const emptyResponse: UptimeFetchDataResponse = {
|
||||||
title: 'Uptime',
|
|
||||||
appLink: '/app/uptime#/',
|
appLink: '/app/uptime#/',
|
||||||
stats: {
|
stats: {
|
||||||
monitors: {
|
monitors: {
|
||||||
|
|
|
@ -21,11 +21,8 @@ export interface Series {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchDataParams {
|
export interface FetchDataParams {
|
||||||
// The start timestamp in milliseconds of the queried time interval
|
absoluteTime: { start: number; end: number };
|
||||||
startTime: string;
|
relativeTime: { start: string; end: string };
|
||||||
// The end timestamp in milliseconds of the queried time interval
|
|
||||||
endTime: string;
|
|
||||||
// The aggregation bucket size in milliseconds if applicable to the data source
|
|
||||||
bucketSize: string;
|
bucketSize: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +38,6 @@ export interface DataHandler<T extends ObservabilityApp = ObservabilityApp> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchDataResponse {
|
export interface FetchDataResponse {
|
||||||
title: string;
|
|
||||||
appLink: string;
|
appLink: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,9 @@
|
||||||
*/
|
*/
|
||||||
import datemath from '@elastic/datemath';
|
import datemath from '@elastic/datemath';
|
||||||
|
|
||||||
export function getParsedDate(range?: string, opts = {}) {
|
export function getAbsoluteTime(range: string, opts = {}) {
|
||||||
if (range) {
|
const parsed = datemath.parse(range, opts);
|
||||||
const parsed = datemath.parse(range, opts);
|
if (parsed) {
|
||||||
if (parsed) {
|
return parsed.valueOf();
|
||||||
return parsed.toISOString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,24 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fetchPingHistogram, fetchSnapshotCount } from '../state/api';
|
import { fetchPingHistogram, fetchSnapshotCount } from '../state/api';
|
||||||
import { UptimeFetchDataResponse } from '../../../observability/public';
|
import { UptimeFetchDataResponse, FetchDataParams } from '../../../observability/public';
|
||||||
|
|
||||||
export async function fetchUptimeOverviewData({
|
export async function fetchUptimeOverviewData({
|
||||||
startTime,
|
absoluteTime,
|
||||||
endTime,
|
relativeTime,
|
||||||
bucketSize,
|
bucketSize,
|
||||||
}: {
|
}: FetchDataParams) {
|
||||||
startTime: string;
|
const start = new Date(absoluteTime.start).toISOString();
|
||||||
endTime: string;
|
const end = new Date(absoluteTime.end).toISOString();
|
||||||
bucketSize: string;
|
|
||||||
}) {
|
|
||||||
const snapshot = await fetchSnapshotCount({
|
const snapshot = await fetchSnapshotCount({
|
||||||
dateRangeStart: startTime,
|
dateRangeStart: start,
|
||||||
dateRangeEnd: endTime,
|
dateRangeEnd: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
const pings = await fetchPingHistogram({ dateStart: startTime, dateEnd: endTime, bucketSize });
|
const pings = await fetchPingHistogram({ dateStart: start, dateEnd: end, bucketSize });
|
||||||
|
|
||||||
const response: UptimeFetchDataResponse = {
|
const response: UptimeFetchDataResponse = {
|
||||||
title: 'Uptime',
|
appLink: `/app/uptime#/?dateRangeStart=${relativeTime.start}&dateRangeEnd=${relativeTime.end}`,
|
||||||
appLink: '/app/uptime#/',
|
|
||||||
stats: {
|
stats: {
|
||||||
monitors: {
|
monitors: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
|
Loading…
Reference in a new issue