mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Move UX JS Errors out of APM UI (#133040)
* Migrate Ux-jsErrors query to Ux plugin * Add untracked files * Clean up old query * Clean up jsErrors api from apm * Remove stale snapshot * Add e2e test for JsErrors chart
This commit is contained in:
parent
a4f2a81163
commit
ccea9773e2
13 changed files with 350 additions and 313 deletions
|
@ -73,102 +73,6 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`rum client dashboard queries fetches js errors 1`] = `
|
||||
Object {
|
||||
"apm": Object {
|
||||
"events": Array [
|
||||
"error",
|
||||
],
|
||||
},
|
||||
"body": Object {
|
||||
"aggs": Object {
|
||||
"errors": Object {
|
||||
"aggs": Object {
|
||||
"bucket_truncate": Object {
|
||||
"bucket_sort": Object {
|
||||
"from": 0,
|
||||
"size": 5,
|
||||
},
|
||||
},
|
||||
"impactedPages": Object {
|
||||
"aggs": Object {
|
||||
"pageCount": Object {
|
||||
"cardinality": Object {
|
||||
"field": "transaction.id",
|
||||
},
|
||||
},
|
||||
},
|
||||
"filter": Object {
|
||||
"term": Object {
|
||||
"transaction.type": "page-load",
|
||||
},
|
||||
},
|
||||
},
|
||||
"sample": Object {
|
||||
"top_hits": Object {
|
||||
"_source": Array [
|
||||
"error.exception.message",
|
||||
"error.exception.type",
|
||||
"error.grouping_key",
|
||||
"@timestamp",
|
||||
],
|
||||
"size": 1,
|
||||
"sort": Array [
|
||||
Object {
|
||||
"@timestamp": "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"terms": Object {
|
||||
"field": "error.grouping_key",
|
||||
"size": 500,
|
||||
},
|
||||
},
|
||||
"totalErrorGroups": Object {
|
||||
"cardinality": Object {
|
||||
"field": "error.grouping_key",
|
||||
},
|
||||
},
|
||||
"totalErrorPages": Object {
|
||||
"cardinality": Object {
|
||||
"field": "transaction.id",
|
||||
},
|
||||
},
|
||||
},
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"@timestamp": Object {
|
||||
"format": "epoch_millis",
|
||||
"gte": 0,
|
||||
"lte": 50000,
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"agent.name": "rum-js",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"service.language.name": "javascript",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must_not": Array [],
|
||||
},
|
||||
},
|
||||
"size": 0,
|
||||
"track_total_hits": true,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`rum client dashboard queries fetches long task metrics 1`] = `
|
||||
Object {
|
||||
"apm": Object {
|
||||
|
|
|
@ -14,7 +14,6 @@ import { getPageViewTrends } from './get_page_view_trends';
|
|||
import { getPageLoadDistribution } from './get_page_load_distribution';
|
||||
import { getLongTaskMetrics } from './get_long_task_metrics';
|
||||
import { getWebCoreVitals } from './get_web_core_vitals';
|
||||
import { getJSErrors } from './get_js_errors';
|
||||
import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values';
|
||||
|
||||
describe('rum client dashboard queries', () => {
|
||||
|
@ -90,17 +89,4 @@ describe('rum client dashboard queries', () => {
|
|||
);
|
||||
expect(mock.params).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('fetches js errors', async () => {
|
||||
mock = await inspectSearchParams((setup) =>
|
||||
getJSErrors({
|
||||
setup,
|
||||
pageSize: 5,
|
||||
pageIndex: 0,
|
||||
start: 0,
|
||||
end: 50000,
|
||||
})
|
||||
);
|
||||
expect(mock.params).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ import { Logger } from '@kbn/core/server';
|
|||
import { isoToEpochRt } from '@kbn/io-ts-utils';
|
||||
import { setupRequest, Setup } from '../../lib/helpers/setup_request';
|
||||
import { getClientMetrics } from './get_client_metrics';
|
||||
import { getJSErrors } from './get_js_errors';
|
||||
import { getLongTaskMetrics } from './get_long_task_metrics';
|
||||
import { getPageLoadDistribution } from './get_page_load_distribution';
|
||||
import { getPageViewTrends } from './get_page_view_trends';
|
||||
|
@ -279,48 +278,6 @@ const rumLongTaskMetrics = createApmServerRoute({
|
|||
},
|
||||
});
|
||||
|
||||
const rumJSErrors = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/ux/js-errors',
|
||||
params: t.type({
|
||||
query: t.intersection([
|
||||
uiFiltersRt,
|
||||
rangeRt,
|
||||
t.type({ pageSize: t.string, pageIndex: t.string }),
|
||||
t.partial({ urlQuery: t.string }),
|
||||
]),
|
||||
}),
|
||||
options: { tags: ['access:apm'] },
|
||||
handler: async (
|
||||
resources
|
||||
): Promise<{
|
||||
totalErrorPages: number;
|
||||
totalErrors: number;
|
||||
totalErrorGroups: number;
|
||||
items:
|
||||
| Array<{
|
||||
count: number;
|
||||
errorGroupId: string | number;
|
||||
errorMessage: string;
|
||||
}>
|
||||
| undefined;
|
||||
}> => {
|
||||
const setup = await setupUXRequest(resources);
|
||||
|
||||
const {
|
||||
query: { pageSize, pageIndex, urlQuery, start, end },
|
||||
} = resources.params;
|
||||
|
||||
return getJSErrors({
|
||||
setup,
|
||||
urlQuery,
|
||||
pageSize: Number(pageSize),
|
||||
pageIndex: Number(pageIndex),
|
||||
start,
|
||||
end,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const rumHasDataRoute = createApmServerRoute({
|
||||
endpoint: 'GET /api/apm/observability_overview/has_rum_data',
|
||||
params: t.partial({
|
||||
|
@ -383,6 +340,5 @@ export const rumRouteRepository = {
|
|||
...rumVisitorsBreakdownRoute,
|
||||
...rumWebCoreVitals,
|
||||
...rumLongTaskMetrics,
|
||||
...rumJSErrors,
|
||||
...rumHasDataRoute,
|
||||
};
|
||||
|
|
|
@ -13,9 +13,17 @@ export const AGENT = 'agent';
|
|||
export const AGENT_NAME = 'agent.name';
|
||||
export const AGENT_VERSION = 'agent.version';
|
||||
|
||||
export const ERROR_EXC_MESSAGE = 'error.exception.message';
|
||||
export const ERROR_EXC_TYPE = 'error.exception.type';
|
||||
export const ERROR_GROUP_ID = 'error.grouping_key';
|
||||
|
||||
export const PROCESSOR_EVENT = 'processor.event';
|
||||
|
||||
export const URL_FULL = 'url.full';
|
||||
export const USER_AGENT_NAME = 'user_agent.name';
|
||||
|
||||
export const SERVICE_LANGUAGE_NAME = 'service.language.name';
|
||||
|
||||
export const TRANSACTION_DURATION = 'transaction.duration.us';
|
||||
export const TRANSACTION_TYPE = 'transaction.type';
|
||||
export const TRANSACTION_RESULT = 'transaction.result';
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
*/
|
||||
|
||||
export * from './url_ux_query.journey';
|
||||
export * from './ux_js_errors.journey';
|
||||
|
|
57
x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts
Normal file
57
x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { journey, step, expect, before } from '@elastic/synthetics';
|
||||
import { UXDashboardDatePicker } from '../page_objects/date_picker';
|
||||
import { byTestId, loginToKibana, waitForLoadingToFinish } from './utils';
|
||||
|
||||
const jsErrorCount = '3 k';
|
||||
const jsErrorLabel = `Total errors
|
||||
|
||||
${jsErrorCount}`;
|
||||
|
||||
journey('UX JsErrors', async ({ page, params }) => {
|
||||
before(async () => {
|
||||
await waitForLoadingToFinish({ page });
|
||||
});
|
||||
|
||||
const queryParams = {
|
||||
percentile: '50',
|
||||
rangeFrom: '2020-05-18T11:51:00.000Z',
|
||||
rangeTo: '2021-10-30T06:37:15.536Z',
|
||||
};
|
||||
const queryString = new URLSearchParams(queryParams).toString();
|
||||
|
||||
const baseUrl = `${params.kibanaUrl}/app/ux`;
|
||||
|
||||
step('Go to UX Dashboard', async () => {
|
||||
await page.goto(`${baseUrl}?${queryString}`, {
|
||||
waitUntil: 'networkidle',
|
||||
});
|
||||
await loginToKibana({
|
||||
page,
|
||||
user: { username: 'viewer_user', password: 'changeme' },
|
||||
});
|
||||
});
|
||||
|
||||
step('Set date range', async () => {
|
||||
const datePickerPage = new UXDashboardDatePicker(page);
|
||||
await datePickerPage.setDefaultE2eRange();
|
||||
});
|
||||
|
||||
step('Confirm error count', async () => {
|
||||
// Wait until chart data is loaded
|
||||
page.waitForLoadState('networkidle');
|
||||
await page.waitForSelector(`text=${jsErrorCount}`);
|
||||
|
||||
const jsErrors = await (
|
||||
await page.waitForSelector(byTestId('uxJsErrorsTotal'))
|
||||
).innerText();
|
||||
|
||||
expect(jsErrors).toBe(jsErrorLabel);
|
||||
});
|
||||
});
|
|
@ -19,9 +19,8 @@ import {
|
|||
import numeral from '@elastic/numeral';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { FETCH_STATUS } from '@kbn/observability-plugin/public';
|
||||
import { useJsErrorsQuery } from '../../../../hooks/use_js_errors_query';
|
||||
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { useKibanaServices } from '../../../../hooks/use_kibana_services';
|
||||
import { I18LABELS } from '../translations';
|
||||
import { CsmSharedContext } from '../csm_shared_context';
|
||||
|
@ -35,34 +34,13 @@ interface JSErrorItem {
|
|||
export function JSErrors() {
|
||||
const { http } = useKibanaServices();
|
||||
const basePath = http.basePath.get();
|
||||
const { rangeId, urlParams, uxUiFilters } = useLegacyUrlParams();
|
||||
|
||||
const { start, end, serviceName, searchTerm } = urlParams;
|
||||
const {
|
||||
urlParams: { serviceName },
|
||||
} = useLegacyUrlParams();
|
||||
|
||||
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 5 });
|
||||
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end && serviceName) {
|
||||
return callApmApi('GET /internal/apm/ux/js-errors', {
|
||||
params: {
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
urlQuery: searchTerm || undefined,
|
||||
uiFilters: JSON.stringify(uxUiFilters),
|
||||
pageSize: String(pagination.pageSize),
|
||||
pageIndex: String(pagination.pageIndex),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
// `rangeId` acts as a cache buster for stable ranges like "Today"
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[start, end, serviceName, uxUiFilters, pagination, searchTerm, rangeId]
|
||||
);
|
||||
const { data, loading } = useJsErrorsQuery(pagination);
|
||||
|
||||
const {
|
||||
sharedData: { totalPageViews },
|
||||
|
@ -130,16 +108,16 @@ export function JSErrors() {
|
|||
)
|
||||
}
|
||||
description={I18LABELS.totalErrors}
|
||||
isLoading={status === FETCH_STATUS.LOADING}
|
||||
isLoading={!!loading}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiBasicTable
|
||||
data-test-subj={'uxJsErrorTable'}
|
||||
loading={status === FETCH_STATUS.LOADING}
|
||||
loading={!!loading}
|
||||
error={
|
||||
status === FETCH_STATUS.FAILURE
|
||||
!loading && !data
|
||||
? i18n.translate('xpack.ux.jsErrorsTable.errorMessage', {
|
||||
defaultMessage: 'Failed to fetch',
|
||||
})
|
||||
|
|
83
x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx
Normal file
83
x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import datemath from '@kbn/datemath';
|
||||
import { useEsSearch } from '@kbn/observability-plugin/public';
|
||||
import { useMemo } from 'react';
|
||||
import { useDataView } from '../components/app/rum_dashboard/local_uifilters/use_data_view';
|
||||
import { jsErrorsQuery } from '../services/data/js_errors_query';
|
||||
import { useLegacyUrlParams } from '../context/url_params_context/use_url_params';
|
||||
|
||||
function callDateMath(value: unknown): number {
|
||||
const DEFAULT_RETURN_VALUE = 0;
|
||||
if (typeof value === 'string') {
|
||||
return datemath.parse(value)?.valueOf() ?? DEFAULT_RETURN_VALUE;
|
||||
}
|
||||
return DEFAULT_RETURN_VALUE;
|
||||
}
|
||||
|
||||
export function useJsErrorsQuery(pagination: {
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
}) {
|
||||
const {
|
||||
rangeId,
|
||||
urlParams: { start, end, searchTerm },
|
||||
uxUiFilters,
|
||||
} = useLegacyUrlParams();
|
||||
const { dataViewTitle } = useDataView();
|
||||
const { data: esQueryResponse, loading } = useEsSearch(
|
||||
{
|
||||
index: dataViewTitle,
|
||||
...jsErrorsQuery(
|
||||
callDateMath(start),
|
||||
callDateMath(end),
|
||||
pagination.pageSize,
|
||||
pagination.pageIndex,
|
||||
searchTerm,
|
||||
uxUiFilters
|
||||
),
|
||||
},
|
||||
[
|
||||
start,
|
||||
end,
|
||||
searchTerm,
|
||||
uxUiFilters,
|
||||
dataViewTitle,
|
||||
pagination.pageSize,
|
||||
pagination.pageIndex,
|
||||
rangeId,
|
||||
],
|
||||
{ name: 'UxJsErrors' }
|
||||
);
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (!esQueryResponse) return {};
|
||||
|
||||
const { totalErrorGroups, totalErrorPages, errors } =
|
||||
esQueryResponse?.aggregations ?? {};
|
||||
|
||||
return {
|
||||
totalErrorPages: totalErrorPages?.value ?? 0,
|
||||
totalErrors: esQueryResponse.hits.total ?? 0,
|
||||
totalErrorGroups: totalErrorGroups?.value ?? 0,
|
||||
items: errors?.buckets.map(({ sample, key, impactedPages }: any) => {
|
||||
return {
|
||||
count: impactedPages.pageCount.value,
|
||||
errorGroupId: key,
|
||||
errorMessage: (
|
||||
sample.hits.hits[0]._source as {
|
||||
error: { exception: Array<{ message: string }> };
|
||||
}
|
||||
).error.exception?.[0].message,
|
||||
};
|
||||
}),
|
||||
};
|
||||
}, [esQueryResponse]);
|
||||
|
||||
return { data, loading };
|
||||
}
|
100
x-pack/plugins/ux/public/services/data/__snapshots__/js_errors_query.test.ts.snap
generated
Normal file
100
x-pack/plugins/ux/public/services/data/__snapshots__/js_errors_query.test.ts.snap
generated
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`jsErrorsQuery fetches js errors 1`] = `
|
||||
Object {
|
||||
"body": Object {
|
||||
"aggs": Object {
|
||||
"errors": Object {
|
||||
"aggs": Object {
|
||||
"bucket_truncate": Object {
|
||||
"bucket_sort": Object {
|
||||
"from": 0,
|
||||
"size": 5,
|
||||
},
|
||||
},
|
||||
"impactedPages": Object {
|
||||
"aggs": Object {
|
||||
"pageCount": Object {
|
||||
"cardinality": Object {
|
||||
"field": "transaction.id",
|
||||
},
|
||||
},
|
||||
},
|
||||
"filter": Object {
|
||||
"term": Object {
|
||||
"transaction.type": "page-load",
|
||||
},
|
||||
},
|
||||
},
|
||||
"sample": Object {
|
||||
"top_hits": Object {
|
||||
"_source": Array [
|
||||
"error.exception.message",
|
||||
"error.exception.type",
|
||||
"error.grouping_key",
|
||||
"@timestamp",
|
||||
],
|
||||
"size": 1,
|
||||
"sort": Array [
|
||||
Object {
|
||||
"@timestamp": "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"terms": Object {
|
||||
"field": "error.grouping_key",
|
||||
"size": 500,
|
||||
},
|
||||
},
|
||||
"totalErrorGroups": Object {
|
||||
"cardinality": Object {
|
||||
"field": "error.grouping_key",
|
||||
},
|
||||
},
|
||||
"totalErrorPages": Object {
|
||||
"cardinality": Object {
|
||||
"field": "transaction.id",
|
||||
},
|
||||
},
|
||||
},
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"@timestamp": Object {
|
||||
"format": "epoch_millis",
|
||||
"gte": 0,
|
||||
"lte": 50000,
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"agent.name": "rum-js",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"service.language.name": "javascript",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"terms": Object {
|
||||
"processor.event": Array [
|
||||
"error",
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
"must_not": Array [],
|
||||
},
|
||||
},
|
||||
"size": 0,
|
||||
"track_total_hits": true,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { jsErrorsQuery } from './js_errors_query';
|
||||
|
||||
describe('jsErrorsQuery', () => {
|
||||
it('fetches js errors', () => {
|
||||
const query = jsErrorsQuery(0, 50000, 5, 0, '', {
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
});
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -5,9 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { mergeProjection } from '../../projections/util/merge_projection';
|
||||
import { SetupUX } from './route';
|
||||
import { getRumErrorsProjection } from '../../projections/rum_page_load_transactions';
|
||||
import { mergeProjection } from '../../../common/utils/merge_projection';
|
||||
import { SetupUX, UxUIFilters } from '../../../typings/ui_filters';
|
||||
import {
|
||||
ERROR_EXC_MESSAGE,
|
||||
ERROR_EXC_TYPE,
|
||||
|
@ -16,22 +15,17 @@ import {
|
|||
TRANSACTION_TYPE,
|
||||
} from '../../../common/elasticsearch_fieldnames';
|
||||
import { TRANSACTION_PAGE_LOAD } from '../../../common/transaction_types';
|
||||
import { getRumErrorsProjection } from './projections';
|
||||
|
||||
export async function getJSErrors({
|
||||
setup,
|
||||
pageSize,
|
||||
pageIndex,
|
||||
urlQuery,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
setup: SetupUX;
|
||||
pageSize: number;
|
||||
pageIndex: number;
|
||||
urlQuery?: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}) {
|
||||
export function jsErrorsQuery(
|
||||
start: number,
|
||||
end: number,
|
||||
pageSize: number,
|
||||
pageIndex: number,
|
||||
urlQuery?: string,
|
||||
uiFilters?: UxUIFilters
|
||||
) {
|
||||
const setup: SetupUX = { uiFilters: uiFilters ? uiFilters : {} };
|
||||
const projection = getRumErrorsProjection({
|
||||
setup,
|
||||
urlQuery,
|
||||
|
@ -98,27 +92,5 @@ export async function getJSErrors({
|
|||
},
|
||||
});
|
||||
|
||||
const { apmEventClient } = setup;
|
||||
|
||||
const response = await apmEventClient.search('get_js_errors', params);
|
||||
|
||||
const { totalErrorGroups, totalErrorPages, errors } =
|
||||
response.aggregations ?? {};
|
||||
|
||||
return {
|
||||
totalErrorPages: totalErrorPages?.value ?? 0,
|
||||
totalErrors: response.hits.total.value ?? 0,
|
||||
totalErrorGroups: totalErrorGroups?.value ?? 0,
|
||||
items: errors?.buckets.map(({ sample, key, impactedPages }) => {
|
||||
return {
|
||||
count: impactedPages.pageCount.value,
|
||||
errorGroupId: key,
|
||||
errorMessage: (
|
||||
sample.hits.hits[0]._source as {
|
||||
error: { exception: Array<{ message: string }> };
|
||||
}
|
||||
).error.exception?.[0].message,
|
||||
};
|
||||
}),
|
||||
};
|
||||
return params;
|
||||
}
|
|
@ -4,12 +4,18 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames';
|
||||
import { ProcessorEvent } from '../../../common/processor_event';
|
||||
import { TRANSACTION_PAGE_LOAD } from '../../../common/transaction_types';
|
||||
import { SetupUX } from '../../../typings/ui_filters';
|
||||
import { getEsFilter } from './get_es_filter';
|
||||
import { rangeQuery } from './range_query';
|
||||
import {
|
||||
AGENT_NAME,
|
||||
SERVICE_LANGUAGE_NAME,
|
||||
PROCESSOR_EVENT,
|
||||
} from '../../../common/elasticsearch_fieldnames';
|
||||
|
||||
export function getRumPageLoadTransactionsProjection({
|
||||
setup,
|
||||
|
@ -66,3 +72,60 @@ export function getRumPageLoadTransactionsProjection({
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export interface RumErrorsProjection {
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: QueryDslQueryContainer[];
|
||||
must_not: QueryDslQueryContainer[];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function getRumErrorsProjection({
|
||||
setup,
|
||||
urlQuery,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
setup: SetupUX;
|
||||
urlQuery?: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}): RumErrorsProjection {
|
||||
return {
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
...rangeQuery(start, end),
|
||||
{ term: { [AGENT_NAME]: 'rum-js' } },
|
||||
{
|
||||
term: {
|
||||
[SERVICE_LANGUAGE_NAME]: 'javascript',
|
||||
},
|
||||
},
|
||||
{
|
||||
terms: {
|
||||
[PROCESSOR_EVENT]: [ProcessorEvent.error],
|
||||
},
|
||||
},
|
||||
...getEsFilter(setup.uiFilters),
|
||||
...(urlQuery
|
||||
? [
|
||||
{
|
||||
wildcard: {
|
||||
'url.full': `*${urlQuery}*`,
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
must_not: [...getEsFilter(setup.uiFilters, true)],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,88 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
|
||||
export default function rumJsErrorsApiTests({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
const supertest = getService('legacySupertestAsApmReadUser');
|
||||
|
||||
registry.when('CSM JS errors with data', { config: 'trial', archives: [] }, () => {
|
||||
it('returns no js errors', async () => {
|
||||
const response = await supertest.get('/internal/apm/ux/js-errors').query({
|
||||
pageSize: 5,
|
||||
pageIndex: 0,
|
||||
start: '2020-09-07T20:35:54.654Z',
|
||||
end: '2020-09-14T20:35:54.654Z',
|
||||
uiFilters: '{"serviceName":["elastic-co-rum-test"]}',
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expectSnapshot(response.body).toMatchInline(`
|
||||
Object {
|
||||
"totalErrorGroups": 0,
|
||||
"totalErrorPages": 0,
|
||||
"totalErrors": 0,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'CSM JS errors without data',
|
||||
{ config: 'trial', archives: ['8.0.0', 'rum_test_data'] },
|
||||
() => {
|
||||
it('returns js errors', async () => {
|
||||
const response = await supertest.get('/internal/apm/ux/js-errors').query({
|
||||
start: '2021-01-18T12:20:17.202Z',
|
||||
end: '2021-01-18T12:25:17.203Z',
|
||||
uiFilters: '{"environment":"ENVIRONMENT_ALL","serviceName":["elastic-co-frontend"]}',
|
||||
pageSize: 5,
|
||||
pageIndex: 0,
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
expectSnapshot(response.body).toMatchInline(`
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"count": 5,
|
||||
"errorGroupId": "de32dc81e2ee5165cbff20046c080a27",
|
||||
"errorMessage": "SyntaxError: Document.querySelector: '' is not a valid selector",
|
||||
},
|
||||
Object {
|
||||
"count": 2,
|
||||
"errorGroupId": "34d83587e17711a7c257ffb080ddb1c6",
|
||||
"errorMessage": "Uncaught SyntaxError: Failed to execute 'querySelector' on 'Document': The provided selector is empty.",
|
||||
},
|
||||
Object {
|
||||
"count": 43,
|
||||
"errorGroupId": "3dd5604267b928139d958706f09f7e09",
|
||||
"errorMessage": "Script error.",
|
||||
},
|
||||
Object {
|
||||
"count": 1,
|
||||
"errorGroupId": "cd3a2b01017ff7bcce70479644f28318",
|
||||
"errorMessage": "Unhandled promise rejection: TypeError: can't convert undefined to object",
|
||||
},
|
||||
Object {
|
||||
"count": 3,
|
||||
"errorGroupId": "23539422cf714db071aba087dd041859",
|
||||
"errorMessage": "Unable to get property 'left' of undefined or null reference",
|
||||
},
|
||||
],
|
||||
"totalErrorGroups": 6,
|
||||
"totalErrorPages": 120,
|
||||
"totalErrors": 2846,
|
||||
}
|
||||
`);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue