From b3a1af8c6b4211b4231c9e07318c545459b9825a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 20 Aug 2024 16:50:54 +0000 Subject: [PATCH 01/74] Add rare logs scenario --- .../src/lib/entity.ts | 12 ++ .../src/lib/infra/host.ts | 10 +- .../src/lib/infra/index.ts | 3 +- .../src/lib/interval.ts | 18 +- .../src/lib/logs/index.ts | 21 +++ .../src/lib/random_events.test.ts | 52 ++++++ .../src/lib/random_events.ts | 76 ++++++++ .../src/lib/timerange.ts | 22 ++- .../helpers/unstructured_logs.test.ts | 17 ++ .../scenarios/helpers/unstructured_logs.ts | 85 +++++++++ .../src/scenarios/rare_logs.ts | 162 ++++++++++++++++++ 11 files changed, 472 insertions(+), 6 deletions(-) create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/random_events.ts create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts diff --git a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts index 9d872a6822462..1120c222c60af 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/entity.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/entity.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +export type ObjectEntry = [keyof T, T[keyof T]]; + export type Fields | undefined = undefined> = { '@timestamp'?: number; } & (TMeta extends undefined ? {} : Partial<{ meta: TMeta }>); @@ -26,4 +28,14 @@ export class Entity { return this; } + + overrides(overrides: Partial) { + const overrideEntries = Object.entries(overrides) as Array>; + + overrideEntries.forEach(([fieldName, value]) => { + this.fields[fieldName] = value; + }); + + return this; + } } diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index a5ca11ad20203..d479b8889de9e 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -23,7 +23,7 @@ interface HostDocument extends Fields { 'cloud.provider'?: string; } -class Host extends Entity { +export class Host extends Entity { cpu() { return new HostMetrics({ ...this.fields, @@ -136,3 +136,11 @@ export function host(name: string): Host { 'cloud.provider': 'gcp', }); } + +export function minimalHost(name: string): Host { + return new Host({ + 'agent.id': 'synthtrace', + 'host.hostname': name, + 'host.name': name, + }); +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts index c325635e27098..3b415d6324a43 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts @@ -7,7 +7,7 @@ */ import { dockerContainer, DockerContainerMetricsDocument } from './docker_container'; -import { host, HostMetricsDocument } from './host'; +import { host, HostMetricsDocument, minimalHost } from './host'; import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container'; import { pod, PodMetricsDocument } from './pod'; import { awsRds, AWSRdsMetricsDocument } from './aws/rds'; @@ -21,6 +21,7 @@ export type InfraDocument = export const infra = { host, + minimalHost, pod, dockerContainer, k8sContainer, diff --git a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts index bb77e6f6ee350..6f08a9038c746 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/interval.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/interval.ts @@ -32,6 +32,10 @@ interface IntervalOptions { rate?: number; } +interface StepDetails { + stepMilliseconds: number; +} + export class Interval { private readonly intervalAmount: number; private readonly intervalUnit: unitOfTime.DurationConstructor; @@ -44,12 +48,16 @@ export class Interval { this._rate = options.rate || 1; } + private getIntervalMilliseconds(): number { + return moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); + } + private getTimestamps() { const from = this.options.from.getTime(); const to = this.options.to.getTime(); let time: number = from; - const diff = moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds(); + const diff = this.getIntervalMilliseconds(); const timestamps: number[] = []; @@ -66,15 +74,19 @@ export class Interval { *generator( map: ( timestamp: number, - index: number + index: number, + stepDetails: StepDetails ) => Serializable | Array> ): SynthtraceGenerator { const timestamps = this.getTimestamps(); + const stepDetails: StepDetails = { + stepMilliseconds: this.getIntervalMilliseconds(), + }; let index = 0; for (const timestamp of timestamps) { - const events = castArray(map(timestamp, index)); + const events = castArray(map(timestamp, index, stepDetails)); index++; for (const event of events) { yield event; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts index a649189de47a5..3fc09e4203dba 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts @@ -63,6 +63,7 @@ export type LogDocument = Fields & 'event.duration': number; 'event.start': Date; 'event.end': Date; + labels?: Record; }>; class Log extends Serializable { @@ -139,6 +140,26 @@ function create(logsOptions: LogsOptions = defaultLogsOptions): Log { ).dataset('synth'); } +function createMinimal({ + dataset = 'synth', + namespace = 'default', +}: { + dataset?: string; + namespace?: string; +} = {}): Log { + return new Log( + { + 'input.type': 'logs', + 'data_stream.namespace': namespace, + 'data_stream.type': 'logs', + 'data_stream.dataset': dataset, + 'event.dataset': dataset, + }, + { isLogsDb: false } + ); +} + export const log = { create, + createMinimal, }; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts b/packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts new file mode 100644 index 0000000000000..27e9e673300fc --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts @@ -0,0 +1,52 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PoissonEvents } from './random_events'; +import { Serializable } from './serializable'; + +describe('poisson events', () => { + it('generates events within the given time range', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 10); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBeGreaterThanOrEqual(1); + + for (const event of events) { + expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); + expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); + } + }); + + it('generates at least one event if the rate is greater than 0', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 1); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBeGreaterThanOrEqual(1); + + for (const event of events) { + expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000); + expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000); + } + }); + + it('generates no event if the rate is 0', () => { + const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 0); + + const events = Array.from( + poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp })) + ); + + expect(events.length).toBe(0); + }); +}); diff --git a/packages/kbn-apm-synthtrace-client/src/lib/random_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/random_events.ts new file mode 100644 index 0000000000000..05d8d8793d1b8 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/random_events.ts @@ -0,0 +1,76 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { castArray } from 'lodash'; +import { SynthtraceGenerator } from '../types'; +import { Fields } from './entity'; +import { Serializable } from './serializable'; + +export class PoissonEvents { + constructor( + private readonly from: Date, + private readonly to: Date, + private readonly rate: number + ) {} + + private getTotalTimePeriod(): number { + return this.to.getTime() - this.from.getTime(); + } + + private getInterarrivalTime(): number { + const distribution = -Math.log(1 - Math.random()) / this.rate; + const totalTimePeriod = this.getTotalTimePeriod(); + return Math.floor(distribution * totalTimePeriod); + } + + *generator( + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): SynthtraceGenerator { + if (this.rate <= 0) { + return; + } + + let currentTime = this.from.getTime(); + const endTime = this.to.getTime(); + let eventIndex = 0; + + while (currentTime < endTime) { + const interarrivalTime = this.getInterarrivalTime(); + currentTime += interarrivalTime; + + if (currentTime < endTime) { + yield* this.generateEvents(currentTime, eventIndex, map); + eventIndex++; + } + } + + // ensure at least one event has been emitted + if (this.rate > 0 && eventIndex === 0) { + const forcedEventTime = + this.from.getTime() + Math.floor(Math.random() * this.getTotalTimePeriod()); + yield* this.generateEvents(forcedEventTime, eventIndex, map); + } + } + + private *generateEvents( + timestamp: number, + eventIndex: number, + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): Generator> { + const events = castArray(map(timestamp, eventIndex)); + for (const event of events) { + yield event; + } + } +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts index 0817ea3d0e34f..9e9e165ca5194 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts @@ -8,9 +8,10 @@ import datemath from '@kbn/datemath'; import type { Moment } from 'moment'; import { Interval } from './interval'; +import { PoissonEvents } from './random_events'; export class Timerange { - constructor(private from: Date, private to: Date) {} + constructor(public readonly from: Date, public readonly to: Date) {} interval(interval: string) { return new Interval({ from: this.from, to: this.to, interval }); @@ -19,6 +20,25 @@ export class Timerange { ratePerMinute(rate: number) { return this.interval(`1m`).rate(rate); } + + poissonEvents(rate: number) { + return new PoissonEvents(this.from, this.to, rate); + } + + splitInto(segmentCount: number): Timerange[] { + const duration = this.to.getTime() - this.from.getTime(); + const segmentDuration = duration / segmentCount; + + return Array.from({ length: segmentCount }, (_, i) => { + const from = new Date(this.from.getTime() + i * segmentDuration); + const to = new Date(from.getTime() + segmentDuration); + return new Timerange(from, to); + }); + } + + toString() { + return `Timerange(from=${this.from.toISOString()}, to=${this.to.toISOString()})`; + } } type DateLike = Date | number | Moment | string; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts new file mode 100644 index 0000000000000..2fdf52254540d --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { generateUnstructuredLogMessage } from './unstructured_logs'; + +test('generates unstructured logs', () => { + const messages = Array(10) + .fill('') + .map(() => generateUnstructuredLogMessage()()); + + console.log(messages); +}); diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts new file mode 100644 index 0000000000000..2f128d1352472 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts @@ -0,0 +1,85 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { Faker, faker } from '@faker-js/faker'; + +export type LogMessageGenerator = (f: Faker) => string[]; + +/** + * Ensures the type safety of the log message generators. + */ +const ensureGeneratorType = >(generators: T): T => { + return generators; +}; + +export const unstructuredLogMessageGenerators = ensureGeneratorType({ + httpAccess: (f: Faker) => [ + `${f.internet.ip()} - - [${f.date + .past() + .toISOString() + .replace('T', ' ') + .replace( + /\..+/, + '' + )}] "${f.internet.httpMethod()} ${f.internet.url()} HTTP/1.1" ${f.helpers.arrayElement([ + 200, 301, 404, 500, + ])} ${f.number.int({ min: 100, max: 5000 })}`, + ], + dbOperation: (f: Faker) => [ + `${f.database.engine()}: ${f.database.column()} ${f.helpers.arrayElement([ + 'created', + 'updated', + 'deleted', + 'inserted', + ])} successfully ${f.number.int({ max: 100000 })} times`, + ], + taskStatusSuccess: (f: Faker) => [ + `${f.hacker.noun()}: ${f.word.words()} ${f.helpers.arrayElement([ + 'triggered', + 'executed', + 'processed', + 'handled', + ])} successfully at ${f.date.recent().toISOString()}`, + ], + taskStatusFailure: (f: Faker) => [ + `${f.hacker.noun()}: ${f.helpers.arrayElement([ + 'triggering', + 'execution', + 'processing', + 'handling', + ])} of ${f.word.words()} failed at ${f.date.recent().toISOString()}`, + ], + error: (f: Faker) => [ + `${f.helpers.arrayElement([ + 'Error', + 'Exception', + 'Failure', + 'Crash', + 'Bug', + 'Issue', + ])}: ${f.hacker.phrase()}`, + `Stopping ${f.number.int(42)} background tasks...`, + 'Shutting down process...', + ], + restart: (f: Faker) => { + const service = f.database.engine(); + return [ + `Restarting ${service}...`, + `Waiting for queue to drain...`, + `Service ${service} restarted ${f.helpers.arrayElement([ + 'successfully', + 'with errors', + 'with warnings', + ])}`, + ]; + }, +}); + +export const generateUnstructuredLogMessage = + (generators: LogMessageGenerator[] = Object.values(unstructuredLogMessageGenerators)) => + (f: Faker = faker) => + f.helpers.arrayElement(generators)(f); diff --git a/packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts new file mode 100644 index 0000000000000..89374e0f9a9cf --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts @@ -0,0 +1,162 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { infra, LogDocument, log } from '@kbn/apm-synthtrace-client'; +import { fakerEN as faker } from '@faker-js/faker'; +import { z } from 'zod'; +import { Scenario } from '../cli/scenario'; +import { withClient } from '../lib/utils/with_client'; +import { + generateUnstructuredLogMessage, + unstructuredLogMessageGenerators, +} from './helpers/unstructured_logs'; + +const scenarioOptsSchema = z.object({ + randomSeed: z.number().default(0), + distribution: z.enum(['uniform', 'poisson']).default('uniform'), + rate: z.number().default(1), + messageGroup: z + .enum(['healthyOperations', 'degradedOperations', 'errorOperations']) + .default('healthyOperations'), +}); + +const scenario: Scenario = async (runOptions) => { + return { + generate: ({ range, clients: { logsEsClient } }) => { + const { logger } = runOptions; + const scenarioOpts = scenarioOptsSchema.parse(runOptions.scenarioOpts ?? {}); + + faker.seed(scenarioOpts.randomSeed); + faker.setDefaultRefDate(range.from.toISOString()); + + logger.debug( + `Generating ${scenarioOpts.distribution} logs with a rate of ${scenarioOpts.rate}...` + ); + + // Logs Data logic + const LOG_LEVELS = ['info', 'debug', 'error', 'warn', 'trace', 'fatal']; + + const clusterDefinions = [ + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-1', + 'orchestrator.namespace': 'default', + 'cloud.provider': 'gcp', + 'cloud.region': 'eu-central-1', + 'cloud.availability_zone': 'eu-central-1a', + 'cloud.project.id': faker.string.nanoid(), + }, + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-2', + 'orchestrator.namespace': 'production', + 'cloud.provider': 'aws', + 'cloud.region': 'us-east-1', + 'cloud.availability_zone': 'us-east-1a', + 'cloud.project.id': faker.string.nanoid(), + }, + { + 'orchestrator.cluster.id': faker.string.nanoid(), + 'orchestrator.cluster.name': 'synth-cluster-3', + 'orchestrator.namespace': 'kube', + 'cloud.provider': 'azure', + 'cloud.region': 'area-51', + 'cloud.availability_zone': 'area-51a', + 'cloud.project.id': faker.string.nanoid(), + }, + ]; + + const hostEntities = [ + { + 'host.name': 'host-1', + 'agent.id': 'synth-agent-1', + 'agent.name': 'nodejs', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[0], + }, + { + 'host.name': 'host-2', + 'agent.id': 'synth-agent-2', + 'agent.name': 'custom', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[1], + }, + { + 'host.name': 'host-3', + 'agent.id': 'synth-agent-3', + 'agent.name': 'python', + 'cloud.instance.id': faker.string.nanoid(), + 'orchestrator.resource.id': faker.string.nanoid(), + ...clusterDefinions[2], + }, + ].map((hostDefinition) => + infra.minimalHost(hostDefinition['host.name']).overrides(hostDefinition) + ); + + const serviceNames = Array(3) + .fill(null) + .map((_, idx) => `synth-service-${idx}`); + + const generatorFactory = + scenarioOpts.distribution === 'uniform' + ? range.interval('1s').rate(scenarioOpts.rate) + : range.poissonEvents(scenarioOpts.rate); + + const logs = generatorFactory.generator((timestamp) => { + const entity = faker.helpers.arrayElement(hostEntities); + const serviceName = faker.helpers.arrayElement(serviceNames); + const level = faker.helpers.arrayElement(LOG_LEVELS); + const messages = logMessageGenerators[scenarioOpts.messageGroup](faker); + + return messages.map((message) => + log + .createMinimal() + .message(message) + .logLevel(level) + .service(serviceName) + .overrides({ + ...entity.fields, + labels: { + scenario: 'rare', + population: scenarioOpts.distribution, + }, + }) + .timestamp(timestamp) + ); + }); + + return [ + withClient( + logsEsClient, + logger.perf('generating_logs', () => [logs]) + ), + ]; + }, + }; +}; + +export default scenario; + +const healthyLogMessageGenerators = [ + unstructuredLogMessageGenerators.dbOperation, + unstructuredLogMessageGenerators.taskStatusSuccess, +]; + +const degradedLogMessageGenerators = [unstructuredLogMessageGenerators.taskStatusFailure]; + +const errorLogMessageGenerators = [ + unstructuredLogMessageGenerators.error, + unstructuredLogMessageGenerators.restart, +]; + +const logMessageGenerators = { + healthyOperations: generateUnstructuredLogMessage(healthyLogMessageGenerators), + degradedOperations: generateUnstructuredLogMessage(degradedLogMessageGenerators), + errorOperations: generateUnstructuredLogMessage(errorLogMessageGenerators), +}; From 0a4316992842d3d4ad3eab895eb3c6ea7b8d3068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 21 Aug 2024 15:15:39 +0000 Subject: [PATCH 02/74] Add empty logs_overview package --- .github/CODEOWNERS | 1 + package.json | 1 + tsconfig.base.json | 2 ++ .../observability/logs_overview/README.md | 3 +++ .../observability/logs_overview/index.ts | 10 ++++++++++ .../logs_overview/jest.config.js | 12 ++++++++++++ .../observability/logs_overview/kibana.jsonc | 5 +++++ .../observability/logs_overview/package.json | 7 +++++++ .../observability/logs_overview/tsconfig.json | 19 +++++++++++++++++++ yarn.lock | 4 ++++ 10 files changed, 64 insertions(+) create mode 100644 x-pack/packages/observability/logs_overview/README.md create mode 100644 x-pack/packages/observability/logs_overview/index.ts create mode 100644 x-pack/packages/observability/logs_overview/jest.config.js create mode 100644 x-pack/packages/observability/logs_overview/kibana.jsonc create mode 100644 x-pack/packages/observability/logs_overview/package.json create mode 100644 x-pack/packages/observability/logs_overview/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c3cab77ee6951..3f05369289d40 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -630,6 +630,7 @@ x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team x-pack/plugins/observability_solution/observability_logs_explorer @elastic/obs-ux-logs-team +x-pack/packages/observability/logs_overview @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/observability_onboarding/e2e @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability_onboarding @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team diff --git a/package.json b/package.json index 3a0c99e9940be..a0d84f47fe7e1 100644 --- a/package.json +++ b/package.json @@ -663,6 +663,7 @@ "@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability", "@kbn/observability-get-padded-alert-time-range-util": "link:x-pack/packages/observability/get_padded_alert_time_range_util", "@kbn/observability-logs-explorer-plugin": "link:x-pack/plugins/observability_solution/observability_logs_explorer", + "@kbn/observability-logs-overview": "link:x-pack/packages/observability/logs_overview", "@kbn/observability-onboarding-plugin": "link:x-pack/plugins/observability_solution/observability_onboarding", "@kbn/observability-plugin": "link:x-pack/plugins/observability_solution/observability", "@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared", diff --git a/tsconfig.base.json b/tsconfig.base.json index d063f6a880441..de3ac356b7145 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1254,6 +1254,8 @@ "@kbn/observability-get-padded-alert-time-range-util/*": ["x-pack/packages/observability/get_padded_alert_time_range_util/*"], "@kbn/observability-logs-explorer-plugin": ["x-pack/plugins/observability_solution/observability_logs_explorer"], "@kbn/observability-logs-explorer-plugin/*": ["x-pack/plugins/observability_solution/observability_logs_explorer/*"], + "@kbn/observability-logs-overview": ["x-pack/packages/observability/logs_overview"], + "@kbn/observability-logs-overview/*": ["x-pack/packages/observability/logs_overview/*"], "@kbn/observability-onboarding-e2e": ["x-pack/plugins/observability_solution/observability_onboarding/e2e"], "@kbn/observability-onboarding-e2e/*": ["x-pack/plugins/observability_solution/observability_onboarding/e2e/*"], "@kbn/observability-onboarding-plugin": ["x-pack/plugins/observability_solution/observability_onboarding"], diff --git a/x-pack/packages/observability/logs_overview/README.md b/x-pack/packages/observability/logs_overview/README.md new file mode 100644 index 0000000000000..20d3f0f02b7df --- /dev/null +++ b/x-pack/packages/observability/logs_overview/README.md @@ -0,0 +1,3 @@ +# @kbn/observability-logs-overview + +Empty package generated by @kbn/generate diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts new file mode 100644 index 0000000000000..7210d7181a9ed --- /dev/null +++ b/x-pack/packages/observability/logs_overview/index.ts @@ -0,0 +1,10 @@ +/* + * 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 function foo() { + return 'hello world'; +} diff --git a/x-pack/packages/observability/logs_overview/jest.config.js b/x-pack/packages/observability/logs_overview/jest.config.js new file mode 100644 index 0000000000000..2ee88ee990253 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/observability/logs_overview'], +}; diff --git a/x-pack/packages/observability/logs_overview/kibana.jsonc b/x-pack/packages/observability/logs_overview/kibana.jsonc new file mode 100644 index 0000000000000..90b3375086720 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/observability-logs-overview", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/x-pack/packages/observability/logs_overview/package.json b/x-pack/packages/observability/logs_overview/package.json new file mode 100644 index 0000000000000..77a529e7e59f7 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/observability-logs-overview", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json new file mode 100644 index 0000000000000..5c989599ec9ad --- /dev/null +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/yarn.lock b/yarn.lock index c5701f90e7584..9135da3b6f6fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5799,6 +5799,10 @@ version "0.0.0" uid "" +"@kbn/observability-logs-overview@link:x-pack/packages/observability/logs_overview": + version "0.0.0" + uid "" + "@kbn/observability-onboarding-e2e@link:x-pack/plugins/observability_solution/observability_onboarding/e2e": version "0.0.0" uid "" From d373e59e55df1bc2959b5ad017ae3356bbea979c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 15:57:53 +0000 Subject: [PATCH 03/74] Add gaussian distribution to the unstructured logs scenario --- .../src/lib/gaussian_events.ts | 73 +++++++++++++++ ..._events.test.ts => poisson_events.test.ts} | 2 +- .../{random_events.ts => poisson_events.ts} | 0 .../src/lib/timerange.ts | 7 +- ...gs.ts => distributed_unstructured_logs.ts} | 89 +++++++++++++------ .../scenarios/helpers/unstructured_logs.ts | 25 ++++-- 6 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts rename packages/kbn-apm-synthtrace-client/src/lib/{random_events.test.ts => poisson_events.test.ts} (97%) rename packages/kbn-apm-synthtrace-client/src/lib/{random_events.ts => poisson_events.ts} (100%) rename packages/kbn-apm-synthtrace/src/scenarios/{rare_logs.ts => distributed_unstructured_logs.ts} (66%) diff --git a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts new file mode 100644 index 0000000000000..c13ebbaafe368 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts @@ -0,0 +1,73 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { castArray } from 'lodash'; +import { SynthtraceGenerator } from '../types'; +import { Fields } from './entity'; +import { Serializable } from './serializable'; + +export class GaussianEvents { + constructor( + private readonly from: Date, + private readonly to: Date, + private readonly mean: Date, + private readonly width: number, + private readonly totalPoints: number + ) {} + + *generator( + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): SynthtraceGenerator { + if (this.totalPoints <= 0) { + return; + } + + const startTime = this.from.getTime(); + const endTime = this.to.getTime(); + const meanTime = this.mean.getTime(); + const densityInterval = 1 / (this.totalPoints - 1); + + for (let eventIndex = 0; eventIndex < this.totalPoints; eventIndex++) { + const quantile = eventIndex * densityInterval; + + const standardScore = Math.sqrt(2) * inverseError(2 * quantile - 1); + const timestamp = Math.round(meanTime + standardScore * this.width); + + if (timestamp >= startTime && timestamp <= endTime) { + yield* this.generateEvents(timestamp, eventIndex, map); + } + } + } + + private *generateEvents( + timestamp: number, + eventIndex: number, + map: ( + timestamp: number, + index: number + ) => Serializable | Array> + ): Generator> { + const events = castArray(map(timestamp, eventIndex)); + for (const event of events) { + yield event; + } + } +} + +function inverseError(x: number): number { + const a = 0.147; + const sign = x < 0 ? -1 : 1; + + const part1 = 2 / (Math.PI * a) + Math.log(1 - x * x) / 2; + const part2 = Math.log(1 - x * x) / a; + + return sign * Math.sqrt(Math.sqrt(part1 * part1 - part2) - part1); +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts similarity index 97% rename from packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts rename to packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts index 27e9e673300fc..580e89e2b2208 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/random_events.test.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PoissonEvents } from './random_events'; +import { PoissonEvents } from './poisson_events'; import { Serializable } from './serializable'; describe('poisson events', () => { diff --git a/packages/kbn-apm-synthtrace-client/src/lib/random_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts similarity index 100% rename from packages/kbn-apm-synthtrace-client/src/lib/random_events.ts rename to packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts diff --git a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts index 9e9e165ca5194..12a58362eb861 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/timerange.ts @@ -7,8 +7,9 @@ */ import datemath from '@kbn/datemath'; import type { Moment } from 'moment'; +import { GaussianEvents } from './gaussian_events'; import { Interval } from './interval'; -import { PoissonEvents } from './random_events'; +import { PoissonEvents } from './poisson_events'; export class Timerange { constructor(public readonly from: Date, public readonly to: Date) {} @@ -25,6 +26,10 @@ export class Timerange { return new PoissonEvents(this.from, this.to, rate); } + gaussianEvents(mean: Date, width: number, totalPoints: number) { + return new GaussianEvents(this.from, this.to, mean, width, totalPoints); + } + splitInto(segmentCount: number): Timerange[] { const duration = this.to.getTime() - this.from.getTime(); const segmentDuration = duration / segmentCount; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts similarity index 66% rename from packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts rename to packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts index 89374e0f9a9cf..00b6340e4257a 100644 --- a/packages/kbn-apm-synthtrace/src/scenarios/rare_logs.ts +++ b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts @@ -11,18 +11,50 @@ import { z } from 'zod'; import { Scenario } from '../cli/scenario'; import { withClient } from '../lib/utils/with_client'; import { + LogMessageGenerator, generateUnstructuredLogMessage, unstructuredLogMessageGenerators, } from './helpers/unstructured_logs'; -const scenarioOptsSchema = z.object({ - randomSeed: z.number().default(0), - distribution: z.enum(['uniform', 'poisson']).default('uniform'), - rate: z.number().default(1), - messageGroup: z - .enum(['healthyOperations', 'degradedOperations', 'errorOperations']) - .default('healthyOperations'), -}); +const scenarioOptsSchema = z.intersection( + z.object({ + randomSeed: z.number().default(0), + messageGroup: z + .enum([ + 'httpAccess', + 'userAuthentication', + 'networkEvent', + 'dbOperations', + 'taskOperations', + 'degradedOperations', + 'errorOperations', + ]) + .default('dbOperations'), + }), + z + .discriminatedUnion('distribution', [ + z.object({ + distribution: z.literal('uniform'), + rate: z.number().default(1), + }), + z.object({ + distribution: z.literal('poisson'), + rate: z.number().default(1), + }), + z.object({ + distribution: z.literal('gaussian'), + mean: z.coerce.date().describe('Time of the peak of the gaussian distribution'), + width: z.number().default(5000).describe('Width of the gaussian distribution in ms'), + totalPoints: z + .number() + .default(100) + .describe('Total number of points in the gaussian distribution'), + }), + ]) + .default({ distribution: 'uniform', rate: 1 }) +); + +type ScenarioOpts = z.output; const scenario: Scenario = async (runOptions) => { return { @@ -33,9 +65,7 @@ const scenario: Scenario = async (runOptions) => { faker.seed(scenarioOpts.randomSeed); faker.setDefaultRefDate(range.from.toISOString()); - logger.debug( - `Generating ${scenarioOpts.distribution} logs with a rate of ${scenarioOpts.rate}...` - ); + logger.debug(`Generating ${scenarioOpts.distribution} logs...`); // Logs Data logic const LOG_LEVELS = ['info', 'debug', 'error', 'warn', 'trace', 'fatal']; @@ -106,7 +136,9 @@ const scenario: Scenario = async (runOptions) => { const generatorFactory = scenarioOpts.distribution === 'uniform' ? range.interval('1s').rate(scenarioOpts.rate) - : range.poissonEvents(scenarioOpts.rate); + : scenarioOpts.distribution === 'poisson' + ? range.poissonEvents(scenarioOpts.rate) + : range.gaussianEvents(scenarioOpts.mean, scenarioOpts.width, scenarioOpts.totalPoints); const logs = generatorFactory.generator((timestamp) => { const entity = faker.helpers.arrayElement(hostEntities); @@ -143,20 +175,21 @@ const scenario: Scenario = async (runOptions) => { export default scenario; -const healthyLogMessageGenerators = [ - unstructuredLogMessageGenerators.dbOperation, - unstructuredLogMessageGenerators.taskStatusSuccess, -]; - -const degradedLogMessageGenerators = [unstructuredLogMessageGenerators.taskStatusFailure]; - -const errorLogMessageGenerators = [ - unstructuredLogMessageGenerators.error, - unstructuredLogMessageGenerators.restart, -]; - const logMessageGenerators = { - healthyOperations: generateUnstructuredLogMessage(healthyLogMessageGenerators), - degradedOperations: generateUnstructuredLogMessage(degradedLogMessageGenerators), - errorOperations: generateUnstructuredLogMessage(errorLogMessageGenerators), -}; + httpAccess: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.httpAccess]), + userAuthentication: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.userAuthentication, + ]), + networkEvent: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.networkEvent]), + dbOperations: generateUnstructuredLogMessage([unstructuredLogMessageGenerators.dbOperation]), + taskOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.taskStatusSuccess, + ]), + degradedOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.taskStatusFailure, + ]), + errorOperations: generateUnstructuredLogMessage([ + unstructuredLogMessageGenerators.error, + unstructuredLogMessageGenerators.restart, + ]), +} satisfies Record; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts index 2f128d1352472..0cfc88ac55a83 100644 --- a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts +++ b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts @@ -9,14 +9,7 @@ import { Faker, faker } from '@faker-js/faker'; export type LogMessageGenerator = (f: Faker) => string[]; -/** - * Ensures the type safety of the log message generators. - */ -const ensureGeneratorType = >(generators: T): T => { - return generators; -}; - -export const unstructuredLogMessageGenerators = ensureGeneratorType({ +export const unstructuredLogMessageGenerators = { httpAccess: (f: Faker) => [ `${f.internet.ip()} - - [${f.date .past() @@ -77,7 +70,21 @@ export const unstructuredLogMessageGenerators = ensureGeneratorType({ ])}`, ]; }, -}); + userAuthentication: (f: Faker) => [ + `User ${f.internet.userName()} ${f.helpers.arrayElement([ + 'logged in', + 'logged out', + 'failed to login', + ])}`, + ], + networkEvent: (f: Faker) => [ + `Network ${f.helpers.arrayElement([ + 'connection', + 'disconnection', + 'data transfer', + ])} ${f.helpers.arrayElement(['from', 'to'])} ${f.internet.ip()}`, + ], +} satisfies Record; export const generateUnstructuredLogMessage = (generators: LogMessageGenerator[] = Object.values(unstructuredLogMessageGenerators)) => From 278365e908ce5e2657804a0f6385f1e31b56cc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 15:59:28 +0000 Subject: [PATCH 04/74] Add support for xstate5 --- package.json | 4 ++++ packages/kbn-optimizer/src/worker/webpack.config.ts | 12 ++++++++++++ yarn.lock | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/package.json b/package.json index a0d84f47fe7e1..aba2ce9b10784 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "**/sharp": "0.32.6", "**/typescript": "5.1.6", "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", + "@xstate5/react/**/xstate": "^5.17.4", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -1006,6 +1007,7 @@ "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", + "@xstate5/react": "npm:@xstate/react@^4.1.1", "adm-zip": "^0.5.9", "ai": "^2.2.33", "ajv": "^8.12.0", @@ -1239,6 +1241,7 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", + "xstate5": "npm:xstate@^5.17.4", "xterm": "^5.1.0", "yauzl": "^2.10.0", "yazl": "^2.5.1", @@ -1260,6 +1263,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-env": "^7.24.7", diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index f81d0e89fb983..2e5fdbf3f7765 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -258,6 +258,18 @@ export function getWebpackConfig( }, }, }, + { + test: /node_modules\/@?xstate5\/.*\.js$/, + use: { + loader: 'babel-loader', + options: { + babelrc: false, + envName: worker.dist ? 'production' : 'development', + presets: [BABEL_PRESET], + plugins: ['@babel/plugin-transform-logical-assignment-operators'], + }, + }, + }, { test: /\.(html|md|txt|tmpl)$/, use: { diff --git a/yarn.lock b/yarn.lock index 9135da3b6f6fb..4448c71b0c522 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12000,6 +12000,14 @@ use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.0.0" +"@xstate5/react@npm:@xstate/react@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.1.tgz#2f580fc5f83d195f95b56df6cd8061c66660d9fa" + integrity sha512-pFp/Y+bnczfaZ0V8B4LOhx3d6Gd71YKAPbzerGqydC2nsYN/mp7RZu3q/w6/kvI2hwR/jeDeetM7xc3JFZH2NA== + dependencies: + use-isomorphic-layout-effect "^1.1.2" + use-sync-external-store "^1.2.0" + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -32750,6 +32758,11 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== +"xstate5@npm:xstate@^5.17.4", xstate@^5.17.4: + version "5.17.4" + resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.17.4.tgz#334ab2da123973634097f7ca48387ae1589c774e" + integrity sha512-KM2FYVOUJ04HlOO4TY3wEXqoYPR/XsDu+ewm+IWw0vilXqND0jVfvv04tEFwp8Mkk7I/oHXM8t1Ex9xJyUS4ZA== + xstate@^4.38.2: version "4.38.2" resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.2.tgz#1b74544fc9c8c6c713ba77f81c6017e65aa89804" From 1f4bd0f2b3c3f02225232c439f4481fc27e09f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:00:17 +0000 Subject: [PATCH 05/74] Add xstate5 console inspector --- packages/kbn-xstate-utils/kibana.jsonc | 2 +- .../kbn-xstate-utils/src/console_inspector.ts | 87 +++++++++++++++++++ packages/kbn-xstate-utils/src/index.ts | 1 + 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/kbn-xstate-utils/src/console_inspector.ts diff --git a/packages/kbn-xstate-utils/kibana.jsonc b/packages/kbn-xstate-utils/kibana.jsonc index cd1151a3f2103..1fb3507854b98 100644 --- a/packages/kbn-xstate-utils/kibana.jsonc +++ b/packages/kbn-xstate-utils/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-common", + "type": "shared-browser", "id": "@kbn/xstate-utils", "owner": "@elastic/obs-ux-logs-team" } diff --git a/packages/kbn-xstate-utils/src/console_inspector.ts b/packages/kbn-xstate-utils/src/console_inspector.ts new file mode 100644 index 0000000000000..b280fc90609c8 --- /dev/null +++ b/packages/kbn-xstate-utils/src/console_inspector.ts @@ -0,0 +1,87 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + ActorRefLike, + AnyActorRef, + InspectedActorEvent, + InspectedEventEvent, + InspectedSnapshotEvent, + InspectionEvent, +} from 'xstate5'; +import { isDevMode } from './dev_tools'; + +export const createConsoleInspector = () => { + if (!isDevMode()) { + return () => {}; + } + + // eslint-disable-next-line no-console + const log = console.info.bind(console); + + const logActorEvent = (actorEvent: InspectedActorEvent) => { + if (isActorRef(actorEvent.actorRef)) { + log( + '✨ %c%s%c is a new actor of type %c%s%c:', + ...styleAsActor(actorEvent.actorRef.id), + ...styleAsKeyword(actorEvent.type), + actorEvent.actorRef + ); + } else { + log('✨ New %c%s%c actor without id:', ...styleAsKeyword(actorEvent.type), actorEvent); + } + }; + + const logEventEvent = (eventEvent: InspectedEventEvent) => { + if (isActorRef(eventEvent.actorRef)) { + log( + '🔔 %c%s%c received event %c%s%c from %c%s%c:', + ...styleAsActor(eventEvent.actorRef.id), + ...styleAsKeyword(eventEvent.event.type), + ...styleAsKeyword(eventEvent.sourceRef?.id), + eventEvent + ); + } else { + log('🔔 Event', ...styleAsKeyword(eventEvent.event.type), ':', eventEvent); + } + }; + + const logSnapshotEvent = (snapshotEvent: InspectedSnapshotEvent) => { + if (isActorRef(snapshotEvent.actorRef)) { + log( + '📸 %c%s%c updated due to %c%s%c:', + ...styleAsActor(snapshotEvent.actorRef.id), + ...styleAsKeyword(snapshotEvent.event.type), + snapshotEvent.snapshot + ); + } else { + log('📸 Snapshot due to %c%s%c:', ...styleAsKeyword(snapshotEvent.event.type), snapshotEvent); + } + }; + + return (inspectionEvent: InspectionEvent) => { + if (inspectionEvent.type === '@xstate.actor') { + logActorEvent(inspectionEvent); + } else if (inspectionEvent.type === '@xstate.event') { + logEventEvent(inspectionEvent); + } else if (inspectionEvent.type === '@xstate.snapshot') { + logSnapshotEvent(inspectionEvent); + } else { + log(`❓ Received inspection event:`, inspectionEvent); + } + }; +}; + +const isActorRef = (actorRefLike: ActorRefLike): actorRefLike is AnyActorRef => + 'id' in actorRefLike; + +const keywordStyle = 'font-weight: bold'; +const styleAsKeyword = (value: any) => [keywordStyle, value, ''] as const; + +const actorStyle = 'font-weight: bold; text-decoration: underline'; +const styleAsActor = (value: any) => [actorStyle, value, ''] as const; diff --git a/packages/kbn-xstate-utils/src/index.ts b/packages/kbn-xstate-utils/src/index.ts index 02cd8a2b176b1..dd8027759df9d 100644 --- a/packages/kbn-xstate-utils/src/index.ts +++ b/packages/kbn-xstate-utils/src/index.ts @@ -8,5 +8,6 @@ export * from './actions'; export * from './dev_tools'; +export * from './console_inspector'; export * from './notification_channel'; export * from './types'; From 76ea2a5b0eeec3f814c40d8ad6fa020168915311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:01:53 +0000 Subject: [PATCH 06/74] Add cateogorization service --- .../observability/logs_overview/index.ts | 4 +- .../categorize_documents.ts | 275 ++++++++++++++++++ .../categorize_logs_service.ts | 165 +++++++++++ .../count_documents.ts | 49 ++++ .../services/categorize_logs_service/index.ts | 8 + .../categorize_logs_service/queries.ts | 127 ++++++++ .../services/categorize_logs_service/types.ts | 19 ++ .../observability/logs_overview/src/types.ts | 74 +++++ .../observability/logs_overview/tsconfig.json | 7 +- .../logs_overview/utils/xstate5_utils.ts | 13 + 10 files changed, 736 insertions(+), 5 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts create mode 100644 x-pack/packages/observability/logs_overview/src/types.ts create mode 100644 x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts index 7210d7181a9ed..b65160ca19875 100644 --- a/x-pack/packages/observability/logs_overview/index.ts +++ b/x-pack/packages/observability/logs_overview/index.ts @@ -5,6 +5,4 @@ * 2.0. */ -export function foo() { - return 'hello world'; -} +export { LogCategories } from './src/components/log_categories'; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts new file mode 100644 index 0000000000000..0d440621d7241 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -0,0 +1,275 @@ +/* + * 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 { ISearchGeneric } from '@kbn/search-types'; +import { lastValueFrom } from 'rxjs'; +import { fromPromise } from 'xstate5'; +import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; +import { z } from '@kbn/zod'; +import { LogsCategorizationParams } from './types'; +import { createCategorizationRequestParams } from './queries'; +import { LogCategory, LogCategoryChange } from '../../types'; + +// the fraction of a category's histogram below which the category is considered rare +const rarityThreshold = 0.2; + +export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => + fromPromise< + { + categories: LogCategory[]; + }, + LogsCategorizationParams & { + samplingProbability: number; + ignoredQueries?: string[]; + minDocsPerCategory?: number; + } + >( + async ({ + input: { + index, + end, + start, + timeField, + messageField, + samplingProbability, + ignoredQueries, + minDocsPerCategory, + }, + signal, + }) => { + const randomSampler = createRandomSamplerWrapper({ + probability: samplingProbability, + seed: 1, + }); + + const requestParams = createCategorizationRequestParams({ + index, + timeField, + messageField, + start, + end, + randomSampler, + ignoredQueries, + minDocsPerCategory, + }); + + const { rawResponse } = await lastValueFrom(search({ params: requestParams })); + + if (rawResponse.aggregations == null) { + throw new Error('No aggregations found in large categories response'); + } + + const logCategoriesAggResult = randomSampler.unwrap(rawResponse.aggregations); + + if (!('categories' in logCategoriesAggResult)) { + throw new Error('No categorization aggregation found in large categories response'); + } + + const logCategories = + (logCategoriesAggResult.categories.buckets as unknown[]).map(mapCategoryBucket) ?? []; + + return { + categories: logCategories, + }; + } + ); + +const mapCategoryBucket = (bucket: any): LogCategory => + esCategoryBucketSchema + .transform((parsedBucket) => ({ + change: mapChangePoint(parsedBucket), + documentCount: parsedBucket.doc_count, + histogram: parsedBucket.histogram, + terms: parsedBucket.key, + })) + .parse(bucket); + +const mapChangePoint = ({ change, histogram }: EsCategoryBucket): LogCategoryChange => { + switch (change.type) { + case 'stationary': + if (isRareInHistogram(histogram)) { + return { + type: 'rare', + timestamp: findFirstNonZeroBucket(histogram)?.timestamp ?? histogram[0].timestamp, + }; + } else { + return { + type: 'none', + }; + } + case 'dip': + case 'spike': + return { + type: change.type, + timestamp: change.bucket.key, + }; + case 'step_change': + return { + type: 'step', + timestamp: change.bucket.key, + }; + case 'distribution_change': + return { + type: 'distribution', + timestamp: change.bucket.key, + }; + case 'trend_change': + return { + type: 'trend', + timestamp: change.bucket.key, + correlationCoefficient: change.details.r_value, + }; + case 'unknown': + return { + type: 'unknown', + rawChange: change.rawChange, + }; + case 'non_stationary': + default: + return { + type: 'other', + }; + } +}; + +/** + * The official types are lacking the change_point aggregation + */ +const esChangePointBucketSchema = z.object({ + key: z.string().datetime(), + doc_count: z.number(), +}); + +const esChangePointDetailsSchema = z.object({ + p_value: z.number(), +}); + +const esChangePointCorrelationSchema = esChangePointDetailsSchema.extend({ + r_value: z.number(), +}); + +const esChangePointSchema = z.union([ + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + dip: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { dip: details } }) => ({ + type: 'dip' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + spike: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { spike: details } }) => ({ + type: 'spike' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + step_change: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { step_change: details } }) => ({ + type: 'step_change' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + trend_change: esChangePointCorrelationSchema, + }), + }) + .transform(({ bucket, type: { trend_change: details } }) => ({ + type: 'trend_change' as const, + bucket, + details, + })), + z + .object({ + bucket: esChangePointBucketSchema, + type: z.object({ + distribution_change: esChangePointDetailsSchema, + }), + }) + .transform(({ bucket, type: { distribution_change: details } }) => ({ + type: 'distribution_change' as const, + bucket, + details, + })), + z + .object({ + type: z.object({ + non_stationary: esChangePointCorrelationSchema.extend({ + trend: z.enum(['increasing', 'decreasing']), + }), + }), + }) + .transform(({ type: { non_stationary: details } }) => ({ + type: 'non_stationary' as const, + details, + })), + z + .object({ + type: z.object({ + stationary: z.object({}), + }), + }) + .transform(() => ({ type: 'stationary' as const })), + z + .object({ + type: z.object({}), + }) + .transform((value) => ({ type: 'unknown' as const, rawChange: JSON.stringify(value) })), +]); + +const esHistogramSchema = z + .object({ + buckets: z.array( + z + .object({ + key_as_string: z.string(), + doc_count: z.number(), + }) + .transform((bucket) => ({ + timestamp: bucket.key_as_string, + documentCount: bucket.doc_count, + })) + ), + }) + .transform(({ buckets }) => buckets); + +type EsHistogram = z.output; + +const esCategoryBucketSchema = z.object({ + key: z.string(), + doc_count: z.number(), + change: esChangePointSchema, + histogram: esHistogramSchema, +}); + +type EsCategoryBucket = z.output; + +// TODO: implement rarity criteria +const isRareInHistogram = (histogram: EsHistogram): boolean => + histogram.filter((bucket) => bucket.documentCount > 0).length < + histogram.length * rarityThreshold; + +const findFirstNonZeroBucket = (histogram: EsHistogram) => + histogram.find((bucket) => bucket.documentCount > 0); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts new file mode 100644 index 0000000000000..8c10efa6c6567 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -0,0 +1,165 @@ +/* + * 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 { MachineImplementationsFrom, assign, setup } from 'xstate5'; +import { getPlaceholderFor } from '../../../utils/xstate5_utils'; +import { categorizeDocuments } from './categorize_documents'; +import { countDocuments } from './count_documents'; +import { CategorizeLogsServiceDependencies, LogsCategorizationParams } from './types'; +import { LogCategory } from '../../types'; + +export const categorizeLogsService = setup({ + types: { + input: {} as LogsCategorizationParams, + output: {} as { + categories: LogCategory[]; + documentCount: number; + samplingProbability: number; + }, + context: {} as { + categories: LogCategory[]; + documentCount: number; + parameters: LogsCategorizationParams; + samplingProbability: number; + error?: Error; + }, + }, + actors: { + countDocuments: getPlaceholderFor(countDocuments), + categorizeDocuments: getPlaceholderFor(categorizeDocuments), + }, + actions: { + storeError: assign((_, params: { error: Error }) => ({ + error: params.error, + })), + storeCategories: assign(({ context }, params: { categories: LogCategory[] }) => ({ + categories: [...context.categories, ...params.categories], + })), + storeDocumentCount: assign( + (_, params: { documentCount: number; samplingProbability: number }) => ({ + documentCount: params.documentCount, + samplingProbability: params.samplingProbability, + }) + ), + }, + guards: { + requiresSampling: ({ context }) => context.samplingProbability < 1, + }, +}).createMachine({ + /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QAmABw-KACw+AQDMAOwAbGEAnGFmPgA0IACe3gFmlD7RIV4AjPlm6SFmXtEAvmVJclh4RKTkVDQMTCzsnDx8gsKiBjLUGDWK9SpN6q1aHbr69JJyxvTWJrk2SCAOTi70bp4Ivv5BoZExcYkpiD65lACsZrchUV5mEeFmIRVVAwp1yo1qLZrtHQCMC4XB4Sh2AA2GAAZnguP15LUlA1VM0NG1tHxprMjKZLNY3OtnPNtt4-IFguEorF4klUghQldKDSwmF7hEsmEvFc3pUQNUviiVDCwOhkAALDQAZVQXChkAAwp9anAuiIxDNpLIVUNZfLIUrdfg4ITVsTNmSELkzFdmWZsmzObkrukAld6d4vCFApEIrkwj5OT57gH3gLjcKqKLxVKWPqFRBlUiCGqQWDcBDoeg4bgEYLkWAE4ak8bTZYiY4Sa5VjsbXbKA7wpELq7Ch6zggQrkIoFShFSiVCo8IuGC0MfpQY5KNAAlMBcVDMDTJwYmgRCDW9HUpurzxfLlirr7llb2KuW2uIAMBXtNiLPHxXYIXLyehA+LyUEI-l62kK0vcY6RsM0ZijOLD7ku9ArmWwKguCUKwvCiJrsQUGHlAx6qrAZrnhspJXtaYS3o22QPiET4vrkb6dgGzK+BEvLejc9xBhU-L0NgEBwG447fA0lYETWoA7AAtBE74ScBu5RmiYwAliuhCdWWxEQEtEMjalzaREGncl4jwOj4MloaBU7gXGUDFkau68eaF6EaJiBMdEZHNmY7LekE76GW5-qxFRpQaQOfIfLJ5nTlZGEwUecEqZeznWiENzueyP4BIG3YBO+FKZQ+uQpUG0RRClplCpFS4lglTkeN4tqXF4TFXC6eQxNEtq+R1LIxAOHWZSVkTlYWk6bmANUiXVuwNZQTV2q1AbRB1HZaSUmQOtEvKUb40TpLkHFlEAA */ + id: 'categorizeLogs', + context: ({ input }) => ({ + categories: [], + documentCount: 0, + parameters: input, + samplingProbability: 0, + }), + initial: 'countingDocuments', + states: { + countingDocuments: { + invoke: { + src: 'countDocuments', + input: ({ context }) => context.parameters, + onDone: [ + { + target: 'fetchingSampledCategories', + guard: 'requiresSampling', + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, + { + target: 'fetchingRemainingCategories', + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, + ], + onError: { + target: 'failed', + actions: [], + }, + }, + }, + + fetchingSampledCategories: { + invoke: { + src: 'categorizeDocuments', + id: 'categorizeSampledCategories', + input: ({ context }) => ({ + ...context.parameters, + samplingProbability: context.samplingProbability, + ignoredQueries: [], + minDocsPerCategory: 10, + }), + onDone: { + target: 'fetchingRemainingCategories', + actions: [ + { + type: 'storeCategories', + params: ({ event }) => event.output, + }, + ], + }, + onError: 'failed', + }, + }, + + fetchingRemainingCategories: { + invoke: { + src: 'categorizeDocuments', + id: 'categorizeRemainingCategories', + input: ({ context }) => ({ + ...context.parameters, + samplingProbability: context.samplingProbability, + ignoredQueries: context.categories.map((category) => category.terms), + minDocsPerCategory: 0, + }), + onDone: { + target: 'done', + actions: [ + { + type: 'storeCategories', + params: ({ event }) => event.output, + }, + ], + }, + onError: 'failed', + }, + }, + + failed: { + type: 'final', + }, + + done: { + type: 'final', + }, + }, + output: ({ context }) => ({ + categories: context.categories, + documentCount: context.documentCount, + samplingProbability: context.samplingProbability, + }), +}); + +export const createCategorizeLogsServiceImplementations = ({ + search, +}: CategorizeLogsServiceDependencies): MachineImplementationsFrom< + typeof categorizeLogsService +> => ({ + actors: { + categorizeDocuments: categorizeDocuments({ search }), + countDocuments: countDocuments({ search }), + }, +}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts new file mode 100644 index 0000000000000..e231745b8c88d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts @@ -0,0 +1,49 @@ +/* + * 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 { getSampleProbability } from '@kbn/ml-random-sampler-utils'; +import { ISearchGeneric } from '@kbn/search-types'; +import { lastValueFrom } from 'rxjs'; +import { fromPromise } from 'xstate5'; +import { LogsCategorizationParams } from './types'; +import { createCategorizationQuery } from './queries'; + +export const countDocuments = ({ search }: { search: ISearchGeneric }) => + fromPromise< + { + documentCount: number; + samplingProbability: number; + }, + LogsCategorizationParams + >(async ({ input: { index, end, start, timeField, messageField }, signal }) => { + const { rawResponse: totalHitsResponse } = await lastValueFrom( + search( + { + params: { + index, + size: 0, + track_total_hits: true, + query: createCategorizationQuery(messageField, timeField, start, end), + }, + }, + { abortSignal: signal } + ) + ); + + const documentCount = + totalHitsResponse.hits.total == null + ? 0 + : typeof totalHitsResponse.hits.total === 'number' + ? totalHitsResponse.hits.total + : totalHitsResponse.hits.total.value; + const samplingProbability = getSampleProbability(documentCount); + + return { + documentCount, + samplingProbability, + }; + }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts new file mode 100644 index 0000000000000..149359b7d2015 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './categorize_logs_service'; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts new file mode 100644 index 0000000000000..b026133fd11bb --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -0,0 +1,127 @@ +/* + * 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { calculateAuto } from '@kbn/calculate-auto'; +import { RandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; +import moment from 'moment'; + +const isoTimestampFormat = "YYYY-MM-DD'T'HH:mm:ss.SSS'Z'"; + +export const createCategorizationQuery = ( + messageField: string, + timeField: string, + start: string, + end: string, + ignoredQueries: string[] = [] +): QueryDslQueryContainer => { + return { + bool: { + filter: [ + { + exists: { + field: messageField, + }, + }, + { + range: { + [timeField]: { + gte: start, + lte: end, + format: 'strict_date_time', + }, + }, + }, + ], + must_not: ignoredQueries.map((ignoredQuery) => ({ + match: { + [messageField]: { + query: ignoredQuery, + operator: 'AND' as const, + fuzziness: 0, + auto_generate_synonyms_phrase_query: false, + }, + }, + })), + }, + }; +}; + +export const createCategorizationRequestParams = ({ + index, + timeField, + messageField, + start, + end, + randomSampler, + minDocsPerCategory = 0, + ignoredQueries = [], +}: { + start: string; + end: string; + index: string; + timeField: string; + messageField: string; + randomSampler: RandomSamplerWrapper; + minDocsPerCategory?: number; + ignoredQueries?: string[]; +}) => { + const startMoment = moment(start, isoTimestampFormat); + const endMoment = moment(end, isoTimestampFormat); + const fixedIntervalDuration = calculateAuto.atLeast( + 24, + moment.duration(endMoment.diff(startMoment)) + ); + const fixedIntervalSize = `${fixedIntervalDuration?.asMinutes()}m`; + + return { + index, + size: 0, + track_total_hits: false, + query: createCategorizationQuery(messageField, timeField, start, end, ignoredQueries), + aggs: randomSampler.wrap({ + histogram: { + date_histogram: { + field: '@timestamp', + fixed_interval: fixedIntervalSize, + extended_bounds: { + min: start, + max: end, + }, + }, + }, + categories: { + categorize_text: { + field: messageField, + size: 10000, + categorization_analyzer: { + tokenizer: 'standard', + }, + ...(minDocsPerCategory > 0 ? { min_doc_count: minDocsPerCategory } : {}), + }, + aggs: { + histogram: { + date_histogram: { + field: timeField, + fixed_interval: fixedIntervalSize, + extended_bounds: { + min: start, + max: end, + }, + }, + }, + change: { + // @ts-expect-error the official types don't support the change_point aggregation + change_point: { + buckets_path: 'histogram>_count', + }, + }, + }, + }, + }), + }; +}; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts new file mode 100644 index 0000000000000..c812b1b5aac3e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts @@ -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 { ISearchGeneric } from '@kbn/search-types'; + +export interface CategorizeLogsServiceDependencies { + search: ISearchGeneric; +} + +export interface LogsCategorizationParams { + start: string; + end: string; + index: string; + timeField: string; + messageField: string; +} diff --git a/x-pack/packages/observability/logs_overview/src/types.ts b/x-pack/packages/observability/logs_overview/src/types.ts new file mode 100644 index 0000000000000..4c3d27eca7e7c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/types.ts @@ -0,0 +1,74 @@ +/* + * 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 interface LogCategory { + change: LogCategoryChange; + documentCount: number; + histogram: LogCategoryHistogramBucket[]; + terms: string; +} + +export type LogCategoryChange = + | LogCategoryNoChange + | LogCategoryRareChange + | LogCategorySpikeChange + | LogCategoryDipChange + | LogCategoryStepChange + | LogCategoryDistributionChange + | LogCategoryTrendChange + | LogCategoryOtherChange + | LogCategoryUnknownChange; + +export interface LogCategoryNoChange { + type: 'none'; +} + +export interface LogCategoryRareChange { + type: 'rare'; + timestamp: string; +} + +export interface LogCategorySpikeChange { + type: 'spike'; + timestamp: string; +} + +export interface LogCategoryDipChange { + type: 'dip'; + timestamp: string; +} + +export interface LogCategoryStepChange { + type: 'step'; + timestamp: string; +} + +export interface LogCategoryTrendChange { + type: 'trend'; + timestamp: string; + correlationCoefficient: number; +} + +export interface LogCategoryDistributionChange { + type: 'distribution'; + timestamp: string; +} + +export interface LogCategoryOtherChange { + type: 'other'; + timestamp?: string; +} + +export interface LogCategoryUnknownChange { + type: 'unknown'; + rawChange: string; +} + +export interface LogCategoryHistogramBucket { + documentCount: number; + timestamp: string; +} diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 5c989599ec9ad..476238cbafcc3 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -5,12 +5,15 @@ "types": [ "jest", "node", - "react" + "react", + "@kbn/ambient-ui-types", + "@kbn/ambient-storybook-types", + "@emotion/react/types/css-prop" ] }, "include": [ "**/*.ts", - "**/*.tsx", + "**/*.tsx", ], "exclude": [ "target/**/*" diff --git a/x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts b/x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts new file mode 100644 index 0000000000000..3df0bf4ea3988 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts @@ -0,0 +1,13 @@ +/* + * 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 getPlaceholderFor = any>( + implementationFactory: ImplementationFactory +): ReturnType => + (() => { + throw new Error('Not implemented'); + }) as ReturnType; From 0528e8bd05fbd61ebc518625faeddcf4ddeac67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:02:12 +0000 Subject: [PATCH 07/74] Add categories grid --- .../src/components/log_categories/index.ts | 8 + .../log_categories/log_categories.tsx | 61 +++++++ .../log_categories/log_categories_grid.tsx | 170 ++++++++++++++++++ .../log_categories_grid_cell.tsx | 97 ++++++++++ .../log_categories_grid_change_time_cell.tsx | 54 ++++++ .../log_categories_grid_change_type_cell.tsx | 108 +++++++++++ .../log_categories_grid_count_cell.tsx | 32 ++++ .../log_categories_grid_histogram_cell.tsx | 99 ++++++++++ .../log_categories_grid_pattern_cell.tsx | 61 +++++++ .../logs_categories_loading_content.tsx | 12 ++ .../logs_categories_result_content.tsx | 28 +++ .../components/app/service_logs/index.tsx | 110 +++++++----- 12 files changed, 797 insertions(+), 43 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts b/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts new file mode 100644 index 0000000000000..786475396237c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './log_categories'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx new file mode 100644 index 0000000000000..1de48f74f97a8 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -0,0 +1,61 @@ +/* + * 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 { ISearchGeneric } from '@kbn/search-types'; +import { createConsoleInspector } from '@kbn/xstate-utils'; +import { useMachine } from '@xstate5/react'; +import React from 'react'; +import { + categorizeLogsService, + createCategorizeLogsServiceImplementations, +} from '../../services/categorize_logs_service'; +import { LogCategoriesLoadingContent } from './logs_categories_loading_content'; +import { + LogCategoriesResultContent, + LogCategoriesResultContentDependencies, +} from './logs_categories_result_content'; + +interface LogCategoriesProps { + dependencies: LogCategoriesDependencies; +} + +export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & { + search: ISearchGeneric; +}; + +export const LogCategories: React.FC = ({ dependencies }) => { + const [categorizeLogsServiceState, _sendToCategorizeLogsService] = useMachine( + categorizeLogsService.provide( + createCategorizeLogsServiceImplementations({ search: dependencies.search }) + ), + { + inspect: consoleInspector, + input: { + index: 'logs-*-*', + start: '2024-12-01T00:00:00.000Z', + end: '2024-12-03T00:00:00.000Z', + timeField: '@timestamp', + messageField: 'message', + }, + } + ); + + if (categorizeLogsServiceState.matches('done')) { + return ( + + ); + } else if (categorizeLogsServiceState.matches('failed')) { + return
Error
; + } else { + return ; + } +}; + +const consoleInspector = createConsoleInspector(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx new file mode 100644 index 0000000000000..995706bf12663 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -0,0 +1,170 @@ +/* + * 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 { + EuiDataGrid, + EuiDataGridColumnSortingConfig, + EuiDataGridPaginationProps, +} from '@elastic/eui'; +import { createConsoleInspector } from '@kbn/xstate-utils'; +import { useMachine } from '@xstate5/react'; +import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { assign, setup } from 'xstate5'; +import _ from 'lodash'; +import { LogCategory } from '../../types'; +import { + LogCategoriesGridCellDependencies, + createCellContext, + logCategoriesGridColumns, + renderLogCategoriesGridCell, +} from './log_categories_grid_cell'; + +export interface LogCategoriesGridProps { + dependencies: LogCategoriesGridDependencies; + logCategories: LogCategory[]; +} + +export type LogCategoriesGridDependencies = LogCategoriesGridCellDependencies; + +export const LogCategoriesGrid: React.FC = ({ + dependencies, + logCategories, +}) => { + const [gridState, dispatchGridEvent] = useMachine(gridStateService, { + input: { + visibleColumns: logCategoriesGridColumns.map(({ id }) => id), + }, + inspect: consoleInspector, + }); + + // TODO: sort data based on sorting columns + const sortedLogCategories = useMemo(() => { + const sortingCriteria = gridState.context.sortingColumns.map( + ({ id, direction }): [(logCategory: LogCategory) => any, 'asc' | 'desc'] => { + switch (id) { + case 'count': + return [(logCategory: LogCategory) => logCategory.documentCount, direction]; + case 'type': + // TODO: use better sorting weight for change types + return [(logCategory: LogCategory) => logCategory.change.type, direction]; + case 'change': + return [ + (logCategory: LogCategory) => + 'timestamp' in logCategory.change ? logCategory.change.timestamp ?? '' : '', + direction, + ]; + default: + return [_.identity, direction]; + } + } + ); + return _.orderBy( + logCategories, + sortingCriteria.map(([accessor]) => accessor), + sortingCriteria.map(([, direction]) => direction) + ); + }, [gridState.context.sortingColumns, logCategories]); + + return ( + + dispatchGridEvent({ type: 'changeVisibleColumns', visibleColumns }), + }} + cellContext={createCellContext(sortedLogCategories, dependencies)} + pagination={{ + ...gridState.context.pagination, + onChangeItemsPerPage: (pageSize) => dispatchGridEvent({ type: 'changePageSize', pageSize }), + onChangePage: (pageIndex) => dispatchGridEvent({ type: 'changePageIndex', pageIndex }), + }} + renderCellValue={renderLogCategoriesGridCell} + rowCount={sortedLogCategories.length} + sorting={{ + columns: gridState.context.sortingColumns, + onSort: (sortingColumns) => + dispatchGridEvent({ type: 'changeSortingColumns', sortingColumns }), + }} + /> + ); +}; + +const gridStateService = setup({ + types: { + context: {} as { + visibleColumns: string[]; + pagination: Pick; + sortingColumns: EuiDataGridColumnSortingConfig[]; + }, + events: {} as + | { + type: 'changePageSize'; + pageSize: number; + } + | { + type: 'changePageIndex'; + pageIndex: number; + } + | { + type: 'changeSortingColumns'; + sortingColumns: EuiDataGridColumnSortingConfig[]; + } + | { + type: 'changeVisibleColumns'; + visibleColumns: string[]; + }, + input: {} as { + visibleColumns: string[]; + }, + }, +}).createMachine({ + id: 'logCategoriesGridState', + context: ({ input }) => ({ + visibleColumns: input.visibleColumns, + pagination: { pageIndex: 0, pageSize: 20, pageSizeOptions: [10, 20, 50] }, + sortingColumns: [{ id: 'change_time', direction: 'desc' }], + }), + on: { + changePageSize: { + actions: assign(({ context, event }) => ({ + pagination: { + ...context.pagination, + pageIndex: 0, + pageSize: event.pageSize, + }, + })), + }, + changePageIndex: { + actions: assign(({ context, event }) => ({ + pagination: { + ...context.pagination, + pageIndex: event.pageIndex, + }, + })), + }, + changeSortingColumns: { + actions: assign(({ event }) => ({ + sortingColumns: event.sortingColumns, + })), + }, + changeVisibleColumns: { + actions: assign(({ event }) => ({ + visibleColumns: event.visibleColumns, + })), + }, + }, +}); + +const consoleInspector = createConsoleInspector(); + +const logCategoriesGridLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.euiDataGrid.logCategoriesLabel', + { defaultMessage: 'Log categories' } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx new file mode 100644 index 0000000000000..9862b00270076 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx @@ -0,0 +1,97 @@ +/* + * 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 { EuiDataGridColumn, RenderCellValue } from '@elastic/eui'; +import React from 'react'; +import { LogCategory } from '../../types'; +import { + LogCategoriesGridChangeTimeCell, + LogCategoriesGridChangeTimeCellDependencies, + logCategoriesGridChangeTimeColumn, +} from './log_categories_grid_change_time_cell'; +import { + LogCategoriesGridChangeTypeCell, + logCategoriesGridChangeTypeColumn, +} from './log_categories_grid_change_type_cell'; +import { + LogCategoriesGridCountCell, + logCategoriesGridCountColumn, +} from './log_categories_grid_count_cell'; +import { + LogCategoriesGridHistogramCell, + LogCategoriesGridHistogramCellDependencies, + logCategoriesGridHistoryColumn, +} from './log_categories_grid_histogram_cell'; +import { + LogCategoriesGridPatternCell, + logCategoriesGridPatternColumn, +} from './log_categories_grid_pattern_cell'; + +export interface LogCategoriesGridCellContext { + dependencies: LogCategoriesGridCellDependencies; + logCategories: LogCategory[]; +} + +export type LogCategoriesGridCellDependencies = LogCategoriesGridHistogramCellDependencies & + LogCategoriesGridChangeTimeCellDependencies; + +export const renderLogCategoriesGridCell: RenderCellValue = ({ + rowIndex, + columnId, + isExpanded, + ...rest +}) => { + const { dependencies, logCategories } = getCellContext(rest); + + const logCategory = logCategories[rowIndex]; + + switch (columnId as LogCategoriesGridColumnId) { + case 'pattern': + return ; + case 'count': + return ; + case 'history': + return ( + + ); + case 'change_type': + return ; + case 'change_time': + return ( + + ); + default: + return <>-; + } +}; + +export const logCategoriesGridColumns = [ + logCategoriesGridPatternColumn, + logCategoriesGridCountColumn, + logCategoriesGridChangeTypeColumn, + logCategoriesGridChangeTimeColumn, + logCategoriesGridHistoryColumn, +] satisfies EuiDataGridColumn[]; + +type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number]['id']; + +const cellContextKey = 'cellContext'; + +const getCellContext = (cellContext: object): LogCategoriesGridCellContext => + (cellContextKey in cellContext + ? cellContext[cellContextKey] + : {}) as LogCategoriesGridCellContext; + +export const createCellContext = ( + logCategories: LogCategory[], + dependencies: LogCategoriesGridCellDependencies +): { [cellContextKey]: LogCategoriesGridCellContext } => ({ + [cellContextKey]: { + dependencies, + logCategories, + }, +}); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx new file mode 100644 index 0000000000000..cd24e870f431b --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx @@ -0,0 +1,54 @@ +/* + * 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 { EuiDataGridColumn } from '@elastic/eui'; +import { SettingsStart } from '@kbn/core-ui-settings-browser'; +import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import React, { useMemo } from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridChangeTimeColumn = { + id: 'change_time' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTimeColumnLabel', + { + defaultMessage: 'Change at', + } + ), + isSortable: true, + initialWidth: 200, + schema: 'datetime', +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridChangeTimeCellProps { + dependencies: LogCategoriesGridChangeTimeCellDependencies; + logCategory: LogCategory; +} + +export interface LogCategoriesGridChangeTimeCellDependencies { + uiSettings: SettingsStart; +} + +export const LogCategoriesGridChangeTimeCell: React.FC = ({ + dependencies, + logCategory, +}) => { + const dateFormat = useMemo( + () => dependencies.uiSettings.client.get('dateFormat'), + [dependencies.uiSettings.client] + ); + if (!('timestamp' in logCategory.change && logCategory.change.timestamp != null)) { + return null; + } + + if (dateFormat) { + return <>{moment(logCategory.change.timestamp).format(dateFormat)}; + } else { + return <>{logCategory.change.timestamp}; + } +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx new file mode 100644 index 0000000000000..a692983617069 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx @@ -0,0 +1,108 @@ +/* + * 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 { EuiBadge, EuiDataGridColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridChangeTypeColumn = { + id: 'change_type' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.changeTypeColumnLabel', + { + defaultMessage: 'Change type', + } + ), + isSortable: true, + initialWidth: 130, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridChangeTypeCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridChangeTypeCell: React.FC = ({ + logCategory, +}) => { + switch (logCategory.change.type) { + case 'dip': + return {dipBadgeLabel}; + case 'spike': + return {spikeBadgeLabel}; + case 'step': + return {stepBadgeLabel}; + case 'distribution': + return {distributionBadgeLabel}; + case 'rare': + return {rareBadgeLabel}; + case 'trend': + return {trendBadgeLabel}; + case 'other': + return {otherBadgeLabel}; + case 'none': + return <>-; + default: + return {unknownBadgeLabel}; + } +}; + +const dipBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.dipChangeTypeBadgeLabel', + { + defaultMessage: 'Dip', + } +); + +const spikeBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Spike', + } +); + +const stepBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Step', + } +); + +const distributionBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.distributionChangeTypeBadgeLabel', + { + defaultMessage: 'Distribution', + } +); + +const trendBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.spikeChangeTypeBadgeLabel', + { + defaultMessage: 'Trend', + } +); + +const otherBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.otherChangeTypeBadgeLabel', + { + defaultMessage: 'Other', + } +); + +const unknownBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.unknownChangeTypeBadgeLabel', + { + defaultMessage: 'Unknown', + } +); + +const rareBadgeLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.rareChangeTypeBadgeLabel', + { + defaultMessage: 'Rare', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx new file mode 100644 index 0000000000000..4b5d8e0179e07 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx @@ -0,0 +1,32 @@ +/* + * 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 { EuiDataGridColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedNumber } from '@kbn/i18n-react'; +import React from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridCountColumn = { + id: 'count' as const, + display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.countColumnLabel', { + defaultMessage: 'Events', + }), + isSortable: true, + schema: 'numeric', + initialWidth: 120, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridCountCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridCountCell: React.FC = ({ + logCategory, +}) => { + return ; +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx new file mode 100644 index 0000000000000..2fb50b0f2f3b4 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_histogram_cell.tsx @@ -0,0 +1,99 @@ +/* + * 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 { + BarSeries, + Chart, + LineAnnotation, + LineAnnotationStyle, + PartialTheme, + Settings, + Tooltip, + TooltipType, +} from '@elastic/charts'; +import { EuiDataGridColumn } from '@elastic/eui'; +import { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { RecursivePartial } from '@kbn/utility-types'; +import React from 'react'; +import { LogCategory, LogCategoryHistogramBucket } from '../../types'; + +export const logCategoriesGridHistoryColumn = { + id: 'history' as const, + display: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.histogramColumnLabel', + { + defaultMessage: 'Timeline', + } + ), + isSortable: false, + initialWidth: 250, + isExpandable: false, +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridHistogramCellProps { + dependencies: LogCategoriesGridHistogramCellDependencies; + logCategory: LogCategory; +} + +export interface LogCategoriesGridHistogramCellDependencies { + charts: ChartsPluginStart; +} + +export const LogCategoriesGridHistogramCell: React.FC = ({ + dependencies: { charts }, + logCategory, +}) => { + const baseTheme = charts.theme.useChartsBaseTheme(); + const sparklineTheme = charts.theme.useSparklineOverrides(); + + return ( + + + + + {'timestamp' in logCategory.change && logCategory.change.timestamp != null ? ( + + ) : null} + + ); +}; + +const localThemeOverrides: PartialTheme = { + scales: { + histogramPadding: 0.1, + }, + background: { + color: 'transparent', + }, +}; + +const annotationStyle: RecursivePartial = { + line: { + strokeWidth: 2, + }, +}; + +const timestampAccessor = (histogram: LogCategoryHistogramBucket) => + new Date(histogram.timestamp).getTime(); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx new file mode 100644 index 0000000000000..ae5471ef0868e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -0,0 +1,61 @@ +/* + * 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 { EuiDataGridColumn, euiFontSize, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { LogCategory } from '../../types'; + +export const logCategoriesGridPatternColumn = { + id: 'pattern' as const, + display: i18n.translate('xpack.observabilityLogsOverview.logCategoriesGrid.patternColumnLabel', { + defaultMessage: 'Pattern', + }), + isSortable: false, + schema: 'string', +} satisfies EuiDataGridColumn; + +export interface LogCategoriesGridPatternCellProps { + logCategory: LogCategory; +} + +export const LogCategoriesGridPatternCell: React.FC = ({ + logCategory, +}) => { + const theme = useEuiTheme(); + const { euiTheme } = theme; + const termsList = useMemo(() => logCategory.terms.split(' '), [logCategory.terms]); + + const commonStyle = css` + display: inline-block; + font-family: ${euiTheme.font.familyCode}; + font-weight: ${euiTheme.font.weight.semiBold}; + ${euiFontSize(theme, 'xs')}; + margin-right: ${euiTheme.size.xs}; + `; + + const termStyle = css` + ${commonStyle}; + `; + + const separatorStyle = css` + ${commonStyle}; + color: ${euiTheme.colors.subduedText}; + `; + + return ( +
+      {termsList.map((term, index) => (
+        
+          
{term}
+ {index !== termsList.length - 1 &&
*
} +
+ ))} +
+ ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx new file mode 100644 index 0000000000000..3cf5240b7bb3c --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx @@ -0,0 +1,12 @@ +/* + * 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 React from 'react'; + +export const LogCategoriesLoadingContent: React.FC = () => { + return
Loading...
; +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx new file mode 100644 index 0000000000000..ab82051b9f635 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx @@ -0,0 +1,28 @@ +/* + * 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 React from 'react'; +import { LogCategory } from '../../types'; +import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; + +export interface LogCategoriesResultContentProps { + dependencies: LogCategoriesResultContentDependencies; + logCategories: LogCategory[]; +} + +export type LogCategoriesResultContentDependencies = LogCategoriesGridDependencies; + +export const LogCategoriesResultContent: React.FC = ({ + dependencies, + logCategories, +}) => { + return ( +
+ +
+ ); +}; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 90f31e29b5960..16cd84babf227 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -5,57 +5,81 @@ * 2.0. */ -import React from 'react'; -import moment from 'moment'; -import { LogStream } from '@kbn/logs-shared-plugin/public'; +import React, { useMemo } from 'react'; +import { LogCategories } from '@kbn/observability-logs-overview'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import { useFetcher } from '../../../hooks/use_fetcher'; -import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; -import { APIReturnType } from '../../../services/rest/create_call_apm_api'; - import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; -import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; -import { useTimeRange } from '../../../hooks/use_time_range'; +// import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { useKibana } from '../../../context/kibana_context/use_kibana'; +// import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; +// import { useFetcher } from '../../../hooks/use_fetcher'; +// import { useTimeRange } from '../../../hooks/use_time_range'; +import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { - const { serviceName } = useApmServiceContext(); - const { - query: { environment, kuery, rangeFrom, rangeTo }, - } = useAnyOfApmParams('/services/{serviceName}/logs', '/logs-services/{serviceName}/logs'); - - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - - const { data } = useFetcher( - (callApmApi) => { - if (start && end) { - return callApmApi('GET /internal/apm/services/{serviceName}/infrastructure_attributes', { - params: { - path: { serviceName }, - query: { - environment, - kuery, - start, - end, - }, - }, - }); - } + services: { + charts, + data: { + search: { search }, + }, + settings: uiSettings, }, - [environment, kuery, serviceName, start, end] - ); + } = useKibana(); + // const { serviceName } = useApmServiceContext(); - return ( - + const logCategoriesDependencies = useMemo( + () => ({ + charts, + search, + uiSettings, + }), + [charts, search, uiSettings] ); + + // TODO: make charts required + if (typeof logCategoriesDependencies.charts === 'undefined') { + return null; + } + + // const { + // query: { environment, kuery, rangeFrom, rangeTo }, + // } = useAnyOfApmParams('/services/{serviceName}/logs', '/logs-services/{serviceName}/logs'); + + // const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + // const { data } = useFetcher( + // (callApmApi) => { + // if (start && end) { + // return callApmApi('GET /internal/apm/services/{serviceName}/infrastructure_attributes', { + // params: { + // path: { serviceName }, + // query: { + // environment, + // kuery, + // start, + // end, + // }, + // }, + // }); + // } + // }, + // [environment, kuery, serviceName, start, end] + // ); + + return ; + + // return ( + // + // ); } export function getInfrastructureKQLFilter({ From 0b7fc2ccb624009159ac2477e0a84cf2d7f790c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:02:30 +0000 Subject: [PATCH 08/74] Enable translation linting for the package --- .eslintrc.js | 1 + x-pack/.i18nrc.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 2b8c6c819bb3e..ba337d7e52161 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -953,6 +953,7 @@ module.exports = { files: [ 'x-pack/plugins/observability_solution/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', 'src/plugins/ai_assistant_management/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/packages/observability/logs_overview/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', ], rules: { '@kbn/i18n/strings_should_be_translated_with_i18n': 'warn', diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 7ff0f3e3ef766..f502bfa00b922 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -89,6 +89,9 @@ "xpack.observabilityLogsExplorer": "plugins/observability_solution/observability_logs_explorer", "xpack.observability_onboarding": "plugins/observability_solution/observability_onboarding", "xpack.observabilityShared": "plugins/observability_solution/observability_shared", + "xpack.observabilityLogsOverview": [ + "packages/observability/logs_overview/src/components" + ], "xpack.osquery": ["plugins/osquery"], "xpack.painlessLab": "plugins/painless_lab", "xpack.profiling": ["plugins/observability_solution/profiling"], From b428bd45ed095e66c185f37a9f4a00382e71eb5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:22:29 +0000 Subject: [PATCH 09/74] Improve typing of the sorting config --- .../log_categories/log_categories_grid.tsx | 25 ++++++++++++++----- .../log_categories_grid_cell.tsx | 4 ++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx index 995706bf12663..36a5cd95c1ba8 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -10,16 +10,18 @@ import { EuiDataGridColumnSortingConfig, EuiDataGridPaginationProps, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { createConsoleInspector } from '@kbn/xstate-utils'; import { useMachine } from '@xstate5/react'; +import _ from 'lodash'; import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; import { assign, setup } from 'xstate5'; -import _ from 'lodash'; import { LogCategory } from '../../types'; import { LogCategoriesGridCellDependencies, + LogCategoriesGridColumnId, createCellContext, + logCategoriesGridColumnIds, logCategoriesGridColumns, renderLogCategoriesGridCell, } from './log_categories_grid_cell'; @@ -49,10 +51,10 @@ export const LogCategoriesGrid: React.FC = ({ switch (id) { case 'count': return [(logCategory: LogCategory) => logCategory.documentCount, direction]; - case 'type': + case 'change_type': // TODO: use better sorting weight for change types return [(logCategory: LogCategory) => logCategory.change.type, direction]; - case 'change': + case 'change_time': return [ (logCategory: LogCategory) => 'timestamp' in logCategory.change ? logCategory.change.timestamp ?? '' : '', @@ -101,7 +103,7 @@ const gridStateService = setup({ context: {} as { visibleColumns: string[]; pagination: Pick; - sortingColumns: EuiDataGridColumnSortingConfig[]; + sortingColumns: LogCategoriesGridSortingConfig[]; }, events: {} as | { @@ -151,7 +153,10 @@ const gridStateService = setup({ }, changeSortingColumns: { actions: assign(({ event }) => ({ - sortingColumns: event.sortingColumns, + sortingColumns: event.sortingColumns.filter( + (sortingConfig): sortingConfig is LogCategoriesGridSortingConfig => + (logCategoriesGridColumnIds as string[]).includes(sortingConfig.id) + ), })), }, changeVisibleColumns: { @@ -168,3 +173,11 @@ const logCategoriesGridLabel = i18n.translate( 'xpack.observabilityLogsOverview.logCategoriesGrid.euiDataGrid.logCategoriesLabel', { defaultMessage: 'Log categories' } ); + +interface TypedEuiDataGridColumnSortingConfig + extends EuiDataGridColumnSortingConfig { + id: ColumnId; +} + +type LogCategoriesGridSortingConfig = + TypedEuiDataGridColumnSortingConfig; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx index 9862b00270076..d6ab4969eaf7b 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx @@ -77,7 +77,9 @@ export const logCategoriesGridColumns = [ logCategoriesGridHistoryColumn, ] satisfies EuiDataGridColumn[]; -type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number]['id']; +export const logCategoriesGridColumnIds = logCategoriesGridColumns.map(({ id }) => id); + +export type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number]['id']; const cellContextKey = 'cellContext'; From 5be73af5003a937690556aa6bd59cd356d0cf9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 16:25:53 +0000 Subject: [PATCH 10/74] Improve default column widths --- .../log_categories/log_categories_grid_change_time_cell.tsx | 2 +- .../log_categories/log_categories_grid_change_type_cell.tsx | 2 +- .../log_categories/log_categories_grid_count_cell.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx index cd24e870f431b..5ad8cbdd49346 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_time_cell.tsx @@ -21,7 +21,7 @@ export const logCategoriesGridChangeTimeColumn = { } ), isSortable: true, - initialWidth: 200, + initialWidth: 220, schema: 'datetime', } satisfies EuiDataGridColumn; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx index a692983617069..af6349bd0e18c 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_change_type_cell.tsx @@ -19,7 +19,7 @@ export const logCategoriesGridChangeTypeColumn = { } ), isSortable: true, - initialWidth: 130, + initialWidth: 110, } satisfies EuiDataGridColumn; export interface LogCategoriesGridChangeTypeCellProps { diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx index 4b5d8e0179e07..f2247aab5212e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_count_cell.tsx @@ -18,7 +18,7 @@ export const logCategoriesGridCountColumn = { }), isSortable: true, schema: 'numeric', - initialWidth: 120, + initialWidth: 100, } satisfies EuiDataGridColumn; export interface LogCategoriesGridCountCellProps { From e0af1bb2d6a3c7b7133af3a9cd243df5747d07d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 2 Sep 2024 19:09:00 +0000 Subject: [PATCH 11/74] Add loading screen with cancellation --- .../log_categories/log_categories.tsx | 28 ++++++-- .../log_categories/log_categories_grid.tsx | 1 - .../logs_categories_loading_content.tsx | 59 ++++++++++++++- .../categorize_logs_service.ts | 72 +++++++++++++++++-- 4 files changed, 147 insertions(+), 13 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 1de48f74f97a8..7256dda0115ad 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -8,7 +8,8 @@ import { ISearchGeneric } from '@kbn/search-types'; import { createConsoleInspector } from '@kbn/xstate-utils'; import { useMachine } from '@xstate5/react'; -import React from 'react'; +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; import { categorizeLogsService, createCategorizeLogsServiceImplementations, @@ -28,7 +29,7 @@ export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & }; export const LogCategories: React.FC = ({ dependencies }) => { - const [categorizeLogsServiceState, _sendToCategorizeLogsService] = useMachine( + const [categorizeLogsServiceState, sendToCategorizeLogsService] = useMachine( categorizeLogsService.provide( createCategorizeLogsServiceImplementations({ search: dependencies.search }) ), @@ -44,6 +45,12 @@ export const LogCategories: React.FC = ({ dependencies }) => } ); + const cancelOperation = useCallback(() => { + sendToCategorizeLogsService({ + type: 'cancel', + }); + }, [sendToCategorizeLogsService]); + if (categorizeLogsServiceState.matches('done')) { return ( = ({ dependencies }) => /> ); } else if (categorizeLogsServiceState.matches('failed')) { - return
Error
; + return ( +
+ {i18n.translate('xpack.observabilityLogsOverview.logCategories.div.errorLabel', { + defaultMessage: 'Error', + })} +
+ ); + } else if (categorizeLogsServiceState.matches('countingDocuments')) { + return ; + } else if ( + categorizeLogsServiceState.matches('fetchingSampledCategories') || + categorizeLogsServiceState.matches('fetchingRemainingCategories') + ) { + return ; } else { - return ; + return null; } }; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx index 36a5cd95c1ba8..d9e960685de99 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -44,7 +44,6 @@ export const LogCategoriesGrid: React.FC = ({ inspect: consoleInspector, }); - // TODO: sort data based on sorting columns const sortedLogCategories = useMemo(() => { const sortingCriteria = gridState.context.sortingColumns.map( ({ id, direction }): [(logCategory: LogCategory) => any, 'asc' | 'desc'] => { diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx index 3cf5240b7bb3c..3e8ac31eaddfc 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx @@ -5,8 +5,63 @@ * 2.0. */ +import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; +import { i18n } from '@kbn/i18n'; -export const LogCategoriesLoadingContent: React.FC = () => { - return
Loading...
; +export interface LogCategoriesLoadingContentProps { + onCancel?: () => void; + stage: 'counting' | 'categorizing'; +} + +export const LogCategoriesLoadingContent: React.FC = ({ + onCancel, + stage, +}) => { + return ( + } + title={ +

+ {stage === 'counting' + ? logCategoriesLoadingStateCountingTitle + : logCategoriesLoadingStateCategorizingTitle} +

+ } + actions={ + onCancel != null + ? [ + { + onCancel(); + }} + > + {logCategoriesLoadingStateCancelButtonLabel} + , + ] + : [] + } + /> + ); }; + +const logCategoriesLoadingStateCountingTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCountingTitle', + { + defaultMessage: 'Estimating log volume', + } +); + +const logCategoriesLoadingStateCategorizingTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStageCategorizingTitle', + { + defaultMessage: 'Categorizing logs', + } +); + +const logCategoriesLoadingStateCancelButtonLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.loadingStateCancelButtonLabel', + { + defaultMessage: 'Cancel', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index 8c10efa6c6567..0189a51942572 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -27,14 +27,17 @@ export const categorizeLogsService = setup({ samplingProbability: number; error?: Error; }, + events: {} as { + type: 'cancel'; + }, }, actors: { countDocuments: getPlaceholderFor(countDocuments), categorizeDocuments: getPlaceholderFor(categorizeDocuments), }, actions: { - storeError: assign((_, params: { error: Error }) => ({ - error: params.error, + storeError: assign((_, params: { error: unknown }) => ({ + error: params.error instanceof Error ? params.error : new Error(String(params.error)), })), storeCategories: assign(({ context }, params: { categories: LogCategory[] }) => ({ categories: [...context.categories, ...params.categories], @@ -50,7 +53,7 @@ export const categorizeLogsService = setup({ requiresSampling: ({ context }) => context.samplingProbability < 1, }, }).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QAmABw-KACw+AQDMAOwAbGEAnGFmPgA0IACe3gFmlD7RIV4AjPlm6SFmXtEAvmVJclh4RKTkVDQMTCzsnDx8gsKiBjLUGDWK9SpN6q1aHbr69JJyxvTWJrk2SCAOTi70bp4Ivv5BoZExcYkpiD65lACsZrchUV5mEeFmIRVVAwp1yo1qLZrtHQCMC4XB4Sh2AA2GAAZnguP15LUlA1VM0NG1tHxprMjKZLNY3OtnPNtt4-IFguEorF4klUghQldKDSwmF7hEsmEvFc3pUQNUviiVDCwOhkAALDQAZVQXChkAAwp9anAuiIxDNpLIVUNZfLIUrdfg4ITVsTNmSELkzFdmWZsmzObkrukAld6d4vCFApEIrkwj5OT57gH3gLjcKqKLxVKWPqFRBlUiCGqQWDcBDoeg4bgEYLkWAE4ak8bTZYiY4Sa5VjsbXbKA7wpELq7Ch6zggQrkIoFShFSiVCo8IuGC0MfpQY5KNAAlMBcVDMDTJwYmgRCDW9HUpurzxfLlirr7llb2KuW2uIAMBXtNiLPHxXYIXLyehA+LyUEI-l62kK0vcY6RsM0ZijOLD7ku9ArmWwKguCUKwvCiJrsQUGHlAx6qrAZrnhspJXtaYS3o22QPiET4vrkb6dgGzK+BEvLejc9xBhU-L0NgEBwG447fA0lYETWoA7AAtBE74ScBu5RmiYwAliuhCdWWxEQEtEMjalzaREGncl4jwOj4MloaBU7gXGUDFkau68eaF6EaJiBMdEZHNmY7LekE76GW5-qxFRpQaQOfIfLJ5nTlZGEwUecEqZeznWiENzueyP4BIG3YBO+FKZQ+uQpUG0RRClplCpFS4lglTkeN4tqXF4TFXC6eQxNEtq+R1LIxAOHWZSVkTlYWk6bmANUiXVuwNZQTV2q1AbRB1HZaSUmQOtEvKUb40TpLkHFlEAA */ + /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QAmAJwAOSgAWP0CAZgA2M0CzAEZwgFYYgHYkgBoQAE9EJK8vIPCYsy8k+K94pJ8YmIBfavS5LDwiUnIqGgYmFnZOHj5BYVEDGWoMRsUWlXb1Lq1e3X16STljemsTGJskEAcnF3o3TwRfAOCwyOi4xJT0rKPQmMpQxPifJNCkyLK-cNr60YVmso2mpOpoejoBGBcLg8JQ7AAbDAAMzwXBG8iaSlaqg6Gm62j4CyWRlMlmsbh2zhWB28-iCIQiUViCWSaUyiD8D3iZh5MS8kSiXhilV+IAaAKxkxBeNmEP4aHoyDA8PJW0pexpRzpp0ZFxZ13ZCHipUofhewQqKXCXkCovFmImVCRYHQyAAFhoAMqoLgIyAAYX+TTg-REYkW0lkQfG3t98ID0fwcFV9kcVNcW0OhRKlDMPneZktPjKBtu4R84UejNCXh5SUCQqSdsTkqdLvdXp9foggYxBBDUJhuDhiPQKNwaPtMa78Z7ieTlgpaY1mcQ2fiufzSULr2L5TZtySfh8lC8x9rgXigXCoT8T2bfcB2Odro9LFj3d7YyTAgVSpVi5qsu1Krgg66bgWRYlgeHJ+HkNpeO825mqEl5eA+36tpQL4diwABKYBcKgzAaF+AIhkIYZDFGj7EARREkSwZHBrAKbbMBGagFmVoQeECShO8No1jc3iIUEHwvH43w+D4RT1hhEqOth7ZvlA9HEfQpHzpC0KwgiyKouimFgOpjFQMx-asYBqa7CBXFrjxeYRPxglhF4IkIIEfKPHBZo+NeISRDUdRii2Sk4appmaUx2nyqgirKmx6p2R4DkfLxLk5G5Hn3JWDavEkMTRFJ4SBGVtQhfQ2AQHAbhTk+FBLrZnGpQgAC04QeW1G4yb1fX9aECkOkCOLTGCBK6E16b7KBDYeYUG7vAkZplXmHzFEN4wjRFnZxgmj61UBzUzfZCB8SeTk5DEJXHJ1hqFQ813rcU8QoQJm0NW2r4aFFWkHfAR3TZqMQFhBJQNreDY2h5iEBDWnLHtahRFRtIX1VhSLEbOU0rqdQqxKeCTXgkiR+EUHlnJQRWJNEr104W8QfVhlFgDjKWHPjDz8lefHGtd5OGkJlA+PENbvJekR3vcFXVEAA */ id: 'categorizeLogs', context: ({ input }) => ({ categories: [], @@ -87,7 +90,24 @@ export const categorizeLogsService = setup({ ], onError: { target: 'failed', - actions: [], + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Counting cancelled') }), + }, + ], }, }, }, @@ -111,7 +131,27 @@ export const categorizeLogsService = setup({ }, ], }, - onError: 'failed', + onError: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Categorization cancelled') }), + }, + ], + }, }, }, @@ -134,7 +174,27 @@ export const categorizeLogsService = setup({ }, ], }, - onError: 'failed', + onError: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + + on: { + cancel: { + target: 'failed', + actions: [ + { + type: 'storeError', + params: () => ({ error: new Error('Categorization cancelled') }), + }, + ], + }, }, }, From 169df2322d0ef7701076f3269d18f3bf860488bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Sep 2024 13:15:57 +0000 Subject: [PATCH 12/74] Bump XState 5 version --- package.json | 4 ++-- yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b5434b113370a..401c3d01be909 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "**/sharp": "0.32.6", "**/typescript": "5.1.6", "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", - "@xstate5/react/**/xstate": "^5.17.4", + "@xstate5/react/**/xstate": "^5.18.0", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -1259,7 +1259,7 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", - "xstate5": "npm:xstate@^5.17.4", + "xstate5": "npm:xstate@^5.18.0", "xterm": "^5.1.0", "yauzl": "^2.10.0", "yazl": "^2.5.1", diff --git a/yarn.lock b/yarn.lock index 31c26e455c310..9370125107940 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32557,10 +32557,10 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== -"xstate5@npm:xstate@^5.17.4", xstate@^5.17.4: - version "5.17.4" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.17.4.tgz#334ab2da123973634097f7ca48387ae1589c774e" - integrity sha512-KM2FYVOUJ04HlOO4TY3wEXqoYPR/XsDu+ewm+IWw0vilXqND0jVfvv04tEFwp8Mkk7I/oHXM8t1Ex9xJyUS4ZA== +"xstate5@npm:xstate@^5.18.0", xstate@^5.18.0: + version "5.18.0" + resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.0.tgz#6f559301dc2e1e4db39642ac5591bb7eb005335b" + integrity sha512-MKlq/jhyFBYm6Z9+P0k9nhMrHYTTg1ZGmhMw8tVe67oDq9nIlEf2/u/bY5kvUvqu4LTCiVl67hnfd92RMLRyVg== xstate@^4.38.2: version "4.38.2" From 901bee3c4af1876891d85c2c9a3c688fb8284b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Sep 2024 17:31:41 +0000 Subject: [PATCH 13/74] Start cleaning up names and introducing the overview component --- .../log_categories/log_categories.tsx | 43 ++++++++++----- ...tsx => log_categories_loading_content.tsx} | 0 ....tsx => log_categories_result_content.tsx} | 0 .../src/components/logs_overview/index.ts | 8 +++ .../logs_overview/logs_overview.tsx | 20 +++++++ .../categorize_documents.ts | 8 +-- .../categorize_logs_service.ts | 6 +- .../count_documents.ts | 8 +-- .../services/categorize_logs_service/types.ts | 8 +-- .../logs_overview/utils/logs_source.ts | 55 +++++++++++++++++++ .../components/app/service_logs/index.tsx | 18 +++--- .../routing/service_detail/index.tsx | 2 +- 12 files changed, 139 insertions(+), 37 deletions(-) rename x-pack/packages/observability/logs_overview/src/components/log_categories/{logs_categories_loading_content.tsx => log_categories_loading_content.tsx} (100%) rename x-pack/packages/observability/logs_overview/src/components/log_categories/{logs_categories_result_content.tsx => log_categories_result_content.tsx} (100%) create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx create mode 100644 x-pack/packages/observability/logs_overview/utils/logs_source.ts diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 7256dda0115ad..573822acebf2e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -5,43 +5,60 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; import { ISearchGeneric } from '@kbn/search-types'; import { createConsoleInspector } from '@kbn/xstate-utils'; import { useMachine } from '@xstate5/react'; -import React, { useCallback } from 'react'; -import { i18n } from '@kbn/i18n'; +import React, { useCallback, useMemo } from 'react'; +import { LogsSourceConfiguration, normalizeLogsSource } from '../../../utils/logs_source'; import { categorizeLogsService, createCategorizeLogsServiceImplementations, } from '../../services/categorize_logs_service'; -import { LogCategoriesLoadingContent } from './logs_categories_loading_content'; +import { LogCategoriesLoadingContent } from './log_categories_loading_content'; import { LogCategoriesResultContent, LogCategoriesResultContentDependencies, -} from './logs_categories_result_content'; +} from './log_categories_result_content'; -interface LogCategoriesProps { +export interface LogCategoriesProps { dependencies: LogCategoriesDependencies; + logsSource: LogsSourceConfiguration; + // The time range could be made optional if we want to support an internal + // time range picker + timeRange: { + start: string; + end: string; + }; } export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & { search: ISearchGeneric; }; -export const LogCategories: React.FC = ({ dependencies }) => { +export const LogCategories: React.FC = ({ + dependencies, + logsSource, + timeRange, +}) => { + const categorizeLogsServiceInput = useMemo(() => { + const normalizedLogsSource = normalizeLogsSource(logsSource); + return { + index: normalizedLogsSource.indexName, + startTimestamp: timeRange.start, + endTimestamp: timeRange.end, + timeField: normalizedLogsSource.timestampField, + messageField: normalizedLogsSource.messageField, + }; + }, [logsSource, timeRange.end, timeRange.start]); + const [categorizeLogsServiceState, sendToCategorizeLogsService] = useMachine( categorizeLogsService.provide( createCategorizeLogsServiceImplementations({ search: dependencies.search }) ), { inspect: consoleInspector, - input: { - index: 'logs-*-*', - start: '2024-12-01T00:00:00.000Z', - end: '2024-12-03T00:00:00.000Z', - timeField: '@timestamp', - messageField: 'message', - }, + input: categorizeLogsServiceInput, } ); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx similarity index 100% rename from x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_loading_content.tsx rename to x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx similarity index 100% rename from x-pack/packages/observability/logs_overview/src/components/log_categories/logs_categories_result_content.tsx rename to x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts new file mode 100644 index 0000000000000..627cdc8447eea --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './logs_overview'; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx new file mode 100644 index 0000000000000..09f26a76587b7 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -0,0 +1,20 @@ +/* + * 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 React from 'react'; +import { LogCategories, LogCategoriesDependencies } from '../log_categories'; + +export interface LogsOverviewProps { + dependencies: LogsOverviewDependencies; +} + +export type LogsOverviewDependencies = LogCategoriesDependencies; + +export const LogsOverview: React.FC = ({ dependencies }) => { + // TODO: pass the right props + return ; +}; diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index 0d440621d7241..c95c874cd0132 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -10,7 +10,7 @@ import { lastValueFrom } from 'rxjs'; import { fromPromise } from 'xstate5'; import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; import { z } from '@kbn/zod'; -import { LogsCategorizationParams } from './types'; +import { LogCategorizationParams } from './types'; import { createCategorizationRequestParams } from './queries'; import { LogCategory, LogCategoryChange } from '../../types'; @@ -22,7 +22,7 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => { categories: LogCategory[]; }, - LogsCategorizationParams & { + LogCategorizationParams & { samplingProbability: number; ignoredQueries?: string[]; minDocsPerCategory?: number; @@ -31,8 +31,8 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => async ({ input: { index, - end, - start, + endTimestamp, + startTimestamp, timeField, messageField, samplingProbability, diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index 0189a51942572..6c94215ce8b4d 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -9,12 +9,12 @@ import { MachineImplementationsFrom, assign, setup } from 'xstate5'; import { getPlaceholderFor } from '../../../utils/xstate5_utils'; import { categorizeDocuments } from './categorize_documents'; import { countDocuments } from './count_documents'; -import { CategorizeLogsServiceDependencies, LogsCategorizationParams } from './types'; +import { CategorizeLogsServiceDependencies, LogCategorizationParams } from './types'; import { LogCategory } from '../../types'; export const categorizeLogsService = setup({ types: { - input: {} as LogsCategorizationParams, + input: {} as LogCategorizationParams, output: {} as { categories: LogCategory[]; documentCount: number; @@ -23,7 +23,7 @@ export const categorizeLogsService = setup({ context: {} as { categories: LogCategory[]; documentCount: number; - parameters: LogsCategorizationParams; + parameters: LogCategorizationParams; samplingProbability: number; error?: Error; }, diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts index e231745b8c88d..241e1158c7349 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts @@ -9,7 +9,7 @@ import { getSampleProbability } from '@kbn/ml-random-sampler-utils'; import { ISearchGeneric } from '@kbn/search-types'; import { lastValueFrom } from 'rxjs'; import { fromPromise } from 'xstate5'; -import { LogsCategorizationParams } from './types'; +import { LogCategorizationParams } from './types'; import { createCategorizationQuery } from './queries'; export const countDocuments = ({ search }: { search: ISearchGeneric }) => @@ -18,8 +18,8 @@ export const countDocuments = ({ search }: { search: ISearchGeneric }) => documentCount: number; samplingProbability: number; }, - LogsCategorizationParams - >(async ({ input: { index, end, start, timeField, messageField }, signal }) => { + LogCategorizationParams + >(async ({ input: { index, endTimestamp, startTimestamp, timeField, messageField }, signal }) => { const { rawResponse: totalHitsResponse } = await lastValueFrom( search( { @@ -27,7 +27,7 @@ export const countDocuments = ({ search }: { search: ISearchGeneric }) => index, size: 0, track_total_hits: true, - query: createCategorizationQuery(messageField, timeField, start, end), + query: createCategorizationQuery(messageField, timeField, startTimestamp, endTimestamp), }, }, { abortSignal: signal } diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts index c812b1b5aac3e..a1e4a72fbfd56 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts @@ -10,10 +10,10 @@ export interface CategorizeLogsServiceDependencies { search: ISearchGeneric; } -export interface LogsCategorizationParams { - start: string; - end: string; +export interface LogCategorizationParams { + endTimestamp: string; index: string; - timeField: string; messageField: string; + startTimestamp: string; + timeField: string; } diff --git a/x-pack/packages/observability/logs_overview/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/utils/logs_source.ts new file mode 100644 index 0000000000000..80cb097391e9a --- /dev/null +++ b/x-pack/packages/observability/logs_overview/utils/logs_source.ts @@ -0,0 +1,55 @@ +/* + * 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 { type AbstractDataView } from '@kbn/data-views-plugin/common'; + +export type LogsSourceConfiguration = + | AdvancedSettingLogsSourceConfiguration + | IndexNameLogsSourceConfiguration + | DataViewLogsSourceConfiguration; + +export interface AdvancedSettingLogsSourceConfiguration { + type: 'advanced_setting'; + timestampField?: string; + messageField?: string; +} + +export interface IndexNameLogsSourceConfiguration { + type: 'index_name'; + indexName: string; + timestampField: string; + messageField: string; +} + +export interface DataViewLogsSourceConfiguration { + type: 'data_view'; + dataView: AbstractDataView; + messageField?: string; +} + +export const normalizeLogsSource = ( + logsSource: LogsSourceConfiguration +): IndexNameLogsSourceConfiguration => { + switch (logsSource.type) { + case 'index_name': + return logsSource; + case 'advanced_setting': + return { + type: 'index_name', + indexName: '', // TODO: get index name from advanced settings + timestampField: logsSource.timestampField ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + case 'data_view': + return { + type: 'index_name', + indexName: logsSource.dataView.getIndexPattern(), + timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + } +}; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 16cd84babf227..5d4e7725409b6 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -9,11 +9,11 @@ import React, { useMemo } from 'react'; import { LogCategories } from '@kbn/observability-logs-overview'; 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'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { useKibana } from '../../../context/kibana_context/use_kibana'; -// import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; +import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; // import { useFetcher } from '../../../hooks/use_fetcher'; -// import { useTimeRange } from '../../../hooks/use_time_range'; +import { useTimeRange } from '../../../hooks/use_time_range'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { @@ -26,7 +26,11 @@ export function ServiceLogs() { settings: uiSettings, }, } = useKibana(); - // const { serviceName } = useApmServiceContext(); + const { serviceName } = useApmServiceContext(); + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useAnyOfApmParams('/services/{serviceName}/logs'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const logCategoriesDependencies = useMemo( () => ({ @@ -42,10 +46,6 @@ export function ServiceLogs() { return null; } - // const { - // query: { environment, kuery, rangeFrom, rangeTo }, - // } = useAnyOfApmParams('/services/{serviceName}/logs', '/logs-services/{serviceName}/logs'); - // const { start, end } = useTimeRange({ rangeFrom, rangeTo }); // const { data } = useFetcher( @@ -67,6 +67,8 @@ export function ServiceLogs() { // [environment, kuery, serviceName, start, end] // ); + // TODO: filter by service name and environment + // TODO: filter by time return ; // return ( diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx index 024af3bdd79a4..c431351f51398 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/service_detail/index.tsx @@ -308,7 +308,7 @@ export const serviceDetailRoute = { }), element: , searchBarOptions: { - showUnifiedSearchBar: false, + showQueryInput: false, }, }), '/services/{serviceName}/infrastructure': { From 1023d69a6db65f74ac8fbfffa91e5cd74d357fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 4 Sep 2024 17:48:03 +0000 Subject: [PATCH 14/74] Provide a self-contained overview via logs_shared --- .../observability/logs_overview/index.ts | 12 +++- .../log_categories/log_categories.tsx | 25 ++++---- .../log_categories_loading_content.tsx | 1 + .../logs_overview/logs_overview.tsx | 42 +++++++++++-- .../logs_overview_error_content.tsx | 27 +++++++++ .../logs_overview_loading_content.tsx | 23 +++++++ .../categorize_logs_service.ts | 2 +- .../logs_overview/src/utils/logs_source.ts | 60 +++++++++++++++++++ .../{ => src}/utils/xstate5_utils.ts | 0 .../observability/logs_overview/tsconfig.json | 15 ++++- .../logs_overview/utils/logs_source.ts | 55 ----------------- .../components/app/service_logs/index.tsx | 31 ++++------ .../apm/public/plugin.ts | 2 + .../logs_shared/kibana.jsonc | 6 +- .../public/components/logs_overview.tsx | 24 ++++++++ .../logs_shared/public/index.ts | 1 + .../logs_shared/public/plugin.ts | 20 ++++++- .../logs_shared/public/types.ts | 14 +++-- 18 files changed, 254 insertions(+), 106 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/utils/logs_source.ts rename x-pack/packages/observability/logs_overview/{ => src}/utils/xstate5_utils.ts (100%) delete mode 100644 x-pack/packages/observability/logs_overview/utils/logs_source.ts create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts index b65160ca19875..e937c4fbc3fea 100644 --- a/x-pack/packages/observability/logs_overview/index.ts +++ b/x-pack/packages/observability/logs_overview/index.ts @@ -5,4 +5,14 @@ * 2.0. */ -export { LogCategories } from './src/components/log_categories'; +export { + LogsOverview, + type LogsOverviewDependencies, + type LogsOverviewProps, +} from './src/components/logs_overview'; +export type { + DataViewLogsSourceConfiguration, + IndexNameLogsSourceConfiguration, + LogsSourceConfiguration, + SharedSettingLogsSourceConfiguration, +} from './src/utils/logs_source'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 573822acebf2e..fe5828d1a97f1 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -9,12 +9,12 @@ import { i18n } from '@kbn/i18n'; import { ISearchGeneric } from '@kbn/search-types'; import { createConsoleInspector } from '@kbn/xstate-utils'; import { useMachine } from '@xstate5/react'; -import React, { useCallback, useMemo } from 'react'; -import { LogsSourceConfiguration, normalizeLogsSource } from '../../../utils/logs_source'; +import React, { useCallback } from 'react'; import { categorizeLogsService, createCategorizeLogsServiceImplementations, } from '../../services/categorize_logs_service'; +import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { LogCategoriesLoadingContent } from './log_categories_loading_content'; import { LogCategoriesResultContent, @@ -23,7 +23,7 @@ import { export interface LogCategoriesProps { dependencies: LogCategoriesDependencies; - logsSource: LogsSourceConfiguration; + logsSource: IndexNameLogsSourceConfiguration; // The time range could be made optional if we want to support an internal // time range picker timeRange: { @@ -41,24 +41,19 @@ export const LogCategories: React.FC = ({ logsSource, timeRange, }) => { - const categorizeLogsServiceInput = useMemo(() => { - const normalizedLogsSource = normalizeLogsSource(logsSource); - return { - index: normalizedLogsSource.indexName, - startTimestamp: timeRange.start, - endTimestamp: timeRange.end, - timeField: normalizedLogsSource.timestampField, - messageField: normalizedLogsSource.messageField, - }; - }, [logsSource, timeRange.end, timeRange.start]); - const [categorizeLogsServiceState, sendToCategorizeLogsService] = useMachine( categorizeLogsService.provide( createCategorizeLogsServiceImplementations({ search: dependencies.search }) ), { inspect: consoleInspector, - input: categorizeLogsServiceInput, + input: { + index: logsSource.indexName, + startTimestamp: timeRange.start, + endTimestamp: timeRange.end, + timeField: logsSource.timestampField, + messageField: logsSource.messageField, + }, } ); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx index 3e8ac31eaddfc..0fde469fe717d 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_loading_content.tsx @@ -32,6 +32,7 @@ export const LogCategoriesLoadingContent: React.FC { onCancel(); }} diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx index 09f26a76587b7..721f40ff2fa45 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -5,16 +5,50 @@ * 2.0. */ +import { type LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import React from 'react'; +import useAsync from 'react-use/lib/useAsync'; +import { LogsSourceConfiguration, normalizeLogsSource } from '../../utils/logs_source'; import { LogCategories, LogCategoriesDependencies } from '../log_categories'; +import { LogsOverviewLoadingContent } from './logs_overview_loading_content'; export interface LogsOverviewProps { dependencies: LogsOverviewDependencies; + logsSource?: LogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; } -export type LogsOverviewDependencies = LogCategoriesDependencies; +export type LogsOverviewDependencies = LogCategoriesDependencies & { + logsDataAccess: LogsDataAccessPluginStart; +}; + +export const LogsOverview: React.FC = ({ + dependencies, + logsSource = { type: 'shared_setting' }, + timeRange, +}) => { + const normalizedLogsSource = useAsync( + () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), + [dependencies.logsDataAccess, logsSource] + ); + + if (normalizedLogsSource.loading) { + return ; + } + + if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { + // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n + return <>Error; + } -export const LogsOverview: React.FC = ({ dependencies }) => { - // TODO: pass the right props - return ; + return ( + + ); }; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx new file mode 100644 index 0000000000000..2f76384d66962 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx @@ -0,0 +1,27 @@ +/* + * 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 { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export interface LogsOverviewErrorContentProps { + error: Error; +} + +export const LogsOverviewErrorContent: React.FC = ({}) => { + return ( + } + title={

{logsOverviewErrorTitle}

} + /> + ); +}; + +const logsOverviewErrorTitle = i18n.translate('xpack.observabilityLogsOverview.errorTitle', { + defaultMessage: 'Error', +}); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx new file mode 100644 index 0000000000000..7645fdb90f0ac --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_loading_content.tsx @@ -0,0 +1,23 @@ +/* + * 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 { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export const LogsOverviewLoadingContent: React.FC = ({}) => { + return ( + } + title={

{logsOverviewLoadingTitle}

} + /> + ); +}; + +const logsOverviewLoadingTitle = i18n.translate('xpack.observabilityLogsOverview.loadingTitle', { + defaultMessage: 'Loading', +}); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index 6c94215ce8b4d..eb3f3b4e551f4 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -6,7 +6,7 @@ */ import { MachineImplementationsFrom, assign, setup } from 'xstate5'; -import { getPlaceholderFor } from '../../../utils/xstate5_utils'; +import { getPlaceholderFor } from '../../utils/xstate5_utils'; import { categorizeDocuments } from './categorize_documents'; import { countDocuments } from './count_documents'; import { CategorizeLogsServiceDependencies, LogCategorizationParams } from './types'; diff --git a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts new file mode 100644 index 0000000000000..0c8767c8702d4 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts @@ -0,0 +1,60 @@ +/* + * 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 { type AbstractDataView } from '@kbn/data-views-plugin/common'; +import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; + +export type LogsSourceConfiguration = + | SharedSettingLogsSourceConfiguration + | IndexNameLogsSourceConfiguration + | DataViewLogsSourceConfiguration; + +export interface SharedSettingLogsSourceConfiguration { + type: 'shared_setting'; + timestampField?: string; + messageField?: string; +} + +export interface IndexNameLogsSourceConfiguration { + type: 'index_name'; + indexName: string; + timestampField: string; + messageField: string; +} + +export interface DataViewLogsSourceConfiguration { + type: 'data_view'; + dataView: AbstractDataView; + messageField?: string; +} + +export const normalizeLogsSource = + ({ logsDataAccess }: { logsDataAccess: LogsDataAccessPluginStart }) => + async (logsSource: LogsSourceConfiguration): Promise => { + switch (logsSource.type) { + case 'index_name': + return logsSource; + case 'shared_setting': + const logSourcesFromSharedSettings = + await logsDataAccess.services.logSourcesService.getLogSources(); + return { + type: 'index_name', + indexName: logSourcesFromSharedSettings + .map((logSource) => logSource.indexPattern) + .join(','), + timestampField: logsSource.timestampField ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + case 'data_view': + return { + type: 'index_name', + indexName: logsSource.dataView.getIndexPattern(), + timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', + messageField: logsSource.messageField ?? 'message', + }; + } + }; diff --git a/x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts b/x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts similarity index 100% rename from x-pack/packages/observability/logs_overview/utils/xstate5_utils.ts rename to x-pack/packages/observability/logs_overview/src/utils/xstate5_utils.ts diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 476238cbafcc3..37fb31cdc68c2 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -18,5 +18,18 @@ "exclude": [ "target/**/*" ], - "kbn_references": [] + "kbn_references": [ + "@kbn/data-views-plugin", + "@kbn/i18n", + "@kbn/search-types", + "@kbn/xstate-utils", + "@kbn/core-ui-settings-browser", + "@kbn/i18n-react", + "@kbn/charts-plugin", + "@kbn/utility-types", + "@kbn/logs-data-access-plugin", + "@kbn/ml-random-sampler-utils", + "@kbn/zod", + "@kbn/calculate-auto", + ] } diff --git a/x-pack/packages/observability/logs_overview/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/utils/logs_source.ts deleted file mode 100644 index 80cb097391e9a..0000000000000 --- a/x-pack/packages/observability/logs_overview/utils/logs_source.ts +++ /dev/null @@ -1,55 +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 { type AbstractDataView } from '@kbn/data-views-plugin/common'; - -export type LogsSourceConfiguration = - | AdvancedSettingLogsSourceConfiguration - | IndexNameLogsSourceConfiguration - | DataViewLogsSourceConfiguration; - -export interface AdvancedSettingLogsSourceConfiguration { - type: 'advanced_setting'; - timestampField?: string; - messageField?: string; -} - -export interface IndexNameLogsSourceConfiguration { - type: 'index_name'; - indexName: string; - timestampField: string; - messageField: string; -} - -export interface DataViewLogsSourceConfiguration { - type: 'data_view'; - dataView: AbstractDataView; - messageField?: string; -} - -export const normalizeLogsSource = ( - logsSource: LogsSourceConfiguration -): IndexNameLogsSourceConfiguration => { - switch (logsSource.type) { - case 'index_name': - return logsSource; - case 'advanced_setting': - return { - type: 'index_name', - indexName: '', // TODO: get index name from advanced settings - timestampField: logsSource.timestampField ?? '@timestamp', - messageField: logsSource.messageField ?? 'message', - }; - case 'data_view': - return { - type: 'index_name', - indexName: logsSource.dataView.getIndexPattern(), - timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', - messageField: logsSource.messageField ?? 'message', - }; - } -}; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 5d4e7725409b6..9cb842eab199e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import React, { useMemo } from 'react'; -import { LogCategories } from '@kbn/observability-logs-overview'; +import React from 'react'; 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'; @@ -19,11 +18,10 @@ import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { const { services: { - charts, data: { search: { search }, }, - settings: uiSettings, + logsShared, }, } = useKibana(); const { serviceName } = useApmServiceContext(); @@ -32,22 +30,6 @@ export function ServiceLogs() { } = useAnyOfApmParams('/services/{serviceName}/logs'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const logCategoriesDependencies = useMemo( - () => ({ - charts, - search, - uiSettings, - }), - [charts, search, uiSettings] - ); - - // TODO: make charts required - if (typeof logCategoriesDependencies.charts === 'undefined') { - return null; - } - - // const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - // const { data } = useFetcher( // (callApmApi) => { // if (start && end) { @@ -69,7 +51,14 @@ export function ServiceLogs() { // TODO: filter by service name and environment // TODO: filter by time - return ; + return ( + + ); // return ( // + import('@kbn/observability-logs-overview').then((mod) => ({ default: mod.LogsOverview })) +); + +export type LogsOverviewProps = Omit; + +export const createLogsOverview = + (dependencies: LogsOverviewDependencies) => (props: LogsOverviewProps) => { + return ; + }; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/index.ts b/x-pack/plugins/observability_solution/logs_shared/public/index.ts index 7a0f731b4a93b..c5eed0885295d 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/index.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/index.ts @@ -50,6 +50,7 @@ export type { UpdatedDateRange, VisibleInterval, } from './components/logging/log_text_stream/scrollable_log_text_stream_view'; +export type { LogsOverviewProps } from './components/logs_overview'; export const WithSummary = dynamic(() => import('./containers/logs/log_summary/with_summary')); export const LogEntryFlyout = dynamic( diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index d6f4ac81fe266..21e42a81cef42 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -12,6 +12,7 @@ import { TraceLogsLocatorDefinition, } from '../common/locators'; import { createLogAIAssistant, createLogsAIAssistantRenderer } from './components/log_ai_assistant'; +import { createLogsOverview } from './components/logs_overview'; import { LogViewsService } from './services/log_views'; import { LogsSharedClientCoreSetup, @@ -52,7 +53,15 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { const { http } = core; - const { data, dataViews, discoverShared, observabilityAIAssistant, logsDataAccess } = plugins; + const { + charts, + data, + dataViews, + discoverShared, + logsDataAccess, + observabilityAIAssistant, + uiSettings, + } = plugins; const logViews = this.logViews.start({ http, @@ -61,9 +70,17 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { search: data.search, }); + const LogsOverview = createLogsOverview({ + charts, + logsDataAccess, + search: data.search.search, + uiSettings, + }); + if (!observabilityAIAssistant) { return { logViews, + LogsOverview, }; } @@ -77,6 +94,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { return { logViews, LogAIAssistant, + LogsOverview, }; } diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index 58b180ee8b6ef..479b4d0e5c962 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -5,19 +5,20 @@ * 2.0. */ +import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; -import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -import { LogsSharedLocators } from '../common/locators'; +import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; -// import type { OsqueryPluginStart } from '../../osquery/public'; -import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; +import type { LogsOverviewProps } from './components/logs_overview'; +import type { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; // Our own setup and start contract values export interface LogsSharedClientSetupExports { @@ -28,6 +29,7 @@ export interface LogsSharedClientSetupExports { export interface LogsSharedClientStartExports { logViews: LogViewsServiceStart; LogAIAssistant?: (props: Omit) => JSX.Element; + LogsOverview: (props: LogsOverviewProps) => JSX.Element; } export interface LogsSharedClientSetupDeps { @@ -35,6 +37,7 @@ export interface LogsSharedClientSetupDeps { } export interface LogsSharedClientStartDeps { + charts: ChartsPluginStart; data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; discoverShared: DiscoverSharedPublicStart; @@ -42,6 +45,7 @@ export interface LogsSharedClientStartDeps { observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; share: SharePluginStart; uiActions: UiActionsStart; + uiSettings: SettingsStart; } export type LogsSharedClientCoreSetup = CoreSetup< From 0d35529037011ae070aafc6653352e207cb36bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 4 Sep 2024 17:55:15 +0000 Subject: [PATCH 15/74] Fix unnecessary uiSettings dependency --- .../logs_shared/kibana.jsonc | 1 - .../logs_shared/public/plugin.ts | 15 ++++----------- .../logs_shared/public/types.ts | 2 -- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index cdf6f75257c6c..10c8fe32cfe9c 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -16,7 +16,6 @@ "logsDataAccess", "observabilityShared", "share", - "uiSettings", "usageCollection", ], "optionalPlugins": [ diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index 21e42a81cef42..7cd0a9ab5258b 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -52,16 +52,9 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { } public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { - const { http } = core; - const { - charts, - data, - dataViews, - discoverShared, - logsDataAccess, - observabilityAIAssistant, - uiSettings, - } = plugins; + const { http, settings } = core; + const { charts, data, dataViews, discoverShared, logsDataAccess, observabilityAIAssistant } = + plugins; const logViews = this.logViews.start({ http, @@ -74,7 +67,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { charts, logsDataAccess, search: data.search.search, - uiSettings, + uiSettings: settings, }); if (!observabilityAIAssistant) { diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index 479b4d0e5c962..e033cf0b204ff 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -6,7 +6,6 @@ */ import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; -import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; @@ -45,7 +44,6 @@ export interface LogsSharedClientStartDeps { observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; share: SharePluginStart; uiActions: UiActionsStart; - uiSettings: SettingsStart; } export type LogsSharedClientCoreSetup = CoreSetup< From d551da4b029c89b1aff77328cf52de15c539a3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 4 Sep 2024 19:39:08 +0000 Subject: [PATCH 16/74] Fix some refactoring mistakes --- .../categorize_documents.ts | 4 +- .../categorize_logs_service/queries.ts | 38 +++++++++++-------- .../components/app/service_logs/index.tsx | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index c95c874cd0132..5c1569e71faef 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -50,8 +50,8 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => index, timeField, messageField, - start, - end, + startTimestamp, + endTimestamp, randomSampler, ignoredQueries, minDocsPerCategory, diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts index b026133fd11bb..146203e3c0abc 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -15,8 +15,8 @@ const isoTimestampFormat = "YYYY-MM-DD'T'HH:mm:ss.SSS'Z'"; export const createCategorizationQuery = ( messageField: string, timeField: string, - start: string, - end: string, + startTimestamp: string, + endTimestamp: string, ignoredQueries: string[] = [] ): QueryDslQueryContainer => { return { @@ -30,8 +30,8 @@ export const createCategorizationQuery = ( { range: { [timeField]: { - gte: start, - lte: end, + gte: startTimestamp, + lte: endTimestamp, format: 'strict_date_time', }, }, @@ -55,14 +55,14 @@ export const createCategorizationRequestParams = ({ index, timeField, messageField, - start, - end, + startTimestamp, + endTimestamp, randomSampler, minDocsPerCategory = 0, ignoredQueries = [], }: { - start: string; - end: string; + startTimestamp: string; + endTimestamp: string; index: string; timeField: string; messageField: string; @@ -70,27 +70,33 @@ export const createCategorizationRequestParams = ({ minDocsPerCategory?: number; ignoredQueries?: string[]; }) => { - const startMoment = moment(start, isoTimestampFormat); - const endMoment = moment(end, isoTimestampFormat); + const startMoment = moment(startTimestamp, isoTimestampFormat); + const endMoment = moment(endTimestamp, isoTimestampFormat); const fixedIntervalDuration = calculateAuto.atLeast( 24, moment.duration(endMoment.diff(startMoment)) ); - const fixedIntervalSize = `${fixedIntervalDuration?.asMinutes()}m`; + const fixedIntervalSize = `${Math.ceil(fixedIntervalDuration?.asMinutes() ?? 1)}m`; return { index, size: 0, track_total_hits: false, - query: createCategorizationQuery(messageField, timeField, start, end, ignoredQueries), + query: createCategorizationQuery( + messageField, + timeField, + startTimestamp, + endTimestamp, + ignoredQueries + ), aggs: randomSampler.wrap({ histogram: { date_histogram: { field: '@timestamp', fixed_interval: fixedIntervalSize, extended_bounds: { - min: start, - max: end, + min: startTimestamp, + max: endTimestamp, }, }, }, @@ -109,8 +115,8 @@ export const createCategorizationRequestParams = ({ field: timeField, fixed_interval: fixedIntervalSize, extended_bounds: { - min: start, - max: end, + min: startTimestamp, + max: endTimestamp, }, }, }, diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 9cb842eab199e..6b216d99c94e8 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -50,7 +50,7 @@ export function ServiceLogs() { // ); // TODO: filter by service name and environment - // TODO: filter by time + // TODO: fix loop when no logsSource is given return ( Date: Wed, 4 Sep 2024 20:43:23 +0000 Subject: [PATCH 17/74] Memoize time overview props --- .../logs_overview/logs_overview.tsx | 48 +++++++++---------- .../components/app/service_logs/index.tsx | 13 ++--- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx index 721f40ff2fa45..e3de15e5be42c 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -25,30 +25,30 @@ export type LogsOverviewDependencies = LogCategoriesDependencies & { logsDataAccess: LogsDataAccessPluginStart; }; -export const LogsOverview: React.FC = ({ - dependencies, - logsSource = { type: 'shared_setting' }, - timeRange, -}) => { - const normalizedLogsSource = useAsync( - () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), - [dependencies.logsDataAccess, logsSource] - ); - - if (normalizedLogsSource.loading) { - return ; - } +export const LogsOverview: React.FC = React.memo( + ({ dependencies, logsSource = defaultLogsSource, timeRange }) => { + const normalizedLogsSource = useAsync( + () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), + [dependencies.logsDataAccess, logsSource] + ); + + if (normalizedLogsSource.loading) { + return ; + } - if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { - // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n - return <>Error; + if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { + // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n + return <>Error; + } + + return ( + + ); } +); - return ( - - ); -}; +const defaultLogsSource: LogsSourceConfiguration = { type: 'shared_setting' }; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 6b216d99c94e8..4d948cca3cd45 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; 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'; @@ -29,6 +29,7 @@ export function ServiceLogs() { query: { environment, kuery, rangeFrom, rangeTo }, } = useAnyOfApmParams('/services/{serviceName}/logs'); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const timeRange = useMemo(() => ({ start, end }), [start, end]); // const { data } = useFetcher( // (callApmApi) => { @@ -50,15 +51,7 @@ export function ServiceLogs() { // ); // TODO: filter by service name and environment - // TODO: fix loop when no logsSource is given - return ( - - ); + return ; // return ( // Date: Thu, 5 Sep 2024 14:20:13 +0000 Subject: [PATCH 18/74] Update zod import --- .../src/scenarios/distributed_unstructured_logs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts index 00b6340e4257a..24bb5e95a2987 100644 --- a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts +++ b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts @@ -7,7 +7,7 @@ */ import { infra, LogDocument, log } from '@kbn/apm-synthtrace-client'; import { fakerEN as faker } from '@faker-js/faker'; -import { z } from 'zod'; +import { z } from '@kbn/zod'; import { Scenario } from '../cli/scenario'; import { withClient } from '../lib/utils/with_client'; import { From 379387793793a2434af8e2872353c7c81b8d0101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 5 Sep 2024 14:20:42 +0000 Subject: [PATCH 19/74] Add service filters and error reporting --- .../log_categories/log_categories.tsx | 14 +- .../log_categories_error_content.tsx | 44 +++++ .../logs_overview/logs_overview.tsx | 16 +- .../logs_overview_error_content.tsx | 22 ++- .../categorize_documents.ts | 8 +- .../count_documents.ts | 61 ++++--- .../categorize_logs_service/queries.ts | 62 ++++--- .../services/categorize_logs_service/types.ts | 2 + .../components/app/service_logs/index.tsx | 151 +++++++++++++++--- 9 files changed, 288 insertions(+), 92 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index fe5828d1a97f1..93002bd388384 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { ISearchGeneric } from '@kbn/search-types'; import { createConsoleInspector } from '@kbn/xstate-utils'; import { useMachine } from '@xstate5/react'; @@ -15,6 +15,7 @@ import { createCategorizeLogsServiceImplementations, } from '../../services/categorize_logs_service'; import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { LogCategoriesErrorContent } from './log_categories_error_content'; import { LogCategoriesLoadingContent } from './log_categories_loading_content'; import { LogCategoriesResultContent, @@ -23,6 +24,7 @@ import { export interface LogCategoriesProps { dependencies: LogCategoriesDependencies; + documentFilters?: QueryDslQueryContainer[]; logsSource: IndexNameLogsSourceConfiguration; // The time range could be made optional if we want to support an internal // time range picker @@ -38,6 +40,7 @@ export type LogCategoriesDependencies = LogCategoriesResultContentDependencies & export const LogCategories: React.FC = ({ dependencies, + documentFilters = [], logsSource, timeRange, }) => { @@ -53,6 +56,7 @@ export const LogCategories: React.FC = ({ endTimestamp: timeRange.end, timeField: logsSource.timestampField, messageField: logsSource.messageField, + documentFilters, }, } ); @@ -71,13 +75,7 @@ export const LogCategories: React.FC = ({ /> ); } else if (categorizeLogsServiceState.matches('failed')) { - return ( -
- {i18n.translate('xpack.observabilityLogsOverview.logCategories.div.errorLabel', { - defaultMessage: 'Error', - })} -
- ); + return ; } else if (categorizeLogsServiceState.matches('countingDocuments')) { return ; } else if ( diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx new file mode 100644 index 0000000000000..445eef7802598 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx @@ -0,0 +1,44 @@ +/* + * 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 { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export interface LogCategoriesErrorContentProps { + error?: Error; +} + +export const LogCategoriesErrorContent: React.FC = ({ error }) => { + return ( + {logsOverviewErrorTitle}} + body={ + +

{error?.stack ?? error ?? unknownErrorDescription}

+
+ } + layout="vertical" + /> + ); +}; + +const logsOverviewErrorTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.errorTitle', + { + defaultMessage: 'Failed to categorize logs', + } +); + +const unknownErrorDescription = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.unknownErrorDescription', + { + defaultMessage: 'An unspecified error occurred.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx index e3de15e5be42c..988656eb1571e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -5,15 +5,18 @@ * 2.0. */ +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { type LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import React from 'react'; import useAsync from 'react-use/lib/useAsync'; import { LogsSourceConfiguration, normalizeLogsSource } from '../../utils/logs_source'; import { LogCategories, LogCategoriesDependencies } from '../log_categories'; +import { LogsOverviewErrorContent } from './logs_overview_error_content'; import { LogsOverviewLoadingContent } from './logs_overview_loading_content'; export interface LogsOverviewProps { dependencies: LogsOverviewDependencies; + documentFilters?: QueryDslQueryContainer[]; logsSource?: LogsSourceConfiguration; timeRange: { start: string; @@ -26,7 +29,12 @@ export type LogsOverviewDependencies = LogCategoriesDependencies & { }; export const LogsOverview: React.FC = React.memo( - ({ dependencies, logsSource = defaultLogsSource, timeRange }) => { + ({ + dependencies, + documentFilters = defaultDocumentFilters, + logsSource = defaultLogsSource, + timeRange, + }) => { const normalizedLogsSource = useAsync( () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), [dependencies.logsDataAccess, logsSource] @@ -37,13 +45,13 @@ export const LogsOverview: React.FC = React.memo( } if (normalizedLogsSource.error != null || normalizedLogsSource.value == null) { - // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n - return <>Error; + return ; } return ( @@ -51,4 +59,6 @@ export const LogsOverview: React.FC = React.memo( } ); +const defaultDocumentFilters: QueryDslQueryContainer[] = []; + const defaultLogsSource: LogsSourceConfiguration = { type: 'shared_setting' }; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx index 2f76384d66962..0f3c08d536884 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx @@ -5,19 +5,26 @@ * 2.0. */ -import { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; export interface LogsOverviewErrorContentProps { - error: Error; + error?: Error; } -export const LogsOverviewErrorContent: React.FC = ({}) => { +export const LogsOverviewErrorContent: React.FC = ({ error }) => { return ( } + color="danger" + iconType="error" title={

{logsOverviewErrorTitle}

} + body={ + +

{error?.stack ?? error ?? unknownErrorDescription}

+
+ } + layout="vertical" /> ); }; @@ -25,3 +32,10 @@ export const LogsOverviewErrorContent: React.FC = const logsOverviewErrorTitle = i18n.translate('xpack.observabilityLogsOverview.errorTitle', { defaultMessage: 'Error', }); + +const unknownErrorDescription = i18n.translate( + 'xpack.observabilityLogsOverview.unknownErrorDescription', + { + defaultMessage: 'An unspecified error occurred.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index 5c1569e71faef..5db7f296abe3a 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -24,7 +24,7 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => }, LogCategorizationParams & { samplingProbability: number; - ignoredQueries?: string[]; + ignoredCategoryTerms?: string[]; minDocsPerCategory?: number; } >( @@ -36,7 +36,8 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => timeField, messageField, samplingProbability, - ignoredQueries, + ignoredCategoryTerms = [], + documentFilters = [], minDocsPerCategory, }, signal, @@ -53,7 +54,8 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => startTimestamp, endTimestamp, randomSampler, - ignoredQueries, + additionalFilters: documentFilters, + ignoredCategoryTerms, minDocsPerCategory, }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts index 241e1158c7349..359f9ddac2bd8 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/count_documents.ts @@ -19,31 +19,42 @@ export const countDocuments = ({ search }: { search: ISearchGeneric }) => samplingProbability: number; }, LogCategorizationParams - >(async ({ input: { index, endTimestamp, startTimestamp, timeField, messageField }, signal }) => { - const { rawResponse: totalHitsResponse } = await lastValueFrom( - search( - { - params: { - index, - size: 0, - track_total_hits: true, - query: createCategorizationQuery(messageField, timeField, startTimestamp, endTimestamp), + >( + async ({ + input: { index, endTimestamp, startTimestamp, timeField, messageField, documentFilters }, + signal, + }) => { + const { rawResponse: totalHitsResponse } = await lastValueFrom( + search( + { + params: { + index, + size: 0, + track_total_hits: true, + query: createCategorizationQuery({ + messageField, + timeField, + startTimestamp, + endTimestamp, + additionalFilters: documentFilters, + }), + }, }, - }, - { abortSignal: signal } - ) - ); + { abortSignal: signal } + ) + ); - const documentCount = - totalHitsResponse.hits.total == null - ? 0 - : typeof totalHitsResponse.hits.total === 'number' - ? totalHitsResponse.hits.total - : totalHitsResponse.hits.total.value; - const samplingProbability = getSampleProbability(documentCount); + const documentCount = + totalHitsResponse.hits.total == null + ? 0 + : typeof totalHitsResponse.hits.total === 'number' + ? totalHitsResponse.hits.total + : totalHitsResponse.hits.total.value; + const samplingProbability = getSampleProbability(documentCount); - return { - documentCount, - samplingProbability, - }; - }); + return { + documentCount, + samplingProbability, + }; + } + ); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts index 146203e3c0abc..10488a827ece6 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -12,13 +12,21 @@ import moment from 'moment'; const isoTimestampFormat = "YYYY-MM-DD'T'HH:mm:ss.SSS'Z'"; -export const createCategorizationQuery = ( - messageField: string, - timeField: string, - startTimestamp: string, - endTimestamp: string, - ignoredQueries: string[] = [] -): QueryDslQueryContainer => { +export const createCategorizationQuery = ({ + messageField, + timeField, + startTimestamp, + endTimestamp, + additionalFilters = [], + ignoredCategoryTerms = [], +}: { + messageField: string; + timeField: string; + startTimestamp: string; + endTimestamp: string; + additionalFilters?: QueryDslQueryContainer[]; + ignoredCategoryTerms?: string[]; +}): QueryDslQueryContainer => { return { bool: { filter: [ @@ -36,17 +44,9 @@ export const createCategorizationQuery = ( }, }, }, + ...additionalFilters, ], - must_not: ignoredQueries.map((ignoredQuery) => ({ - match: { - [messageField]: { - query: ignoredQuery, - operator: 'AND' as const, - fuzziness: 0, - auto_generate_synonyms_phrase_query: false, - }, - }, - })), + must_not: ignoredCategoryTerms.map(createCategoryQuery(messageField)), }, }; }; @@ -59,7 +59,8 @@ export const createCategorizationRequestParams = ({ endTimestamp, randomSampler, minDocsPerCategory = 0, - ignoredQueries = [], + additionalFilters = [], + ignoredCategoryTerms = [], }: { startTimestamp: string; endTimestamp: string; @@ -68,7 +69,8 @@ export const createCategorizationRequestParams = ({ messageField: string; randomSampler: RandomSamplerWrapper; minDocsPerCategory?: number; - ignoredQueries?: string[]; + additionalFilters?: QueryDslQueryContainer[]; + ignoredCategoryTerms?: string[]; }) => { const startMoment = moment(startTimestamp, isoTimestampFormat); const endMoment = moment(endTimestamp, isoTimestampFormat); @@ -82,13 +84,14 @@ export const createCategorizationRequestParams = ({ index, size: 0, track_total_hits: false, - query: createCategorizationQuery( + query: createCategorizationQuery({ messageField, timeField, startTimestamp, endTimestamp, - ignoredQueries - ), + additionalFilters, + ignoredCategoryTerms, + }), aggs: randomSampler.wrap({ histogram: { date_histogram: { @@ -103,7 +106,7 @@ export const createCategorizationRequestParams = ({ categories: { categorize_text: { field: messageField, - size: 10000, + size: 1000, categorization_analyzer: { tokenizer: 'standard', }, @@ -131,3 +134,16 @@ export const createCategorizationRequestParams = ({ }), }; }; + +export const createCategoryQuery = + (messageField: string) => + (categoryTerms: string): QueryDslQueryContainer => ({ + match: { + [messageField]: { + query: categoryTerms, + operator: 'AND' as const, + fuzziness: 0, + auto_generate_synonyms_phrase_query: false, + }, + }, + }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts index a1e4a72fbfd56..e094317a98d62 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/types.ts @@ -4,6 +4,7 @@ * 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 { ISearchGeneric } from '@kbn/search-types'; export interface CategorizeLogsServiceDependencies { @@ -11,6 +12,7 @@ export interface CategorizeLogsServiceDependencies { } export interface LogCategorizationParams { + documentFilters: QueryDslQueryContainer[]; endTimestamp: string; index: string; messageField: string; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 4d948cca3cd45..99361ddd76a1a 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -6,23 +6,19 @@ */ import React, { useMemo } from 'react'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; 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'; import { useKibana } from '../../../context/kibana_context/use_kibana'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; -// import { useFetcher } from '../../../hooks/use_fetcher'; +import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { const { - services: { - data: { - search: { search }, - }, - logsShared, - }, + services: { logsShared }, } = useKibana(); const { serviceName } = useApmServiceContext(); const { @@ -31,27 +27,34 @@ export function ServiceLogs() { const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const timeRange = useMemo(() => ({ start, end }), [start, end]); - // const { data } = useFetcher( - // (callApmApi) => { - // if (start && end) { - // return callApmApi('GET /internal/apm/services/{serviceName}/infrastructure_attributes', { - // params: { - // path: { serviceName }, - // query: { - // environment, - // kuery, - // start, - // end, - // }, - // }, - // }); - // } - // }, - // [environment, kuery, serviceName, start, end] - // ); + const { data: logFilters } = useFetcher( + async (callApmApi) => { + if (start == null || end == null) { + return; + } + + const { containerIds } = await callApmApi( + 'GET /internal/apm/services/{serviceName}/infrastructure_attributes', + { + params: { + path: { serviceName }, + query: { + environment, + kuery, + start, + end, + }, + }, + } + ); + + return [getInfrastructureFilter({ containerIds, environment, serviceName })]; + }, + [environment, kuery, serviceName, start, end] + ); // TODO: filter by service name and environment - return ; + return ; // return ( // Date: Thu, 5 Sep 2024 14:26:51 +0000 Subject: [PATCH 20/74] Fix fetching remaining categories --- .../categorize_logs_service/categorize_documents.ts | 6 +++--- .../categorize_logs_service/categorize_logs_service.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index 5db7f296abe3a..d787fd6b50148 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -24,8 +24,8 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => }, LogCategorizationParams & { samplingProbability: number; - ignoredCategoryTerms?: string[]; - minDocsPerCategory?: number; + ignoredCategoryTerms: string[]; + minDocsPerCategory: number; } >( async ({ @@ -36,7 +36,7 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => timeField, messageField, samplingProbability, - ignoredCategoryTerms = [], + ignoredCategoryTerms, documentFilters = [], minDocsPerCategory, }, diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index eb3f3b4e551f4..6aa071e12603f 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -119,7 +119,7 @@ export const categorizeLogsService = setup({ input: ({ context }) => ({ ...context.parameters, samplingProbability: context.samplingProbability, - ignoredQueries: [], + ignoredCategoryTerms: [], minDocsPerCategory: 10, }), onDone: { @@ -162,7 +162,7 @@ export const categorizeLogsService = setup({ input: ({ context }) => ({ ...context.parameters, samplingProbability: context.samplingProbability, - ignoredQueries: context.categories.map((category) => category.terms), + ignoredCategoryTerms: context.categories.map((category) => category.terms), minDocsPerCategory: 0, }), onDone: { From 870d3474c24907aa454b7e64b6300d98c36cd9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 12:12:51 +0000 Subject: [PATCH 21/74] Add logs overview feature flag --- .../settings/setting_ids/index.ts | 1 + .../components/app/service_logs/index.tsx | 72 +++++++++++++++---- .../public/components/logs_overview.tsx | 24 ++++++- .../logs_shared/public/types.ts | 4 +- .../logs_shared/server/feature_flags.ts | 33 +++++++++ .../logs_shared/server/plugin.ts | 28 ++++---- 6 files changed, 131 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index 9f0c226717079..6c475946fa050 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -141,6 +141,7 @@ export const OBSERVABILITY_APM_ENABLE_SERVICE_INVENTORY_TABLE_SEARCH_BAR = 'observability:apmEnableServiceInventoryTableSearchBar'; export const OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID = 'observability:logsExplorer:allowedDataViews'; +export const OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID = 'observability:newLogsOverview'; export const OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE = 'observability:entityCentricExperience'; export const OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID = 'observability:logSources'; export const OBSERVABILITY_AI_ASSISTANT_LOGS_INDEX_PATTERN_ID = diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index 99361ddd76a1a..b2c479f46f32b 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -6,7 +6,9 @@ */ import React, { useMemo } from 'react'; +import moment from 'moment'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { LogStream } from '@kbn/logs-shared-plugin/public'; 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'; @@ -17,6 +19,63 @@ import { useTimeRange } from '../../../hooks/use_time_range'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; export function ServiceLogs() { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibana(); + + const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); + + if (isLogsOverviewEnabled) { + return ; + } else { + return ; + } +} + +export function ClassicServiceLogsStream() { + const { serviceName } = useApmServiceContext(); + + const { + query: { environment, kuery, rangeFrom, rangeTo }, + } = useAnyOfApmParams('/services/{serviceName}/logs'); + + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + const { data } = useFetcher( + (callApmApi) => { + if (start && end) { + return callApmApi('GET /internal/apm/services/{serviceName}/infrastructure_attributes', { + params: { + path: { serviceName }, + query: { + environment, + kuery, + start, + end, + }, + }, + }); + } + }, + [environment, kuery, serviceName, start, end] + ); + + return ( + + ); +} + +export function ServiceLogsOverview() { const { services: { logsShared }, } = useKibana(); @@ -53,20 +112,7 @@ export function ServiceLogs() { [environment, kuery, serviceName, start, end] ); - // TODO: filter by service name and environment return ; - - // return ( - // - // ); } export function getInfrastructureKQLFilter({ diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx index 862f747a70c46..e0baff2237ff6 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx @@ -5,12 +5,14 @@ * 2.0. */ +import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; import type { - LogsOverviewDependencies, LogsOverviewProps as FullLogsOverviewProps, + LogsOverviewDependencies, } from '@kbn/observability-logs-overview'; import { dynamic } from '@kbn/shared-ux-utility'; import React from 'react'; +import useObservable from 'react-use/lib/useObservable'; const LazyLogsOverview = dynamic(() => import('@kbn/observability-logs-overview').then((mod) => ({ default: mod.LogsOverview })) @@ -18,7 +20,23 @@ const LazyLogsOverview = dynamic(() => export type LogsOverviewProps = Omit; -export const createLogsOverview = - (dependencies: LogsOverviewDependencies) => (props: LogsOverviewProps) => { +export const createLogsOverview = (dependencies: LogsOverviewDependencies) => { + const SelfContainedLogsOverview = (props: LogsOverviewProps) => { return ; }; + + const isEnabled$ = dependencies.uiSettings.client.get$( + OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID, + defaultIsEnabled + ); + + SelfContainedLogsOverview.useIsEnabled = (): boolean => { + return useObservable(isEnabled$, defaultIsEnabled); + }; + + return SelfContainedLogsOverview; +}; + +const defaultIsEnabled = false; + +export type SelfContainedLogsOverview = ReturnType; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index e033cf0b204ff..4237c28c621b8 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -16,7 +16,7 @@ import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/publi import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; -import type { LogsOverviewProps } from './components/logs_overview'; +import type { SelfContainedLogsOverview } from './components/logs_overview'; import type { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; // Our own setup and start contract values @@ -28,7 +28,7 @@ export interface LogsSharedClientSetupExports { export interface LogsSharedClientStartExports { logViews: LogViewsServiceStart; LogAIAssistant?: (props: Omit) => JSX.Element; - LogsOverview: (props: LogsOverviewProps) => JSX.Element; + LogsOverview: SelfContainedLogsOverview; } export interface LogsSharedClientSetupDeps { diff --git a/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts b/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts new file mode 100644 index 0000000000000..0298416bd3f26 --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/server/feature_flags.ts @@ -0,0 +1,33 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management-settings-ids'; + +const technicalPreviewLabel = i18n.translate('xpack.logsShared.technicalPreviewSettingLabel', { + defaultMessage: 'Technical Preview', +}); + +export const featureFlagUiSettings: Record = { + [OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID]: { + category: ['observability'], + name: i18n.translate('xpack.logsShared.newLogsOverviewSettingName', { + defaultMessage: 'New logs overview', + }), + value: false, + description: i18n.translate('xpack.logsShared.newLogsOverviewSettingDescription', { + defaultMessage: '{technicalPreviewLabel} Enable the new logs overview experience.', + + values: { technicalPreviewLabel: `[${technicalPreviewLabel}]` }, + }), + type: 'boolean', + schema: schema.boolean(), + requiresPageReload: true, + }, +}; diff --git a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts index 7c97e175ed64f..d1f6399104fc2 100644 --- a/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/server/plugin.ts @@ -5,8 +5,19 @@ * 2.0. */ -import { PluginInitializerContext, CoreStart, Plugin, Logger } from '@kbn/core/server'; - +import { CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import { defaultLogViewId } from '../common/log_views'; +import { LogsSharedConfig } from '../common/plugin_config'; +import { registerDeprecations } from './deprecations'; +import { featureFlagUiSettings } from './feature_flags'; +import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; +import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; +import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; +import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; +import { initLogsSharedServer } from './logs_shared_server'; +import { logViewSavedObjectType } from './saved_objects'; +import { LogEntriesService } from './services/log_entries'; +import { LogViewsService } from './services/log_views'; import { LogsSharedPluginCoreSetup, LogsSharedPluginSetup, @@ -15,17 +26,6 @@ import { LogsSharedServerPluginStartDeps, UsageCollector, } from './types'; -import { logViewSavedObjectType } from './saved_objects'; -import { initLogsSharedServer } from './logs_shared_server'; -import { LogViewsService } from './services/log_views'; -import { KibanaFramework } from './lib/adapters/framework/kibana_framework_adapter'; -import { LogsSharedBackendLibs, LogsSharedDomainLibs } from './lib/logs_shared_types'; -import { LogsSharedLogEntriesDomain } from './lib/domains/log_entries_domain'; -import { LogsSharedKibanaLogEntriesAdapter } from './lib/adapters/log_entries/kibana_log_entries_adapter'; -import { LogEntriesService } from './services/log_entries'; -import { LogsSharedConfig } from '../common/plugin_config'; -import { registerDeprecations } from './deprecations'; -import { defaultLogViewId } from '../common/log_views'; export class LogsSharedPlugin implements @@ -88,6 +88,8 @@ export class LogsSharedPlugin registerDeprecations({ core }); + core.uiSettings.register(featureFlagUiSettings); + return { ...domainLibs, logViews, From d08f104f4f8a40167d84b7ba0518f9a250aa3740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 16:09:06 +0000 Subject: [PATCH 22/74] Add logs overview in infra hosts --- .../components/tabs/logs/logs_tab_content.tsx | 92 ++++++++++++++----- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx index 27344ccd1f108..3752e284c1b62 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx @@ -5,21 +5,37 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { LogStream } from '@kbn/logs-shared-plugin/public'; -import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; import { InfraLoadingPanel } from '../../../../../../components/loading'; +import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; +import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; +import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; import { useHostsViewContext } from '../../../hooks/use_hosts_view'; -import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; import { useLogsSearchUrlState } from '../../../hooks/use_logs_search_url_state'; +import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; import { LogsLinkToStream } from './logs_link_to_stream'; import { LogsSearchBar } from './logs_search_bar'; -import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build'; -import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference'; export const LogsTabContent = () => { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibanaContextForPlugin(); + const isLogsOverviewEnabled = LogsOverview.useIsEnabled(); + if (isLogsOverviewEnabled) { + return ; + } else { + return ; + } +}; + +export const LogsTabLogStreamContent = () => { const [filterQuery] = useLogsSearchUrlState(); const { getDateRangeAsTimestamp } = useUnifiedSearchContext(); const { from, to } = useMemo(() => getDateRangeAsTimestamp(), [getDateRangeAsTimestamp]); @@ -53,22 +69,7 @@ export const LogsTabContent = () => { }, [filterQuery.query, hostNodes]); if (loading || logViewLoading || !logView) { - return ( - - - - } - /> - - - ); + return ; } return ( @@ -84,6 +85,7 @@ export const LogsTabContent = () => { query={logsLinkToStreamQuery} logView={logView} /> + ] @@ -112,3 +114,51 @@ const createHostsFilterQueryParam = (hostNodes: string[]): string => { return hostsQueryParam; }; + +const LogsTabLogsOverviewContent = () => { + const { + services: { + logsShared: { LogsOverview }, + }, + } = useKibanaContextForPlugin(); + + const { parsedDateRange } = useUnifiedSearchContext(); + const timeRange = useMemo( + () => ({ start: parsedDateRange.from, end: parsedDateRange.to }), + [parsedDateRange.from, parsedDateRange.to] + ); + + const { hostNodes, loading } = useHostsViewContext(); + const logFilters = useMemo( + () => [ + buildCombinedAssetFilter({ + field: 'host.name', + values: hostNodes.map((p) => p.name), + }).query as QueryDslQueryContainer, + ], + [hostNodes] + ); + + if (loading) { + return ; + } + + return ; +}; + +const LogsTabLoadingContent = () => ( + + + + } + /> + + +); From 6ecd0561324e846809122ec41eae024279e2ad32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 16:25:09 +0000 Subject: [PATCH 23/74] Fix sampling probability of second pass --- .../services/categorize_logs_service/categorize_logs_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index 6aa071e12603f..1626d201722dc 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -161,7 +161,7 @@ export const categorizeLogsService = setup({ id: 'categorizeRemainingCategories', input: ({ context }) => ({ ...context.parameters, - samplingProbability: context.samplingProbability, + samplingProbability: 1, ignoredCategoryTerms: context.categories.map((category) => category.terms), minDocsPerCategory: 0, }), From b0b1fe741556725a358b7e724a080c160d510630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 19:41:52 +0000 Subject: [PATCH 24/74] Signal categories limit being reached --- .../categorize_documents.ts | 4 ++ .../categorize_logs_service.ts | 43 +++++++++++++++---- .../categorize_logs_service/queries.ts | 4 +- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index d787fd6b50148..02e24b9174c5d 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -16,11 +16,13 @@ import { LogCategory, LogCategoryChange } from '../../types'; // the fraction of a category's histogram below which the category is considered rare const rarityThreshold = 0.2; +const maxCategoriesCount = 1000; export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => fromPromise< { categories: LogCategory[]; + hasReachedLimit: boolean; }, LogCategorizationParams & { samplingProbability: number; @@ -57,6 +59,7 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => additionalFilters: documentFilters, ignoredCategoryTerms, minDocsPerCategory, + maxCategoriesCount, }); const { rawResponse } = await lastValueFrom(search({ params: requestParams })); @@ -76,6 +79,7 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => return { categories: logCategories, + hasReachedLimit: logCategories.length >= maxCategoriesCount, }; } ); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts index 1626d201722dc..deeb758d2d737 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_logs_service.ts @@ -6,11 +6,11 @@ */ import { MachineImplementationsFrom, assign, setup } from 'xstate5'; +import { LogCategory } from '../../types'; import { getPlaceholderFor } from '../../utils/xstate5_utils'; import { categorizeDocuments } from './categorize_documents'; import { countDocuments } from './count_documents'; import { CategorizeLogsServiceDependencies, LogCategorizationParams } from './types'; -import { LogCategory } from '../../types'; export const categorizeLogsService = setup({ types: { @@ -18,14 +18,16 @@ export const categorizeLogsService = setup({ output: {} as { categories: LogCategory[]; documentCount: number; + hasReachedLimit: boolean; samplingProbability: number; }, context: {} as { categories: LogCategory[]; documentCount: number; + error?: Error; + hasReachedLimit: boolean; parameters: LogCategorizationParams; samplingProbability: number; - error?: Error; }, events: {} as { type: 'cancel'; @@ -39,9 +41,12 @@ export const categorizeLogsService = setup({ storeError: assign((_, params: { error: unknown }) => ({ error: params.error instanceof Error ? params.error : new Error(String(params.error)), })), - storeCategories: assign(({ context }, params: { categories: LogCategory[] }) => ({ - categories: [...context.categories, ...params.categories], - })), + storeCategories: assign( + ({ context }, params: { categories: LogCategory[]; hasReachedLimit: boolean }) => ({ + categories: [...context.categories, ...params.categories], + hasReachedLimit: params.hasReachedLimit, + }) + ), storeDocumentCount: assign( (_, params: { documentCount: number; samplingProbability: number }) => ({ documentCount: params.documentCount, @@ -50,16 +55,19 @@ export const categorizeLogsService = setup({ ), }, guards: { - requiresSampling: ({ context }) => context.samplingProbability < 1, + hasTooFewDocuments: (_guardArgs, params: { documentCount: number }) => params.documentCount < 1, + requiresSampling: (_guardArgs, params: { samplingProbability: number }) => + params.samplingProbability < 1, }, }).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QAmAJwAOSgAWP0CAZgA2M0CzAEZwgFYYgHYkgBoQAE9EJK8vIPCYsy8k+K94pJ8YmIBfavS5LDwiUnIqGgYmFnZOHj5BYVEDGWoMRsUWlXb1Lq1e3X16STljemsTGJskEAcnF3o3TwRfAOCwyOi4xJT0rKPQmMpQxPifJNCkyLK-cNr60YVmso2mpOpoejoBGBcLg8JQ7AAbDAAMzwXBG8iaSlaqg6Gm62j4CyWRlMlmsbh2zhWB28-iCIQiUViCWSaUyiD8D3iZh5MS8kSiXhilV+IAaAKxkxBeNmEP4aHoyDA8PJW0pexpRzpp0ZFxZ13ZCHipUofhewQqKXCXkCovFmImVCRYHQyAAFhoAMqoLgIyAAYX+TTg-REYkW0lkQfG3t98ID0fwcFV9kcVNcW0OhRKlDMPneZktPjKBtu4R84UejNCXh5SUCQqSdsTkqdLvdXp9foggYxBBDUJhuDhiPQKNwaPtMa78Z7ieTlgpaY1mcQ2fiufzSULr2L5TZtySfh8lC8x9rgXigXCoT8T2bfcB2Odro9LFj3d7YyTAgVSpVi5qsu1Krgg66bgWRYlgeHJ+HkNpeO825mqEl5eA+36tpQL4diwABKYBcKgzAaF+AIhkIYZDFGj7EARREkSwZHBrAKbbMBGagFmVoQeECShO8No1jc3iIUEHwvH43w+D4RT1hhEqOth7ZvlA9HEfQpHzpC0KwgiyKouimFgOpjFQMx-asYBqa7CBXFrjxeYRPxglhF4IkIIEfKPHBZo+NeISRDUdRii2Sk4appmaUx2nyqgirKmx6p2R4DkfLxLk5G5Hn3JWDavEkMTRFJ4SBGVtQhfQ2AQHAbhTk+FBLrZnGpQgAC04QeW1G4yb1fX9aECkOkCOLTGCBK6E16b7KBDYeYUG7vAkZplXmHzFEN4wjRFnZxgmj61UBzUzfZCB8SeTk5DEJXHJ1hqFQ813rcU8QoQJm0NW2r4aFFWkHfAR3TZqMQFhBJQNreDY2h5iEBDWnLHtahRFRtIX1VhSLEbOU0rqdQqxKeCTXgkiR+EUHlnJQRWJNEr104W8QfVhlFgDjKWHPjDz8lefHGtd5OGkJlA+PENbvJekR3vcFXVEAA */ + /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ id: 'categorizeLogs', context: ({ input }) => ({ categories: [], documentCount: 0, + hasReachedLimit: false, parameters: input, - samplingProbability: 0, + samplingProbability: 1, }), initial: 'countingDocuments', states: { @@ -68,9 +76,25 @@ export const categorizeLogsService = setup({ src: 'countDocuments', input: ({ context }) => context.parameters, onDone: [ + { + target: 'done', + guard: { + type: 'hasTooFewDocuments', + params: ({ event }) => event.output, + }, + actions: [ + { + type: 'storeDocumentCount', + params: ({ event }) => event.output, + }, + ], + }, { target: 'fetchingSampledCategories', - guard: 'requiresSampling', + guard: { + type: 'requiresSampling', + params: ({ event }) => event.output, + }, actions: [ { type: 'storeDocumentCount', @@ -209,6 +233,7 @@ export const categorizeLogsService = setup({ output: ({ context }) => ({ categories: context.categories, documentCount: context.documentCount, + hasReachedLimit: context.hasReachedLimit, samplingProbability: context.samplingProbability, }), }); diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts index 10488a827ece6..849567895f934 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -61,6 +61,7 @@ export const createCategorizationRequestParams = ({ minDocsPerCategory = 0, additionalFilters = [], ignoredCategoryTerms = [], + maxCategoriesCount = 1000, }: { startTimestamp: string; endTimestamp: string; @@ -71,6 +72,7 @@ export const createCategorizationRequestParams = ({ minDocsPerCategory?: number; additionalFilters?: QueryDslQueryContainer[]; ignoredCategoryTerms?: string[]; + maxCategoriesCount?: number; }) => { const startMoment = moment(startTimestamp, isoTimestampFormat); const endMoment = moment(endTimestamp, isoTimestampFormat); @@ -106,7 +108,7 @@ export const createCategorizationRequestParams = ({ categories: { categorize_text: { field: messageField, - size: 1000, + size: maxCategoriesCount, categorization_analyzer: { tokenizer: 'standard', }, From 8c09788753271efc7c8a5838641d8d50af5c5f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 19:42:49 +0000 Subject: [PATCH 25/74] Respect the abort signal when categorizing --- .../services/categorize_logs_service/categorize_documents.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index 02e24b9174c5d..9d1ba3f2cbc44 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -62,7 +62,9 @@ export const categorizeDocuments = ({ search }: { search: ISearchGeneric }) => maxCategoriesCount, }); - const { rawResponse } = await lastValueFrom(search({ params: requestParams })); + const { rawResponse } = await lastValueFrom( + search({ params: requestParams }, { abortSignal: signal }) + ); if (rawResponse.aggregations == null) { throw new Error('No aggregations found in large categories response'); From b028eabcb2be50313ec0edf82148bb3efc7d924b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 6 Sep 2024 20:01:03 +0000 Subject: [PATCH 26/74] Add empty state screen --- .../log_categories_result_content.tsx | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index ab82051b9f635..72413b2004c65 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import { EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import React from 'react'; import { LogCategory } from '../../types'; import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; @@ -20,9 +22,40 @@ export const LogCategoriesResultContent: React.FC { + if (logCategories.length === 0) { + return ; + } else { + return ( +
+ +
+ ); + } +}; + +export const LogCategoriesEmptyResultContent: React.FC = () => { return ( -
- -
+ {emptyResultContentDescription}

} + color="subdued" + layout="horizontal" + title={

{emptyResultContentTitle}

} + titleSize="m" + /> ); }; + +const emptyResultContentTitle = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.emptyResultContentTitle', + { + defaultMessage: 'No log categories found', + } +); + +const emptyResultContentDescription = i18n.translate( + 'xpack.observabilityLogsOverview.logCategories.emptyResultContentDescription', + { + defaultMessage: + 'No suitable documents within the time range. Try searching for a longer time period.', + } +); From 6aad1a15fe6b6e77cd9a9b7edfedaeeb8069bf7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 12 Sep 2024 15:15:25 +0000 Subject: [PATCH 27/74] Fix race condition when rendering apm service details --- .../observability/logs_overview/index.ts | 3 +++ .../src/components/logs_overview/index.ts | 2 ++ .../public/components/app/service_logs/index.tsx | 14 +++++++++++--- .../public/components/logs_overview.tsx | 16 ++++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/index.ts index e937c4fbc3fea..057d1d3acd152 100644 --- a/x-pack/packages/observability/logs_overview/index.ts +++ b/x-pack/packages/observability/logs_overview/index.ts @@ -7,7 +7,10 @@ export { LogsOverview, + LogsOverviewErrorContent, + LogsOverviewLoadingContent, type LogsOverviewDependencies, + type LogsOverviewErrorContentProps, type LogsOverviewProps, } from './src/components/logs_overview'; export type { diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts index 627cdc8447eea..878f634f078ad 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/index.ts @@ -6,3 +6,5 @@ */ export * from './logs_overview'; +export * from './logs_overview_error_content'; +export * from './logs_overview_loading_content'; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index b2c479f46f32b..a1dadbf186b91 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -14,7 +14,7 @@ import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../com import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { useKibana } from '../../../context/kibana_context/use_kibana'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; -import { useFetcher } from '../../../hooks/use_fetcher'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; @@ -86,7 +86,7 @@ export function ServiceLogsOverview() { const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const timeRange = useMemo(() => ({ start, end }), [start, end]); - const { data: logFilters } = useFetcher( + const { data: logFilters, status } = useFetcher( async (callApmApi) => { if (start == null || end == null) { return; @@ -112,7 +112,15 @@ export function ServiceLogsOverview() { [environment, kuery, serviceName, start, end] ); - return ; + if (status === FETCH_STATUS.SUCCESS) { + return ; + } else if (status === FETCH_STATUS.FAILURE) { + return ( + + ); + } else { + return ; + } } export function getInfrastructureKQLFilter({ diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx index e0baff2237ff6..88bb77899d6d2 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx @@ -18,6 +18,18 @@ const LazyLogsOverview = dynamic(() => import('@kbn/observability-logs-overview').then((mod) => ({ default: mod.LogsOverview })) ); +const LazyLogsOverviewErrorContent = dynamic(() => + import('@kbn/observability-logs-overview').then((mod) => ({ + default: mod.LogsOverviewErrorContent, + })) +); + +const LazyLogsOverviewLoadingContent = dynamic(() => + import('@kbn/observability-logs-overview').then((mod) => ({ + default: mod.LogsOverviewLoadingContent, + })) +); + export type LogsOverviewProps = Omit; export const createLogsOverview = (dependencies: LogsOverviewDependencies) => { @@ -34,6 +46,10 @@ export const createLogsOverview = (dependencies: LogsOverviewDependencies) => { return useObservable(isEnabled$, defaultIsEnabled); }; + SelfContainedLogsOverview.ErrorContent = LazyLogsOverviewErrorContent; + + SelfContainedLogsOverview.LoadingContent = LazyLogsOverviewLoadingContent; + return SelfContainedLogsOverview; }; From 7f1fb14e6db3788fa2232fe9319fa1911fbed289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 12 Sep 2024 15:19:43 +0000 Subject: [PATCH 28/74] Improve loading content in hosts --- .../hosts/components/tabs/logs/logs_tab_content.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx index 3752e284c1b62..78443c9a6ec81 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx @@ -128,7 +128,7 @@ const LogsTabLogsOverviewContent = () => { [parsedDateRange.from, parsedDateRange.to] ); - const { hostNodes, loading } = useHostsViewContext(); + const { hostNodes, loading, error } = useHostsViewContext(); const logFilters = useMemo( () => [ buildCombinedAssetFilter({ @@ -140,10 +140,12 @@ const LogsTabLogsOverviewContent = () => { ); if (loading) { - return ; + return ; + } else if (error != null) { + return ; + } else { + return ; } - - return ; }; const LogsTabLoadingContent = () => ( From 4e95f041a98580bef37a4b38554f20c077f553d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 10:42:15 +0000 Subject: [PATCH 29/74] Update XState v5 version --- package.json | 6 +++--- yarn.lock | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 00e06d9a25017..219887b00390b 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "**/sharp": "0.32.6", "**/typescript": "5.1.6", "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", - "@xstate5/react/**/xstate": "^5.18.0", + "@xstate5/react/**/xstate": "^5.18.1", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -1025,7 +1025,7 @@ "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", - "@xstate5/react": "npm:@xstate/react@^4.1.1", + "@xstate5/react": "npm:@xstate/react@^4.1.2", "adm-zip": "^0.5.9", "ai": "^2.2.33", "ajv": "^8.12.0", @@ -1261,7 +1261,7 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", - "xstate5": "npm:xstate@^5.18.0", + "xstate5": "npm:xstate@^5.18.1", "xterm": "^5.1.0", "yauzl": "^2.10.0", "yazl": "^2.5.1", diff --git a/yarn.lock b/yarn.lock index 80a3a0d7335a8..d0078333007bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12022,10 +12022,10 @@ use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.0.0" -"@xstate5/react@npm:@xstate/react@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.1.tgz#2f580fc5f83d195f95b56df6cd8061c66660d9fa" - integrity sha512-pFp/Y+bnczfaZ0V8B4LOhx3d6Gd71YKAPbzerGqydC2nsYN/mp7RZu3q/w6/kvI2hwR/jeDeetM7xc3JFZH2NA== +"@xstate5/react@npm:@xstate/react@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.2.tgz#4bfcdf2d9e9ef1eaea7388d1896649345e6679cd" + integrity sha512-orAidFrKCrU0ZwN5l/ABPlBfW2ziRDT2RrYoktRlZ0WRoLvA2E/uAC1JpZt43mCLtc8jrdwYCgJiqx1V8NvGTw== dependencies: use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.2.0" @@ -32640,10 +32640,10 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== -"xstate5@npm:xstate@^5.18.0", xstate@^5.18.0: - version "5.18.0" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.0.tgz#6f559301dc2e1e4db39642ac5591bb7eb005335b" - integrity sha512-MKlq/jhyFBYm6Z9+P0k9nhMrHYTTg1ZGmhMw8tVe67oDq9nIlEf2/u/bY5kvUvqu4LTCiVl67hnfd92RMLRyVg== +"xstate5@npm:xstate@^5.18.1", xstate@^5.18.1: + version "5.18.1" + resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.1.tgz#c4d43ceaba6e6c31705d36bd96e285de4be4f7f4" + integrity sha512-m02IqcCQbaE/kBQLunwub/5i8epvkD2mFutnL17Oeg1eXTShe1sRF4D5mhv1dlaFO4vbW5gRGRhraeAD5c938g== xstate@^4.38.2: version "4.38.2" From a6ab7e1beb74d0c00ed79d222675208f07202f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 11:36:47 +0000 Subject: [PATCH 30/74] Clean up TODOs and comments --- .../log_categories/log_categories_grid_pattern_cell.tsx | 7 +++---- .../categorize_logs_service/categorize_documents.ts | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx index ae5471ef0868e..ce01bc8136416 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -34,8 +34,6 @@ export const LogCategoriesGridPatternCell: React.FC +
{termsList.map((term, index) => (
{term}
- {index !== termsList.length - 1 &&
*
} +
))} diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts index 9d1ba3f2cbc44..7260efe63d435 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/categorize_documents.ts @@ -274,7 +274,6 @@ const esCategoryBucketSchema = z.object({ type EsCategoryBucket = z.output; -// TODO: implement rarity criteria const isRareInHistogram = (histogram: EsHistogram): boolean => histogram.filter((bucket) => bucket.documentCount > 0).length < histogram.length * rarityThreshold; From 5bbda50195f57fdf71922a93a76be7270cbb84ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 11:37:51 +0000 Subject: [PATCH 31/74] Remove temporary test --- .../scenarios/helpers/unstructured_logs.test.ts | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts deleted file mode 100644 index 2fdf52254540d..0000000000000 --- a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.test.ts +++ /dev/null @@ -1,17 +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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { generateUnstructuredLogMessage } from './unstructured_logs'; - -test('generates unstructured logs', () => { - const messages = Array(10) - .fill('') - .map(() => generateUnstructuredLogMessage()()); - - console.log(messages); -}); From 7843215e248b9c22c7ef4085624f999b2afef752 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:50:13 +0000 Subject: [PATCH 32/74] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-apm-synthtrace/tsconfig.json | 1 + .../plugins/observability_solution/logs_shared/tsconfig.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/kbn-apm-synthtrace/tsconfig.json b/packages/kbn-apm-synthtrace/tsconfig.json index d0f5c5801597a..db93e36421b83 100644 --- a/packages/kbn-apm-synthtrace/tsconfig.json +++ b/packages/kbn-apm-synthtrace/tsconfig.json @@ -10,6 +10,7 @@ "@kbn/apm-synthtrace-client", "@kbn/dev-utils", "@kbn/elastic-agent-utils", + "@kbn/zod", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 38cbba7c252c0..788f55c9b6fc5 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -44,5 +44,9 @@ "@kbn/logs-data-access-plugin", "@kbn/core-deprecations-common", "@kbn/core-deprecations-server", + "@kbn/management-settings-ids", + "@kbn/observability-logs-overview", + "@kbn/charts-plugin", + "@kbn/core-ui-settings-common", ] } From e3f30430be6010143d4f524af0c1488be6d1fb22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 12:27:11 +0000 Subject: [PATCH 33/74] Update license headers --- .../src/lib/gaussian_events.ts | 9 +++++---- .../src/lib/poisson_events.test.ts | 9 +++++---- .../src/lib/poisson_events.ts | 9 +++++---- .../src/scenarios/distributed_unstructured_logs.ts | 10 ++++++---- .../src/scenarios/helpers/unstructured_logs.ts | 10 ++++++---- packages/kbn-xstate-utils/src/console_inspector.ts | 9 +++++---- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts index c13ebbaafe368..4f1db28017d29 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts @@ -1,9 +1,10 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { castArray } from 'lodash'; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts index 580e89e2b2208..0741884550f32 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts @@ -1,9 +1,10 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { PoissonEvents } from './poisson_events'; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts index 05d8d8793d1b8..e7fd24b8323e7 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/poisson_events.ts @@ -1,9 +1,10 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { castArray } from 'lodash'; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts index 24bb5e95a2987..83860635ae64a 100644 --- a/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts +++ b/packages/kbn-apm-synthtrace/src/scenarios/distributed_unstructured_logs.ts @@ -1,10 +1,12 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ + import { infra, LogDocument, log } from '@kbn/apm-synthtrace-client'; import { fakerEN as faker } from '@faker-js/faker'; import { z } from '@kbn/zod'; diff --git a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts index 0cfc88ac55a83..490bd449e2b60 100644 --- a/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts +++ b/packages/kbn-apm-synthtrace/src/scenarios/helpers/unstructured_logs.ts @@ -1,10 +1,12 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ + import { Faker, faker } from '@faker-js/faker'; export type LogMessageGenerator = (f: Faker) => string[]; diff --git a/packages/kbn-xstate-utils/src/console_inspector.ts b/packages/kbn-xstate-utils/src/console_inspector.ts index b280fc90609c8..8792ab44f3c28 100644 --- a/packages/kbn-xstate-utils/src/console_inspector.ts +++ b/packages/kbn-xstate-utils/src/console_inspector.ts @@ -1,9 +1,10 @@ /* * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { From 34022938147f455c8f2b15e926d85df73b1552eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 12:27:26 +0000 Subject: [PATCH 34/74] Remove unused import --- .../log_categories/log_categories_grid_pattern_cell.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx index ce01bc8136416..87155e02ea048 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiDataGridColumn, euiFontSize, useEuiTheme } from '@elastic/eui'; +import { EuiDataGridColumn, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; From 542d1f1048f43c9e6f89f2f3a5106c4f7486ad3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 15:31:31 +0000 Subject: [PATCH 35/74] Revert term separators back to asterisks --- .../log_categories/log_categories_grid_pattern_cell.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx index 87155e02ea048..d507487a99e3c 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -48,11 +48,11 @@ export const LogCategoriesGridPatternCell: React.FC -
+
*
{termsList.map((term, index) => (
{term}
-
+
*
))} From eb089a655735608aa99a65d5d4b79a4970110566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 19:15:34 +0000 Subject: [PATCH 36/74] Add a logs_overview mock --- .../public/components/logs_overview/index.tsx | 8 +++++ .../logs_overview/logs_overview.mock.tsx | 32 +++++++++++++++++++ .../{ => logs_overview}/logs_overview.tsx | 18 +++++++++-- .../logs_shared/public/mocks.tsx | 2 ++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx rename x-pack/plugins/observability_solution/logs_shared/public/components/{ => logs_overview}/logs_overview.tsx (76%) diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx new file mode 100644 index 0000000000000..627cdc8447eea --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/index.tsx @@ -0,0 +1,8 @@ +/* + * 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 * from './logs_overview'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx new file mode 100644 index 0000000000000..435766bff793d --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.mock.tsx @@ -0,0 +1,32 @@ +/* + * 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 React from 'react'; +import type { + LogsOverviewProps, + SelfContainedLogsOverviewComponent, + SelfContainedLogsOverviewHelpers, +} from './logs_overview'; + +export const createLogsOverviewMock = () => { + const LogsOverviewMock = jest.fn(LogsOverviewMockImpl) as unknown as ILogsOverviewMock; + + LogsOverviewMock.useIsEnabled = jest.fn(() => true); + + LogsOverviewMock.ErrorContent = jest.fn(() =>
); + + LogsOverviewMock.LoadingContent = jest.fn(() =>
); + + return LogsOverviewMock; +}; + +const LogsOverviewMockImpl = (_props: LogsOverviewProps) => { + return
; +}; + +type ILogsOverviewMock = jest.Mocked & + jest.Mocked; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx similarity index 76% rename from x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx rename to x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx index 88bb77899d6d2..7b60aee5be57c 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logs_overview/logs_overview.tsx @@ -9,6 +9,7 @@ import { OBSERVABILITY_LOGS_SHARED_NEW_LOGS_OVERVIEW_ID } from '@kbn/management- import type { LogsOverviewProps as FullLogsOverviewProps, LogsOverviewDependencies, + LogsOverviewErrorContentProps, } from '@kbn/observability-logs-overview'; import { dynamic } from '@kbn/shared-ux-utility'; import React from 'react'; @@ -32,7 +33,20 @@ const LazyLogsOverviewLoadingContent = dynamic(() => export type LogsOverviewProps = Omit; -export const createLogsOverview = (dependencies: LogsOverviewDependencies) => { +export interface SelfContainedLogsOverviewHelpers { + useIsEnabled: () => boolean; + ErrorContent: React.ComponentType; + LoadingContent: React.ComponentType; +} + +export type SelfContainedLogsOverviewComponent = React.ComponentType; + +export type SelfContainedLogsOverview = SelfContainedLogsOverviewComponent & + SelfContainedLogsOverviewHelpers; + +export const createLogsOverview = ( + dependencies: LogsOverviewDependencies +): SelfContainedLogsOverview => { const SelfContainedLogsOverview = (props: LogsOverviewProps) => { return ; }; @@ -54,5 +68,3 @@ export const createLogsOverview = (dependencies: LogsOverviewDependencies) => { }; const defaultIsEnabled = false; - -export type SelfContainedLogsOverview = ReturnType; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx index a9b0ebd6a6aa3..ffb867abbcc17 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/mocks.tsx @@ -6,12 +6,14 @@ */ import { createLogAIAssistantMock } from './components/log_ai_assistant/log_ai_assistant.mock'; +import { createLogsOverviewMock } from './components/logs_overview/logs_overview.mock'; import { createLogViewsServiceStartMock } from './services/log_views/log_views_service.mock'; import { LogsSharedClientStartExports } from './types'; export const createLogsSharedPluginStartMock = (): jest.Mocked => ({ logViews: createLogViewsServiceStartMock(), LogAIAssistant: createLogAIAssistantMock(), + LogsOverview: createLogsOverviewMock(), }); export const _ensureTypeCompatibility = (): LogsSharedClientStartExports => From 78b0d4cb042a6cbb73065a2879828ac717be2291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 16 Sep 2024 20:19:31 +0000 Subject: [PATCH 37/74] Fix telemetry schema --- .../server/collectors/management/schema.ts | 6 ++++++ .../server/collectors/management/types.ts | 1 + src/plugins/telemetry/schema/oss_plugins.json | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index d1ab81f3e60a7..0b7b0b6bbb894 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -694,4 +694,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'observability:newLogsOverview': { + type: 'boolean', + _meta: { + description: 'Enable the new logs overview component.', + }, + }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index c66f4f07a296e..355619b50dbe4 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -55,6 +55,7 @@ export interface UsageStats { 'observability:apmEnableServiceInventoryTableSearchBar': boolean; 'observability:logsExplorer:allowedDataViews': string[]; 'observability:logSources': string[]; + 'observability:newLogsOverview': boolean; 'observability:aiAssistantLogsIndexPattern': string; 'observability:aiAssistantSimulatedFunctionCalling': boolean; 'observability:aiAssistantSearchConnectorIndexPattern': string; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 70fbeec73bc5d..e000b3f510d36 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10630,6 +10630,12 @@ "_meta": { "description": "Non-default value of setting." } + }, + "observability:newLogsOverview": { + "type": "boolean", + "_meta": { + "description": "Enable the new logs overview component." + } } } }, From c1962c0c0a187eed2faad49d8a9bd5ec3122a9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 18 Sep 2024 16:18:37 +0000 Subject: [PATCH 38/74] Add link to open all log entries in discover --- .../discover_link/discover_link.tsx | 108 ++++++++++++++++++ .../src/components/discover_link/index.ts | 8 ++ .../log_categories/log_categories.tsx | 3 + .../log_categories_control_bar.tsx | 44 +++++++ .../log_categories_result_content.tsx | 36 +++++- .../logs_shared/public/plugin.ts | 12 +- 6 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx new file mode 100644 index 0000000000000..f921cc8223424 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx @@ -0,0 +1,108 @@ +/* + * 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 type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiButton } from '@elastic/eui'; +import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; +import { FilterStateStore, buildCustomFilter } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; +import { getRouterLinkProps } from '@kbn/router-utils'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import React, { useCallback, useMemo } from 'react'; +import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; + +export interface DiscoverLinkProps { + documentFilters?: QueryDslQueryContainer[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; + dependencies: DiscoverLinkDependencies; +} + +export interface DiscoverLinkDependencies { + share: SharePluginStart; +} + +export const DiscoverLink = React.memo( + ({ dependencies: { share }, documentFilters, logsSource, timeRange }: DiscoverLinkProps) => { + const discoverLocatorParams = useMemo( + () => ({ + dataViewSpec: { + title: logsSource.indexName, + timeFieldName: logsSource.timestampField, + }, + timeRange: { + from: timeRange.start, + to: timeRange.end, + }, + filters: documentFilters?.map((filter) => + buildCustomFilter( + logsSource.indexName, + filter, + false, + false, + categorizedLogsFilterLabel, + FilterStateStore.APP_STATE + ) + ), + }), + [ + documentFilters, + logsSource.indexName, + logsSource.timestampField, + timeRange.end, + timeRange.start, + ] + ); + + const discoverLocator = useMemo( + () => share.url.locators.get('DISCOVER_APP_LOCATOR'), + [share.url.locators] + ); + + const discoverUrl = useMemo( + () => discoverLocator?.getRedirectUrl(discoverLocatorParams), + [discoverLocatorParams, discoverLocator] + ); + + const navigateToDiscover = useCallback(() => { + discoverLocator?.navigate(discoverLocatorParams); + }, [discoverLocatorParams, discoverLocator]); + + const discoverLinkProps = getRouterLinkProps({ + href: discoverUrl, + onClick: navigateToDiscover, + }); + + return ( + + {discoverLinkTitle} + + ); + } +); + +export const discoverLinkTitle = i18n.translate( + 'xpack.observabilityLogsOverview.discoverLinkTitle', + { + defaultMessage: 'Open in Discover', + } +); + +export const categorizedLogsFilterLabel = i18n.translate( + 'xpack.observabilityLogsOverview.categorizedLogsFilterLabel', + { + defaultMessage: 'Categorized log entries', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts b/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts new file mode 100644 index 0000000000000..738bf51d4529d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './discover_link'; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 93002bd388384..6204667827281 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -71,7 +71,10 @@ export const LogCategories: React.FC = ({ return ( ); } else if (categorizeLogsServiceState.matches('failed')) { diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx new file mode 100644 index 0000000000000..4538b0ec2fd5d --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx @@ -0,0 +1,44 @@ +/* + * 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 type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import React from 'react'; +import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { DiscoverLink } from '../discover_link'; + +export interface LogCategoriesControlBarProps { + documentFilters?: QueryDslQueryContainer[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; + dependencies: LogCategoriesControlBarDependencies; +} + +export interface LogCategoriesControlBarDependencies { + share: SharePluginStart; +} + +export const LogCategoriesControlBar: React.FC = React.memo( + ({ dependencies, documentFilters, logsSource, timeRange }) => { + return ( + + + + + + ); + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index 72413b2004c65..e16bdda7cb44a 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -5,30 +5,56 @@ * 2.0. */ -import { EuiEmptyPrompt } from '@elastic/eui'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { LogCategory } from '../../types'; +import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { + LogCategoriesControlBar, + LogCategoriesControlBarDependencies, +} from './log_categories_control_bar'; import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; export interface LogCategoriesResultContentProps { dependencies: LogCategoriesResultContentDependencies; + documentFilters?: QueryDslQueryContainer[]; logCategories: LogCategory[]; + logsSource: IndexNameLogsSourceConfiguration; + timeRange: { + start: string; + end: string; + }; } -export type LogCategoriesResultContentDependencies = LogCategoriesGridDependencies; +export type LogCategoriesResultContentDependencies = LogCategoriesControlBarDependencies & + LogCategoriesGridDependencies; export const LogCategoriesResultContent: React.FC = ({ dependencies, + documentFilters, logCategories, + logsSource, + timeRange, }) => { if (logCategories.length === 0) { return ; } else { return ( -
- -
+ + + + + + + + ); } }; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index 7cd0a9ab5258b..fc17e9b17cc82 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -53,8 +53,15 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { const { http, settings } = core; - const { charts, data, dataViews, discoverShared, logsDataAccess, observabilityAIAssistant } = - plugins; + const { + charts, + data, + dataViews, + discoverShared, + logsDataAccess, + observabilityAIAssistant, + share, + } = plugins; const logViews = this.logViews.start({ http, @@ -68,6 +75,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { logsDataAccess, search: data.search.search, uiSettings: settings, + share, }); if (!observabilityAIAssistant) { From 90282ccdd37ae5a4cf4b45fdd9cf5ce25eed58cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 18 Sep 2024 16:24:14 +0000 Subject: [PATCH 39/74] Fix dataview spec passed to locator --- .../src/components/discover_link/discover_link.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx index f921cc8223424..fe108289985a9 100644 --- a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx @@ -34,6 +34,8 @@ export const DiscoverLink = React.memo( const discoverLocatorParams = useMemo( () => ({ dataViewSpec: { + id: logsSource.indexName, + name: logsSource.indexName, title: logsSource.indexName, timeFieldName: logsSource.timestampField, }, From 1a90cb864306831dc43b5f14ea8b812332e7843c Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:54:28 +0000 Subject: [PATCH 40/74] [CI] Auto-commit changed files from 'node scripts/notice' --- x-pack/packages/observability/logs_overview/tsconfig.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 37fb31cdc68c2..886062ae8855f 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -31,5 +31,9 @@ "@kbn/ml-random-sampler-utils", "@kbn/zod", "@kbn/calculate-auto", + "@kbn/discover-plugin", + "@kbn/es-query", + "@kbn/router-utils", + "@kbn/share-plugin", ] } From 598d9a9b82d3d5396c0c163d35b72ceeba1a8d04 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:19:21 +0100 Subject: [PATCH 41/74] package.json changes from yarn kbn bootstrap --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d736eb483855..4f05ba83b424b 100644 --- a/package.json +++ b/package.json @@ -94,9 +94,9 @@ "**/sharp": "0.32.6", "**/typescript": "5.1.6", "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", - "@xstate5/react/**/xstate": "^5.18.1", "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", + "@xstate5/react/**/xstate": "^5.18.1", "globby/fast-glob": "^3.2.11" }, "dependencies": { From a34ab227e0b9322c31f3c2825aec6a344a9345a6 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:28:41 +0100 Subject: [PATCH 42/74] Fix two types --- .../components/log_categories/log_categories_error_content.tsx | 2 +- .../components/logs_overview/logs_overview_error_content.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx index 445eef7802598..1a335e3265294 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_error_content.tsx @@ -21,7 +21,7 @@ export const LogCategoriesErrorContent: React.FC title={

{logsOverviewErrorTitle}

} body={ -

{error?.stack ?? error ?? unknownErrorDescription}

+

{error?.stack ?? error?.toString() ?? unknownErrorDescription}

} layout="vertical" diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx index 0f3c08d536884..73586756bb908 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview_error_content.tsx @@ -21,7 +21,7 @@ export const LogsOverviewErrorContent: React.FC = title={

{logsOverviewErrorTitle}

} body={ -

{error?.stack ?? error ?? unknownErrorDescription}

+

{error?.stack ?? error?.toString() ?? unknownErrorDescription}

} layout="vertical" From c6d26db8c88cc22f47dd72a029979f24ef11ed36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 9 Oct 2024 14:54:44 +0000 Subject: [PATCH 43/74] Use timeField parameter instead of hard-coded field name --- .../src/services/categorize_logs_service/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts index 849567895f934..aef12da303bcc 100644 --- a/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts +++ b/x-pack/packages/observability/logs_overview/src/services/categorize_logs_service/queries.ts @@ -97,7 +97,7 @@ export const createCategorizationRequestParams = ({ aggs: randomSampler.wrap({ histogram: { date_histogram: { - field: '@timestamp', + field: timeField, fixed_interval: fixedIntervalSize, extended_bounds: { min: startTimestamp, From 7e34bc030322061162054543afbc81ae7a588429 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:35:19 +0100 Subject: [PATCH 44/74] Add a flyout to show category document examples --- .../data_types/logs/cell_actions_popover.tsx | 50 ++--- .../logs/summary_column/summary_column.tsx | 7 +- src/plugins/discover/public/plugin.tsx | 28 +++ src/plugins/discover/public/types.ts | 6 + .../discover_link/discover_link.tsx | 4 +- .../log_categories/log_categories.tsx | 49 ++++- .../log_categories_control_bar.tsx | 4 +- .../log_categories/log_categories_grid.tsx | 30 +++ .../log_categories_grid_cell.tsx | 2 +- .../log_categories_grid_expand_button.tsx | 71 +++++++ .../log_categories_grid_pattern_cell.tsx | 37 +--- .../log_categories_result_content.tsx | 38 +++- .../log_category_details_error_content.tsx | 41 ++++ .../log_category_details_flyout.tsx | 137 +++++++++++++ .../log_category_details_loading_content.tsx | 19 ++ .../log_category_document_examples_table.tsx | 139 +++++++++++++ .../logs_overview/logs_overview.tsx | 10 +- .../shared/log_category_pattern.tsx | 50 +++++ .../category_details_service.ts | 191 ++++++++++++++++++ .../category_documents.ts | 63 ++++++ .../category_details_service/index.ts | 8 + .../category_details_service/queries.ts | 58 ++++++ .../category_details_service/types.ts | 31 +++ .../logs_overview/src/utils/log_category.ts | 12 ++ .../logs_overview/src/utils/logs_source.ts | 53 ++++- .../observability/logs_overview/tsconfig.json | 2 + .../logs_shared/kibana.jsonc | 2 + .../logs_shared/public/plugin.ts | 7 + .../logs_shared/public/types.ts | 4 + .../logs_shared/tsconfig.json | 1 + 30 files changed, 1072 insertions(+), 82 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_error_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_loading_content.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/components/shared/log_category_pattern.tsx create mode 100644 x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/category_details_service/index.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts create mode 100644 x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts create mode 100644 x-pack/packages/observability/logs_overview/src/utils/log_category.ts diff --git a/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx b/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx index 7b9d68e8f3dd7..1858bb2323637 100644 --- a/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx +++ b/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx @@ -109,30 +109,32 @@ export function CellActionsPopover({ /> - - - - {filterForText} - - - {filterOutText} - - - + {onFilter ? ( + + + + {filterForText} + + + {filterOutText} + + + + ) : null} {(copy) => ( diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx b/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx index ac7e20b944a4a..1e0d79d59aedc 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx +++ b/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx @@ -39,8 +39,9 @@ export interface SummaryColumnFactoryDeps { } export type SummaryColumnProps = DataGridCellValueElementProps; +export type AllSummaryColumnProps = SummaryColumnProps & SummaryColumnFactoryDeps; -const SummaryColumn = (props: SummaryColumnProps & SummaryColumnFactoryDeps) => { +const SummaryColumn = (props: AllSummaryColumnProps) => { const { isDetails } = props; if (isDetails) { @@ -57,7 +58,7 @@ const SummaryCell = ({ density: maybeNullishDensity, rowHeight: maybeNullishRowHeight, ...props -}: SummaryColumnProps & SummaryColumnFactoryDeps) => { +}: AllSummaryColumnProps) => { const { onFilter, row } = props; const density = maybeNullishDensity ?? DataGridDensity.COMPACT; @@ -96,7 +97,7 @@ const SummaryCell = ({ ); }; -const SummaryCellPopover = (props: SummaryColumnProps & SummaryColumnFactoryDeps) => { +const SummaryCellPopover = (props: AllSummaryColumnProps) => { const { row, dataView, fieldFormats, onFilter, closePopover } = props; const resourceFields = createResourceFields(row); diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index dbbcc90a7d451..572888f872193 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -24,6 +24,9 @@ import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { SEARCH_EMBEDDABLE_TYPE, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; import { SavedSearchAttributes, SavedSearchType } from '@kbn/saved-search-plugin/common'; import { i18n } from '@kbn/i18n'; +import { dynamic } from '@kbn/shared-ux-utility'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; @@ -60,6 +63,12 @@ import { DataSourceProfileService } from './context_awareness/profiles/data_sour import { DocumentProfileService } from './context_awareness/profiles/document_profile'; import { ProfilesManager } from './context_awareness/profiles_manager'; import { DiscoverEBTManager } from './services/discover_ebt_manager'; +import type { AllSummaryColumnProps } from './components/data_types/logs/summary_column/summary_column'; +import { getLogLevelBadgeCell } from './components/data_types/logs/log_level_badge_cell'; + +const LazySummaryColumn = dynamic( + () => import('./components/data_types/logs/summary_column/summary_column') +); /** * Contains Discover, one of the oldest parts of Kibana @@ -314,6 +323,25 @@ export class DiscoverPlugin DiscoverContainer: (props: DiscoverContainerProps) => ( ), + logColumns: { + SummaryColumn: (props: AllSummaryColumnProps) => { + return ( + + + + ); + }, + getLogLevelCell: ( + logLevelField: string + ): React.ComponentType => { + const LogLevelCell = getLogLevelBadgeCell(logLevelField); + return (props: DataGridCellValueElementProps) => ( + + + + ); + }, + }, }; } diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index 3b24341e1a654..ea389ef25a67b 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -42,9 +42,11 @@ import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { DiscoverAppLocator } from '../common'; import { DiscoverCustomizationContext } from './customizations'; import { type DiscoverContainerProps } from './components/discover_container'; +import type { AllSummaryColumnProps } from './components/data_types/logs/summary_column/summary_column'; /** * @public @@ -121,6 +123,10 @@ export interface DiscoverStart { */ readonly locator: undefined | DiscoverAppLocator; readonly DiscoverContainer: ComponentType; + logColumns: { + SummaryColumn: (props: AllSummaryColumnProps) => React.JSX.Element; + getLogLevelCell: (logLevelField: string) => React.ComponentType; + }; } /** diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx index fe108289985a9..71dc7c26f343e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx @@ -13,11 +13,11 @@ import { i18n } from '@kbn/i18n'; import { getRouterLinkProps } from '@kbn/router-utils'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import React, { useCallback, useMemo } from 'react'; -import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import type { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; export interface DiscoverLinkProps { documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; + logsSource: ResolvedIndexNameLogsSourceConfiguration; timeRange: { start: string; end: string; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 6204667827281..e54cab30537fc 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -14,18 +14,23 @@ import { categorizeLogsService, createCategorizeLogsServiceImplementations, } from '../../services/categorize_logs_service'; -import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { LogCategoriesErrorContent } from './log_categories_error_content'; import { LogCategoriesLoadingContent } from './log_categories_loading_content'; import { LogCategoriesResultContent, LogCategoriesResultContentDependencies, } from './log_categories_result_content'; +import { + categoryDetailsService, + createCategoryDetailsServiceImplementations, +} from '../../services/category_details_service'; +import { LogCategory } from '../../types'; export interface LogCategoriesProps { dependencies: LogCategoriesDependencies; documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; + logsSource: ResolvedIndexNameLogsSourceConfiguration; // The time range could be made optional if we want to support an internal // time range picker timeRange: { @@ -61,12 +66,49 @@ export const LogCategories: React.FC = ({ } ); + const [categoryDetailsServiceState, sendToCategoryDetailsService] = useMachine( + categoryDetailsService.provide( + createCategoryDetailsServiceImplementations({ search: dependencies.search }) + ), + { + inspect: consoleInspector, + input: { + index: logsSource.indexName, + startTimestamp: timeRange.start, + endTimestamp: timeRange.end, + timeField: logsSource.timestampField, + messageField: logsSource.messageField, + additionalFilters: documentFilters, + dataView: logsSource.dataView, + }, + } + ); + const cancelOperation = useCallback(() => { sendToCategorizeLogsService({ type: 'cancel', }); }, [sendToCategorizeLogsService]); + const closeFlyout = useCallback(() => { + sendToCategoryDetailsService({ + type: 'setExpandedCategory', + category: null, + rowIndex: null, + }); + }, [sendToCategoryDetailsService]); + + const expandCategory = useCallback( + (category: LogCategory | null, rowIndex: number | null) => { + sendToCategoryDetailsService({ + type: 'setExpandedCategory', + category, + rowIndex, + }); + }, + [sendToCategoryDetailsService] + ); + if (categorizeLogsServiceState.matches('done')) { return ( = ({ logCategories={categorizeLogsServiceState.context.categories} logsSource={logsSource} timeRange={timeRange} + categoryDetailsServiceState={categoryDetailsServiceState} + onCloseFlyout={closeFlyout} + onExpandCategory={expandCategory} /> ); } else if (categorizeLogsServiceState.matches('failed')) { diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx index 4538b0ec2fd5d..0ec9121b2c972 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx @@ -9,12 +9,12 @@ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/type import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import React from 'react'; -import type { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import type { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { DiscoverLink } from '../discover_link'; export interface LogCategoriesControlBarProps { documentFilters?: QueryDslQueryContainer[]; - logsSource: IndexNameLogsSourceConfiguration; + logsSource: ResolvedIndexNameLogsSourceConfiguration; timeRange: { start: string; end: string; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx index d9e960685de99..6d4295c2534d1 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -9,6 +9,7 @@ import { EuiDataGrid, EuiDataGridColumnSortingConfig, EuiDataGridPaginationProps, + EuiScreenReaderOnly, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { createConsoleInspector } from '@kbn/xstate-utils'; @@ -25,17 +26,26 @@ import { logCategoriesGridColumns, renderLogCategoriesGridCell, } from './log_categories_grid_cell'; +import { createLogCategoriesGridExpandButton } from './log_categories_grid_expand_button'; export interface LogCategoriesGridProps { dependencies: LogCategoriesGridDependencies; logCategories: LogCategory[]; + expandedRowIndex: number | null; + onExpandCategory: (category: LogCategory, rowIndex: number) => void; + onCloseFlyout: () => void; } export type LogCategoriesGridDependencies = LogCategoriesGridCellDependencies; +const DEFAULT_CONTROL_COLUMN_WIDTH = 40; + export const LogCategoriesGrid: React.FC = ({ dependencies, logCategories, + expandedRowIndex, + onExpandCategory, + onCloseFlyout, }) => { const [gridState, dispatchGridEvent] = useMachine(gridStateService, { input: { @@ -93,6 +103,26 @@ export const LogCategoriesGrid: React.FC = ({ onSort: (sortingColumns) => dispatchGridEvent({ type: 'changeSortingColumns', sortingColumns }), }} + leadingControlColumns={[ + { + id: 'toggleFlyout', + width: DEFAULT_CONTROL_COLUMN_WIDTH, + headerCellRender: () => ( + + + {i18n.translate('xpack.observabilityLogsOverview.controlColumnHeader', { + defaultMessage: 'Control column', + })} + + + ), + rowCellRender: createLogCategoriesGridExpandButton({ + expandedRowIndex, + onExpandCategory, + onCloseFlyout, + }), + }, + ]} /> ); }; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx index d6ab4969eaf7b..7e40d192df227 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_cell.tsx @@ -83,7 +83,7 @@ export type LogCategoriesGridColumnId = (typeof logCategoriesGridColumns)[number const cellContextKey = 'cellContext'; -const getCellContext = (cellContext: object): LogCategoriesGridCellContext => +export const getCellContext = (cellContext: object): LogCategoriesGridCellContext => (cellContextKey in cellContext ? cellContext[cellContextKey] : {}) as LogCategoriesGridCellContext; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx new file mode 100644 index 0000000000000..8b44ccf47cc1e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx @@ -0,0 +1,71 @@ +/* + * 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 { EuiButtonIcon, EuiToolTip, RenderCellValue } from '@elastic/eui'; +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { getCellContext } from './log_categories_grid_cell'; +import { LogCategory } from '../../types'; + +const buttonLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.controlColumns.toggleFlyout', + { + defaultMessage: 'Toggle flyout with details', + } +); + +interface CreateLogCategoriesGridExpandButtonProps { + expandedRowIndex: number | null; + onExpandCategory: (category: LogCategory, rowIndex: number) => void; + onCloseFlyout: () => void; +} + +export const createLogCategoriesGridExpandButton = + ({ + expandedRowIndex, + onExpandCategory, + onCloseFlyout, + }: CreateLogCategoriesGridExpandButtonProps): RenderCellValue => + (props) => { + const { rowIndex } = props; + const { logCategories } = getCellContext(props); + const logCategory = logCategories[rowIndex]; + const isCurrentRowExpanded = expandedRowIndex === rowIndex; + const onClickHandler = useCallback(() => { + if (isCurrentRowExpanded) { + onCloseFlyout(); + } else { + onExpandCategory(logCategory, rowIndex); + } + }, [isCurrentRowExpanded, logCategory, rowIndex]); + + return ( + + ); + }; + +interface ExpandButtonProps { + isCurrentRowExpanded: boolean; + onClickHandler: () => void; +} + +const ExpandButton: React.FC = ({ isCurrentRowExpanded, onClickHandler }) => { + return ( + + + + ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx index d507487a99e3c..7507ab5b23f44 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_pattern_cell.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { EuiDataGridColumn, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { EuiDataGridColumn } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; +import React from 'react'; import { LogCategory } from '../../types'; +import { LogCategoryPattern } from '../shared/log_category_pattern'; export const logCategoriesGridPatternColumn = { id: 'pattern' as const, @@ -27,34 +27,5 @@ export interface LogCategoriesGridPatternCellProps { export const LogCategoriesGridPatternCell: React.FC = ({ logCategory, }) => { - const theme = useEuiTheme(); - const { euiTheme } = theme; - const termsList = useMemo(() => logCategory.terms.split(' '), [logCategory.terms]); - - const commonStyle = css` - display: inline-block; - font-family: ${euiTheme.font.familyCode}; - margin-right: ${euiTheme.size.xs}; - `; - - const termStyle = css` - ${commonStyle}; - `; - - const separatorStyle = css` - ${commonStyle}; - color: ${euiTheme.colors.successText}; - `; - - return ( -
-      
*
- {termsList.map((term, index) => ( - -
{term}
-
*
-
- ))} -
- ); + return ; }; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index e16bdda7cb44a..ad578e0599f83 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -9,27 +9,37 @@ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/type import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { StateFrom } from 'xstate5'; import { LogCategory } from '../../types'; -import { IndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { LogCategoriesControlBar, LogCategoriesControlBarDependencies, } from './log_categories_control_bar'; import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; +import { + LogCategoriesFlyoutDependencies, + LogCategoryDetailsFlyout, +} from '../log_category_details/log_category_details_flyout'; +import { categoryDetailsService } from '../../services/category_details_service'; export interface LogCategoriesResultContentProps { dependencies: LogCategoriesResultContentDependencies; documentFilters?: QueryDslQueryContainer[]; logCategories: LogCategory[]; - logsSource: IndexNameLogsSourceConfiguration; + logsSource: ResolvedIndexNameLogsSourceConfiguration; timeRange: { start: string; end: string; }; + categoryDetailsServiceState: StateFrom; + onCloseFlyout: () => void; + onExpandCategory: (category: LogCategory, rowIndex: number) => void; } export type LogCategoriesResultContentDependencies = LogCategoriesControlBarDependencies & - LogCategoriesGridDependencies; + LogCategoriesGridDependencies & + LogCategoriesFlyoutDependencies; export const LogCategoriesResultContent: React.FC = ({ dependencies, @@ -37,6 +47,9 @@ export const LogCategoriesResultContent: React.FC { if (logCategories.length === 0) { return ; @@ -52,7 +65,24 @@ export const LogCategoriesResultContent: React.FC - + + {categoryDetailsServiceState.context.expandedCategory && ( + + )} ); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_error_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_error_content.tsx new file mode 100644 index 0000000000000..509d35b0068e5 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_error_content.tsx @@ -0,0 +1,41 @@ +/* + * 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 { EuiCodeBlock, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export interface LogCategoryDetailsErrorContentProps { + error?: Error; + title: string; +} + +export const LogCategoryDetailsErrorContent: React.FC = ({ + error, + title, +}) => { + return ( + {title}} + body={ + +

{error?.stack ?? error?.toString() ?? unknownErrorDescription}

+
+ } + layout="vertical" + /> + ); +}; + +const unknownErrorDescription = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoryDetails.unknownErrorDescription', + { + defaultMessage: 'An unspecified error occurred.', + } +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx new file mode 100644 index 0000000000000..dc2e6bf50507b --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -0,0 +1,137 @@ +/* + * 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 { + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiSpacer, + EuiTitle, + useGeneratedHtmlId, +} from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { StateFrom } from 'xstate5'; +import { SettingsStart } from '@kbn/core-ui-settings-browser'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { DiscoverStart } from '@kbn/discover-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; +import { SharePluginStart } from '@kbn/share-plugin/public'; +import { LogCategory } from '../../types'; +import { LogCategoryPattern } from '../shared/log_category_pattern'; +import { categoryDetailsService } from '../../services/category_details_service'; +import { LogCategoryDocumentExamplesTable } from './log_category_document_examples_table'; +import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { LogCategoryDetailsLoadingContent } from './log_category_details_loading_content'; +import { LogCategoryDetailsErrorContent } from './log_category_details_error_content'; +import { DiscoverLink } from '../discover_link'; +import { createCategoryQuery } from '../../services/categorize_logs_service/queries'; + +export interface LogCategoriesFlyoutDependencies { + uiSettings: SettingsStart; + fieldFormats: FieldFormatsStart; + share: SharePluginStart; + columns: { + SummaryColumn: DiscoverStart['logColumns']['SummaryColumn']; + LogLevelCell: ReturnType; + }; +} + +interface LogCategoryDetailsFlyoutProps { + onCloseFlyout: () => void; + logCategory: LogCategory; + categoryDetailsServiceState: StateFrom; + dependencies: LogCategoriesFlyoutDependencies; + logsSource: ResolvedIndexNameLogsSourceConfiguration; + documentFilters?: QueryDslQueryContainer[]; + timeRange: { + start: string; + end: string; + }; +} + +export const LogCategoryDetailsFlyout: React.FC = ({ + onCloseFlyout, + logCategory, + categoryDetailsServiceState, + dependencies, + logsSource, + documentFilters, + timeRange, +}) => { + const flyoutTitleId = useGeneratedHtmlId({ + prefix: 'flyoutTitle', + }); + + const linkFilters = useMemo(() => { + return [ + ...(documentFilters ? documentFilters : []), + createCategoryQuery(logsSource.messageField)(logCategory.terms), + ]; + }, [documentFilters, logCategory.terms, logsSource.messageField]); + + return ( + onCloseFlyout()} aria-labelledby={flyoutTitleId}> + + + + +

+ , + }} + /> +

+
+
+ + + + +
+
+ + {categoryDetailsServiceState.matches({ hasCategory: 'fetchingDocuments' }) ? ( + + ) : categoryDetailsServiceState.matches({ hasCategory: 'error' }) ? ( + + ) : ( + + )} + +
+ ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_loading_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_loading_content.tsx new file mode 100644 index 0000000000000..fd6aa50a38221 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_loading_content.tsx @@ -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 { EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; +import React from 'react'; + +interface LogCategoryDetailsLoadingContentProps { + message: string; +} + +export const LogCategoryDetailsLoadingContent: React.FC = ({ + message, +}) => { + return } title={

{message}

} />; +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx new file mode 100644 index 0000000000000..cbd2896463e3a --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -0,0 +1,139 @@ +/* + * 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 { EuiBasicTable, EuiBasicTableColumn, EuiSpacer, EuiText } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; +import moment from 'moment'; +import { LogCategoryDocument } from '../../services/category_details_service/types'; +import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import type { LogCategoriesFlyoutDependencies } from './log_category_details_flyout'; + +export type LogCategoryDocumentExamplesTableDependencies = LogCategoriesFlyoutDependencies; + +export interface LogCategoryDocumentExamplesTableProps { + dependencies: LogCategoryDocumentExamplesTableDependencies; + categoryDocuments: LogCategoryDocument[]; + logsSource: ResolvedIndexNameLogsSourceConfiguration; +} + +const TimestampCell = ({ + dependencies, + timestamp, +}: { + dependencies: LogCategoryDocumentExamplesTableDependencies; + timestamp?: string | number; +}) => { + const dateFormat = useMemo( + () => dependencies.uiSettings.client.get('dateFormat'), + [dependencies.uiSettings.client] + ); + if (!timestamp) return null; + + if (dateFormat) { + return <>{moment(timestamp).format(dateFormat)}; + } else { + return <>{timestamp}; + } +}; + +export const LogCategoryDocumentExamplesTable: React.FC = ({ + categoryDocuments, + dependencies, + logsSource, +}) => { + const columns: Array> = [ + { + field: 'row', + name: 'Timestamp', + width: '20%', + render: (row: any) => { + return ( + + ); + }, + }, + { + field: 'row', + name: 'Log level', + width: '10%', + render: (row: any) => { + return ( + {}} + closePopover={() => {}} + /> + ); + }, + }, + { + field: 'row', + name: 'Summary', + width: '70%', + render: (row: any) => { + return ( + {}} + closePopover={() => {}} + density={DataGridDensity.COMPACT} + rowHeight={ROWS_HEIGHT_OPTIONS.single} + shouldShowFieldHandler={() => false} + /> + ); + }, + }, + ]; + return ( + <> + + {i18n.translate( + 'xpack.observabilityLogsOverview.logCategoryDocumentExamplesTable.documentCountText', + { + defaultMessage: 'Displaying the last {documentsCount} documents.', + values: { + documentsCount: categoryDocuments.length, + }, + } + )} + + + + + ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx index 988656eb1571e..77535228f7af6 100644 --- a/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/logs_overview/logs_overview.tsx @@ -9,6 +9,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { type LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import React from 'react'; import useAsync from 'react-use/lib/useAsync'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; import { LogsSourceConfiguration, normalizeLogsSource } from '../../utils/logs_source'; import { LogCategories, LogCategoriesDependencies } from '../log_categories'; import { LogsOverviewErrorContent } from './logs_overview_error_content'; @@ -26,6 +27,7 @@ export interface LogsOverviewProps { export type LogsOverviewDependencies = LogCategoriesDependencies & { logsDataAccess: LogsDataAccessPluginStart; + dataViews: DataViewsContract; }; export const LogsOverview: React.FC = React.memo( @@ -36,8 +38,12 @@ export const LogsOverview: React.FC = React.memo( timeRange, }) => { const normalizedLogsSource = useAsync( - () => normalizeLogsSource({ logsDataAccess: dependencies.logsDataAccess })(logsSource), - [dependencies.logsDataAccess, logsSource] + () => + normalizeLogsSource({ + logsDataAccess: dependencies.logsDataAccess, + dataViewsService: dependencies.dataViews, + })(logsSource), + [dependencies.dataViews, dependencies.logsDataAccess, logsSource] ); if (normalizedLogsSource.loading) { diff --git a/x-pack/packages/observability/logs_overview/src/components/shared/log_category_pattern.tsx b/x-pack/packages/observability/logs_overview/src/components/shared/log_category_pattern.tsx new file mode 100644 index 0000000000000..8a8deb5918324 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/shared/log_category_pattern.tsx @@ -0,0 +1,50 @@ +/* + * 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 { useEuiTheme } from '@elastic/eui'; +import { useMemo } from 'react'; +import { css } from '@emotion/react'; +import React from 'react'; +import { getLogCategoryTerms } from '../../utils/log_category'; +import { LogCategory } from '../../types'; + +interface LogCategoryPatternProps { + logCategory: LogCategory; +} + +export const LogCategoryPattern: React.FC = ({ logCategory }) => { + const theme = useEuiTheme(); + const { euiTheme } = theme; + const termsList = useMemo(() => getLogCategoryTerms(logCategory), [logCategory]); + + const commonStyle = css` + display: inline-block; + font-family: ${euiTheme.font.familyCode}; + margin-right: ${euiTheme.size.xs}; + `; + + const termStyle = css` + ${commonStyle}; + `; + + const separatorStyle = css` + ${commonStyle}; + color: ${euiTheme.colors.successText}; + `; + + return ( +
+      
*
+ {termsList.map((term, index) => ( + +
{term}
+
*
+
+ ))} +
+ ); +}; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts new file mode 100644 index 0000000000000..958f717548600 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts @@ -0,0 +1,191 @@ +/* + * 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 { MachineImplementationsFrom, assign, setup } from 'xstate5'; +import { LogCategory } from '../../types'; +import { getPlaceholderFor } from '../../utils/xstate5_utils'; +import { + CategoryDetailsServiceDependencies, + LogCategoryDocument, + LogCategoryDetailsParams, +} from './types'; +import { getCategoryDocuments } from './category_documents'; + +export const categoryDetailsService = setup({ + types: { + input: {} as LogCategoryDetailsParams, + output: {} as { + categoryDocuments: LogCategoryDocument[] | null; + }, + context: {} as { + parameters: LogCategoryDetailsParams; + error?: Error; + expandedRowIndex: number | null; + expandedCategory: LogCategory | null; + categoryDocuments: LogCategoryDocument[]; + }, + events: {} as + | { + type: 'cancel'; + } + | { + type: 'setExpandedCategory'; + rowIndex: number | null; + category: LogCategory | null; + }, + }, + actors: { + getCategoryDocuments: getPlaceholderFor(getCategoryDocuments), + }, + actions: { + storeCategory: assign( + ({ context, event }, params: { category: LogCategory | null; rowIndex: number | null }) => ({ + expandedCategory: params.category, + expandedRowIndex: params.rowIndex, + }) + ), + storeDocuments: assign( + ({ context, event }, params: { categoryDocuments: LogCategoryDocument[] }) => ({ + categoryDocuments: params.categoryDocuments, + }) + ), + storeError: assign((_, params: { error: unknown }) => ({ + error: params.error instanceof Error ? params.error : new Error(String(params.error)), + })), + }, + guards: { + hasCategory: (_guardArgs, params: { expandedCategory: LogCategory | null }) => + params.expandedCategory !== null, + hasDocumentExamples: ( + _guardArgs, + params: { categoryDocuments: LogCategoryDocument[] | null } + ) => params.categoryDocuments !== null && params.categoryDocuments.length > 0, + }, +}).createMachine({ + /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ + id: 'logCategoryDetails', + context: ({ input }) => ({ + expandedCategory: null, + expandedRowIndex: null, + categoryDocuments: [], + parameters: input, + }), + initial: 'idle', + states: { + idle: { + on: { + setExpandedCategory: { + target: 'checkingCategoryState', + actions: [ + { + type: 'storeCategory', + params: ({ event }) => event, + }, + ], + }, + }, + }, + checkingCategoryState: { + always: [ + { + guard: { + type: 'hasCategory', + params: ({ event, context }) => { + return { + expandedCategory: context.expandedCategory, + }; + }, + }, + target: '#hasCategory.fetchingDocuments', + }, + { target: 'idle' }, + ], + }, + hasCategory: { + id: 'hasCategory', + initial: 'fetchingDocuments', + on: { + setExpandedCategory: { + target: 'checkingCategoryState', + actions: [ + { + type: 'storeCategory', + params: ({ event }) => event, + }, + ], + }, + }, + states: { + fetchingDocuments: { + invoke: { + src: 'getCategoryDocuments', + id: 'fetchCategoryDocumentExamples', + input: ({ context }) => ({ + ...context.parameters, + categoryTerms: context.expandedCategory!.terms, + }), + onDone: [ + { + guard: { + type: 'hasDocumentExamples', + params: ({ event }) => { + return event.output; + }, + }, + target: 'hasData', + actions: [ + { + type: 'storeDocuments', + params: ({ event }) => { + return event.output; + }, + }, + ], + }, + { + target: 'noData', + actions: [ + { + type: 'storeDocuments', + params: ({ event }) => { + return { categoryDocuments: [] }; + }, + }, + ], + }, + ], + onError: { + target: 'error', + actions: [ + { + type: 'storeError', + params: ({ event }) => ({ error: event.error }), + }, + ], + }, + }, + }, + hasData: {}, + noData: {}, + error: {}, + }, + }, + }, + output: ({ context }) => ({ + categoryDocuments: context.categoryDocuments, + }), +}); + +export const createCategoryDetailsServiceImplementations = ({ + search, +}: CategoryDetailsServiceDependencies): MachineImplementationsFrom< + typeof categoryDetailsService +> => ({ + actors: { + getCategoryDocuments: getCategoryDocuments({ search }), + }, +}); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts new file mode 100644 index 0000000000000..b513fa79fc686 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts @@ -0,0 +1,63 @@ +/* + * 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 { ISearchGeneric } from '@kbn/search-types'; +import { fromPromise } from 'xstate5'; +import { lastValueFrom } from 'rxjs'; +import { flattenHit } from '@kbn/data-service'; +import { LogCategoryDocument, LogCategoryDocumentsParams } from './types'; +import { createGetLogCategoryDocumentsRequestParams } from './queries'; + +export const getCategoryDocuments = ({ search }: { search: ISearchGeneric }) => + fromPromise< + { + categoryDocuments: LogCategoryDocument[]; + }, + LogCategoryDocumentsParams + >( + async ({ + input: { + index, + endTimestamp, + startTimestamp, + timeField, + messageField, + categoryTerms, + additionalFilters = [], + dataView, + }, + signal, + }) => { + const requestParams = createGetLogCategoryDocumentsRequestParams({ + index, + timeField, + messageField, + startTimestamp, + endTimestamp, + additionalFilters, + categoryTerms, + }); + + const { rawResponse } = await lastValueFrom( + search({ params: requestParams }, { abortSignal: signal }) + ); + + const categoryDocuments: LogCategoryDocument[] = + rawResponse.hits?.hits.map((hit) => { + return { + row: { + raw: hit._source, + flattened: flattenHit(hit, dataView), + }, + }; + }) ?? []; + + return { + categoryDocuments, + }; + } + ); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/index.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/index.ts new file mode 100644 index 0000000000000..5df79dbab2cbd --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './category_details_service'; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts new file mode 100644 index 0000000000000..e9872afbf2669 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts @@ -0,0 +1,58 @@ +/* + * 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { createCategoryQuery } from '../categorize_logs_service/queries'; + +export const createGetLogCategoryDocumentsRequestParams = ({ + index, + timeField, + messageField, + startTimestamp, + endTimestamp, + additionalFilters = [], + categoryTerms = '', + documentCount = 20, +}: { + startTimestamp: string; + endTimestamp: string; + index: string; + timeField: string; + messageField: string; + additionalFilters?: QueryDslQueryContainer[]; + categoryTerms?: string; + documentCount?: number; +}) => { + return { + index, + size: documentCount, + track_total_hits: false, + sort: [{ [timeField]: { order: 'desc' } }], + query: { + bool: { + filter: [ + { + exists: { + field: messageField, + }, + }, + { + range: { + [timeField]: { + gte: startTimestamp, + lte: endTimestamp, + format: 'strict_date_time', + }, + }, + }, + ...additionalFilters, + ], + must: createCategoryQuery(messageField)(categoryTerms), + }, + }, + }; +}; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts new file mode 100644 index 0000000000000..72369275578e3 --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts @@ -0,0 +1,31 @@ +/* + * 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { ISearchGeneric } from '@kbn/search-types'; +import { type DataView } from '@kbn/data-views-plugin/common'; +import type { DataTableRecord } from '@kbn/discover-utils'; + +export interface LogCategoryDocument { + row: Pick; +} + +export interface LogCategoryDetailsParams { + additionalFilters: QueryDslQueryContainer[]; + endTimestamp: string; + index: string; + messageField: string; + startTimestamp: string; + timeField: string; + dataView: DataView; +} + +export interface CategoryDetailsServiceDependencies { + search: ISearchGeneric; +} + +export type LogCategoryDocumentsParams = LogCategoryDetailsParams & { categoryTerms: string }; diff --git a/x-pack/packages/observability/logs_overview/src/utils/log_category.ts b/x-pack/packages/observability/logs_overview/src/utils/log_category.ts new file mode 100644 index 0000000000000..3a5e72522d78e --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/utils/log_category.ts @@ -0,0 +1,12 @@ +/* + * 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 { LogCategory } from '../types'; + +export const getLogCategoryTerms = (logCategory: LogCategory) => { + return logCategory.terms.split(' '); +}; diff --git a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts index 0c8767c8702d4..15c318766be0e 100644 --- a/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts +++ b/x-pack/packages/observability/logs_overview/src/utils/logs_source.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type AbstractDataView } from '@kbn/data-views-plugin/common'; +import { type DataViewsContract, type DataView } from '@kbn/data-views-plugin/common'; import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; export type LogsSourceConfiguration = @@ -28,33 +28,68 @@ export interface IndexNameLogsSourceConfiguration { export interface DataViewLogsSourceConfiguration { type: 'data_view'; - dataView: AbstractDataView; + dataView: DataView; messageField?: string; } +export type ResolvedIndexNameLogsSourceConfiguration = IndexNameLogsSourceConfiguration & { + dataView: DataView; +}; + export const normalizeLogsSource = - ({ logsDataAccess }: { logsDataAccess: LogsDataAccessPluginStart }) => - async (logsSource: LogsSourceConfiguration): Promise => { + ({ + logsDataAccess, + dataViewsService, + }: { + logsDataAccess: LogsDataAccessPluginStart; + dataViewsService: DataViewsContract; + }) => + async ( + logsSource: LogsSourceConfiguration + ): Promise => { switch (logsSource.type) { case 'index_name': - return logsSource; + return { + ...logsSource, + dataView: await getDataViewForLogSource(logsSource, dataViewsService), + }; case 'shared_setting': const logSourcesFromSharedSettings = await logsDataAccess.services.logSourcesService.getLogSources(); - return { - type: 'index_name', + const sharedSettingLogsSource = { + type: 'index_name' as const, indexName: logSourcesFromSharedSettings .map((logSource) => logSource.indexPattern) .join(','), timestampField: logsSource.timestampField ?? '@timestamp', messageField: logsSource.messageField ?? 'message', }; - case 'data_view': return { - type: 'index_name', + ...sharedSettingLogsSource, + dataView: await getDataViewForLogSource(sharedSettingLogsSource, dataViewsService), + }; + case 'data_view': + const dataViewLogsSource = { + type: 'index_name' as const, indexName: logsSource.dataView.getIndexPattern(), timestampField: logsSource.dataView.timeFieldName ?? '@timestamp', messageField: logsSource.messageField ?? 'message', }; + return { + ...dataViewLogsSource, + dataView: logsSource.dataView, + }; } }; + +// Ad-hoc Data View +const getDataViewForLogSource = async ( + logSourceConfiguration: IndexNameLogsSourceConfiguration, + dataViewsService: DataViewsContract +) => { + const dataView = await dataViewsService.create({ + title: logSourceConfiguration.indexName, + timeFieldName: logSourceConfiguration.timestampField, + }); + return dataView; +}; diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 886062ae8855f..ff229bb68829e 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -35,5 +35,7 @@ "@kbn/es-query", "@kbn/router-utils", "@kbn/share-plugin", + "@kbn/field-formats-plugin", + "@kbn/unified-data-table", ] } diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index 10c8fe32cfe9c..a6329c585800a 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -11,8 +11,10 @@ "requiredPlugins": [ "charts", "data", + "fieldFormats", "dataViews", "discoverShared", + "discover", "logsDataAccess", "observabilityShared", "share", diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts index fc17e9b17cc82..a1ae176d5c161 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts @@ -61,6 +61,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { logsDataAccess, observabilityAIAssistant, share, + fieldFormats, } = plugins; const logViews = this.logViews.start({ @@ -76,6 +77,12 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { search: data.search.search, uiSettings: settings, share, + dataViews, + fieldFormats, + columns: { + SummaryColumn: plugins.discover.logColumns.SummaryColumn, + LogLevelCell: plugins.discover.logColumns.getLogLevelCell('log.level'), + }, }); if (!observabilityAIAssistant) { diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index 4237c28c621b8..ce199cb01cd79 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -14,6 +14,8 @@ import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/pub import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { DiscoverStart } from '@kbn/discover-plugin/public'; import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; import type { SelfContainedLogsOverview } from './components/logs_overview'; @@ -40,10 +42,12 @@ export interface LogsSharedClientStartDeps { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; discoverShared: DiscoverSharedPublicStart; + discover: DiscoverStart; logsDataAccess: LogsDataAccessPluginStart; observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; share: SharePluginStart; uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; } export type LogsSharedClientCoreSetup = CoreSetup< diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 788f55c9b6fc5..f171c79afccd0 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -48,5 +48,6 @@ "@kbn/observability-logs-overview", "@kbn/charts-plugin", "@kbn/core-ui-settings-common", + "@kbn/field-formats-plugin", ] } From 246b0f778b81553847717d3fbe201456c4aef028 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:57:31 +0000 Subject: [PATCH 45/74] [CI] Auto-commit changed files from 'node scripts/notice' --- x-pack/packages/observability/logs_overview/tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index ff229bb68829e..a1e7847935fc2 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -37,5 +37,7 @@ "@kbn/share-plugin", "@kbn/field-formats-plugin", "@kbn/unified-data-table", + "@kbn/data-service", + "@kbn/discover-utils", ] } From 6a5087e2cc784dd7e9f0d178800c40f129b548c9 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:58:21 +0000 Subject: [PATCH 46/74] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/observability_solution/logs_shared/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index f171c79afccd0..47ca88b558171 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -49,5 +49,6 @@ "@kbn/charts-plugin", "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", + "@kbn/discover-plugin", ] } From 0b08c2caecdaab1ae8b144178c25c544d537b353 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:17:56 +0100 Subject: [PATCH 47/74] Remove line from merge conflict --- .../metrics/hosts/components/tabs/logs/logs_tab_content.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx index 78443c9a6ec81..68a5db6d4d484 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/logs/logs_tab_content.tsx @@ -85,7 +85,6 @@ export const LogsTabLogStreamContent = () => { query={logsLinkToStreamQuery} logView={logView} /> - ] From c290819c1c1e1cb5a67d437cca7783c0e2302c8f Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:30:50 +0100 Subject: [PATCH 48/74] Extract out columns / cells to new package - This is to avoid many circular dependencies --- package.json | 1 + .../README.md | 3 + .../jest.config.js | 11 +- .../kibana.jsonc | 5 + .../package.json | 6 + .../logs/components}/cell_actions_popover.tsx | 6 +- .../src/data_types/logs/components/index.ts | 10 + .../log_level_badge_cell.test.tsx | 4 +- .../log_level_badge_cell.tsx | 6 +- .../service_name_badge_with_actions.tsx | 9 +- .../components}/summary_column/content.tsx | 2 +- .../logs/components/summary_column/index.ts | 13 + .../components}/summary_column/resource.tsx | 5 +- .../summary_column/summary_column.test.tsx | 50 +-- .../summary_column/summary_column.tsx | 171 ++++++++++ .../logs/components}/summary_column/utils.tsx | 59 ++-- .../logs/components/translations.tsx | 305 ++++++++++++++++++ .../tsconfig.json | 36 +++ packages/kbn-discover-utils/index.ts | 2 +- .../logs/components/{index.ts => index.tsx} | 0 .../src/data_types/logs/constants.ts | 70 ++++ .../src/data_types/logs/index.ts | 2 +- .../src/data_types/logs/types.ts | 7 + .../utils/get_available_resource_fields.ts | 4 +- packages/kbn-discover-utils/tsconfig.json | 4 +- .../common/data_types/logs/constants.ts | 62 +--- .../data_types/logs/summary_column/index.tsx | 8 +- .../logs/summary_column/summary_column.tsx | 173 +--------- .../accessors/get_cell_renderers.tsx | 2 +- src/plugins/discover/public/plugin.tsx | 28 -- src/plugins/discover/public/types.ts | 6 - src/plugins/discover/tsconfig.json | 6 +- src/plugins/unified_doc_viewer/kibana.jsonc | 1 + tsconfig.base.json | 2 + .../log_category_details_flyout.tsx | 7 +- .../observability/logs_overview/tsconfig.json | 5 +- .../logs_shared/kibana.jsonc | 2 +- .../public/{plugin.ts => plugin.tsx} | 17 +- .../logs_shared/tsconfig.json | 1 + yarn.lock | 4 + 40 files changed, 769 insertions(+), 346 deletions(-) create mode 100644 packages/kbn-discover-contextual-components/README.md rename src/plugins/discover/common/data_types/logs/display_options.ts => packages/kbn-discover-contextual-components/jest.config.js (75%) create mode 100644 packages/kbn-discover-contextual-components/kibana.jsonc create mode 100644 packages/kbn-discover-contextual-components/package.json rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/cell_actions_popover.tsx (95%) create mode 100644 packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell}/log_level_badge_cell.test.tsx (93%) rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell}/log_level_badge_cell.tsx (85%) rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/service_name_badge_with_actions.tsx (85%) rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/summary_column/content.tsx (97%) create mode 100644 packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/index.ts rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/summary_column/resource.tsx (89%) rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/summary_column/summary_column.test.tsx (86%) create mode 100644 packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx rename {src/plugins/discover/public/components/data_types/logs => packages/kbn-discover-contextual-components/src/data_types/logs/components}/summary_column/utils.tsx (72%) create mode 100644 packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx create mode 100644 packages/kbn-discover-contextual-components/tsconfig.json rename packages/kbn-discover-utils/src/data_types/logs/components/{index.ts => index.tsx} (100%) create mode 100644 packages/kbn-discover-utils/src/data_types/logs/constants.ts rename {src/plugins/discover/public => packages/kbn-discover-utils/src/data_types/logs}/utils/get_available_resource_fields.ts (87%) rename x-pack/plugins/observability_solution/logs_shared/public/{plugin.ts => plugin.tsx} (78%) diff --git a/package.json b/package.json index f6412a3da925a..9f36437008219 100644 --- a/package.json +++ b/package.json @@ -452,6 +452,7 @@ "@kbn/default-nav-ml": "link:packages/default-nav/ml", "@kbn/dev-tools-plugin": "link:src/plugins/dev_tools", "@kbn/developer-examples-plugin": "link:examples/developer_examples", + "@kbn/discover-contextual-components": "link:packages/kbn-discover-contextual-components", "@kbn/discover-customization-examples-plugin": "link:examples/discover_customization_examples", "@kbn/discover-enhanced-plugin": "link:x-pack/plugins/discover_enhanced", "@kbn/discover-plugin": "link:src/plugins/discover", diff --git a/packages/kbn-discover-contextual-components/README.md b/packages/kbn-discover-contextual-components/README.md new file mode 100644 index 0000000000000..ae9e2402c2a69 --- /dev/null +++ b/packages/kbn-discover-contextual-components/README.md @@ -0,0 +1,3 @@ +# @kbn/discover-contextual-components + +Houses contextual (e.g. logs) components that are used by Discover. diff --git a/src/plugins/discover/common/data_types/logs/display_options.ts b/packages/kbn-discover-contextual-components/jest.config.js similarity index 75% rename from src/plugins/discover/common/data_types/logs/display_options.ts rename to packages/kbn-discover-contextual-components/jest.config.js index 05803ba0bde7f..37624c643d4d0 100644 --- a/src/plugins/discover/common/data_types/logs/display_options.ts +++ b/packages/kbn-discover-contextual-components/jest.config.js @@ -7,9 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export interface SmartFieldGridColumnOptions { - type: 'smart-field'; - smartField: 'content' | 'resource'; - fallbackFields: string[]; - width?: number; -} +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-discover-contextual-components'], +}; diff --git a/packages/kbn-discover-contextual-components/kibana.jsonc b/packages/kbn-discover-contextual-components/kibana.jsonc new file mode 100644 index 0000000000000..8e06123264576 --- /dev/null +++ b/packages/kbn-discover-contextual-components/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/discover-contextual-components", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/packages/kbn-discover-contextual-components/package.json b/packages/kbn-discover-contextual-components/package.json new file mode 100644 index 0000000000000..ef68d35fa857f --- /dev/null +++ b/packages/kbn-discover-contextual-components/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/discover-contextual-components", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" +} \ No newline at end of file diff --git a/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx similarity index 95% rename from src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx index 1858bb2323637..2eaebd6e5fe6a 100644 --- a/src/plugins/discover/public/components/data_types/logs/cell_actions_popover.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx @@ -24,7 +24,9 @@ import { import { css } from '@emotion/react'; import { useBoolean } from '@kbn/react-hooks'; import { euiThemeVars } from '@kbn/ui-theme'; -import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { CoreStart } from '@kbn/core-lifecycle-browser'; import { actionFilterForText, actionFilterOutText, @@ -158,6 +160,8 @@ export function CellActionsPopover({ export interface FieldBadgeWithActionsProps extends Pick { icon?: EuiBadgeProps['iconType']; + core?: CoreStart; + share?: SharePluginStart; } export function FieldBadgeWithActions({ diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts b/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts new file mode 100644 index 0000000000000..65832358f15b5 --- /dev/null +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts @@ -0,0 +1,10 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './summary_column'; diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.test.tsx similarity index 93% rename from src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.test.tsx index 319f3738a6682..460c97dfd115b 100644 --- a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.test.tsx @@ -7,12 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { buildDataTableRecord, DataTableRecord } from '@kbn/discover-utils'; -import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; import { render, screen } from '@testing-library/react'; import React from 'react'; import { getLogLevelBadgeCell } from './log_level_badge_cell'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__/data_view'; +import { DataTableRecord, buildDataTableRecord } from '@kbn/discover-utils'; const renderCell = (logLevelField: string, record: DataTableRecord) => { const LogLevelBadgeCell = getLogLevelBadgeCell(logLevelField); diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.tsx similarity index 85% rename from src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.tsx index bff3bdddee026..9b7f766911760 100644 --- a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell.tsx @@ -9,8 +9,8 @@ import type { CSSObject } from '@emotion/react'; import React from 'react'; -import { LogLevelBadge } from '@kbn/discover-utils'; -import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table/src/types'; +import { LogLevelBadge } from '@kbn/discover-utils/src/data_types/logs/components/log_level_badge'; const dataTestSubj = 'logLevelBadgeCell'; const badgeCss: CSSObject = { marginTop: '-4px' }; @@ -32,3 +32,5 @@ export const getLogLevelBadgeCell = /> ); }; + +export type LogLevelBadgeCell = ReturnType; diff --git a/src/plugins/discover/public/components/data_types/logs/service_name_badge_with_actions.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/service_name_badge_with_actions.tsx similarity index 85% rename from src/plugins/discover/public/components/data_types/logs/service_name_badge_with_actions.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/service_name_badge_with_actions.tsx index 581c889b8e98e..87d212f8bb372 100644 --- a/src/plugins/discover/public/components/data_types/logs/service_name_badge_with_actions.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/service_name_badge_with_actions.tsx @@ -11,17 +11,16 @@ import React from 'react'; import { getRouterLinkProps } from '@kbn/router-utils'; import { EuiLink } from '@elastic/eui'; import { OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE } from '@kbn/management-settings-ids'; -import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; -import { useDiscoverServices } from '../../../hooks/use_discover_services'; +import type { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { FieldBadgeWithActions, FieldBadgeWithActionsProps } from './cell_actions_popover'; const SERVICE_ENTITY_LOCATOR = 'SERVICE_ENTITY_LOCATOR'; export function ServiceNameBadgeWithActions(props: FieldBadgeWithActionsProps) { - const { share, core } = useDiscoverServices(); - const canViewApm = core.application.capabilities.apm?.show || false; + const { share, core } = props; + const canViewApm = core?.application.capabilities.apm?.show || false; const isEntityCentricExperienceSettingEnabled = canViewApm - ? core.uiSettings.get(OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE) + ? core?.uiSettings.get(OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE) : false; const derivedPropsForEntityExperience = isEntityCentricExperienceSettingEnabled diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/content.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx similarity index 97% rename from src/plugins/discover/public/components/data_types/logs/summary_column/content.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx index 0da98cbf7145e..7ca3944e6aed6 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/content.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx @@ -14,7 +14,7 @@ import { getLogDocumentOverview, getMessageFieldWithFallbacks, } from '@kbn/discover-utils'; -import * as constants from '../../../../../common/data_types/logs/constants'; +import * as constants from '@kbn/discover-utils/src/data_types/logs/constants'; import { formatJsonDocumentForContent } from './utils'; interface ContentProps extends DataGridCellValueElementProps { diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/index.ts b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/index.ts new file mode 100644 index 0000000000000..006ec34d0a475 --- /dev/null +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/index.ts @@ -0,0 +1,13 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './content'; +export * from './resource'; +export * from './summary_column'; +export * from './utils'; diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/resource.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/resource.tsx similarity index 89% rename from src/plugins/discover/public/components/data_types/logs/summary_column/resource.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/resource.tsx index a7955fadde622..5ea7ddda7a6b7 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/resource.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/resource.tsx @@ -8,8 +8,8 @@ */ import React from 'react'; -import { EuiBadge, EuiFlexGroup } from '@elastic/eui'; -import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { CommonProps, EuiBadge, EuiFlexGroup } from '@elastic/eui'; +import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { ResourceFieldDescriptor } from './utils'; const MAX_LIMITED_FIELDS_VISIBLE = 3; @@ -19,6 +19,7 @@ interface ResourceProps { /* When true, the column will render a predefined number of resources and indicates with a badge how many more we have */ limited?: boolean; onFilter?: DocViewFilterFn; + css?: CommonProps['css']; } export const Resource = ({ fields, limited = false, onFilter, ...props }: ResourceProps) => { diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.test.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.test.tsx similarity index 86% rename from src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.test.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.test.tsx index b8eeea613c9c6..6b337167279e3 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.test.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.test.tsx @@ -8,41 +8,41 @@ */ import React from 'react'; -import { buildDataTableRecord, DataTableRecord } from '@kbn/discover-utils'; -import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; import { render, screen } from '@testing-library/react'; import SummaryColumn, { SummaryColumnFactoryDeps, SummaryColumnProps } from './summary_column'; import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; -import * as constants from '../../../../../common/data_types/logs/constants'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { discoverServiceMock } from '../../../../__mocks__/services'; +import * as constants from '@kbn/discover-utils/src/data_types/logs/constants'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; +import { coreMock as corePluginMock } from '@kbn/core/public/mocks'; +import { DataTableRecord, buildDataTableRecord } from '@kbn/discover-utils'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__/data_view'; const renderSummary = ( record: DataTableRecord, opts: Partial = {} ) => { render( - - {}} - closePopover={() => {}} - density={DataGridDensity.COMPACT} - rowHeight={ROWS_HEIGHT_OPTIONS.single} - onFilter={jest.fn()} - shouldShowFieldHandler={() => true} - {...opts} - /> - + {}} + closePopover={() => {}} + density={DataGridDensity.COMPACT} + rowHeight={ROWS_HEIGHT_OPTIONS.single} + onFilter={jest.fn()} + shouldShowFieldHandler={() => true} + core={corePluginMock.createStart()} + share={sharePluginMock.createStartContract()} + {...opts} + /> ); }; diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx new file mode 100644 index 0000000000000..d630b686255c6 --- /dev/null +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx @@ -0,0 +1,171 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { DataGridDensity, type DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import React from 'react'; +import { EuiButtonIcon, EuiCodeBlock, EuiFlexGroup, EuiText, EuiTitle } from '@elastic/eui'; +import { JsonCodeEditor } from '@kbn/unified-doc-viewer-plugin/public'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { + ShouldShowFieldInTableHandler, + getLogDocumentOverview, + getMessageFieldWithFallbacks, +} from '@kbn/discover-utils'; +import { ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table/src/constants'; +import { Resource } from './resource'; +import { Content } from './content'; +import { createResourceFields, formatJsonDocumentForContent } from './utils'; +import { + closeCellActionPopoverText, + contentLabel, + jsonLabel, + resourceLabel, +} from '../translations'; + +export interface SummaryColumnFactoryDeps { + density: DataGridDensity | undefined; + rowHeight: number | undefined; + shouldShowFieldHandler: ShouldShowFieldInTableHandler; + onFilter?: DocViewFilterFn; + core: CoreStart; + share?: SharePluginStart; +} + +export type SummaryColumnProps = DataGridCellValueElementProps; +export type AllSummaryColumnProps = SummaryColumnProps & SummaryColumnFactoryDeps; + +export const SummaryColumn = (props: AllSummaryColumnProps) => { + const { isDetails } = props; + + if (isDetails) { + return ; + } + + return ; +}; + +// eslint-disable-next-line import/no-default-export +export default SummaryColumn; + +const SummaryCell = ({ + density: maybeNullishDensity, + rowHeight: maybeNullishRowHeight, + ...props +}: AllSummaryColumnProps) => { + const { onFilter, row, share, core } = props; + + const density = maybeNullishDensity ?? DataGridDensity.COMPACT; + const isCompressed = density === DataGridDensity.COMPACT; + + const rowHeight = maybeNullishRowHeight ?? ROWS_HEIGHT_OPTIONS.single; + const isSingleLine = rowHeight === ROWS_HEIGHT_OPTIONS.single || rowHeight === 1; + + const resourceFields = createResourceFields(row, core, share); + const shouldRenderResource = resourceFields.length > 0; + + return isSingleLine ? ( + + {shouldRenderResource && ( + + )} + + + ) : ( + <> + {shouldRenderResource && ( + + )} + + + ); +}; + +const SummaryCellPopover = (props: AllSummaryColumnProps) => { + const { row, dataView, fieldFormats, onFilter, closePopover, share, core } = props; + + const resourceFields = createResourceFields(row, core, share); + const shouldRenderResource = resourceFields.length > 0; + + const documentOverview = getLogDocumentOverview(row, { dataView, fieldFormats }); + const { field, value } = getMessageFieldWithFallbacks(documentOverview); + const shouldRenderContent = Boolean(field && value); + + const shouldRenderSource = !shouldRenderContent; + + return ( + + + {shouldRenderResource && ( + + + {resourceLabel} + + + + )} + + + {contentLabel} + + {shouldRenderContent && ( + + + {field} + + + {value} + + + )} + {shouldRenderSource && ( + + + {jsonLabel} + + + + )} + + + ); +}; + +const singleLineResourceCss = { + flexGrow: 0, + lineHeight: 'normal', + marginTop: -1, +}; + +const multiLineResourceCss = { display: 'inline-flex' }; diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/utils.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx similarity index 72% rename from src/plugins/discover/public/components/data_types/logs/summary_column/utils.tsx rename to packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx index 470ec8a0f86fa..b7ba9e724a407 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/utils.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx @@ -7,18 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getFieldValue, LogDocument, ResourceFields } from '@kbn/discover-utils/src'; -import { DataTableRecord } from '@kbn/discover-utils'; import { dynamic } from '@kbn/shared-ux-utility'; import React from 'react'; import { css } from '@emotion/react'; import { AgentName } from '@kbn/elastic-agent-utils'; import { euiThemeVars } from '@kbn/ui-theme'; -import { getAvailableResourceFields } from '../../../../utils/get_available_resource_fields'; -import * as constants from '../../../../../common/data_types/logs/constants'; -import { ServiceNameBadgeWithActions } from '../service_name_badge_with_actions'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import * as constants from '@kbn/discover-utils/src/data_types/logs/constants'; +import { DataTableRecord, getFieldValue } from '@kbn/discover-utils'; +import { LogDocument, ResourceFields } from '@kbn/discover-utils/src'; +import { getAvailableResourceFields } from '@kbn/discover-utils/src/data_types/logs/utils/get_available_resource_fields'; import { FieldBadgeWithActions, FieldBadgeWithActionsProps } from '../cell_actions_popover'; - +import { ServiceNameBadgeWithActions } from '../service_name_badge_with_actions'; /** * getUnformattedResourceFields definitions */ @@ -58,33 +59,43 @@ const resourceCustomComponentsMap: Partial< }; export interface ResourceFieldDescriptor { - ResourceBadge: React.ComponentType; + ResourceBadge: React.ComponentType>; Icon?: () => JSX.Element; name: keyof ResourceFields; value: string; } -export const createResourceFields = (row: DataTableRecord): ResourceFieldDescriptor[] => { +export const createResourceFields = ( + row: DataTableRecord, + core: CoreStart, + share?: SharePluginStart +): ResourceFieldDescriptor[] => { const resourceDoc = getUnformattedResourceFields(row as LogDocument); const availableResourceFields = getAvailableResourceFields(resourceDoc); - const resourceFields = availableResourceFields.map((name) => ({ - name, - value: resourceDoc[name] as string, - ResourceBadge: resourceCustomComponentsMap[name] ?? FieldBadgeWithActions, - ...(name === constants.SERVICE_NAME_FIELD && { - Icon: () => ( - - ), - }), - })); + const resourceFields = availableResourceFields.map((name) => { + const ResourceBadgeComponent = resourceCustomComponentsMap[name] ?? FieldBadgeWithActions; + const resourceBadgeComponentWithDependencies = (props: FieldBadgeWithActionsProps) => ( + + ); + return { + name, + value: resourceDoc[name] as string, + ResourceBadge: resourceBadgeComponentWithDependencies, + ...(name === constants.SERVICE_NAME_FIELD && { + Icon: () => ( + + ), + }), + }; + }); return resourceFields; }; diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx new file mode 100644 index 0000000000000..bbc39022bd503 --- /dev/null +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx @@ -0,0 +1,305 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiCode } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export const flyoutContentLabel = i18n.translate('discover.logs.flyoutDetail.label.message', { + defaultMessage: 'Content breakdown', +}); + +export const jsonLabel = i18n.translate('discover.logs.dataTable.header.popover.json', { + defaultMessage: 'JSON', +}); + +export const contentLabel = i18n.translate('discover.logs.dataTable.header.popover.content', { + defaultMessage: 'Content', +}); + +export const resourceLabel = i18n.translate('discover.logs.dataTable.header.popover.resource', { + defaultMessage: 'Resource', +}); + +export const actionsLabel = i18n.translate('discover.logs.dataTable.header.popover.actions', { + defaultMessage: 'Actions', +}); + +export const actionsLabelLowerCase = i18n.translate( + 'discover.logs.dataTable.header.popover.actions.lowercase', + { + defaultMessage: 'actions', + } +); + +export const flyoutServiceLabel = i18n.translate('discover.logs.flyoutDetail.label.service', { + defaultMessage: 'Service', +}); + +export const flyoutTraceLabel = i18n.translate('discover.logs.flyoutDetail.label.trace', { + defaultMessage: 'Trace', +}); + +export const flyoutHostNameLabel = i18n.translate('discover.logs.flyoutDetail.label.hostName', { + defaultMessage: 'Host name', +}); + +export const serviceInfraAccordionTitle = i18n.translate( + 'discover.logs.flyoutDetail.accordion.title.serviceInfra', + { + defaultMessage: 'Service & Infrastructure', + } +); + +export const cloudAccordionTitle = i18n.translate( + 'discover.logs.flyoutDetail.accordion.title.cloud', + { + defaultMessage: 'Cloud', + } +); + +export const otherAccordionTitle = i18n.translate( + 'discover.logs.flyoutDetail.accordion.title.other', + { + defaultMessage: 'Other', + } +); + +export const flyoutOrchestratorClusterNameLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.orchestratorClusterName', + { + defaultMessage: 'Orchestrator cluster Name', + } +); + +export const flyoutOrchestratorResourceIdLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.orchestratorResourceId', + { + defaultMessage: 'Orchestrator resource ID', + } +); + +export const flyoutCloudProviderLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.cloudProvider', + { + defaultMessage: 'Cloud provider', + } +); + +export const flyoutCloudRegionLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.cloudRegion', + { + defaultMessage: 'Cloud region', + } +); + +export const flyoutCloudAvailabilityZoneLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.cloudAvailabilityZone', + { + defaultMessage: 'Cloud availability zone', + } +); + +export const flyoutCloudProjectIdLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.cloudProjectId', + { + defaultMessage: 'Cloud project ID', + } +); + +export const flyoutCloudInstanceIdLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.cloudInstanceId', + { + defaultMessage: 'Cloud instance ID', + } +); + +export const flyoutLogPathFileLabel = i18n.translate( + 'discover.logs.flyoutDetail.label.logPathFile', + { + defaultMessage: 'Log path file', + } +); + +export const flyoutNamespaceLabel = i18n.translate('discover.logs.flyoutDetail.label.namespace', { + defaultMessage: 'Namespace', +}); + +export const flyoutDatasetLabel = i18n.translate('discover.logs.flyoutDetail.label.dataset', { + defaultMessage: 'Dataset', +}); + +export const flyoutShipperLabel = i18n.translate('discover.logs.flyoutDetail.label.shipper', { + defaultMessage: 'Shipper', +}); + +export const actionFilterForText = (text: string) => + i18n.translate('discover.logs.flyoutDetail.value.hover.filterFor', { + defaultMessage: 'Filter for this {value}', + values: { + value: text, + }, + }); + +export const actionFilterOutText = (text: string) => + i18n.translate('discover.logs.flyoutDetail.value.hover.filterOut', { + defaultMessage: 'Filter out this {value}', + values: { + value: text, + }, + }); + +export const filterOutText = i18n.translate('discover.logs.popoverAction.filterOut', { + defaultMessage: 'Filter out', +}); + +export const filterForText = i18n.translate('discover.logs.popoverAction.filterFor', { + defaultMessage: 'Filter for', +}); + +export const flyoutHoverActionFilterForFieldPresentText = i18n.translate( + 'discover.logs.flyoutDetail.value.hover.filterForFieldPresent', + { + defaultMessage: 'Filter for field present', + } +); + +export const flyoutHoverActionToggleColumnText = i18n.translate( + 'discover.logs.flyoutDetail.value.hover.toggleColumn', + { + defaultMessage: 'Toggle column in table', + } +); + +export const flyoutHoverActionCopyToClipboardText = i18n.translate( + 'discover.logs.flyoutDetail.value.hover.copyToClipboard', + { + defaultMessage: 'Copy to clipboard', + } +); + +export const copyValueText = i18n.translate('discover.logs.popoverAction.copyValue', { + defaultMessage: 'Copy value', +}); + +export const copyValueAriaText = (fieldName: string) => + i18n.translate('discover.logs.popoverAction.copyValueAriaText', { + defaultMessage: 'Copy value of {fieldName}', + values: { + fieldName, + }, + }); + +export const flyoutAccordionShowMoreText = (count: number) => + i18n.translate('discover.logs.flyoutDetail.section.showMore', { + defaultMessage: '+ {hiddenCount} more', + values: { + hiddenCount: count, + }, + }); + +export const openCellActionPopoverAriaText = i18n.translate( + 'discover.logs.popoverAction.openPopover', + { + defaultMessage: 'Open popover', + } +); + +export const closeCellActionPopoverText = i18n.translate( + 'discover.logs.popoverAction.closePopover', + { + defaultMessage: 'Close popover', + } +); + +export const contentHeaderTooltipParagraph1 = ( + log.level, + message: message, + }} + /> +); + +export const contentHeaderTooltipParagraph2 = i18n.translate( + 'discover.logs.dataTable.header.content.tooltip.paragraph2', + { + defaultMessage: 'When the message field is empty, one of the following is displayed:', + } +); + +export const resourceHeaderTooltipParagraph = i18n.translate( + 'discover.logs.dataTable.header.resource.tooltip.paragraph', + { + defaultMessage: "Fields that provide information on the document's source, such as:", + } +); + +export const actionsHeaderTooltipParagraph = i18n.translate( + 'discover.logs.dataTable.header.actions.tooltip.paragraph', + { + defaultMessage: 'Fields that provide actionable information, such as:', + } +); + +export const actionsHeaderTooltipExpandAction = i18n.translate( + 'discover.logs.dataTable.header.actions.tooltip.expand', + { defaultMessage: 'Expand log details' } +); + +export const actionsHeaderTooltipDegradedAction = ( + + _ignored + + ), + }} + /> +); + +export const actionsHeaderTooltipStacktraceAction = i18n.translate( + 'discover.logs.dataTable.header.actions.tooltip.stacktrace', + { defaultMessage: 'Access to available stacktraces based on:' } +); + +export const degradedDocButtonLabelWhenPresent = i18n.translate( + 'discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent', + { + defaultMessage: + "This document couldn't be parsed correctly. Not all fields are properly populated", + } +); + +export const degradedDocButtonLabelWhenNotPresent = i18n.translate( + 'discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent', + { + defaultMessage: 'All fields in this document were parsed correctly', + } +); + +export const stacktraceAvailableControlButton = i18n.translate( + 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.available', + { + defaultMessage: 'Stacktraces available', + } +); + +export const stacktraceNotAvailableControlButton = i18n.translate( + 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable', + { + defaultMessage: 'Stacktraces not available', + } +); diff --git a/packages/kbn-discover-contextual-components/tsconfig.json b/packages/kbn-discover-contextual-components/tsconfig.json new file mode 100644 index 0000000000000..4c03098e79601 --- /dev/null +++ b/packages/kbn-discover-contextual-components/tsconfig.json @@ -0,0 +1,36 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/field-formats-plugin", + "@kbn/discover-utils", + "@kbn/router-utils", + "@kbn/management-settings-ids", + "@kbn/share-plugin", + "@kbn/ui-theme", + "@kbn/unified-data-table", + "@kbn/unified-doc-viewer", + "@kbn/react-hooks", + "@kbn/core-lifecycle-browser", + "@kbn/i18n", + "@kbn/i18n-react", + "@kbn/unified-doc-viewer-plugin", + "@kbn/core", + "@kbn/shared-ux-utility", + "@kbn/elastic-agent-utils", + "@kbn/custom-icons", + ] +} diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index ed6d58ca3da8d..24a2b755359aa 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -52,13 +52,13 @@ export { getLogLevelCoalescedValue, getLogLevelCoalescedValueLabel, LogLevelCoalescedValue, - LogLevelBadge, getFieldValue, getVisibleColumns, canPrependTimeFieldColumn, DiscoverFlyouts, dismissAllFlyoutsExceptFor, dismissFlyouts, + LogLevelBadge, } from './src'; export type { LogsContextService } from './src'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/components/index.ts b/packages/kbn-discover-utils/src/data_types/logs/components/index.tsx similarity index 100% rename from packages/kbn-discover-utils/src/data_types/logs/components/index.ts rename to packages/kbn-discover-utils/src/data_types/logs/components/index.tsx diff --git a/packages/kbn-discover-utils/src/data_types/logs/constants.ts b/packages/kbn-discover-utils/src/data_types/logs/constants.ts new file mode 100644 index 0000000000000..82edebaff0e81 --- /dev/null +++ b/packages/kbn-discover-utils/src/data_types/logs/constants.ts @@ -0,0 +1,70 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { fieldConstants } from '../..'; +import { SmartFieldGridColumnOptions } from './types'; + +export * from '../../field_constants'; + +export const LOGS_EXPLORER_PROFILE_ID = 'logs-explorer'; + +// Virtual column fields +export const CONTENT_FIELD = 'content'; +export const RESOURCE_FIELD = 'resource'; + +// Sizing +export const DATA_GRID_COLUMN_WIDTH_SMALL = 240; +export const DATA_GRID_COLUMN_WIDTH_MEDIUM = 320; +export const ACTIONS_COLUMN_WIDTH = 80; + +export const RESOURCE_FIELD_CONFIGURATION: SmartFieldGridColumnOptions = { + type: 'smart-field', + smartField: RESOURCE_FIELD, + fallbackFields: [fieldConstants.HOST_NAME_FIELD, fieldConstants.SERVICE_NAME_FIELD], + width: DATA_GRID_COLUMN_WIDTH_MEDIUM, +}; + +export const CONTENT_FIELD_CONFIGURATION: SmartFieldGridColumnOptions = { + type: 'smart-field', + smartField: CONTENT_FIELD, + fallbackFields: [fieldConstants.MESSAGE_FIELD], +}; + +export const SMART_FALLBACK_FIELDS = { + [CONTENT_FIELD]: CONTENT_FIELD_CONFIGURATION, + [RESOURCE_FIELD]: RESOURCE_FIELD_CONFIGURATION, +}; + +// UI preferences +export const DEFAULT_COLUMNS = [RESOURCE_FIELD_CONFIGURATION, CONTENT_FIELD_CONFIGURATION]; +export const DEFAULT_ROWS_PER_PAGE = 100; + +// List of prefixes which needs to be filtered out for Display in Content Column +export const FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT = [ + '_', // Filter fields like '_id', '_score' + '@timestamp', + 'agent.', + 'elastic_agent.', + 'data_stream.', + 'ecs.', + 'host.', + 'container.', + 'cloud.', + 'kubernetes.', + 'orchestrator.', + 'log.', + 'service.', +]; + +export const DEFAULT_ALLOWED_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; +export const DEFAULT_ALLOWED_LOGS_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; + +export const LOG_LEVEL_FIELDS = ['log.level', 'log_level']; +export const SERVICE_NAME_FIELDS = ['service.name', 'service_name']; +export const AGENT_NAME_FIELD = 'agent.name'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/index.ts b/packages/kbn-discover-utils/src/data_types/logs/index.ts index 7ec996ee31010..30b023b6328bb 100644 --- a/packages/kbn-discover-utils/src/data_types/logs/index.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/index.ts @@ -8,7 +8,7 @@ */ export * from './types'; -export * from './components'; export * from './utils'; export * from './logs_context_service'; +export * from './components'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/types.ts b/packages/kbn-discover-utils/src/data_types/logs/types.ts index 843205d6e8b1e..123ad6c631026 100644 --- a/packages/kbn-discover-utils/src/data_types/logs/types.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/types.ts @@ -86,3 +86,10 @@ export interface StackTraceFields { 'error.exception.stacktrace'?: string; 'error.log.stacktrace'?: string; } + +export interface SmartFieldGridColumnOptions { + type: 'smart-field'; + smartField: 'content' | 'resource'; + fallbackFields: string[]; + width?: number; +} diff --git a/src/plugins/discover/public/utils/get_available_resource_fields.ts b/packages/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts similarity index 87% rename from src/plugins/discover/public/utils/get_available_resource_fields.ts rename to packages/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts index 588194d2a13ca..e59b7a99c9163 100644 --- a/src/plugins/discover/public/utils/get_available_resource_fields.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts @@ -7,8 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ResourceFields } from '@kbn/discover-utils/src'; -import * as constants from '../../common/data_types/logs/constants'; +import { ResourceFields } from '../../..'; +import * as constants from '../constants'; export const getAvailableResourceFields = (resourceDoc: ResourceFields) => { const resourceFields: Array = [ diff --git a/packages/kbn-discover-utils/tsconfig.json b/packages/kbn-discover-utils/tsconfig.json index 724051e5863c4..ffff768f80301 100644 --- a/packages/kbn-discover-utils/tsconfig.json +++ b/packages/kbn-discover-utils/tsconfig.json @@ -25,8 +25,8 @@ "@kbn/field-types", "@kbn/i18n", "@kbn/core-ui-settings-browser", - "@kbn/ui-theme", "@kbn/expressions-plugin", - "@kbn/logs-data-access-plugin" + "@kbn/logs-data-access-plugin", + "@kbn/ui-theme", ] } diff --git a/src/plugins/discover/common/data_types/logs/constants.ts b/src/plugins/discover/common/data_types/logs/constants.ts index 18259dcc56b28..a9ca3697763f9 100644 --- a/src/plugins/discover/common/data_types/logs/constants.ts +++ b/src/plugins/discover/common/data_types/logs/constants.ts @@ -7,64 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { fieldConstants } from '@kbn/discover-utils'; -import { SmartFieldGridColumnOptions } from './display_options'; - -export * from '@kbn/discover-utils/src/field_constants'; - -export const LOGS_EXPLORER_PROFILE_ID = 'logs-explorer'; - -// Virtual column fields -export const CONTENT_FIELD = 'content'; -export const RESOURCE_FIELD = 'resource'; - -// Sizing -export const DATA_GRID_COLUMN_WIDTH_SMALL = 240; -export const DATA_GRID_COLUMN_WIDTH_MEDIUM = 320; -export const ACTIONS_COLUMN_WIDTH = 80; - -export const RESOURCE_FIELD_CONFIGURATION: SmartFieldGridColumnOptions = { - type: 'smart-field', - smartField: RESOURCE_FIELD, - fallbackFields: [fieldConstants.HOST_NAME_FIELD, fieldConstants.SERVICE_NAME_FIELD], - width: DATA_GRID_COLUMN_WIDTH_MEDIUM, -}; - -export const CONTENT_FIELD_CONFIGURATION: SmartFieldGridColumnOptions = { - type: 'smart-field', - smartField: CONTENT_FIELD, - fallbackFields: [fieldConstants.MESSAGE_FIELD], -}; - -export const SMART_FALLBACK_FIELDS = { - [CONTENT_FIELD]: CONTENT_FIELD_CONFIGURATION, - [RESOURCE_FIELD]: RESOURCE_FIELD_CONFIGURATION, -}; - -// UI preferences -export const DEFAULT_COLUMNS = [RESOURCE_FIELD_CONFIGURATION, CONTENT_FIELD_CONFIGURATION]; -export const DEFAULT_ROWS_PER_PAGE = 100; - -// List of prefixes which needs to be filtered out for Display in Content Column -export const FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT = [ - '_', // Filter fields like '_id', '_score' - '@timestamp', - 'agent.', - 'elastic_agent.', - 'data_stream.', - 'ecs.', - 'host.', - 'container.', - 'cloud.', - 'kubernetes.', - 'orchestrator.', - 'log.', - 'service.', -]; - -export const DEFAULT_ALLOWED_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; -export const DEFAULT_ALLOWED_LOGS_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; - -export const LOG_LEVEL_FIELDS = ['log.level', 'log_level']; -export const SERVICE_NAME_FIELDS = ['service.name', 'service_name']; -export const AGENT_NAME_FIELD = 'agent.name'; +export * from '@kbn/discover-utils/src/data_types/logs/constants'; diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx b/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx index 20fe4380199f3..b7b0625a522af 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx +++ b/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx @@ -8,13 +8,11 @@ */ import React from 'react'; -import { dynamic } from '@kbn/shared-ux-utility'; import { getShouldShowFieldHandler } from '@kbn/discover-utils'; import { DataView } from '@kbn/data-views-plugin/common'; +import { SummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; import { CellRenderersExtensionParams } from '../../../../context_awareness'; -import type { SummaryColumnProps } from './summary_column'; - -const SummaryColumn = dynamic(() => import('./summary_column')); +import { SummaryColumn } from './summary_column'; export type SummaryColumnGetterDeps = CellRenderersExtensionParams; @@ -22,7 +20,7 @@ export const getSummaryColumn = (params: SummaryColumnGetterDeps) => { const { actions, dataView, density, rowHeight } = params; const shouldShowFieldHandler = createGetShouldShowFieldHandler(dataView); - return (props: SummaryColumnProps) => ( + return (props: Omit) => ( { - const { isDetails } = props; - - if (isDetails) { - return ; - } - - return ; +import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; +import { useDiscoverServices } from '../../../../hooks/use_discover_services'; + +const LazySummaryColumn = dynamic( + () => + import( + '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column' + ) +); + +export const SummaryColumn = (props: Omit) => { + const { share, core } = useDiscoverServices(); + return ; }; - -// eslint-disable-next-line import/no-default-export -export default SummaryColumn; - -const SummaryCell = ({ - density: maybeNullishDensity, - rowHeight: maybeNullishRowHeight, - ...props -}: AllSummaryColumnProps) => { - const { onFilter, row } = props; - - const density = maybeNullishDensity ?? DataGridDensity.COMPACT; - const isCompressed = density === DataGridDensity.COMPACT; - - const rowHeight = maybeNullishRowHeight ?? ROWS_HEIGHT_OPTIONS.single; - const isSingleLine = rowHeight === ROWS_HEIGHT_OPTIONS.single || rowHeight === 1; - - const resourceFields = createResourceFields(row); - const shouldRenderResource = resourceFields.length > 0; - - return isSingleLine ? ( - - {shouldRenderResource && ( - - )} - - - ) : ( - <> - {shouldRenderResource && ( - - )} - - - ); -}; - -const SummaryCellPopover = (props: AllSummaryColumnProps) => { - const { row, dataView, fieldFormats, onFilter, closePopover } = props; - - const resourceFields = createResourceFields(row); - const shouldRenderResource = resourceFields.length > 0; - - const documentOverview = getLogDocumentOverview(row, { dataView, fieldFormats }); - const { field, value } = getMessageFieldWithFallbacks(documentOverview); - const shouldRenderContent = Boolean(field && value); - - const shouldRenderSource = !shouldRenderContent; - - return ( - - - {shouldRenderResource && ( - - - {resourceLabel} - - - - )} - - - {contentLabel} - - {shouldRenderContent && ( - - - {field} - - - {value} - - - )} - {shouldRenderSource && ( - - - {jsonLabel} - - - - )} - - - ); -}; - -const singleLineResourceCss = { - flexGrow: 0, - lineHeight: 'normal', - marginTop: -1, -}; - -const multiLineResourceCss = { display: 'inline-flex' }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx b/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx index 9e45892070120..1ce554bb880ee 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx @@ -8,12 +8,12 @@ */ import { SOURCE_COLUMN } from '@kbn/unified-data-table'; +import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; import { getSummaryColumn } from '../../../../../components/data_types/logs/summary_column'; import { LOG_LEVEL_FIELDS, SERVICE_NAME_FIELDS, } from '../../../../../../common/data_types/logs/constants'; -import { getLogLevelBadgeCell } from '../../../../../components/data_types/logs/log_level_badge_cell'; import { getServiceNameCell } from '../../../../../components/data_types/logs/service_name_cell'; import type { DataSourceProfileProvider } from '../../../../profiles'; diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 572888f872193..dbbcc90a7d451 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -24,9 +24,6 @@ import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { SEARCH_EMBEDDABLE_TYPE, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; import { SavedSearchAttributes, SavedSearchType } from '@kbn/saved-search-plugin/common'; import { i18n } from '@kbn/i18n'; -import { dynamic } from '@kbn/shared-ux-utility'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; @@ -63,12 +60,6 @@ import { DataSourceProfileService } from './context_awareness/profiles/data_sour import { DocumentProfileService } from './context_awareness/profiles/document_profile'; import { ProfilesManager } from './context_awareness/profiles_manager'; import { DiscoverEBTManager } from './services/discover_ebt_manager'; -import type { AllSummaryColumnProps } from './components/data_types/logs/summary_column/summary_column'; -import { getLogLevelBadgeCell } from './components/data_types/logs/log_level_badge_cell'; - -const LazySummaryColumn = dynamic( - () => import('./components/data_types/logs/summary_column/summary_column') -); /** * Contains Discover, one of the oldest parts of Kibana @@ -323,25 +314,6 @@ export class DiscoverPlugin DiscoverContainer: (props: DiscoverContainerProps) => ( ), - logColumns: { - SummaryColumn: (props: AllSummaryColumnProps) => { - return ( - - - - ); - }, - getLogLevelCell: ( - logLevelField: string - ): React.ComponentType => { - const LogLevelCell = getLogLevelBadgeCell(logLevelField); - return (props: DataGridCellValueElementProps) => ( - - - - ); - }, - }, }; } diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index ea389ef25a67b..3b24341e1a654 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -42,11 +42,9 @@ import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; -import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { DiscoverAppLocator } from '../common'; import { DiscoverCustomizationContext } from './customizations'; import { type DiscoverContainerProps } from './components/discover_container'; -import type { AllSummaryColumnProps } from './components/data_types/logs/summary_column/summary_column'; /** * @public @@ -123,10 +121,6 @@ export interface DiscoverStart { */ readonly locator: undefined | DiscoverAppLocator; readonly DiscoverContainer: ComponentType; - logColumns: { - SummaryColumn: (props: AllSummaryColumnProps) => React.JSX.Element; - getLogLevelCell: (logLevelField: string) => React.ComponentType; - }; } /** diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index fb6ec66985647..f3f533da91511 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -96,11 +96,9 @@ "@kbn/observability-ai-assistant-plugin", "@kbn/fields-metadata-plugin", "@kbn/security-solution-common", - "@kbn/router-utils", - "@kbn/management-settings-ids", - "@kbn/react-hooks", "@kbn/logs-data-access-plugin", - "@kbn/core-lifecycle-browser" + "@kbn/core-lifecycle-browser", + "@kbn/discover-contextual-components" ], "exclude": [ "target/**/*" diff --git a/src/plugins/unified_doc_viewer/kibana.jsonc b/src/plugins/unified_doc_viewer/kibana.jsonc index 56ea8951e3a2d..6bd1b738c0ccb 100644 --- a/src/plugins/unified_doc_viewer/kibana.jsonc +++ b/src/plugins/unified_doc_viewer/kibana.jsonc @@ -12,3 +12,4 @@ "optionalPlugins": ["fieldsMetadata"] } } + \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index 12df74345a444..f6dd203ffd99c 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -764,6 +764,8 @@ "@kbn/dev-utils/*": ["packages/kbn-dev-utils/*"], "@kbn/developer-examples-plugin": ["examples/developer_examples"], "@kbn/developer-examples-plugin/*": ["examples/developer_examples/*"], + "@kbn/discover-contextual-components": ["packages/kbn-discover-contextual-components"], + "@kbn/discover-contextual-components/*": ["packages/kbn-discover-contextual-components/*"], "@kbn/discover-customization-examples-plugin": ["examples/discover_customization_examples"], "@kbn/discover-customization-examples-plugin/*": ["examples/discover_customization_examples/*"], "@kbn/discover-enhanced-plugin": ["x-pack/plugins/discover_enhanced"], diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index dc2e6bf50507b..b6b99b782dead 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -20,10 +20,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { StateFrom } from 'xstate5'; import { SettingsStart } from '@kbn/core-ui-settings-browser'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { DiscoverStart } from '@kbn/discover-plugin/public'; import { i18n } from '@kbn/i18n'; import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { SharePluginStart } from '@kbn/share-plugin/public'; +import type { LogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; +import type { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; import { LogCategory } from '../../types'; import { LogCategoryPattern } from '../shared/log_category_pattern'; import { categoryDetailsService } from '../../services/category_details_service'; @@ -39,8 +40,8 @@ export interface LogCategoriesFlyoutDependencies { fieldFormats: FieldFormatsStart; share: SharePluginStart; columns: { - SummaryColumn: DiscoverStart['logColumns']['SummaryColumn']; - LogLevelCell: ReturnType; + SummaryColumn: React.ComponentType>; + LogLevelCell: LogLevelBadgeCell; }; } diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index a1e7847935fc2..da6d8c8361f5b 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -31,13 +31,14 @@ "@kbn/ml-random-sampler-utils", "@kbn/zod", "@kbn/calculate-auto", - "@kbn/discover-plugin", "@kbn/es-query", "@kbn/router-utils", "@kbn/share-plugin", "@kbn/field-formats-plugin", - "@kbn/unified-data-table", "@kbn/data-service", "@kbn/discover-utils", + "@kbn/discover-plugin", + "@kbn/unified-data-table", + "@kbn/discover-contextual-components", ] } diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index a6329c585800a..cacdc0cdce992 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -23,7 +23,7 @@ "optionalPlugins": [ "observabilityAIAssistant", ], - "requiredBundles": ["kibanaUtils", "kibanaReact"], + "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedDocViewer"], "extraPublicDirs": ["common"] } } diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx similarity index 78% rename from x-pack/plugins/observability_solution/logs_shared/public/plugin.ts rename to x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx index a1ae176d5c161..bad7c80881b91 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx @@ -6,6 +6,10 @@ */ import { CoreStart } from '@kbn/core/public'; +import { dynamic } from '@kbn/shared-ux-utility'; +import React from 'react'; +import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; +import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; import { LogsLocatorDefinition, NodeLogsLocatorDefinition, @@ -21,6 +25,13 @@ import { LogsSharedClientStartDeps, } from './types'; +const LazySummaryColumn = dynamic( + () => + import( + '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column' + ) +); + export class LogsSharedPlugin implements LogsSharedClientPluginClass { private logViews: LogViewsService; @@ -80,8 +91,10 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { dataViews, fieldFormats, columns: { - SummaryColumn: plugins.discover.logColumns.SummaryColumn, - LogLevelCell: plugins.discover.logColumns.getLogLevelCell('log.level'), + SummaryColumn: (props: Omit) => { + return ; + }, + LogLevelCell: getLogLevelBadgeCell('log.level'), }, }); diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 47ca88b558171..4cd73eb4c3af1 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -50,5 +50,6 @@ "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", "@kbn/discover-plugin", + "@kbn/discover-contextual-components", ] } diff --git a/yarn.lock b/yarn.lock index e7042d208b96d..fa5c079683c6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4823,6 +4823,10 @@ version "0.0.0" uid "" +"@kbn/discover-contextual-components@link:packages/kbn-discover-contextual-components": + version "0.0.0" + uid "" + "@kbn/discover-customization-examples-plugin@link:examples/discover_customization_examples": version "0.0.0" uid "" From 4e55806fe11bbac2250730aa7927b3dfa3b22259 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:43:27 +0000 Subject: [PATCH 49/74] [CI] Auto-commit changed files from 'node scripts/generate codeowners' --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a8cc39b7b072b..5c00f721bfd3c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -385,6 +385,7 @@ packages/kbn-dev-proc-runner @elastic/kibana-operations src/plugins/dev_tools @elastic/kibana-management packages/kbn-dev-utils @elastic/kibana-operations examples/developer_examples @elastic/appex-sharedux +packages/kbn-discover-contextual-components @elastic/obs-ux-logs-team examples/discover_customization_examples @elastic/kibana-data-discovery x-pack/plugins/discover_enhanced @elastic/kibana-data-discovery src/plugins/discover @elastic/kibana-data-discovery From 8c8b2a3f8407803477aa814ddb07094dd3075bfa Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:18:46 +0100 Subject: [PATCH 50/74] Update i18nrc.json --- .i18nrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.i18nrc.json b/.i18nrc.json index 036be597ac969..5c7642e6283eb 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -27,7 +27,7 @@ "dataViews": "src/plugins/data_views", "defaultNavigation": "packages/default-nav", "devTools": "src/plugins/dev_tools", - "discover": ["src/plugins/discover", "packages/kbn-discover-utils"], + "discover": ["src/plugins/discover", "packages/kbn-discover-utils", "packages/kbn-discover-contextual-components"], "savedSearch": "src/plugins/saved_search", "embeddableApi": "src/plugins/embeddable", "presentationPanel": "src/plugins/presentation_panel", From 6e60316ed1bef8ea4894221ae04b67794663d022 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:19:11 +0100 Subject: [PATCH 51/74] More descriptive filter labels --- .../components/discover_link/discover_link.tsx | 13 ++++++++++--- .../log_categories_control_bar.tsx | 9 +++++++-- .../log_category_details_flyout.tsx | 17 +++++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx index 3c97bead1a36e..676468c2f4a32 100644 --- a/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/discover_link/discover_link.tsx @@ -14,8 +14,15 @@ import { getRouterLinkProps } from '@kbn/router-utils'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import React, { useCallback, useMemo } from 'react'; import type { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; + +interface LinkFilter { + filter: QueryDslQueryContainer; + meta?: { + name?: string; + }; +} export interface DiscoverLinkProps { - documentFilters?: QueryDslQueryContainer[]; + documentFilters?: LinkFilter[]; logsSource: ResolvedIndexNameLogsSourceConfiguration; timeRange: { start: string; @@ -45,10 +52,10 @@ export const DiscoverLink = React.memo( filters: documentFilters?.map((filter) => buildCustomFilter( logsSource.indexName, - filter, + filter.filter, false, false, - categorizedLogsFilterLabel, + filter.meta?.name ?? categorizedLogsFilterLabel, FilterStateStore.APP_STATE ) ), diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx index 0ec9121b2c972..7c13ac1446320 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_control_bar.tsx @@ -8,7 +8,7 @@ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { SharePluginStart } from '@kbn/share-plugin/public'; -import React from 'react'; +import React, { useMemo } from 'react'; import type { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { DiscoverLink } from '../discover_link'; @@ -28,12 +28,17 @@ export interface LogCategoriesControlBarDependencies { export const LogCategoriesControlBar: React.FC = React.memo( ({ dependencies, documentFilters, logsSource, timeRange }) => { + const linkFilters = useMemo( + () => documentFilters?.map((filter) => ({ filter })), + [documentFilters] + ); + return ( diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index b6b99b782dead..094092b0613f3 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -73,8 +73,21 @@ export const LogCategoryDetailsFlyout: React.FC = const linkFilters = useMemo(() => { return [ - ...(documentFilters ? documentFilters : []), - createCategoryQuery(logsSource.messageField)(logCategory.terms), + ...(documentFilters ? documentFilters.map((filter) => ({ filter })) : []), + { + filter: createCategoryQuery(logsSource.messageField)(logCategory.terms), + meta: { + name: i18n.translate( + 'xpack.observabilityLogsOverview.logCategoryDetailsFlyout.discoverLinkFilterName', + { + defaultMessage: 'Category: {terms}', + values: { + terms: logCategory.terms, + }, + } + ), + }, + }, ]; }, [documentFilters, logCategory.terms, logsSource.messageField]); From b956a492854ee1d0ff5e18d72269fd8cd9725a50 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:25:06 +0100 Subject: [PATCH 52/74] Auto-sort imports --- .../src/components/log_categories/log_categories.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index e54cab30537fc..34537bfa0c9dd 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -14,6 +14,11 @@ import { categorizeLogsService, createCategorizeLogsServiceImplementations, } from '../../services/categorize_logs_service'; +import { + categoryDetailsService, + createCategoryDetailsServiceImplementations, +} from '../../services/category_details_service'; +import { LogCategory } from '../../types'; import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { LogCategoriesErrorContent } from './log_categories_error_content'; import { LogCategoriesLoadingContent } from './log_categories_loading_content'; @@ -21,11 +26,6 @@ import { LogCategoriesResultContent, LogCategoriesResultContentDependencies, } from './log_categories_result_content'; -import { - categoryDetailsService, - createCategoryDetailsServiceImplementations, -} from '../../services/category_details_service'; -import { LogCategory } from '../../types'; export interface LogCategoriesProps { dependencies: LogCategoriesDependencies; From d827ac7fbe96ef403677d4a82fe7bbc3bcef9e8b Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:31:11 +0100 Subject: [PATCH 53/74] Better grouped naming --- .../components/log_categories/log_categories.tsx | 4 ++-- .../log_categories/log_categories_grid.tsx | 6 +++--- .../log_categories_grid_expand_button.tsx | 10 +++++----- .../log_categories_result_content.tsx | 16 ++++++++-------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx index 34537bfa0c9dd..1ce45ca6b3727 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories.tsx @@ -98,7 +98,7 @@ export const LogCategories: React.FC = ({ }); }, [sendToCategoryDetailsService]); - const expandCategory = useCallback( + const openFlyout = useCallback( (category: LogCategory | null, rowIndex: number | null) => { sendToCategoryDetailsService({ type: 'setExpandedCategory', @@ -119,7 +119,7 @@ export const LogCategories: React.FC = ({ timeRange={timeRange} categoryDetailsServiceState={categoryDetailsServiceState} onCloseFlyout={closeFlyout} - onExpandCategory={expandCategory} + onOpenFlyout={openFlyout} /> ); } else if (categorizeLogsServiceState.matches('failed')) { diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx index 6d4295c2534d1..c474499ca2975 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -32,7 +32,7 @@ export interface LogCategoriesGridProps { dependencies: LogCategoriesGridDependencies; logCategories: LogCategory[]; expandedRowIndex: number | null; - onExpandCategory: (category: LogCategory, rowIndex: number) => void; + onOpenFlyout: (category: LogCategory, rowIndex: number) => void; onCloseFlyout: () => void; } @@ -44,7 +44,7 @@ export const LogCategoriesGrid: React.FC = ({ dependencies, logCategories, expandedRowIndex, - onExpandCategory, + onOpenFlyout, onCloseFlyout, }) => { const [gridState, dispatchGridEvent] = useMachine(gridStateService, { @@ -118,7 +118,7 @@ export const LogCategoriesGrid: React.FC = ({ ), rowCellRender: createLogCategoriesGridExpandButton({ expandedRowIndex, - onExpandCategory, + onOpenFlyout, onCloseFlyout, }), }, diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx index 8b44ccf47cc1e..40262d755afb4 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx @@ -6,10 +6,10 @@ */ import { EuiButtonIcon, EuiToolTip, RenderCellValue } from '@elastic/eui'; -import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { getCellContext } from './log_categories_grid_cell'; +import React, { useCallback } from 'react'; import { LogCategory } from '../../types'; +import { getCellContext } from './log_categories_grid_cell'; const buttonLabel = i18n.translate( 'xpack.observabilityLogsOverview.logCategoriesGrid.controlColumns.toggleFlyout', @@ -20,14 +20,14 @@ const buttonLabel = i18n.translate( interface CreateLogCategoriesGridExpandButtonProps { expandedRowIndex: number | null; - onExpandCategory: (category: LogCategory, rowIndex: number) => void; + onOpenFlyout: (category: LogCategory, rowIndex: number) => void; onCloseFlyout: () => void; } export const createLogCategoriesGridExpandButton = ({ expandedRowIndex, - onExpandCategory, + onOpenFlyout, onCloseFlyout, }: CreateLogCategoriesGridExpandButtonProps): RenderCellValue => (props) => { @@ -39,7 +39,7 @@ export const createLogCategoriesGridExpandButton = if (isCurrentRowExpanded) { onCloseFlyout(); } else { - onExpandCategory(logCategory, rowIndex); + onOpenFlyout(logCategory, rowIndex); } }, [isCurrentRowExpanded, logCategory, rowIndex]); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index ad578e0599f83..c2b1a0989c2ec 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -10,18 +10,18 @@ import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { StateFrom } from 'xstate5'; +import { categoryDetailsService } from '../../services/category_details_service'; import { LogCategory } from '../../types'; import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import { + LogCategoriesFlyoutDependencies, + LogCategoryDetailsFlyout, +} from '../log_category_details/log_category_details_flyout'; import { LogCategoriesControlBar, LogCategoriesControlBarDependencies, } from './log_categories_control_bar'; import { LogCategoriesGrid, LogCategoriesGridDependencies } from './log_categories_grid'; -import { - LogCategoriesFlyoutDependencies, - LogCategoryDetailsFlyout, -} from '../log_category_details/log_category_details_flyout'; -import { categoryDetailsService } from '../../services/category_details_service'; export interface LogCategoriesResultContentProps { dependencies: LogCategoriesResultContentDependencies; @@ -34,7 +34,7 @@ export interface LogCategoriesResultContentProps { }; categoryDetailsServiceState: StateFrom; onCloseFlyout: () => void; - onExpandCategory: (category: LogCategory, rowIndex: number) => void; + onOpenFlyout: (category: LogCategory, rowIndex: number) => void; } export type LogCategoriesResultContentDependencies = LogCategoriesControlBarDependencies & @@ -49,7 +49,7 @@ export const LogCategoriesResultContent: React.FC { if (logCategories.length === 0) { return ; @@ -69,7 +69,7 @@ export const LogCategoriesResultContent: React.FC {categoryDetailsServiceState.context.expandedCategory && ( From d31a0f5f90b8a7b3816824729d167688c3f45e42 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:48:06 +0100 Subject: [PATCH 54/74] Move control columns to separate file --- .../log_categories/log_categories_grid.tsx | 30 +++---------- .../log_categories_grid_control_columns.tsx | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_control_columns.tsx diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx index c474499ca2975..badd316371ec6 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid.tsx @@ -9,7 +9,6 @@ import { EuiDataGrid, EuiDataGridColumnSortingConfig, EuiDataGridPaginationProps, - EuiScreenReaderOnly, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { createConsoleInspector } from '@kbn/xstate-utils'; @@ -26,7 +25,7 @@ import { logCategoriesGridColumns, renderLogCategoriesGridCell, } from './log_categories_grid_cell'; -import { createLogCategoriesGridExpandButton } from './log_categories_grid_expand_button'; +import { createLogCategoriesGridControlColumns } from './log_categories_grid_control_columns'; export interface LogCategoriesGridProps { dependencies: LogCategoriesGridDependencies; @@ -38,8 +37,6 @@ export interface LogCategoriesGridProps { export type LogCategoriesGridDependencies = LogCategoriesGridCellDependencies; -const DEFAULT_CONTROL_COLUMN_WIDTH = 40; - export const LogCategoriesGrid: React.FC = ({ dependencies, logCategories, @@ -103,26 +100,11 @@ export const LogCategoriesGrid: React.FC = ({ onSort: (sortingColumns) => dispatchGridEvent({ type: 'changeSortingColumns', sortingColumns }), }} - leadingControlColumns={[ - { - id: 'toggleFlyout', - width: DEFAULT_CONTROL_COLUMN_WIDTH, - headerCellRender: () => ( - - - {i18n.translate('xpack.observabilityLogsOverview.controlColumnHeader', { - defaultMessage: 'Control column', - })} - - - ), - rowCellRender: createLogCategoriesGridExpandButton({ - expandedRowIndex, - onOpenFlyout, - onCloseFlyout, - }), - }, - ]} + leadingControlColumns={createLogCategoriesGridControlColumns({ + expandedRowIndex, + onOpenFlyout, + onCloseFlyout, + })} /> ); }; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_control_columns.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_control_columns.tsx new file mode 100644 index 0000000000000..546754ae1cc5b --- /dev/null +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_control_columns.tsx @@ -0,0 +1,45 @@ +/* + * 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 { EuiScreenReaderOnly } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { LogCategory } from '../../types'; +import { createLogCategoriesGridExpandButton } from './log_categories_grid_expand_button'; + +const DEFAULT_CONTROL_COLUMN_WIDTH = 40; + +interface ControlColumnsProps { + expandedRowIndex: number | null; + onOpenFlyout: (category: LogCategory, rowIndex: number) => void; + onCloseFlyout: () => void; +} + +export const createLogCategoriesGridControlColumns = (props: ControlColumnsProps) => { + const { expandedRowIndex, onOpenFlyout, onCloseFlyout } = props; + + return [ + { + id: 'toggleFlyout', + width: DEFAULT_CONTROL_COLUMN_WIDTH, + headerCellRender: () => ( + + + {i18n.translate('xpack.observabilityLogsOverview.controlColumnHeader', { + defaultMessage: 'Control column', + })} + + + ), + rowCellRender: createLogCategoriesGridExpandButton({ + expandedRowIndex, + onOpenFlyout, + onCloseFlyout, + }), + }, + ]; +}; From 00584d2c5461b9f8a06bb3c640537d409c4885b7 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:49:25 +0100 Subject: [PATCH 55/74] Move label --- .../log_categories_grid_expand_button.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx index 40262d755afb4..34c8e72e2d91a 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_grid_expand_button.tsx @@ -11,13 +11,6 @@ import React, { useCallback } from 'react'; import { LogCategory } from '../../types'; import { getCellContext } from './log_categories_grid_cell'; -const buttonLabel = i18n.translate( - 'xpack.observabilityLogsOverview.logCategoriesGrid.controlColumns.toggleFlyout', - { - defaultMessage: 'Toggle flyout with details', - } -); - interface CreateLogCategoriesGridExpandButtonProps { expandedRowIndex: number | null; onOpenFlyout: (category: LogCategory, rowIndex: number) => void; @@ -69,3 +62,10 @@ const ExpandButton: React.FC = ({ isCurrentRowExpanded, onCli ); }; + +const buttonLabel = i18n.translate( + 'xpack.observabilityLogsOverview.logCategoriesGrid.controlColumns.toggleFlyout', + { + defaultMessage: 'Toggle flyout with details', + } +); From f7cc019d6e3a0c8ac1f0c867d9dea65074e15f32 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Tue, 15 Oct 2024 10:50:17 +0100 Subject: [PATCH 56/74] Update x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Stürmer --- .../log_category_details/log_category_details_flyout.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index b6b99b782dead..f5f4d5ef9ed8a 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -87,13 +87,12 @@ export const LogCategoryDetailsFlyout: React.FC =

, - }} + defaultMessage="Category details" />

+ +
From 4537b8adf0172fe08dd334f2e0969d846840108d Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:53:48 +0100 Subject: [PATCH 57/74] Remove spacer --- .../log_category_details/log_category_details_flyout.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index 094092b0613f3..9b39f2ae39ab3 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -11,7 +11,6 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, - EuiSpacer, EuiTitle, useGeneratedHtmlId, } from '@elastic/eui'; @@ -94,7 +93,7 @@ export const LogCategoryDetailsFlyout: React.FC = return ( onCloseFlyout()} aria-labelledby={flyoutTitleId}> - +

@@ -109,7 +108,6 @@ export const LogCategoryDetailsFlyout: React.FC = - Date: Tue, 15 Oct 2024 11:06:02 +0100 Subject: [PATCH 58/74] Inverse dependencies --- .../log_category_details_flyout.tsx | 20 +++++-------------- .../log_category_document_examples_table.tsx | 18 ++++++++++++++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index 9b39f2ae39ab3..f84fe39ca08a8 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -17,32 +17,22 @@ import { import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { StateFrom } from 'xstate5'; -import { SettingsStart } from '@kbn/core-ui-settings-browser'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { i18n } from '@kbn/i18n'; import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; -import { SharePluginStart } from '@kbn/share-plugin/public'; -import type { LogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; -import type { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; import { LogCategory } from '../../types'; import { LogCategoryPattern } from '../shared/log_category_pattern'; import { categoryDetailsService } from '../../services/category_details_service'; -import { LogCategoryDocumentExamplesTable } from './log_category_document_examples_table'; +import { + LogCategoryDocumentExamplesTable, + LogCategoryDocumentExamplesTableDependencies, +} from './log_category_document_examples_table'; import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; import { LogCategoryDetailsLoadingContent } from './log_category_details_loading_content'; import { LogCategoryDetailsErrorContent } from './log_category_details_error_content'; import { DiscoverLink } from '../discover_link'; import { createCategoryQuery } from '../../services/categorize_logs_service/queries'; -export interface LogCategoriesFlyoutDependencies { - uiSettings: SettingsStart; - fieldFormats: FieldFormatsStart; - share: SharePluginStart; - columns: { - SummaryColumn: React.ComponentType>; - LogLevelCell: LogLevelBadgeCell; - }; -} +export type LogCategoriesFlyoutDependencies = LogCategoryDocumentExamplesTableDependencies; interface LogCategoryDetailsFlyoutProps { onCloseFlyout: () => void; diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index cbd2896463e3a..c4b9045be0c9e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -10,11 +10,23 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; import moment from 'moment'; -import { LogCategoryDocument } from '../../services/category_details_service/types'; +import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; +import type { SettingsStart } from '@kbn/core-ui-settings-browser'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { LogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; +import type { LogCategoryDocument } from '../../services/category_details_service/types'; import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; -import type { LogCategoriesFlyoutDependencies } from './log_category_details_flyout'; -export type LogCategoryDocumentExamplesTableDependencies = LogCategoriesFlyoutDependencies; +export interface LogCategoryDocumentExamplesTableDependencies { + uiSettings: SettingsStart; + fieldFormats: FieldFormatsStart; + share: SharePluginStart; + columns: { + SummaryColumn: React.ComponentType>; + LogLevelCell: LogLevelBadgeCell; + }; +} export interface LogCategoryDocumentExamplesTableProps { dependencies: LogCategoryDocumentExamplesTableDependencies; From 8de365524ce80249764ee023238fcb96e58d8a0c Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:17:15 +0100 Subject: [PATCH 59/74] Remove rowHeader as we don't use it --- .../log_category_document_examples_table.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index c4b9045be0c9e..e729e57e3dd6c 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -143,7 +143,6 @@ export const LogCategoryDocumentExamplesTable: React.FC From bf14132c971635d3ac629735d2ff2ca2b03626a0 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:18:06 +0100 Subject: [PATCH 60/74] Last > latest wording --- .../log_category_document_examples_table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index e729e57e3dd6c..3e14b7b9128ab 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -127,7 +127,7 @@ export const LogCategoryDocumentExamplesTable: React.FC Date: Tue, 15 Oct 2024 11:18:54 +0100 Subject: [PATCH 61/74] Update packages/kbn-discover-contextual-components/kibana.jsonc Co-authored-by: Julia Rechkunova --- packages/kbn-discover-contextual-components/kibana.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-discover-contextual-components/kibana.jsonc b/packages/kbn-discover-contextual-components/kibana.jsonc index 8e06123264576..cfb9b1d5431ef 100644 --- a/packages/kbn-discover-contextual-components/kibana.jsonc +++ b/packages/kbn-discover-contextual-components/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-browser", "id": "@kbn/discover-contextual-components", - "owner": "@elastic/obs-ux-logs-team" + "owner": ["@elastic/obs-ux-logs-team", "@elastic/kibana-data-discovery"] } From 88e38cc5829e167e9c499ee064e725f4465c2ded Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:22:49 +0100 Subject: [PATCH 62/74] Move query into filter --- .../log_category_details/log_category_details_flyout.tsx | 1 - .../src/services/category_details_service/queries.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index 970a73c448160..659511f3c9a17 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -93,7 +93,6 @@ export const LogCategoryDetailsFlyout: React.FC = />

-
diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts index e9872afbf2669..cd1053077c334 100644 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts @@ -49,9 +49,9 @@ export const createGetLogCategoryDocumentsRequestParams = ({ }, }, }, + createCategoryQuery(messageField)(categoryTerms), ...additionalFilters, ], - must: createCategoryQuery(messageField)(categoryTerms), }, }, }; From 537b0523f93fe156962bc8597ca9ffada22d7a58 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:35:29 +0000 Subject: [PATCH 63/74] [CI] Auto-commit changed files from 'node scripts/lint_packages --fix' --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0daf1e714def6..eb1b3963c3353 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -385,7 +385,7 @@ packages/kbn-dev-proc-runner @elastic/kibana-operations src/plugins/dev_tools @elastic/kibana-management packages/kbn-dev-utils @elastic/kibana-operations examples/developer_examples @elastic/appex-sharedux -packages/kbn-discover-contextual-components @elastic/obs-ux-logs-team +packages/kbn-discover-contextual-components @elastic/obs-ux-logs-team @elastic/kibana-data-discovery examples/discover_customization_examples @elastic/kibana-data-discovery x-pack/plugins/discover_enhanced @elastic/kibana-data-discovery src/plugins/discover @elastic/kibana-data-discovery From 601d1f94ded99df3c1f5f27486513d09da1a1785 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:19:15 +0100 Subject: [PATCH 64/74] Amend config for tests in new package --- packages/kbn-discover-contextual-components/jest.config.js | 2 +- packages/kbn-discover-contextual-components/tsconfig.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/kbn-discover-contextual-components/jest.config.js b/packages/kbn-discover-contextual-components/jest.config.js index 37624c643d4d0..bacfd33649ce4 100644 --- a/packages/kbn-discover-contextual-components/jest.config.js +++ b/packages/kbn-discover-contextual-components/jest.config.js @@ -8,7 +8,7 @@ */ module.exports = { - preset: '@kbn/test/jest_node', + preset: '@kbn/test', rootDir: '../..', roots: ['/packages/kbn-discover-contextual-components'], }; diff --git a/packages/kbn-discover-contextual-components/tsconfig.json b/packages/kbn-discover-contextual-components/tsconfig.json index 4c03098e79601..57706e333abc1 100644 --- a/packages/kbn-discover-contextual-components/tsconfig.json +++ b/packages/kbn-discover-contextual-components/tsconfig.json @@ -4,7 +4,9 @@ "outDir": "target/types", "types": [ "jest", - "node" + "node", + "@testing-library/jest-dom", + "@testing-library/react" ] }, "include": [ From 0d8959c4d7e395973995c1a6f0a3011fb5d1fb2a Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:34:36 +0100 Subject: [PATCH 65/74] Add a spacer in for some breathing room Wrapping in EuiText will add background colours to the pre --- .../log_category_details/log_category_details_flyout.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx index 659511f3c9a17..2f478c771dbfa 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_details_flyout.tsx @@ -11,6 +11,7 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, + EuiSpacer, EuiTitle, useGeneratedHtmlId, } from '@elastic/eui'; @@ -93,6 +94,7 @@ export const LogCategoryDetailsFlyout: React.FC = /> + From 34d9f9734e50a0d854cd6dfc63cf1b86fcc6ad08 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:17:30 +0100 Subject: [PATCH 66/74] PR feedback --- .../index.ts | 10 + .../package.json | 3 +- .../logs/components/cell_actions_popover.tsx | 8 +- .../src/data_types/logs/components/index.ts | 1 + .../log_level_badge_cell.tsx | 2 +- .../service_name_badge_with_actions.tsx | 8 +- .../logs/components/summary_column/utils.tsx | 5 +- .../logs/components/translations.tsx | 233 ------------- .../src/index.ts | 10 + .../src/data_types/logs/utils/index.ts | 1 + .../data_types/logs/summary_column/index.tsx | 2 +- .../logs/summary_column/summary_column.tsx | 2 +- .../data_types/logs/translations.tsx | 305 ------------------ .../accessors/get_cell_renderers.tsx | 2 +- .../logs_shared/kibana.jsonc | 1 - 15 files changed, 43 insertions(+), 550 deletions(-) create mode 100644 packages/kbn-discover-contextual-components/index.ts create mode 100644 packages/kbn-discover-contextual-components/src/index.ts delete mode 100644 src/plugins/discover/public/components/data_types/logs/translations.tsx diff --git a/packages/kbn-discover-contextual-components/index.ts b/packages/kbn-discover-contextual-components/index.ts new file mode 100644 index 0000000000000..55b900ad5137a --- /dev/null +++ b/packages/kbn-discover-contextual-components/index.ts @@ -0,0 +1,10 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './src'; diff --git a/packages/kbn-discover-contextual-components/package.json b/packages/kbn-discover-contextual-components/package.json index ef68d35fa857f..4a63d975cda42 100644 --- a/packages/kbn-discover-contextual-components/package.json +++ b/packages/kbn-discover-contextual-components/package.json @@ -2,5 +2,6 @@ "name": "@kbn/discover-contextual-components", "private": true, "version": "1.0.0", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", + "sideEffects": false } \ No newline at end of file diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx index 2eaebd6e5fe6a..96651cf26189b 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx @@ -160,17 +160,23 @@ export function CellActionsPopover({ export interface FieldBadgeWithActionsProps extends Pick { icon?: EuiBadgeProps['iconType']; +} + +interface FieldBadgeWithActionsDependencies { core?: CoreStart; share?: SharePluginStart; } +export type FieldBadgeWithActionsPropsAndDependencies = FieldBadgeWithActionsProps & + FieldBadgeWithActionsDependencies; + export function FieldBadgeWithActions({ icon, onFilter, property, renderValue, value, -}: FieldBadgeWithActionsProps) { +}: FieldBadgeWithActionsPropsAndDependencies) { return ( >; + ResourceBadge: React.ComponentType; Icon?: () => JSX.Element; name: keyof ResourceFields; value: string; diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx index bbc39022bd503..52e083f8b86b8 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/translations.tsx @@ -7,14 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiCode } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export const flyoutContentLabel = i18n.translate('discover.logs.flyoutDetail.label.message', { - defaultMessage: 'Content breakdown', -}); export const jsonLabel = i18n.translate('discover.logs.dataTable.header.popover.json', { defaultMessage: 'JSON', @@ -28,118 +21,6 @@ export const resourceLabel = i18n.translate('discover.logs.dataTable.header.popo defaultMessage: 'Resource', }); -export const actionsLabel = i18n.translate('discover.logs.dataTable.header.popover.actions', { - defaultMessage: 'Actions', -}); - -export const actionsLabelLowerCase = i18n.translate( - 'discover.logs.dataTable.header.popover.actions.lowercase', - { - defaultMessage: 'actions', - } -); - -export const flyoutServiceLabel = i18n.translate('discover.logs.flyoutDetail.label.service', { - defaultMessage: 'Service', -}); - -export const flyoutTraceLabel = i18n.translate('discover.logs.flyoutDetail.label.trace', { - defaultMessage: 'Trace', -}); - -export const flyoutHostNameLabel = i18n.translate('discover.logs.flyoutDetail.label.hostName', { - defaultMessage: 'Host name', -}); - -export const serviceInfraAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.serviceInfra', - { - defaultMessage: 'Service & Infrastructure', - } -); - -export const cloudAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.cloud', - { - defaultMessage: 'Cloud', - } -); - -export const otherAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.other', - { - defaultMessage: 'Other', - } -); - -export const flyoutOrchestratorClusterNameLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.orchestratorClusterName', - { - defaultMessage: 'Orchestrator cluster Name', - } -); - -export const flyoutOrchestratorResourceIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.orchestratorResourceId', - { - defaultMessage: 'Orchestrator resource ID', - } -); - -export const flyoutCloudProviderLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudProvider', - { - defaultMessage: 'Cloud provider', - } -); - -export const flyoutCloudRegionLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudRegion', - { - defaultMessage: 'Cloud region', - } -); - -export const flyoutCloudAvailabilityZoneLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudAvailabilityZone', - { - defaultMessage: 'Cloud availability zone', - } -); - -export const flyoutCloudProjectIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudProjectId', - { - defaultMessage: 'Cloud project ID', - } -); - -export const flyoutCloudInstanceIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudInstanceId', - { - defaultMessage: 'Cloud instance ID', - } -); - -export const flyoutLogPathFileLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.logPathFile', - { - defaultMessage: 'Log path file', - } -); - -export const flyoutNamespaceLabel = i18n.translate('discover.logs.flyoutDetail.label.namespace', { - defaultMessage: 'Namespace', -}); - -export const flyoutDatasetLabel = i18n.translate('discover.logs.flyoutDetail.label.dataset', { - defaultMessage: 'Dataset', -}); - -export const flyoutShipperLabel = i18n.translate('discover.logs.flyoutDetail.label.shipper', { - defaultMessage: 'Shipper', -}); - export const actionFilterForText = (text: string) => i18n.translate('discover.logs.flyoutDetail.value.hover.filterFor', { defaultMessage: 'Filter for this {value}', @@ -164,27 +45,6 @@ export const filterForText = i18n.translate('discover.logs.popoverAction.filterF defaultMessage: 'Filter for', }); -export const flyoutHoverActionFilterForFieldPresentText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.filterForFieldPresent', - { - defaultMessage: 'Filter for field present', - } -); - -export const flyoutHoverActionToggleColumnText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.toggleColumn', - { - defaultMessage: 'Toggle column in table', - } -); - -export const flyoutHoverActionCopyToClipboardText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.copyToClipboard', - { - defaultMessage: 'Copy to clipboard', - } -); - export const copyValueText = i18n.translate('discover.logs.popoverAction.copyValue', { defaultMessage: 'Copy value', }); @@ -197,14 +57,6 @@ export const copyValueAriaText = (fieldName: string) => }, }); -export const flyoutAccordionShowMoreText = (count: number) => - i18n.translate('discover.logs.flyoutDetail.section.showMore', { - defaultMessage: '+ {hiddenCount} more', - values: { - hiddenCount: count, - }, - }); - export const openCellActionPopoverAriaText = i18n.translate( 'discover.logs.popoverAction.openPopover', { @@ -218,88 +70,3 @@ export const closeCellActionPopoverText = i18n.translate( defaultMessage: 'Close popover', } ); - -export const contentHeaderTooltipParagraph1 = ( - log.level, - message: message, - }} - /> -); - -export const contentHeaderTooltipParagraph2 = i18n.translate( - 'discover.logs.dataTable.header.content.tooltip.paragraph2', - { - defaultMessage: 'When the message field is empty, one of the following is displayed:', - } -); - -export const resourceHeaderTooltipParagraph = i18n.translate( - 'discover.logs.dataTable.header.resource.tooltip.paragraph', - { - defaultMessage: "Fields that provide information on the document's source, such as:", - } -); - -export const actionsHeaderTooltipParagraph = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.paragraph', - { - defaultMessage: 'Fields that provide actionable information, such as:', - } -); - -export const actionsHeaderTooltipExpandAction = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.expand', - { defaultMessage: 'Expand log details' } -); - -export const actionsHeaderTooltipDegradedAction = ( - - _ignored - - ), - }} - /> -); - -export const actionsHeaderTooltipStacktraceAction = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.stacktrace', - { defaultMessage: 'Access to available stacktraces based on:' } -); - -export const degradedDocButtonLabelWhenPresent = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent', - { - defaultMessage: - "This document couldn't be parsed correctly. Not all fields are properly populated", - } -); - -export const degradedDocButtonLabelWhenNotPresent = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent', - { - defaultMessage: 'All fields in this document were parsed correctly', - } -); - -export const stacktraceAvailableControlButton = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.available', - { - defaultMessage: 'Stacktraces available', - } -); - -export const stacktraceNotAvailableControlButton = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable', - { - defaultMessage: 'Stacktraces not available', - } -); diff --git a/packages/kbn-discover-contextual-components/src/index.ts b/packages/kbn-discover-contextual-components/src/index.ts new file mode 100644 index 0000000000000..d8dbfe74d2f95 --- /dev/null +++ b/packages/kbn-discover-contextual-components/src/index.ts @@ -0,0 +1,10 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './data_types/logs/components'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/utils/index.ts b/packages/kbn-discover-utils/src/data_types/logs/utils/index.ts index 0b266fa5b4935..365365eb7ac13 100644 --- a/packages/kbn-discover-utils/src/data_types/logs/utils/index.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/utils/index.ts @@ -9,3 +9,4 @@ export * from './get_log_level_color'; export * from './get_log_level_coalesed_value'; +export * from './get_available_resource_fields'; diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx b/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx index b7b0625a522af..dbcef4f558b33 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx +++ b/src/plugins/discover/public/components/data_types/logs/summary_column/index.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { getShouldShowFieldHandler } from '@kbn/discover-utils'; import { DataView } from '@kbn/data-views-plugin/common'; -import { SummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; +import { SummaryColumnProps } from '@kbn/discover-contextual-components'; import { CellRenderersExtensionParams } from '../../../../context_awareness'; import { SummaryColumn } from './summary_column'; diff --git a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx b/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx index 4846f6752ebf5..b04d921d1694f 100644 --- a/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx +++ b/src/plugins/discover/public/components/data_types/logs/summary_column/summary_column.tsx @@ -9,7 +9,7 @@ import { dynamic } from '@kbn/shared-ux-utility'; import React from 'react'; -import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; +import { AllSummaryColumnProps } from '@kbn/discover-contextual-components'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; const LazySummaryColumn = dynamic( diff --git a/src/plugins/discover/public/components/data_types/logs/translations.tsx b/src/plugins/discover/public/components/data_types/logs/translations.tsx deleted file mode 100644 index bbc39022bd503..0000000000000 --- a/src/plugins/discover/public/components/data_types/logs/translations.tsx +++ /dev/null @@ -1,305 +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", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiCode } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export const flyoutContentLabel = i18n.translate('discover.logs.flyoutDetail.label.message', { - defaultMessage: 'Content breakdown', -}); - -export const jsonLabel = i18n.translate('discover.logs.dataTable.header.popover.json', { - defaultMessage: 'JSON', -}); - -export const contentLabel = i18n.translate('discover.logs.dataTable.header.popover.content', { - defaultMessage: 'Content', -}); - -export const resourceLabel = i18n.translate('discover.logs.dataTable.header.popover.resource', { - defaultMessage: 'Resource', -}); - -export const actionsLabel = i18n.translate('discover.logs.dataTable.header.popover.actions', { - defaultMessage: 'Actions', -}); - -export const actionsLabelLowerCase = i18n.translate( - 'discover.logs.dataTable.header.popover.actions.lowercase', - { - defaultMessage: 'actions', - } -); - -export const flyoutServiceLabel = i18n.translate('discover.logs.flyoutDetail.label.service', { - defaultMessage: 'Service', -}); - -export const flyoutTraceLabel = i18n.translate('discover.logs.flyoutDetail.label.trace', { - defaultMessage: 'Trace', -}); - -export const flyoutHostNameLabel = i18n.translate('discover.logs.flyoutDetail.label.hostName', { - defaultMessage: 'Host name', -}); - -export const serviceInfraAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.serviceInfra', - { - defaultMessage: 'Service & Infrastructure', - } -); - -export const cloudAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.cloud', - { - defaultMessage: 'Cloud', - } -); - -export const otherAccordionTitle = i18n.translate( - 'discover.logs.flyoutDetail.accordion.title.other', - { - defaultMessage: 'Other', - } -); - -export const flyoutOrchestratorClusterNameLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.orchestratorClusterName', - { - defaultMessage: 'Orchestrator cluster Name', - } -); - -export const flyoutOrchestratorResourceIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.orchestratorResourceId', - { - defaultMessage: 'Orchestrator resource ID', - } -); - -export const flyoutCloudProviderLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudProvider', - { - defaultMessage: 'Cloud provider', - } -); - -export const flyoutCloudRegionLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudRegion', - { - defaultMessage: 'Cloud region', - } -); - -export const flyoutCloudAvailabilityZoneLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudAvailabilityZone', - { - defaultMessage: 'Cloud availability zone', - } -); - -export const flyoutCloudProjectIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudProjectId', - { - defaultMessage: 'Cloud project ID', - } -); - -export const flyoutCloudInstanceIdLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.cloudInstanceId', - { - defaultMessage: 'Cloud instance ID', - } -); - -export const flyoutLogPathFileLabel = i18n.translate( - 'discover.logs.flyoutDetail.label.logPathFile', - { - defaultMessage: 'Log path file', - } -); - -export const flyoutNamespaceLabel = i18n.translate('discover.logs.flyoutDetail.label.namespace', { - defaultMessage: 'Namespace', -}); - -export const flyoutDatasetLabel = i18n.translate('discover.logs.flyoutDetail.label.dataset', { - defaultMessage: 'Dataset', -}); - -export const flyoutShipperLabel = i18n.translate('discover.logs.flyoutDetail.label.shipper', { - defaultMessage: 'Shipper', -}); - -export const actionFilterForText = (text: string) => - i18n.translate('discover.logs.flyoutDetail.value.hover.filterFor', { - defaultMessage: 'Filter for this {value}', - values: { - value: text, - }, - }); - -export const actionFilterOutText = (text: string) => - i18n.translate('discover.logs.flyoutDetail.value.hover.filterOut', { - defaultMessage: 'Filter out this {value}', - values: { - value: text, - }, - }); - -export const filterOutText = i18n.translate('discover.logs.popoverAction.filterOut', { - defaultMessage: 'Filter out', -}); - -export const filterForText = i18n.translate('discover.logs.popoverAction.filterFor', { - defaultMessage: 'Filter for', -}); - -export const flyoutHoverActionFilterForFieldPresentText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.filterForFieldPresent', - { - defaultMessage: 'Filter for field present', - } -); - -export const flyoutHoverActionToggleColumnText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.toggleColumn', - { - defaultMessage: 'Toggle column in table', - } -); - -export const flyoutHoverActionCopyToClipboardText = i18n.translate( - 'discover.logs.flyoutDetail.value.hover.copyToClipboard', - { - defaultMessage: 'Copy to clipboard', - } -); - -export const copyValueText = i18n.translate('discover.logs.popoverAction.copyValue', { - defaultMessage: 'Copy value', -}); - -export const copyValueAriaText = (fieldName: string) => - i18n.translate('discover.logs.popoverAction.copyValueAriaText', { - defaultMessage: 'Copy value of {fieldName}', - values: { - fieldName, - }, - }); - -export const flyoutAccordionShowMoreText = (count: number) => - i18n.translate('discover.logs.flyoutDetail.section.showMore', { - defaultMessage: '+ {hiddenCount} more', - values: { - hiddenCount: count, - }, - }); - -export const openCellActionPopoverAriaText = i18n.translate( - 'discover.logs.popoverAction.openPopover', - { - defaultMessage: 'Open popover', - } -); - -export const closeCellActionPopoverText = i18n.translate( - 'discover.logs.popoverAction.closePopover', - { - defaultMessage: 'Close popover', - } -); - -export const contentHeaderTooltipParagraph1 = ( - log.level, - message: message, - }} - /> -); - -export const contentHeaderTooltipParagraph2 = i18n.translate( - 'discover.logs.dataTable.header.content.tooltip.paragraph2', - { - defaultMessage: 'When the message field is empty, one of the following is displayed:', - } -); - -export const resourceHeaderTooltipParagraph = i18n.translate( - 'discover.logs.dataTable.header.resource.tooltip.paragraph', - { - defaultMessage: "Fields that provide information on the document's source, such as:", - } -); - -export const actionsHeaderTooltipParagraph = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.paragraph', - { - defaultMessage: 'Fields that provide actionable information, such as:', - } -); - -export const actionsHeaderTooltipExpandAction = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.expand', - { defaultMessage: 'Expand log details' } -); - -export const actionsHeaderTooltipDegradedAction = ( - - _ignored - - ), - }} - /> -); - -export const actionsHeaderTooltipStacktraceAction = i18n.translate( - 'discover.logs.dataTable.header.actions.tooltip.stacktrace', - { defaultMessage: 'Access to available stacktraces based on:' } -); - -export const degradedDocButtonLabelWhenPresent = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent', - { - defaultMessage: - "This document couldn't be parsed correctly. Not all fields are properly populated", - } -); - -export const degradedDocButtonLabelWhenNotPresent = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent', - { - defaultMessage: 'All fields in this document were parsed correctly', - } -); - -export const stacktraceAvailableControlButton = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.available', - { - defaultMessage: 'Stacktraces available', - } -); - -export const stacktraceNotAvailableControlButton = i18n.translate( - 'discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable', - { - defaultMessage: 'Stacktraces not available', - } -); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx b/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx index 1ce554bb880ee..5cafa13bd5193 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/common/logs_data_source_profile/accessors/get_cell_renderers.tsx @@ -8,7 +8,7 @@ */ import { SOURCE_COLUMN } from '@kbn/unified-data-table'; -import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; +import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components'; import { getSummaryColumn } from '../../../../../components/data_types/logs/summary_column'; import { LOG_LEVEL_FIELDS, diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index cacdc0cdce992..f5e9f76c2ace6 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -14,7 +14,6 @@ "fieldFormats", "dataViews", "discoverShared", - "discover", "logsDataAccess", "observabilityShared", "share", From 76ead24690b22403788beed6fb33aa9bf82136cd Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:45:34 +0000 Subject: [PATCH 67/74] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-discover-contextual-components/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kbn-discover-contextual-components/tsconfig.json b/packages/kbn-discover-contextual-components/tsconfig.json index 57706e333abc1..21d65228b9597 100644 --- a/packages/kbn-discover-contextual-components/tsconfig.json +++ b/packages/kbn-discover-contextual-components/tsconfig.json @@ -28,7 +28,6 @@ "@kbn/react-hooks", "@kbn/core-lifecycle-browser", "@kbn/i18n", - "@kbn/i18n-react", "@kbn/unified-doc-viewer-plugin", "@kbn/core", "@kbn/shared-ux-utility", From 7b2545e7341b01b2b442c855a982b48920fb0852 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:16:23 +0100 Subject: [PATCH 68/74] Don't prebind deps --- .../log_category_document_examples_table.tsx | 6 +++++- .../observability_solution/logs_shared/public/plugin.tsx | 9 +++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index 3e14b7b9128ab..7bb4cd2089a52 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -15,15 +15,17 @@ import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import { LogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; import type { LogCategoryDocument } from '../../services/category_details_service/types'; import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; export interface LogCategoryDocumentExamplesTableDependencies { + core: CoreStart; uiSettings: SettingsStart; fieldFormats: FieldFormatsStart; share: SharePluginStart; columns: { - SummaryColumn: React.ComponentType>; + SummaryColumn: React.ComponentType; LogLevelCell: LogLevelBadgeCell; }; } @@ -116,6 +118,8 @@ export const LogCategoryDocumentExamplesTable: React.FC false} + core={dependencies.core} + share={dependencies.share} /> ); }, diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx index bad7c80881b91..55488b9b771c8 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx @@ -7,9 +7,7 @@ import { CoreStart } from '@kbn/core/public'; import { dynamic } from '@kbn/shared-ux-utility'; -import React from 'react'; -import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; -import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; +import { getLogLevelBadgeCell } from '@kbn/discover-contextual-components'; import { LogsLocatorDefinition, NodeLogsLocatorDefinition, @@ -83,6 +81,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { }); const LogsOverview = createLogsOverview({ + core, charts, logsDataAccess, search: data.search.search, @@ -91,9 +90,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { dataViews, fieldFormats, columns: { - SummaryColumn: (props: Omit) => { - return ; - }, + SummaryColumn: LazySummaryColumn, LogLevelCell: getLogLevelBadgeCell('log.level'), }, }); From 87869d9e38e5a16f16e51d200d0f9bc78c28893b Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:30:38 +0100 Subject: [PATCH 69/74] Amend constants imports / exports --- .../components/summary_column/content.tsx | 4 +- .../summary_column/summary_column.tsx | 2 +- .../logs/components/summary_column/utils.tsx | 57 +++++++++++-------- packages/kbn-discover-utils/index.ts | 2 + 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx index 7ca3944e6aed6..cc576efff17db 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx @@ -14,7 +14,7 @@ import { getLogDocumentOverview, getMessageFieldWithFallbacks, } from '@kbn/discover-utils'; -import * as constants from '@kbn/discover-utils/src/data_types/logs/constants'; +import { MESSAGE_FIELD } from '@kbn/discover-utils'; import { formatJsonDocumentForContent } from './utils'; interface ContentProps extends DataGridCellValueElementProps { @@ -32,7 +32,7 @@ const LogMessage = ({ value: string; className: string; }) => { - const shouldRenderFieldName = field !== constants.MESSAGE_FIELD; + const shouldRenderFieldName = field !== MESSAGE_FIELD; if (shouldRenderFieldName) { return ( diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx index d630b686255c6..98f772fcf41d1 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx @@ -19,7 +19,7 @@ import { getLogDocumentOverview, getMessageFieldWithFallbacks, } from '@kbn/discover-utils'; -import { ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table/src/constants'; +import { ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; import { Resource } from './resource'; import { Content } from './content'; import { createResourceFields, formatJsonDocumentForContent } from './utils'; diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx index 48cd9c16e2df0..7dacc3393763e 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx @@ -14,7 +14,18 @@ import { AgentName } from '@kbn/elastic-agent-utils'; import { euiThemeVars } from '@kbn/ui-theme'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; -import * as constants from '@kbn/discover-utils/src/data_types/logs/constants'; +import { + AGENT_NAME_FIELD, + CLOUD_INSTANCE_ID_FIELD, + CONTAINER_ID_FIELD, + CONTAINER_NAME_FIELD, + FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT, + HOST_NAME_FIELD, + ORCHESTRATOR_CLUSTER_NAME_FIELD, + ORCHESTRATOR_NAMESPACE_FIELD, + ORCHESTRATOR_RESOURCE_ID_FIELD, + SERVICE_NAME_FIELD, +} from '@kbn/discover-utils'; import { DataTableRecord, getFieldValue } from '@kbn/discover-utils'; import { LogDocument, ResourceFields, getAvailableResourceFields } from '@kbn/discover-utils/src'; import { FieldBadgeWithActions, FieldBadgeWithActionsProps } from '../cell_actions_popover'; @@ -23,26 +34,26 @@ import { ServiceNameBadgeWithActions } from '../service_name_badge_with_actions' * getUnformattedResourceFields definitions */ export const getUnformattedResourceFields = (doc: LogDocument): ResourceFields => { - const serviceName = getFieldValue(doc, constants.SERVICE_NAME_FIELD); - const hostName = getFieldValue(doc, constants.HOST_NAME_FIELD); - const agentName = getFieldValue(doc, constants.AGENT_NAME_FIELD); - const orchestratorClusterName = getFieldValue(doc, constants.ORCHESTRATOR_CLUSTER_NAME_FIELD); - const orchestratorResourceId = getFieldValue(doc, constants.ORCHESTRATOR_RESOURCE_ID_FIELD); - const orchestratorNamespace = getFieldValue(doc, constants.ORCHESTRATOR_NAMESPACE_FIELD); - const containerName = getFieldValue(doc, constants.CONTAINER_NAME_FIELD); - const containerId = getFieldValue(doc, constants.CONTAINER_ID_FIELD); - const cloudInstanceId = getFieldValue(doc, constants.CLOUD_INSTANCE_ID_FIELD); + const serviceName = getFieldValue(doc, SERVICE_NAME_FIELD); + const hostName = getFieldValue(doc, HOST_NAME_FIELD); + const agentName = getFieldValue(doc, AGENT_NAME_FIELD); + const orchestratorClusterName = getFieldValue(doc, ORCHESTRATOR_CLUSTER_NAME_FIELD); + const orchestratorResourceId = getFieldValue(doc, ORCHESTRATOR_RESOURCE_ID_FIELD); + const orchestratorNamespace = getFieldValue(doc, ORCHESTRATOR_NAMESPACE_FIELD); + const containerName = getFieldValue(doc, CONTAINER_NAME_FIELD); + const containerId = getFieldValue(doc, CONTAINER_ID_FIELD); + const cloudInstanceId = getFieldValue(doc, CLOUD_INSTANCE_ID_FIELD); return { - [constants.SERVICE_NAME_FIELD]: serviceName, - [constants.HOST_NAME_FIELD]: hostName, - [constants.AGENT_NAME_FIELD]: agentName, - [constants.ORCHESTRATOR_CLUSTER_NAME_FIELD]: orchestratorClusterName, - [constants.ORCHESTRATOR_RESOURCE_ID_FIELD]: orchestratorResourceId, - [constants.ORCHESTRATOR_NAMESPACE_FIELD]: orchestratorNamespace, - [constants.CONTAINER_NAME_FIELD]: containerName, - [constants.CONTAINER_ID_FIELD]: containerId, - [constants.CLOUD_INSTANCE_ID_FIELD]: cloudInstanceId, + [SERVICE_NAME_FIELD]: serviceName, + [HOST_NAME_FIELD]: hostName, + [AGENT_NAME_FIELD]: agentName, + [ORCHESTRATOR_CLUSTER_NAME_FIELD]: orchestratorClusterName, + [ORCHESTRATOR_RESOURCE_ID_FIELD]: orchestratorResourceId, + [ORCHESTRATOR_NAMESPACE_FIELD]: orchestratorNamespace, + [CONTAINER_NAME_FIELD]: containerName, + [CONTAINER_ID_FIELD]: containerId, + [CLOUD_INSTANCE_ID_FIELD]: cloudInstanceId, }; }; @@ -54,7 +65,7 @@ const AgentIcon = dynamic(() => import('@kbn/custom-icons/src/components/agent_i const resourceCustomComponentsMap: Partial< Record> > = { - [constants.SERVICE_NAME_FIELD]: ServiceNameBadgeWithActions, + [SERVICE_NAME_FIELD]: ServiceNameBadgeWithActions, }; export interface ResourceFieldDescriptor { @@ -82,10 +93,10 @@ export const createResourceFields = ( name, value: resourceDoc[name] as string, ResourceBadge: resourceBadgeComponentWithDependencies, - ...(name === constants.SERVICE_NAME_FIELD && { + ...(name === SERVICE_NAME_FIELD && { Icon: () => ( { }; const isFieldAllowed = (field: string) => - !constants.FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT.some((prefix) => field.startsWith(prefix)); + !FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT.some((prefix) => field.startsWith(prefix)); diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index 24a2b755359aa..7234944783037 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -64,3 +64,5 @@ export { export type { LogsContextService } from './src'; export * from './src/types'; + +export * from './src/data_types/logs/constants'; From 017461000254f5b9deb12ce2d379f900c18a6c5f Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:44:01 +0100 Subject: [PATCH 70/74] i18n --fix --- .../translations/translations/fr-FR.json | 35 ------------------- .../translations/translations/ja-JP.json | 35 ------------------- .../translations/translations/zh-CN.json | 35 ------------------- 3 files changed, 105 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index fc240ba84ad29..5a344cf806119 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -2480,45 +2480,10 @@ "discover.localMenu.saveTitle": "Enregistrer", "discover.localMenu.shareSearchDescription": "Partager la recherche", "discover.localMenu.shareTitle": "Partager", - "discover.logs.dataTable.controlColumn.actions.button.degradedDoc": "Accès à un document dégradé avec le champ {ignoredProperty}", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent": "Tous les champs de ce document ont été analysés correctement", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent": "Ce document n'a pas pu être analysé correctement. Tous les champs n'ont pas été remplis correctement", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.available": "Traces d'appel disponibles", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable": "Traces d'appel indisponibles", - "discover.logs.dataTable.header.actions.tooltip.expand": "Développer les détails du log", - "discover.logs.dataTable.header.actions.tooltip.paragraph": "Les champs fournissant des informations exploitables, comme :", - "discover.logs.dataTable.header.actions.tooltip.stacktrace": "L'accès aux traces d'appel disponibles est basé sur :", - "discover.logs.dataTable.header.content.tooltip.paragraph1": "Affiche le {logLevel} du document et les champs {message}.", - "discover.logs.dataTable.header.content.tooltip.paragraph2": "Lorsque le champ de message est vide, l'une des informations suivantes s'affiche :", - "discover.logs.dataTable.header.popover.actions": "Actions", - "discover.logs.dataTable.header.popover.actions.lowercase": "actions", "discover.logs.dataTable.header.popover.content": "Contenu", "discover.logs.dataTable.header.popover.resource": "Ressource", - "discover.logs.dataTable.header.resource.tooltip.paragraph": "Les champs fournissant des informations sur la source du document, comme :", - "discover.logs.flyoutDetail.accordion.title.cloud": "Cloud", - "discover.logs.flyoutDetail.accordion.title.other": "Autre", - "discover.logs.flyoutDetail.accordion.title.serviceInfra": "Service et Infrastructure", - "discover.logs.flyoutDetail.label.cloudAvailabilityZone": "Zone de disponibilité du cloud", - "discover.logs.flyoutDetail.label.cloudInstanceId": "ID d'instance du cloud", - "discover.logs.flyoutDetail.label.cloudProjectId": "ID de projet du cloud", - "discover.logs.flyoutDetail.label.cloudProvider": "Fournisseur cloud", - "discover.logs.flyoutDetail.label.cloudRegion": "Région du cloud", - "discover.logs.flyoutDetail.label.dataset": "Ensemble de données", - "discover.logs.flyoutDetail.label.hostName": "Nom d'hôte", - "discover.logs.flyoutDetail.label.logPathFile": "Fichier de chemin d'accès au log", - "discover.logs.flyoutDetail.label.message": "Répartition du contenu", - "discover.logs.flyoutDetail.label.namespace": "Espace de nom", - "discover.logs.flyoutDetail.label.orchestratorClusterName": "Nom de cluster de l'orchestrateur", - "discover.logs.flyoutDetail.label.orchestratorResourceId": "ID de ressource de l'orchestrateur", - "discover.logs.flyoutDetail.label.service": "Service", - "discover.logs.flyoutDetail.label.shipper": "Agent de transfert", - "discover.logs.flyoutDetail.label.trace": "Trace", - "discover.logs.flyoutDetail.section.showMore": "+ {hiddenCount} autres", - "discover.logs.flyoutDetail.value.hover.copyToClipboard": "Copier dans le presse-papiers", "discover.logs.flyoutDetail.value.hover.filterFor": "Filtrer sur cette {value}", - "discover.logs.flyoutDetail.value.hover.filterForFieldPresent": "Filtrer sur le champ", "discover.logs.flyoutDetail.value.hover.filterOut": "Exclure cette {value}", - "discover.logs.flyoutDetail.value.hover.toggleColumn": "Afficher/Masquer la colonne dans le tableau", "discover.logs.popoverAction.closePopover": "Fermer la fenêtre contextuelle", "discover.logs.popoverAction.copyValue": "Copier la valeur", "discover.logs.popoverAction.copyValueAriaText": "Copier la valeur de {fieldName}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4d39022965da0..acaa7a2a7e58e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2479,45 +2479,10 @@ "discover.localMenu.saveTitle": "保存", "discover.localMenu.shareSearchDescription": "検索を共有します", "discover.localMenu.shareTitle": "共有", - "discover.logs.dataTable.controlColumn.actions.button.degradedDoc": "{ignoredProperty}フィールドの劣化したドキュメントにアクセス", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent": "このドキュメントのすべてのフィールドは正しく解析されました", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent": "このドキュメントを正しく解析できませんでした。一部のフィールドが正しく入力されていません", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.available": "スタックトレースがあります", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable": "スタックトレースがありません", - "discover.logs.dataTable.header.actions.tooltip.expand": "ログの詳細を展開", - "discover.logs.dataTable.header.actions.tooltip.paragraph": "次のようなアクショナブルな情報を提供するフィールド:", - "discover.logs.dataTable.header.actions.tooltip.stacktrace": "次に基づいて使用可能なスタックトレースにアクセス:", - "discover.logs.dataTable.header.content.tooltip.paragraph1": "ドキュメントの{logLevel}と{message}フィールドを表示します。", - "discover.logs.dataTable.header.content.tooltip.paragraph2": "メッセージフィールドが空のときには、次のいずれかが表示されます。", - "discover.logs.dataTable.header.popover.actions": "アクション", - "discover.logs.dataTable.header.popover.actions.lowercase": "アクション", "discover.logs.dataTable.header.popover.content": "コンテンツ", "discover.logs.dataTable.header.popover.resource": "リソース", - "discover.logs.dataTable.header.resource.tooltip.paragraph": "次のようなドキュメントのソースに関する情報を提供するフィールド:", - "discover.logs.flyoutDetail.accordion.title.cloud": "クラウド", - "discover.logs.flyoutDetail.accordion.title.other": "Other", - "discover.logs.flyoutDetail.accordion.title.serviceInfra": "サービスとインフラストラクチャー", - "discover.logs.flyoutDetail.label.cloudAvailabilityZone": "クラウドアベイラビリティゾーン", - "discover.logs.flyoutDetail.label.cloudInstanceId": "クラウドインスタンスID", - "discover.logs.flyoutDetail.label.cloudProjectId": "クラウドプロジェクトID", - "discover.logs.flyoutDetail.label.cloudProvider": "クラウドプロバイダー", - "discover.logs.flyoutDetail.label.cloudRegion": "クラウドリージョン", - "discover.logs.flyoutDetail.label.dataset": "データセット", - "discover.logs.flyoutDetail.label.hostName": "ホスト名", - "discover.logs.flyoutDetail.label.logPathFile": "ログパスファイル", - "discover.logs.flyoutDetail.label.message": "コンテンツの内訳", - "discover.logs.flyoutDetail.label.namespace": "名前空間", - "discover.logs.flyoutDetail.label.orchestratorClusterName": "オーケストレータークラスター名", - "discover.logs.flyoutDetail.label.orchestratorResourceId": "オーケストレーターリソースID", - "discover.logs.flyoutDetail.label.service": "サービス", - "discover.logs.flyoutDetail.label.shipper": "シッパー", - "discover.logs.flyoutDetail.label.trace": "トレース", - "discover.logs.flyoutDetail.section.showMore": "+ その他{hiddenCount}件", - "discover.logs.flyoutDetail.value.hover.copyToClipboard": "クリップボードにコピー", "discover.logs.flyoutDetail.value.hover.filterFor": "この{value}でフィルターを適用", - "discover.logs.flyoutDetail.value.hover.filterForFieldPresent": "フィールド表示のフィルター", "discover.logs.flyoutDetail.value.hover.filterOut": "この{value}を除外", - "discover.logs.flyoutDetail.value.hover.toggleColumn": "表の列を切り替える", "discover.logs.popoverAction.closePopover": "ポップオーバーを閉じる", "discover.logs.popoverAction.copyValue": "値をコピー", "discover.logs.popoverAction.copyValueAriaText": "{fieldName}の値をコピー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 27ee1dd00a563..6e8822ac3874e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2481,45 +2481,10 @@ "discover.localMenu.saveTitle": "保存", "discover.localMenu.shareSearchDescription": "共享搜索", "discover.localMenu.shareTitle": "共享", - "discover.logs.dataTable.controlColumn.actions.button.degradedDoc": "包含 {ignoredProperty} 字段的已降级文档的访问权限", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocNotPresent": "此文档中的所有字段均进行了正确解析", - "discover.logs.dataTable.controlColumn.actions.button.degradedDocPresent": "无法正确解析此文档。并非所有字段都进行了正确填充", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.available": "堆栈跟踪可用", - "discover.logs.dataTable.controlColumn.actions.button.stacktrace.notAvailable": "堆栈跟踪不可用", - "discover.logs.dataTable.header.actions.tooltip.expand": "展开日志详情", - "discover.logs.dataTable.header.actions.tooltip.paragraph": "提供可操作信息的字段,例如:", - "discover.logs.dataTable.header.actions.tooltip.stacktrace": "基于以下项访问可用堆栈跟踪:", - "discover.logs.dataTable.header.content.tooltip.paragraph1": "显示该文档的 {logLevel} 和 {message} 字段。", - "discover.logs.dataTable.header.content.tooltip.paragraph2": "消息字段为空时,将显示以下项之一:", - "discover.logs.dataTable.header.popover.actions": "操作", - "discover.logs.dataTable.header.popover.actions.lowercase": "操作", "discover.logs.dataTable.header.popover.content": "内容", "discover.logs.dataTable.header.popover.resource": "资源", - "discover.logs.dataTable.header.resource.tooltip.paragraph": "提供有关文档来源信息的字段,例如:", - "discover.logs.flyoutDetail.accordion.title.cloud": "云", - "discover.logs.flyoutDetail.accordion.title.other": "其他", - "discover.logs.flyoutDetail.accordion.title.serviceInfra": "服务和基础设施", - "discover.logs.flyoutDetail.label.cloudAvailabilityZone": "云可用区", - "discover.logs.flyoutDetail.label.cloudInstanceId": "云实例 ID", - "discover.logs.flyoutDetail.label.cloudProjectId": "云项目 ID", - "discover.logs.flyoutDetail.label.cloudProvider": "云服务提供商", - "discover.logs.flyoutDetail.label.cloudRegion": "云区域", - "discover.logs.flyoutDetail.label.dataset": "数据集", - "discover.logs.flyoutDetail.label.hostName": "主机名", - "discover.logs.flyoutDetail.label.logPathFile": "日志路径文件", - "discover.logs.flyoutDetail.label.message": "内容细目", - "discover.logs.flyoutDetail.label.namespace": "命名空间", - "discover.logs.flyoutDetail.label.orchestratorClusterName": "Orchestrator 集群名称", - "discover.logs.flyoutDetail.label.orchestratorResourceId": "Orchestrator 资源 ID", - "discover.logs.flyoutDetail.label.service": "服务", - "discover.logs.flyoutDetail.label.shipper": "采集器", - "discover.logs.flyoutDetail.label.trace": "跟踪", - "discover.logs.flyoutDetail.section.showMore": "+ 另外 {hiddenCount} 个", - "discover.logs.flyoutDetail.value.hover.copyToClipboard": "复制到剪贴板", "discover.logs.flyoutDetail.value.hover.filterFor": "筛留此 {value}", - "discover.logs.flyoutDetail.value.hover.filterForFieldPresent": "筛留存在的字段", "discover.logs.flyoutDetail.value.hover.filterOut": "筛除此 {value}", - "discover.logs.flyoutDetail.value.hover.toggleColumn": "在表中切换列", "discover.logs.popoverAction.closePopover": "关闭弹出框", "discover.logs.popoverAction.copyValue": "复制值", "discover.logs.popoverAction.copyValueAriaText": "复制 {fieldName} 的值", From 78064e13db9108d830a6b601f5314a74a9ab5f05 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:10:17 +0000 Subject: [PATCH 71/74] [CI] Auto-commit changed files from 'node scripts/notice' --- x-pack/packages/observability/logs_overview/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index da6d8c8361f5b..29595ce0162fe 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -40,5 +40,6 @@ "@kbn/discover-plugin", "@kbn/unified-data-table", "@kbn/discover-contextual-components", + "@kbn/core-lifecycle-browser", ] } From 4dc459df32a60b56ad072748f4a50f79b8720356 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:18:13 +0100 Subject: [PATCH 72/74] PR changes --- .../src/index.ts | 6 ++++++ .../log_category_document_examples_table.tsx | 17 +++++++---------- .../logs_shared/public/plugin.tsx | 13 ------------- .../logs_shared/public/types.ts | 2 -- .../logs_shared/tsconfig.json | 1 - 5 files changed, 13 insertions(+), 26 deletions(-) diff --git a/packages/kbn-discover-contextual-components/src/index.ts b/packages/kbn-discover-contextual-components/src/index.ts index d8dbfe74d2f95..52ee5931aa4fc 100644 --- a/packages/kbn-discover-contextual-components/src/index.ts +++ b/packages/kbn-discover-contextual-components/src/index.ts @@ -7,4 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { dynamic } from '@kbn/shared-ux-utility'; + export * from './data_types/logs/components'; + +export const LazySummaryColumn = dynamic( + () => import('./data_types/logs/components/summary_column/summary_column') +); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index 7bb4cd2089a52..6b43fa86fe49e 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -10,12 +10,11 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; import moment from 'moment'; -import { AllSummaryColumnProps } from '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; -import { LogLevelBadgeCell } from '@kbn/discover-contextual-components/src/data_types/logs/components/log_level_badge_cell/log_level_badge_cell'; import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { getLogLevelBadgeCell, LazySummaryColumn } from '@kbn/discover-contextual-components'; import type { LogCategoryDocument } from '../../services/category_details_service/types'; import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; @@ -24,10 +23,6 @@ export interface LogCategoryDocumentExamplesTableDependencies { uiSettings: SettingsStart; fieldFormats: FieldFormatsStart; share: SharePluginStart; - columns: { - SummaryColumn: React.ComponentType; - LogLevelCell: LogLevelBadgeCell; - }; } export interface LogCategoryDocumentExamplesTableProps { @@ -56,6 +51,8 @@ const TimestampCell = ({ } }; +const LogLevelBadgeCell = getLogLevelBadgeCell('log.level'); + export const LogCategoryDocumentExamplesTable: React.FC = ({ categoryDocuments, dependencies, @@ -65,7 +62,7 @@ export const LogCategoryDocumentExamplesTable: React.FC { return ( { return ( - { return ( - - import( - '@kbn/discover-contextual-components/src/data_types/logs/components/summary_column/summary_column' - ) -); - export class LogsSharedPlugin implements LogsSharedClientPluginClass { private logViews: LogViewsService; @@ -89,10 +80,6 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { share, dataViews, fieldFormats, - columns: { - SummaryColumn: LazySummaryColumn, - LogLevelCell: getLogLevelBadgeCell('log.level'), - }, }); if (!observabilityAIAssistant) { diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index ce199cb01cd79..e2435fa1f4915 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -15,7 +15,6 @@ import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai- import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { DiscoverStart } from '@kbn/discover-plugin/public'; import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; import type { SelfContainedLogsOverview } from './components/logs_overview'; @@ -42,7 +41,6 @@ export interface LogsSharedClientStartDeps { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; discoverShared: DiscoverSharedPublicStart; - discover: DiscoverStart; logsDataAccess: LogsDataAccessPluginStart; observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; share: SharePluginStart; diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 4cd73eb4c3af1..e68a49924cf9f 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -49,7 +49,6 @@ "@kbn/charts-plugin", "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", - "@kbn/discover-plugin", "@kbn/discover-contextual-components", ] } From 88bbf99e4e657b56400a698394360764b5d648e3 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:28:01 +0100 Subject: [PATCH 73/74] Amendments from upstream changes --- .../src/data_types/logs/components/index.ts | 1 + .../public/components/data_types/logs/service_name_cell.tsx | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts b/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts index ff20c3ca38f7c..e96c7f101ef0e 100644 --- a/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts +++ b/packages/kbn-discover-contextual-components/src/data_types/logs/components/index.ts @@ -9,3 +9,4 @@ export * from './summary_column'; export * from './log_level_badge_cell/log_level_badge_cell'; +export * from './service_name_badge_with_actions'; diff --git a/src/plugins/discover/public/components/data_types/logs/service_name_cell.tsx b/src/plugins/discover/public/components/data_types/logs/service_name_cell.tsx index cd94cd609dc69..3d543f7f0c954 100644 --- a/src/plugins/discover/public/components/data_types/logs/service_name_cell.tsx +++ b/src/plugins/discover/public/components/data_types/logs/service_name_cell.tsx @@ -15,9 +15,10 @@ import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { css } from '@emotion/react'; import { getFieldValue } from '@kbn/discover-utils'; import { euiThemeVars } from '@kbn/ui-theme'; +import { ServiceNameBadgeWithActions } from '@kbn/discover-contextual-components'; +import { useDiscoverServices } from '../../../hooks/use_discover_services'; import { CellRenderersExtensionParams } from '../../../context_awareness'; import { AGENT_NAME_FIELD } from '../../../../common/data_types/logs/constants'; -import { ServiceNameBadgeWithActions } from './service_name_badge_with_actions'; const AgentIcon = dynamic(() => import('@kbn/custom-icons/src/components/agent_icon')); const dataTestSubj = 'serviceNameCell'; @@ -28,6 +29,7 @@ const agentIconStyle = css` export const getServiceNameCell = (serviceNameField: string, { actions }: CellRenderersExtensionParams) => (props: DataGridCellValueElementProps) => { + const { core, share } = useDiscoverServices(); const serviceNameValue = getFieldValue(props.row, serviceNameField) as string; const agentName = getFieldValue(props.row, AGENT_NAME_FIELD) as AgentName; @@ -47,6 +49,8 @@ export const getServiceNameCell = icon={getIcon} value={serviceNameValue} property={serviceNameField} + core={core} + share={share} /> ); }; From 336b0a0626f6a72de999935f1e54b1c35645f6ac Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:41:01 +0000 Subject: [PATCH 74/74] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- x-pack/plugins/observability_solution/logs_shared/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index e68a49924cf9f..f171c79afccd0 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -49,6 +49,5 @@ "@kbn/charts-plugin", "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", - "@kbn/discover-contextual-components", ] }