Skip to content

Commit

Permalink
[Profiling] adding KQL bar to embeddables (elastic#171016)
Browse files Browse the repository at this point in the history
Adding KQL bar to the `Flamegraph` and `Top 10 functions` embeddable.



https://github.com/elastic/kibana/assets/55978943/ddd74947-d6e6-4fc5-a563-c1f62853a434

New version:
<img width="1649" alt="Screenshot 2023-11-21 at 11 14 32"
src="https://github.com/elastic/kibana/assets/55978943/16899d1e-485d-477a-bda0-48a22e9e0e56">

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
cauemarcondes and kibanamachine authored Nov 23, 2023
1 parent 2f258a2 commit 07432ab
Show file tree
Hide file tree
Showing 20 changed files with 414 additions and 86 deletions.
62 changes: 62 additions & 0 deletions x-pack/plugins/apm/common/utils/kuery_utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 { toKueryFilterFormat, mergeKueries } from './kuery_utils';

describe('toKueryFilterFormat', () => {
it('returns a single value', () => {
expect(toKueryFilterFormat('key', ['foo'])).toEqual(`key : "foo"`);
});

it('returns multiple values default separator', () => {
expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'])).toEqual(
`key : "foo" OR key : "bar" OR key : "baz"`
);
});

it('returns multiple values custom separator', () => {
expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'], 'AND')).toEqual(
`key : "foo" AND key : "bar" AND key : "baz"`
);
});

it('return empty string when no hostname', () => {
expect(toKueryFilterFormat('key', [])).toEqual('');
});

describe('mergeKueries', () => {
it('returns empty string when both kueries are empty', () => {
expect(mergeKueries(['', ''])).toEqual('');
});

it('returns only first kuery when second is empty', () => {
expect(mergeKueries(['host.name: "foo"', ''])).toEqual(
'host.name: "foo"'
);
});

it('returns second kuery when first is empty', () => {
expect(mergeKueries(['', 'host.name: "foo"'])).toEqual(
'host.name: "foo"'
);
});

it('returns merged kueries with default separator', () => {
expect(
mergeKueries([
'host.name: "foo" OR host.name: "bar"',
'process.id: "1"',
])
).toEqual('host.name: "foo" OR host.name: "bar" AND process.id: "1"');
});

it('uses custom separator', () => {
expect(
mergeKueries(['host.name: "foo"', 'process.id: "1"'], 'OR')
).toEqual('host.name: "foo" OR process.id: "1"');
});
});
});
19 changes: 19 additions & 0 deletions x-pack/plugins/apm/common/utils/kuery_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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 { isEmpty } from 'lodash';

type Separator = 'OR' | 'AND';

export const toKueryFilterFormat = (
key: string,
values: string[],
separator: Separator = 'OR'
) => values.map((value) => `${key} : "${value}"`).join(` ${separator} `);

export const mergeKueries = (filters: string[], separator: Separator = 'AND') =>
filters.filter((filter) => !isEmpty(filter)).join(` ${separator} `);
29 changes: 0 additions & 29 deletions x-pack/plugins/apm/common/utils/to_kuery_filter_format.test.ts

This file was deleted.

14 changes: 0 additions & 14 deletions x-pack/plugins/apm/common/utils/to_kuery_filter_format.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,37 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { EmbeddableProfilingSearchBar } from '@kbn/observability-shared-plugin/public';
import React, { useMemo } from 'react';
import { useHistory } from 'react-router-dom';
import { ApmDocumentType } from '../../../../common/document_type';
import { useApmParams } from '../../../hooks/use_apm_params';
import { useLocalStorage } from '../../../hooks/use_local_storage';
import { usePreferredDataSourceAndBucketSize } from '../../../hooks/use_preferred_data_source_and_bucket_size';
import { useProfilingPlugin } from '../../../hooks/use_profiling_plugin';
import { useTimeRange } from '../../../hooks/use_time_range';
import { ApmPluginStartDeps } from '../../../plugin';
import { push } from '../../shared/links/url_helpers';
import { ProfilingFlamegraph } from './profiling_flamegraph';
import { ProfilingTopNFunctions } from './profiling_top_functions';

export function ProfilingOverview() {
const history = useHistory();
const { services } = useKibana<ApmPluginStartDeps>();
const {
path: { serviceName },
query: { rangeFrom, rangeTo, environment, kuery },
} = useApmParams('/services/{serviceName}/profiling');
const { isProfilingAvailable } = useProfilingPlugin();
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
const { start, end, refreshTimeRange } = useTimeRange({ rangeFrom, rangeTo });
const preferred = usePreferredDataSourceAndBucketSize({
start,
end,
kuery,
type: ApmDocumentType.TransactionMetric,
numBuckets: 20,
});

const [
apmUniversalProfilingShowCallout,
setAPMUniversalProfilingShowCallout,
Expand All @@ -67,6 +72,7 @@ export function ProfilingOverview() {
end={end}
environment={environment}
dataSource={preferred?.source}
kuery={kuery}
/>
</>
),
Expand All @@ -87,12 +93,13 @@ export function ProfilingOverview() {
startIndex={0}
endIndex={10}
dataSource={preferred?.source}
kuery={kuery}
/>
</>
),
},
];
}, [end, environment, preferred?.source, serviceName, start]);
}, [end, environment, kuery, preferred?.source, serviceName, start]);

if (!isProfilingAvailable) {
return null;
Expand Down Expand Up @@ -147,6 +154,22 @@ export function ProfilingOverview() {
<EuiSpacer />
</>
)}
<EmbeddableProfilingSearchBar
kuery={kuery}
rangeFrom={rangeFrom}
rangeTo={rangeTo}
onQuerySubmit={(next) => {
push(history, {
query: {
kuery: next.query,
rangeFrom: next.dateRange.from,
rangeTo: next.dateRange.to,
},
});
}}
onRefresh={refreshTimeRange}
/>
<EuiSpacer />
<EuiTabbedContent
tabs={tabs}
initialSelectedTab={tabs[0]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import React from 'react';
import { ApmDataSourceWithSummary } from '../../../../common/data_source';
import { ApmDocumentType } from '../../../../common/document_type';
import { HOST_NAME } from '../../../../common/es_fields/apm';
import { toKueryFilterFormat } from '../../../../common/utils/to_kuery_filter_format';
import {
mergeKueries,
toKueryFilterFormat,
} from '../../../../common/utils/kuery_utils';
import {
FETCH_STATUS,
isPending,
Expand All @@ -36,6 +39,7 @@ interface Props {
dataSource?: ApmDataSourceWithSummary<
ApmDocumentType.TransactionMetric | ApmDocumentType.TransactionEvent
>;
kuery: string;
}

export function ProfilingFlamegraph({
Expand All @@ -44,6 +48,7 @@ export function ProfilingFlamegraph({
serviceName,
environment,
dataSource,
kuery,
}: Props) {
const { profilingLocators } = useProfilingPlugin();

Expand All @@ -61,13 +66,14 @@ export function ProfilingFlamegraph({
environment,
documentType: dataSource.documentType,
rollupInterval: dataSource.rollupInterval,
kuery,
},
},
}
);
}
},
[dataSource, serviceName, start, end, environment]
[dataSource, serviceName, start, end, environment, kuery]
);

const hostNamesKueryFormat = toKueryFilterFormat(
Expand All @@ -86,7 +92,7 @@ export function ProfilingFlamegraph({
<EuiLink
data-test-subj="apmProfilingFlamegraphGoToFlamegraphLink"
href={profilingLocators?.flamegraphLocator.getRedirectUrl({
kuery: hostNamesKueryFormat,
kuery: mergeKueries([`(${hostNamesKueryFormat})`, kuery]),
})}
>
{i18n.translate('xpack.apm.profiling.flamegraph.link', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EmbeddableFunctions } from '@kbn/observability-shared-plugin/public';
import React from 'react';
import { ApmDataSourceWithSummary } from '../../../../common/data_source';
import { ApmDocumentType } from '../../../../common/document_type';
import { HOST_NAME } from '../../../../common/es_fields/apm';
import { toKueryFilterFormat } from '../../../../common/utils/to_kuery_filter_format';
import {
mergeKueries,
toKueryFilterFormat,
} from '../../../../common/utils/kuery_utils';
import { isPending, useFetcher } from '../../../hooks/use_fetcher';
import { useProfilingPlugin } from '../../../hooks/use_profiling_plugin';
import { HostnamesFilterWarning } from './host_names_filter_warning';
import { ApmDataSourceWithSummary } from '../../../../common/data_source';
import { ApmDocumentType } from '../../../../common/document_type';

interface Props {
serviceName: string;
Expand All @@ -27,6 +30,7 @@ interface Props {
dataSource?: ApmDataSourceWithSummary<
ApmDocumentType.TransactionMetric | ApmDocumentType.TransactionEvent
>;
kuery: string;
}

export function ProfilingTopNFunctions({
Expand All @@ -37,6 +41,7 @@ export function ProfilingTopNFunctions({
startIndex,
endIndex,
dataSource,
kuery,
}: Props) {
const { profilingLocators } = useProfilingPlugin();

Expand All @@ -56,13 +61,23 @@ export function ProfilingTopNFunctions({
endIndex,
documentType: dataSource.documentType,
rollupInterval: dataSource.rollupInterval,
kuery,
},
},
}
);
}
},
[dataSource, serviceName, start, end, environment, startIndex, endIndex]
[
dataSource,
serviceName,
start,
end,
environment,
startIndex,
endIndex,
kuery,
]
);

const hostNamesKueryFormat = toKueryFilterFormat(
Expand All @@ -81,7 +96,7 @@ export function ProfilingTopNFunctions({
<EuiLink
data-test-subj="apmProfilingTopNFunctionsGoToUniversalProfilingFlamegraphLink"
href={profilingLocators?.topNFunctionsLocator.getRedirectUrl({
kuery: hostNamesKueryFormat,
kuery: mergeKueries([`(${hostNamesKueryFormat})`, kuery]),
})}
>
{i18n.translate('xpack.apm.profiling.topnFunctions.link', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,7 @@ export const serviceDetailRoute = {
}),
element: <ProfilingOverview />,
searchBarOptions: {
showTimeComparison: false,
showTransactionTypeSelector: false,
showQueryInput: false,
hidden: true,
},
}),
},
Expand Down
Loading

0 comments on commit 07432ab

Please sign in to comment.