Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
bef912c
Add support to disable highlighting for certain filters we deem internal
achyutjhunjhunwala Oct 16, 2025
456b4fb
Replicate behaviour to Hosts view
achyutjhunjhunwala Oct 17, 2025
8eeedc6
Fix logic in host view to filter only user specific filters
achyutjhunjhunwala Oct 17, 2025
4529436
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Oct 20, 2025
11f9ccc
Add logic to control highlighting
achyutjhunjhunwala Oct 20, 2025
5550b9e
Update src/platform/plugins/shared/data/common/search/search_source/s…
achyutjhunjhunwala Oct 21, 2025
bca740a
Fix review comments
achyutjhunjhunwala Oct 21, 2025
eefddd3
apply the same code review to service logs as well
achyutjhunjhunwala Oct 21, 2025
77d2b7e
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Oct 22, 2025
adea8ef
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Oct 22, 2025
451d4d7
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Nov 3, 2025
2291e42
Remove skip highlight meta filter and replace the logic with passing …
achyutjhunjhunwala Nov 4, 2025
f8e9acd
Fix some of the old review comments
achyutjhunjhunwala Nov 4, 2025
24b8cf6
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Nov 4, 2025
2d209e3
Add skip highlight for Discover Traces Flyout which shows logs
achyutjhunjhunwala Nov 4, 2025
c1242f7
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Nov 4, 2025
ecfa6d7
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Nov 4, 2025
ab173d5
Fix more review comments and broken test snapshots
achyutjhunjhunwala Nov 5, 2025
18ef484
Merge branch 'main' into add-support-for-hidden-filters-in-logs-overv…
achyutjhunjhunwala Nov 5, 2025
7f5cb01
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type CustomFilter = Filter;
* @param negate
* @param alias
* @param store
* @param skipHighlight - When true, this filter will be excluded from highlight queries
* @returns
*
* @public
Expand All @@ -32,14 +33,16 @@ export function buildCustomFilter(
disabled: boolean,
negate: boolean,
alias: string | null,
store: FilterStateStore
store: FilterStateStore,
skipHighlight?: boolean
): Filter {
const meta: FilterMeta = {
index: indexPatternString,
type: FILTERS.CUSTOM,
disabled,
negate,
alias,
skipHighlight,
};
const filter: Filter = { ...queryDsl, meta };
filter.$state = { store };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export type FilterMeta = {
key?: string;
params?: FilterMetaParams;
value?: string;
skipHighlight?: boolean;
};

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,10 @@ export class SearchSource {
case 'filter':
return addToRoot(
'filters',
(typeof data.filters === 'function' ? data.filters() : data.filters || []).concat(val)
(typeof data.filters === 'function' ? data.filters() : data.filters ?? []).concat(val)
);
case 'query':
return addToRoot(key, (data.query || []).concat(val));
return addToRoot(key, (data.query ?? []).concat(val));
case 'fields':
// This will pass the passed in parameters to the new fields API.
// Also if will only return scripted fields that are part of the specified
Expand Down Expand Up @@ -879,21 +879,40 @@ export class SearchSource {
});
}

const allFilters =
typeof searchRequest.filters === 'function'
? searchRequest.filters()
: searchRequest.filters ?? [];

const builtQuery = this.getBuiltEsQuery({
index: searchRequest.index,
query: searchRequest.query,
filters: searchRequest.filters,
filters: allFilters,
getConfig,
sort: body.sort,
});

const highlightQuery = searchRequest.highlightAll
? this.buildHighlightQuery({
index: searchRequest.index,
query: searchRequest.query,
filters: allFilters,
getConfig,
})
: undefined;

const bodyToReturn = {
...body,
pit: searchRequest.pit,
query: builtQuery,
highlight:
searchRequest.highlightAll && builtQuery
? getHighlightRequest(getConfig(UI_SETTINGS.DOC_HIGHLIGHT))
? highlightQuery
? {
...getHighlightRequest(getConfig(UI_SETTINGS.DOC_HIGHLIGHT)),
highlight_query: highlightQuery,
}
: getHighlightRequest(getConfig(UI_SETTINGS.DOC_HIGHLIGHT))
: undefined,
// remove _source, since everything's coming from fields API, scripted, or stored fields
_source: fieldListProvided && !sourceFieldsProvided ? false : body._source,
Expand Down Expand Up @@ -978,6 +997,26 @@ export class SearchSource {
);
}

/**
* Build a highlight query excluding filters with skipHighlight metadata.
* Used to prevent non-highlighting filters (context filters) from being highlighted.
*/
private buildHighlightQuery({
index,
query = [],
filters = [],
getConfig,
}: SearchRequest & { filters: Filter[] }) {
const highlightFilters = filters.filter((f) => !f.meta?.skipHighlight);

if (highlightFilters.length === 0 && (!query || query.length === 0)) {
return undefined;
}

const esQueryConfigs = getEsQueryConfig({ get: getConfig });
return buildEsQuery(this.getDataView(index), query, highlightFilters, esQueryConfigs);
}

private getRemainingFields({
uniqFieldNames,
scriptFields,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ export const LogEvents = React.memo<LogEventsProps>(
({
dependencies,
documentFilters,
nonHighlightingFilters,
logsSource,
timeRange,
grouping,
groupingCapabilities,
height,
onChangeGrouping,
}) => {
const allFilters = React.useMemo(
() => [...(documentFilters || []), ...(nonHighlightingFilters || [])],
[documentFilters, nonHighlightingFilters]
);
return (
<EuiFlexGroup
direction="column"
Expand All @@ -49,7 +54,7 @@ export const LogEvents = React.memo<LogEventsProps>(
<EuiFlexItem grow={false}>
<LogEventsControlBar
dependencies={dependencies}
documentFilters={documentFilters}
documentFilters={allFilters}
logsSource={logsSource}
timeRange={timeRange}
grouping={grouping}
Expand All @@ -61,6 +66,7 @@ export const LogEvents = React.memo<LogEventsProps>(
<LogEventsResultContent
dependencies={dependencies}
documentFilters={documentFilters}
nonHighlightingFilters={nonHighlightingFilters}
logsSource={logsSource}
timeRange={timeRange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import type { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_

export interface LogEventsResultContentProps {
dependencies: LogEventsResultContentDependencies;
documentFilters: QueryDslQueryContainer[];
documentFilters?: QueryDslQueryContainer[];
nonHighlightingFilters?: QueryDslQueryContainer[];
logsSource: ResolvedIndexNameLogsSourceConfiguration;
timeRange: {
start: string;
Expand All @@ -31,7 +32,7 @@ export interface LogEventsResultContentDependencies {
}

export const LogEventsResultContent = React.memo<LogEventsResultContentProps>(
({ dependencies, documentFilters, logsSource, timeRange }) => {
({ dependencies, documentFilters = [], nonHighlightingFilters = [], logsSource, timeRange }) => {
const savedSearchDependencies = React.useMemo(
() => ({
embeddable: dependencies.embeddable,
Expand All @@ -50,18 +51,33 @@ export const LogEventsResultContent = React.memo<LogEventsResultContentProps>(
);

const savedSearchFilters = React.useMemo(
() =>
documentFilters.map((filter) =>
() => [
// Document filters (will be highlighted)
...documentFilters.map((filter) =>
buildCustomFilter(
logsSource.indexName,
filter,
false,
false,
'Document Filters',
FilterStateStore.APP_STATE
FilterStateStore.APP_STATE,
false
)
),
[documentFilters, logsSource.indexName]
// Non-highlighting filters (won't be highlighted)
...nonHighlightingFilters.map((filter) =>
buildCustomFilter(
logsSource.indexName,
filter,
false,
false,
'Context Filters',
FilterStateStore.APP_STATE,
true
)
),
],
[documentFilters, nonHighlightingFilters, logsSource.indexName]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import { LogsOverviewStateContext, logsOverviewStateMachine } from './logs_overv

export type LogsOverviewProps = Pick<LogsOverviewContentProps, 'height' | 'timeRange'> & {
dependencies: LogsOverviewDependencies;
documentFilters?: QueryDslQueryContainer[] | undefined;
documentFilters?: QueryDslQueryContainer[];
nonHighlightingFilters?: QueryDslQueryContainer[];
featureFlags?: LogsOverviewFeatureFlags | undefined;
logsSource?: LogsSourceConfiguration | undefined;
};
Expand All @@ -42,6 +43,7 @@ export const LogsOverview: React.FC<LogsOverviewProps> = React.memo(
({
dependencies,
documentFilters = defaultDocumentFilters,
nonHighlightingFilters = defaultDocumentFilters,
featureFlags = defaultFeatureFlags,
height,
logsSource = defaultLogsSource,
Expand Down Expand Up @@ -71,6 +73,7 @@ export const LogsOverview: React.FC<LogsOverviewProps> = React.memo(
<LogsOverviewContent
dependencies={dependencies}
documentFilters={documentFilters}
nonHighlightingFilters={nonHighlightingFilters}
height={height}
timeRange={timeRange}
/>
Expand All @@ -83,14 +86,14 @@ export type LogsOverviewContentProps = Pick<
LogCategoriesProps,
'height' | 'timeRange' | 'documentFilters'
> &
Pick<LogEventsProps, 'height' | 'timeRange' | 'documentFilters'> & {
dependencies: LogsOverviewDependencies;
Pick<LogEventsProps, 'height' | 'timeRange' | 'documentFilters' | 'nonHighlightingFilters'> & {
dependencies: LogsOverviewContentDependencies;
};

export type LogsOverviewContentDependencies = LogCategoriesDependencies & LogEventsDependencies;

export const LogsOverviewContent = React.memo<LogsOverviewContentProps>(
({ dependencies, documentFilters, height, timeRange }) => {
({ dependencies, documentFilters, nonHighlightingFilters, height, timeRange }) => {
const logsOverviewStateActorRef = LogsOverviewStateContext.useActorRef();

const logsOverviewState = LogsOverviewStateContext.useSelector(identity);
Expand Down Expand Up @@ -123,6 +126,11 @@ export const LogsOverviewContent = React.memo<LogsOverviewContentProps>(
[logsOverviewStateActorRef]
);

const allFiltersForCategories = React.useMemo(
() => [...(documentFilters || []), ...(nonHighlightingFilters || [])],
[documentFilters, nonHighlightingFilters]
);

if (logsOverviewState.matches('initializing')) {
return <LogsOverviewLoadingContent />;
} else if (logsOverviewState.matches('failedToInitialize')) {
Expand All @@ -136,7 +144,7 @@ export const LogsOverviewContent = React.memo<LogsOverviewContentProps>(
return (
<LogCategories
dependencies={dependencies}
documentFilters={documentFilters}
documentFilters={allFiltersForCategories}
logsSource={logsOverviewState.context.logsSource.value}
timeRange={timeRange}
grouping={grouping}
Expand All @@ -150,6 +158,7 @@ export const LogsOverviewContent = React.memo<LogsOverviewContentProps>(
<LogEvents
dependencies={dependencies}
documentFilters={documentFilters}
nonHighlightingFilters={nonHighlightingFilters}
logsSource={logsOverviewState.context.logsSource.value}
timeRange={timeRange}
grouping={grouping}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

import React, { useMemo } from 'react';
import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { buildEsQuery } from '@kbn/es-query';
import { getEsQueryConfig } from '@kbn/data-plugin/public';
import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm';
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
Expand All @@ -19,7 +18,7 @@ import { useTimeRange } from '../../../hooks/use_time_range';

export function ServiceLogs() {
const {
services: { logsShared, uiSettings },
services: { logsShared },
} = useKibana();

const { serviceName } = useApmServiceContext();
Expand Down Expand Up @@ -55,24 +54,35 @@ export function ServiceLogs() {
[environment, kuery, serviceName, start, end]
);

const logFilters = useMemo(() => {
return [
...(assetFilter != null ? [assetFilter] : []),
buildEsQuery(
undefined,
{
language: 'kuery',
query: kuery,
},
[],
getEsQueryConfig(uiSettings)
),
];
}, [assetFilter, kuery, uiSettings]);
const internalLogFilters = useMemo(() => {
return assetFilter != null ? [assetFilter] : [];
}, [assetFilter]);

const documentLogFilters = useMemo(() => {
if (!kuery) {
return [];
}

try {
return [toElasticsearchQuery(fromKueryExpression(kuery))];
} catch (err) {
// Invalid/incomplete query, return empty array to avoid breaking the component
return [];
}
}, [kuery]);

if (status === FETCH_STATUS.SUCCESS || (status === FETCH_STATUS.LOADING && logFilters != null)) {
if (
status === FETCH_STATUS.SUCCESS ||
(status === FETCH_STATUS.LOADING &&
(internalLogFilters.length > 0 || documentLogFilters.length > 0))
) {
return (
<logsShared.LogsOverview documentFilters={logFilters} timeRange={timeRange} height="60vh" />
<logsShared.LogsOverview
documentFilters={documentLogFilters}
nonHighlightingFilters={internalLogFilters}
timeRange={timeRange}
height="60vh"
/>
);
} else if (status === FETCH_STATUS.FAILURE) {
return (
Expand Down
Loading