+
{noHits ? (
<>{emptyStateChart}>
@@ -250,7 +251,7 @@ export class HistogramInner extends PureComponent {
{
return {
@@ -297,6 +298,7 @@ HistogramInner.propTypes = {
tooltipHeader: PropTypes.func,
verticalLineHover: PropTypes.func,
width: PropTypes.number.isRequired,
+ height: PropTypes.number,
xType: PropTypes.string,
legends: PropTypes.array,
noHits: PropTypes.bool,
@@ -311,6 +313,7 @@ HistogramInner.defaultProps = {
verticalLineHover: () => null,
xType: 'linear',
noHits: false,
+ height: XY_HEIGHT,
};
export default makeWidthFlexible(HistogramInner);
diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts b/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts
deleted file mode 100644
index e91d3953942d9..0000000000000
--- a/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import {
- ERROR_GROUP_ID,
- PROCESSOR_EVENT,
- SERVICE_NAME,
-} from '../../../common/elasticsearch_fieldnames';
-import { ProcessorEvent } from '../../../common/processor_event';
-import { getMetricsDateHistogramParams } from '../helpers/metrics';
-import {
- Setup,
- SetupTimeRange,
- SetupUIFilters,
-} from '../helpers/setup_request';
-import { rangeFilter } from '../../../common/utils/range_filter';
-
-export async function getErrorRate({
- serviceName,
- groupId,
- setup,
-}: {
- serviceName: string;
- groupId?: string;
- setup: Setup & SetupTimeRange & SetupUIFilters;
-}) {
- const { start, end, uiFiltersES, client, indices } = setup;
-
- const filter = [
- { term: { [SERVICE_NAME]: serviceName } },
- { range: rangeFilter(start, end) },
- ...uiFiltersES,
- ];
-
- const aggs = {
- response_times: {
- date_histogram: getMetricsDateHistogramParams(start, end),
- },
- };
-
- const getTransactionBucketAggregation = async () => {
- const resp = await client.search({
- index: indices['apm_oss.transactionIndices'],
- body: {
- size: 0,
- query: {
- bool: {
- filter: [
- ...filter,
- { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } },
- ],
- },
- },
- aggs,
- },
- });
- return {
- totalHits: resp.hits.total.value,
- responseTimeBuckets: resp.aggregations?.response_times.buckets,
- };
- };
- const getErrorBucketAggregation = async () => {
- const groupIdFilter = groupId
- ? [{ term: { [ERROR_GROUP_ID]: groupId } }]
- : [];
- const resp = await client.search({
- index: indices['apm_oss.errorIndices'],
- body: {
- size: 0,
- query: {
- bool: {
- filter: [
- ...filter,
- ...groupIdFilter,
- { term: { [PROCESSOR_EVENT]: ProcessorEvent.error } },
- ],
- },
- },
- aggs,
- },
- });
- return resp.aggregations?.response_times.buckets;
- };
-
- const [transactions, errorResponseTimeBuckets] = await Promise.all([
- getTransactionBucketAggregation(),
- getErrorBucketAggregation(),
- ]);
-
- const transactionCountByTimestamp: Record = {};
- if (transactions?.responseTimeBuckets) {
- transactions.responseTimeBuckets.forEach((bucket) => {
- transactionCountByTimestamp[bucket.key] = bucket.doc_count;
- });
- }
-
- const errorRates = errorResponseTimeBuckets?.map((bucket) => {
- const { key, doc_count: errorCount } = bucket;
- const relativeRate = errorCount / transactionCountByTimestamp[key];
- return { x: key, y: relativeRate };
- });
-
- return {
- noHits: transactions?.totalHits === 0,
- errorRates,
- };
-}
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts
new file mode 100644
index 0000000000000..5b66f7d7a45e7
--- /dev/null
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts
@@ -0,0 +1,86 @@
+/*
+ * 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 {
+ PROCESSOR_EVENT,
+ HTTP_RESPONSE_STATUS_CODE,
+ TRANSACTION_NAME,
+ TRANSACTION_TYPE,
+} from '../../../common/elasticsearch_fieldnames';
+import { ProcessorEvent } from '../../../common/processor_event';
+import { rangeFilter } from '../../../common/utils/range_filter';
+import { getMetricsDateHistogramParams } from '../helpers/metrics';
+import {
+ Setup,
+ SetupTimeRange,
+ SetupUIFilters,
+} from '../helpers/setup_request';
+
+export async function getErrorRate({
+ serviceName,
+ transactionType,
+ transactionName,
+ setup,
+}: {
+ serviceName: string;
+ transactionType?: string;
+ transactionName?: string;
+ setup: Setup & SetupTimeRange & SetupUIFilters;
+}) {
+ const { start, end, uiFiltersES, client, indices } = setup;
+
+ const transactionNamefilter = transactionName
+ ? [{ term: { [TRANSACTION_NAME]: transactionName } }]
+ : [];
+ const transactionTypefilter = transactionType
+ ? [{ term: { [TRANSACTION_TYPE]: transactionType } }]
+ : [];
+
+ const filter = [
+ { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } },
+ { range: rangeFilter(start, end) },
+ { exists: { field: HTTP_RESPONSE_STATUS_CODE } },
+ ...transactionNamefilter,
+ ...transactionTypefilter,
+ ...uiFiltersES,
+ ];
+
+ const params = {
+ index: indices['apm_oss.transactionIndices'],
+ body: {
+ size: 0,
+ query: { bool: { filter } },
+ aggs: {
+ total_transactions: {
+ date_histogram: getMetricsDateHistogramParams(start, end),
+ aggs: {
+ erroneous_transactions: {
+ filter: { range: { [HTTP_RESPONSE_STATUS_CODE]: { gte: 400 } } },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const resp = await client.search(params);
+
+ const noHits = resp.hits.total.value === 0;
+
+ const erroneousTransactionsRate =
+ resp.aggregations?.total_transactions.buckets.map(
+ ({ key, doc_count: totalTransactions, erroneous_transactions }) => {
+ const errornousTransactionsCount =
+ // @ts-ignore
+ erroneous_transactions.doc_count;
+ return {
+ x: key,
+ y: errornousTransactionsCount / totalTransactions,
+ };
+ }
+ ) || [];
+
+ return { noHits, erroneousTransactionsRate };
+}
diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts
index 513c44904683e..c046f371b2774 100644
--- a/x-pack/plugins/apm/server/routes/create_apm_api.ts
+++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts
@@ -13,7 +13,6 @@ import {
errorDistributionRoute,
errorGroupsRoute,
errorsRoute,
- errorRateRoute,
} from './errors';
import {
serviceAgentNameRoute,
@@ -49,6 +48,7 @@ import {
transactionGroupsRoute,
transactionGroupsAvgDurationByCountry,
transactionGroupsAvgDurationByBrowser,
+ transactionGroupsErrorRateRoute,
} from './transaction_groups';
import {
errorGroupsLocalFiltersRoute,
@@ -99,7 +99,6 @@ const createApmApi = () => {
.add(errorDistributionRoute)
.add(errorGroupsRoute)
.add(errorsRoute)
- .add(errorRateRoute)
// Services
.add(serviceAgentNameRoute)
@@ -139,6 +138,7 @@ const createApmApi = () => {
.add(transactionGroupsRoute)
.add(transactionGroupsAvgDurationByBrowser)
.add(transactionGroupsAvgDurationByCountry)
+ .add(transactionGroupsErrorRateRoute)
// UI filters
.add(errorGroupsLocalFiltersRoute)
diff --git a/x-pack/plugins/apm/server/routes/errors.ts b/x-pack/plugins/apm/server/routes/errors.ts
index 97314a9a61661..1615550027d3c 100644
--- a/x-pack/plugins/apm/server/routes/errors.ts
+++ b/x-pack/plugins/apm/server/routes/errors.ts
@@ -11,7 +11,6 @@ import { getErrorGroup } from '../lib/errors/get_error_group';
import { getErrorGroups } from '../lib/errors/get_error_groups';
import { setupRequest } from '../lib/helpers/setup_request';
import { uiFiltersRt, rangeRt } from './default_api_types';
-import { getErrorRate } from '../lib/errors/get_error_rate';
export const errorsRoute = createRoute(() => ({
path: '/api/apm/services/{serviceName}/errors',
@@ -81,26 +80,3 @@ export const errorDistributionRoute = createRoute(() => ({
return getErrorDistribution({ serviceName, groupId, setup });
},
}));
-
-export const errorRateRoute = createRoute(() => ({
- path: '/api/apm/services/{serviceName}/errors/rate',
- params: {
- path: t.type({
- serviceName: t.string,
- }),
- query: t.intersection([
- t.partial({
- groupId: t.string,
- }),
- uiFiltersRt,
- rangeRt,
- ]),
- },
- handler: async ({ context, request }) => {
- const setup = await setupRequest(context, request);
- const { params } = context;
- const { serviceName } = params.path;
- const { groupId } = params.query;
- return getErrorRate({ serviceName, groupId, setup });
- },
-}));
diff --git a/x-pack/plugins/apm/server/routes/transaction_groups.ts b/x-pack/plugins/apm/server/routes/transaction_groups.ts
index 3d939b04795c6..dca2fb1d9b295 100644
--- a/x-pack/plugins/apm/server/routes/transaction_groups.ts
+++ b/x-pack/plugins/apm/server/routes/transaction_groups.ts
@@ -14,6 +14,7 @@ import { createRoute } from './create_route';
import { uiFiltersRt, rangeRt } from './default_api_types';
import { getTransactionAvgDurationByBrowser } from '../lib/transactions/avg_duration_by_browser';
import { getTransactionAvgDurationByCountry } from '../lib/transactions/avg_duration_by_country';
+import { getErrorRate } from '../lib/transaction_groups/get_error_rate';
import { UIFilters } from '../../typings/ui_filters';
export const transactionGroupsRoute = createRoute(() => ({
@@ -209,3 +210,32 @@ export const transactionGroupsAvgDurationByCountry = createRoute(() => ({
});
},
}));
+
+export const transactionGroupsErrorRateRoute = createRoute(() => ({
+ path: '/api/apm/services/{serviceName}/transaction_groups/error_rate',
+ params: {
+ path: t.type({
+ serviceName: t.string,
+ }),
+ query: t.intersection([
+ uiFiltersRt,
+ rangeRt,
+ t.partial({
+ transactionType: t.string,
+ transactionName: t.string,
+ }),
+ ]),
+ },
+ handler: async ({ context, request }) => {
+ const setup = await setupRequest(context, request);
+ const { params } = context;
+ const { serviceName } = params.path;
+ const { transactionType, transactionName } = params.query;
+ return getErrorRate({
+ serviceName,
+ transactionType,
+ transactionName,
+ setup,
+ });
+ },
+}));
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index ef95f5f9c09d8..5734056f36bd9 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -4481,9 +4481,7 @@
"xpack.apm.transactionActionMenu.viewInUptime": "ステータス",
"xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "サンプルドキュメントを表示",
"xpack.apm.transactionBreakdown.chartTitle": "スパンタイプ別時間",
- "xpack.apm.transactionBreakdown.hideChart": "グラフを非表示",
"xpack.apm.transactionBreakdown.noData": "この時間範囲のデータがありません。",
- "xpack.apm.transactionBreakdown.showChart": "グラフを表示",
"xpack.apm.transactionDetails.errorCount": "{errorCount, number} {errorCount, plural, one {件のエラー} other {件のエラー}}",
"xpack.apm.transactionDetails.errorsOverviewLinkTooltip": "{errorCount, plural, one {1 件の関連エラーを表示} other {# 件の関連エラーを表示}}",
"xpack.apm.transactionDetails.notFoundLabel": "トランザクションが見つかりませんでした。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 108fb4ba32046..823a787a11e5d 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -4485,9 +4485,7 @@
"xpack.apm.transactionActionMenu.viewInUptime": "状态",
"xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "查看样例文档",
"xpack.apm.transactionBreakdown.chartTitle": "跨度类型花费的时间",
- "xpack.apm.transactionBreakdown.hideChart": "隐藏图表",
"xpack.apm.transactionBreakdown.noData": "此时间范围内没有数据。",
- "xpack.apm.transactionBreakdown.showChart": "显示图表",
"xpack.apm.transactionDetails.errorCount": "{errorCount, number} 个 {errorCount, plural, one {错误} other {错误}}",
"xpack.apm.transactionDetails.errorsOverviewLinkTooltip": "{errorCount, plural, one {查看 1 个相关错误} other {查看 # 个相关错误}}",
"xpack.apm.transactionDetails.notFoundLabel": "未找到任何事务。",