forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Logs Explorer] Support logs data views (elastic#176078)
## 📓 Summary Closes elastic#175767 🧪 You can access a live deployment of this PR [here](https://issue-deploy-kibana-pr176078.kb.us-west2.gcp.elastic-cloud.com/app/observability-logs-explorer/). There has been a lot of talking around supporting selection for data views and staying on the Logs Explorer for those concerning logs data streams. This work supports selecting and exploring Discover data views on Logs Explorer. This is currently limited to logs data views. https://github.com/elastic/kibana/assets/34506779/cccd6863-e1c1-4fa6-a530-9aed5d8d97c1 ## Next steps We had already an offline conversation with the team about how naming the selector, selection modes and related entities is becoming inconsistent and more difficult to maintain. To keep this PR narrowed to the data views support, an upcoming PR will focus on renaming according to the new selector's responsibilities. ## Core changes ### DataViewDescriptor The `DataViewDescriptor` instance is a way to describe a data view in the context of Logs Explorer. This does not represent a DataView object complete of fields and all the details provided with a DataView instance, but it instead encapsulates the logic around identifying what data type a data view is about, as well as defining the logic to use it with the new `dataView` selection mode. It creates a new instance starting from a `DataViewListItem` object, which is a minimal object provided by the dataViews service to list existing data views. ### LogExplorerController The `LogExplorerController` state machine now handles the selected entry depending on its type, triggering different flows. There are 3 different journeys depending on the selected entry: - For a data view entry which is not about logs, the page redirects to Discover with the data view selected - For a data view entry about logs, the data loads in the Logs Explorer, switching to the persisted DataView. - For a dataset entry, an ad-hoc data view loads in the Logs Explorer. To avoid updating twice the data view (once during initialization, and immediately after during selection validation), the validation flow has been anticipated and restructured to follow different flows, depending on the selection type. <img width="1953" alt="Screenshot 2024-02-09 at 12 02 10" src="https://github.com/elastic/kibana/assets/34506779/a63201f5-67b2-4890-8823-6ffd6691e249"> ### Dataset selector The selector state machine unifies the selection handler and expands the selection modes, adding a new `dataView` mode which handles logs data view selections. <img width="1281" alt="Screenshot 2024-02-05 at 16 24 31" src="https://github.com/elastic/kibana/assets/34506779/80e04331-7b93-40fc-af1d-32ef4ef705f5"> --------- Co-authored-by: Marco Antonio Ghiani <marcoantonio.ghiani@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
1aa5e38
commit dd06f81
Showing
34 changed files
with
793 additions
and
256 deletions.
There are no files selected for viewing
83 changes: 83 additions & 0 deletions
83
...bservability_solution/logs_explorer/common/data_views/models/data_view_descriptor.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { DataViewDescriptor } from './data_view_descriptor'; | ||
|
||
describe('DataViewDescriptor', () => { | ||
it('should correctly assert whether a data view has "logs" type', () => { | ||
const id = 'test-id'; | ||
|
||
// Assert truthy cases | ||
expect(DataViewDescriptor.create({ id, title: 'auditbeat*' }).isLogsDataType()).toBeTruthy(); | ||
expect(DataViewDescriptor.create({ id, title: 'auditbeat-*' }).isLogsDataType()).toBeTruthy(); | ||
expect(DataViewDescriptor.create({ id, title: 'logs*' }).isLogsDataType()).toBeTruthy(); | ||
expect(DataViewDescriptor.create({ id, title: 'logs-*' }).isLogsDataType()).toBeTruthy(); | ||
expect(DataViewDescriptor.create({ id, title: 'logs-*-*' }).isLogsDataType()).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'logs-system.syslog-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'logs-system.syslog-default' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-*-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-system.syslog-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ | ||
id, | ||
title: 'cluster1:logs-system.syslog-default', | ||
}).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'logs-*,cluster1:logs-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'logs-*,cluster1:logs-*,' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-*,cluster2:logs-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-*,cluster2:logs-*' }).isLogsDataType() | ||
).toBeTruthy(); | ||
expect( | ||
DataViewDescriptor.create({ | ||
id, | ||
title: '*:logs-system.syslog-*,*:logs-system.errors-*', | ||
}).isLogsDataType() | ||
).toBeTruthy(); | ||
|
||
// Assert falsy cases | ||
expect(DataViewDescriptor.create({ id, title: 'auditbeats*' }).isLogsDataType()).toBeFalsy(); | ||
expect(DataViewDescriptor.create({ id, title: 'auditbeats-*' }).isLogsDataType()).toBeFalsy(); | ||
expect(DataViewDescriptor.create({ id, title: 'logss*' }).isLogsDataType()).toBeFalsy(); | ||
expect(DataViewDescriptor.create({ id, title: 'logss-*' }).isLogsDataType()).toBeFalsy(); | ||
expect(DataViewDescriptor.create({ id, title: 'metrics*' }).isLogsDataType()).toBeFalsy(); | ||
expect(DataViewDescriptor.create({ id, title: 'metrics-*' }).isLogsDataType()).toBeFalsy(); | ||
expect( | ||
DataViewDescriptor.create({ | ||
id, | ||
title: '*:metrics-system.syslog-*,logs-system.errors-*', | ||
}).isLogsDataType() | ||
).toBeFalsy(); | ||
expect( | ||
DataViewDescriptor.create({ id, title: 'cluster1:logs-*,clust,er2:logs-*' }).isLogsDataType() | ||
).toBeFalsy(); | ||
expect( | ||
DataViewDescriptor.create({ | ||
id, | ||
title: 'cluster1:logs-*, cluster2:logs-*', | ||
}).isLogsDataType() | ||
).toBeFalsy(); | ||
}); | ||
}); |
102 changes: 102 additions & 0 deletions
102
...ins/observability_solution/logs_explorer/common/data_views/models/data_view_descriptor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* 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 { DataViewListItem } from '@kbn/data-views-plugin/common'; | ||
import { DataViewSpecWithId } from '../../dataset_selection'; | ||
import { DataViewDescriptorType } from '../types'; | ||
import { buildIndexPatternRegExp } from '../utils'; | ||
|
||
type Allowlist = Array<string | RegExp>; | ||
|
||
const LOGS_ALLOWLIST: Allowlist = [ | ||
buildIndexPatternRegExp(['logs', 'auditbeat', 'filebeat', 'winbeat']), | ||
// Add more strings or regex patterns as needed | ||
]; | ||
|
||
export class DataViewDescriptor { | ||
id: DataViewDescriptorType['id']; | ||
dataType: DataViewDescriptorType['dataType']; | ||
kibanaSpaces: DataViewDescriptorType['kibanaSpaces']; | ||
name: DataViewDescriptorType['name']; | ||
title: DataViewDescriptorType['title']; | ||
type: DataViewDescriptorType['type']; | ||
|
||
private constructor(dataViewDescriptor: DataViewDescriptorType) { | ||
this.id = dataViewDescriptor.id; | ||
this.dataType = dataViewDescriptor.dataType; | ||
this.kibanaSpaces = dataViewDescriptor.kibanaSpaces; | ||
this.name = dataViewDescriptor.name; | ||
this.title = dataViewDescriptor.title; | ||
this.type = dataViewDescriptor.type; | ||
} | ||
|
||
getFullTitle() { | ||
return this.name; | ||
} | ||
|
||
toDataviewSpec(): DataViewSpecWithId { | ||
return { | ||
id: this.id, | ||
name: this.name, | ||
title: this.title, | ||
}; | ||
} | ||
|
||
toPlain() { | ||
return { | ||
id: this.id, | ||
dataType: this.dataType, | ||
name: this.name, | ||
title: this.title, | ||
}; | ||
} | ||
|
||
public static create({ id, namespaces, title, type, name }: DataViewListItem) { | ||
const nameWithFallbackTitle = name ?? title; | ||
const dataType = DataViewDescriptor.#extractDataType(title); | ||
const kibanaSpaces = namespaces; | ||
|
||
return new DataViewDescriptor({ | ||
id, | ||
dataType, | ||
kibanaSpaces, | ||
name: nameWithFallbackTitle, | ||
title, | ||
type, | ||
}); | ||
} | ||
|
||
static #extractDataType(title: string): DataViewDescriptorType['dataType'] { | ||
if (isAllowed(title, LOGS_ALLOWLIST)) { | ||
return 'logs'; | ||
} | ||
|
||
return 'unknown'; | ||
} | ||
|
||
public isLogsDataType() { | ||
return this.dataType === 'logs'; | ||
} | ||
|
||
public isUnknownDataType() { | ||
return this.dataType === 'unknown'; | ||
} | ||
} | ||
|
||
function isAllowed(value: string, allowList: Allowlist) { | ||
for (const allowedItem of allowList) { | ||
if (typeof allowedItem === 'string') { | ||
return value === allowedItem; | ||
} | ||
if (allowedItem instanceof RegExp) { | ||
return allowedItem.test(value); | ||
} | ||
} | ||
|
||
// If no match is found in the allowList, return false | ||
return false; | ||
} |
29 changes: 29 additions & 0 deletions
29
x-pack/plugins/observability_solution/logs_explorer/common/data_views/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* 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 * as rt from 'io-ts'; | ||
|
||
const dataTypeRT = rt.keyof({ | ||
logs: null, | ||
unknown: null, | ||
}); | ||
|
||
export const dataViewDescriptorRT = rt.exact( | ||
rt.intersection([ | ||
rt.type({ | ||
id: rt.string, | ||
name: rt.string, | ||
title: rt.string, | ||
dataType: dataTypeRT, | ||
}), | ||
rt.partial({ | ||
kibanaSpaces: rt.array(rt.string), | ||
type: rt.string, | ||
}), | ||
]) | ||
); | ||
|
||
export type DataViewDescriptorType = rt.TypeOf<typeof dataViewDescriptorRT>; |
15 changes: 15 additions & 0 deletions
15
x-pack/plugins/observability_solution/logs_explorer/common/data_views/utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
export const buildIndexPatternRegExp = (basePatterns: string[]) => { | ||
// Create the base patterns union with strict boundaries | ||
const basePatternGroup = `\\b(${basePatterns.join('|')})\\b[^,\\s]+`; | ||
// Apply base patterns union for local and remote clusters | ||
const localAndRemotePatternGroup = `((${basePatternGroup})|([^:,\\s]+:${basePatternGroup}))`; | ||
// Handle trailing comma and multiple pattern concatenation | ||
return new RegExp(`^${localAndRemotePatternGroup}(,${localAndRemotePatternGroup})*(,$|$)`, 'i'); | ||
}; |
47 changes: 47 additions & 0 deletions
47
...gins/observability_solution/logs_explorer/common/dataset_selection/data_view_selection.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* 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 { DataViewDescriptor } from '../data_views/models/data_view_descriptor'; | ||
import { DatasetSelectionStrategy, DataViewSelectionPayload } from './types'; | ||
|
||
export class DataViewSelection implements DatasetSelectionStrategy { | ||
selectionType: 'dataView'; | ||
selection: { | ||
dataView: DataViewDescriptor; | ||
}; | ||
|
||
private constructor(dataViewDescriptor: DataViewDescriptor) { | ||
this.selectionType = 'dataView'; | ||
this.selection = { | ||
dataView: dataViewDescriptor, | ||
}; | ||
} | ||
|
||
toDataviewSpec() { | ||
return this.selection.dataView.toDataviewSpec(); | ||
} | ||
|
||
toPlainSelection() { | ||
return { | ||
selectionType: this.selectionType, | ||
selection: { | ||
dataView: this.selection.dataView.toPlain(), | ||
}, | ||
}; | ||
} | ||
|
||
public static fromSelection(selection: DataViewSelectionPayload) { | ||
const { dataView } = selection; | ||
|
||
const dataViewDescriptor = DataViewDescriptor.create(dataView); | ||
return DataViewSelection.create(dataViewDescriptor); | ||
} | ||
|
||
public static create(dataViewDescriptor: DataViewDescriptor) { | ||
return new DataViewSelection(dataViewDescriptor); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.