From 298d54781738071b6faa287549db9f6ed8c0d248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 9 Jan 2020 17:31:36 +0100 Subject: [PATCH 01/17] Add category examples route --- .../http_api/log_analysis/results/index.ts | 1 + .../results/log_entry_category_examples.ts | 74 ++++++++ .../common/log_analysis/job_parameters.ts | 7 + .../logs/log_analysis/api/ml_api_types.ts | 7 - .../api/ml_get_jobs_summary_api.ts | 8 +- .../logs/log_analysis/api/ml_get_module.ts | 7 +- .../log_analysis/api/ml_setup_module_api.ts | 12 +- .../plugins/infra/server/infra_server.ts | 2 + .../framework/kibana_framework_adapter.ts | 5 + .../infra/server/lib/log_analysis/errors.ts | 23 +++ .../log_entry_categories_analysis.ts | 163 +++++++++++++++++- .../server/lib/log_analysis/queries/common.ts | 8 + .../queries/log_entry_categories.ts | 13 +- .../queries/log_entry_category_examples.ts | 75 ++++++++ .../lib/log_analysis/queries/ml_jobs.ts | 21 +++ .../routes/log_analysis/results/index.ts | 1 + .../results/log_entry_category_examples.ts | 86 +++++++++ 17 files changed, 484 insertions(+), 29 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts create mode 100644 x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts create mode 100644 x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts create mode 100644 x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/index.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/index.ts index d9ca9a96ffe51..15615046bdd6a 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/index.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/index.ts @@ -6,4 +6,5 @@ export * from './log_entry_categories'; export * from './log_entry_category_datasets'; +export * from './log_entry_category_examples'; export * from './log_entry_rate'; diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts new file mode 100644 index 0000000000000..8d1e0d24349c6 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as rt from 'io-ts'; + +import { + badRequestErrorRT, + forbiddenErrorRT, + timeRangeRT, + routeTimingMetadataRT, +} from '../../shared'; + +export const LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH = + '/api/infra/log_analysis/results/log_entry_category_examples'; + +/** + * request + */ + +export const getLogEntryCategoryExamplesRequestPayloadRT = rt.type({ + data: rt.type({ + // the category to fetch the examples for + categoryId: rt.number, + // the number of examples to fetch + exampleCount: rt.number, + // the id of the source configuration + sourceId: rt.string, + // the time range to fetch the category examples from + timeRange: timeRangeRT, + }), +}); + +export type GetLogEntryCategoryExamplesRequestPayload = rt.TypeOf< + typeof getLogEntryCategoryExamplesRequestPayloadRT +>; + +/** + * response + */ + +const logEntryCategoryExampleRT = rt.type({ + timestamp: rt.number, + message: rt.string, +}); + +export type LogEntryCategoryExample = rt.TypeOf; + +export const getLogEntryCategoryExamplesSuccessReponsePayloadRT = rt.intersection([ + rt.type({ + data: rt.type({ + examples: rt.array(logEntryCategoryExampleRT), + }), + }), + rt.partial({ + timing: routeTimingMetadataRT, + }), +]); + +export type GetLogEntryCategoryExamplesSuccessResponsePayload = rt.TypeOf< + typeof getLogEntryCategoryExamplesSuccessReponsePayloadRT +>; + +export const getLogEntryCategoryExamplesResponsePayloadRT = rt.union([ + getLogEntryCategoryExamplesSuccessReponsePayloadRT, + badRequestErrorRT, + forbiddenErrorRT, +]); + +export type GetLogEntryCategoryExamplesReponsePayload = rt.TypeOf< + typeof getLogEntryCategoryExamplesResponsePayloadRT +>; diff --git a/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts b/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts index 8c08e24d8665d..94643e21f1ea6 100644 --- a/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts +++ b/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts @@ -28,3 +28,10 @@ export const jobSourceConfigurationRT = rt.type({ }); export type JobSourceConfiguration = rt.TypeOf; + +export const jobCustomSettingsRT = rt.partial({ + job_revision: rt.number, + logs_source_config: rt.partial(jobSourceConfigurationRT.props), +}); + +export type JobCustomSettings = rt.TypeOf; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts index 9d4d419ceebe3..ee70edc31d49b 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts @@ -6,13 +6,6 @@ import * as rt from 'io-ts'; -import { jobSourceConfigurationRT } from '../../../../../common/log_analysis'; - -export const jobCustomSettingsRT = rt.partial({ - job_revision: rt.number, - logs_source_config: rt.partial(jobSourceConfigurationRT.props), -}); - export const getMlCapabilitiesResponsePayloadRT = rt.type({ capabilities: rt.type({ canGetJobs: rt.boolean, diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts index a067285026e33..87d6f8ba2f674 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; import { npStart } from 'ui/new_platform'; -import { jobCustomSettingsRT } from './ml_api_types'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; -import { getJobId } from '../../../../../common/log_analysis'; + +import { getJobId, jobCustomSettingsRT } from '../../../../../common/log_analysis'; +import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; export const callJobsSummaryAPI = async ( spaceId: string, diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts index ae90c7bb84130..639335396e08f 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts @@ -5,12 +5,13 @@ */ import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; import { npStart } from 'ui/new_platform'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; -import { jobCustomSettingsRT } from './ml_api_types'; + +import { jobCustomSettingsRT } from '../../../../../common/log_analysis'; +import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; export const callGetMlModuleAPI = async (moduleId: string) => { const response = await npStart.core.http.fetch(`/api/ml/modules/get_module/${moduleId}`, { diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts index 774a521ff1d34..e032021ada736 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts @@ -5,12 +5,13 @@ */ import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; import { npStart } from 'ui/new_platform'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; -import { getJobIdPrefix } from '../../../../../common/log_analysis'; + +import { getJobIdPrefix, jobCustomSettingsRT } from '../../../../../common/log_analysis'; +import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; export const callSetupMlModuleAPI = async ( moduleId: string, @@ -48,7 +49,10 @@ const setupMlModuleTimeParamsRT = rt.partial({ end: rt.number, }); -const setupMlModuleJobOverridesRT = rt.object; +const setupMlModuleJobOverridesRT = rt.type({ + job_id: rt.string, + custom_settings: jobCustomSettingsRT, +}); export type SetupMlModuleJobOverrides = rt.TypeOf; diff --git a/x-pack/legacy/plugins/infra/server/infra_server.ts b/x-pack/legacy/plugins/infra/server/infra_server.ts index 4f290cb05f056..f058b9e52c75b 100644 --- a/x-pack/legacy/plugins/infra/server/infra_server.ts +++ b/x-pack/legacy/plugins/infra/server/infra_server.ts @@ -14,6 +14,7 @@ import { InfraBackendLibs } from './lib/infra_types'; import { initGetLogEntryCategoriesRoute, initGetLogEntryCategoryDatasetsRoute, + initGetLogEntryCategoryExamplesRoute, initGetLogEntryRateRoute, initValidateLogAnalysisIndicesRoute, } from './routes/log_analysis'; @@ -45,6 +46,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initIpToHostName(libs); initGetLogEntryCategoriesRoute(libs); initGetLogEntryCategoryDatasetsRoute(libs); + initGetLogEntryCategoryExamplesRoute(libs); initGetLogEntryRateRoute(libs); initSnapshotRoute(libs); initNodeDetailsRoute(libs); diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 4b1aa774a523f..1a6f4e32352c0 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -176,6 +176,11 @@ export class KibanaFramework { method: 'indices.get' | 'ml.getBuckets', options?: object ): Promise; + callWithRequest( + requestContext: RequestHandlerContext, + method: 'ml.getJobs', + options?: object + ): Promise; callWithRequest( requestContext: RequestHandlerContext, endpoint: string, diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/errors.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/errors.ts index d1c8316ad061b..e07126416f4ce 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/errors.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/errors.ts @@ -4,9 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable max-classes-per-file */ + export class NoLogAnalysisResultsIndexError extends Error { constructor(message?: string) { super(message); Object.setPrototypeOf(this, new.target.prototype); } } + +export class NoLogAnalysisMlJobError extends Error { + constructor(message?: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + } +} + +export class InsufficientLogAnalysisMlJobConfigurationError extends Error { + constructor(message?: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + } +} + +export class UnknownCategoryError extends Error { + constructor(categoryId: number) { + super(`Unknown ml category ${categoryId}`); + Object.setPrototypeOf(this, new.target.prototype); + } +} diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index f2b6c468df69f..f10bdc2f503cf 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -5,11 +5,20 @@ */ import { KibanaRequest, RequestHandlerContext } from '../../../../../../../src/core/server'; -import { getJobId, logEntryCategoriesJobTypes } from '../../../common/log_analysis'; +import { + getJobId, + logEntryCategoriesJobTypes, + jobCustomSettingsRT, +} from '../../../common/log_analysis'; import { startTracingSpan, TracingSpan } from '../../../common/performance_tracing'; import { decodeOrThrow } from '../../../common/runtime_types'; import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; -import { NoLogAnalysisResultsIndexError } from './errors'; +import { + NoLogAnalysisResultsIndexError, + NoLogAnalysisMlJobError, + InsufficientLogAnalysisMlJobConfigurationError, + UnknownCategoryError, +} from './errors'; import { createLogEntryCategoriesQuery, logEntryCategoriesResponseRT, @@ -25,10 +34,15 @@ import { LogEntryDatasetBucket, logEntryDatasetsResponseRT, } from './queries/log_entry_data_sets'; +import { mlJobsResponseRT, createMlJobsQuery } from './queries/ml_jobs'; import { createTopLogEntryCategoriesQuery, topLogEntryCategoriesResponseRT, } from './queries/top_log_entry_categories'; +import { + createLogEntryCategoryExamplesQuery, + logEntryCategoryExamplesResponseRT, +} from './queries/log_entry_category_examples'; const COMPOSITE_AGGREGATION_BATCH_SIZE = 1000; @@ -175,6 +189,80 @@ export class LogEntryCategoriesAnalysis { }; } + public async getLogEntryCategoryExamples( + requestContext: RequestHandlerContext, + request: KibanaRequest, + sourceId: string, + startTime: number, + endTime: number, + categoryId: number, + exampleCount: number + ) { + const finalizeLogEntryCategoryExamplesSpan = startTracingSpan( + 'get category example log entries' + ); + + const logEntryCategoriesCountJobId = getJobId( + this.libs.framework.getSpaceId(request), + sourceId, + logEntryCategoriesJobTypes[0] + ); + + const { + mlJob, + timing: { spans: fetchMlJobSpans }, + } = await this.fetchMlJob(requestContext, logEntryCategoriesCountJobId); + + const customSettings = decodeOrThrow(jobCustomSettingsRT)(mlJob.custom_settings); + const indices = customSettings?.logs_source_config?.indexPattern; + const timestampField = customSettings?.logs_source_config?.timestampField; + + if (indices == null || timestampField == null) { + throw new InsufficientLogAnalysisMlJobConfigurationError( + `Failed to find index configuration for ml job ${logEntryCategoriesCountJobId}` + ); + } + + const { + logEntryCategoriesById, + timing: { spans: fetchLogEntryCategoriesSpans }, + } = await this.fetchLogEntryCategories(requestContext, logEntryCategoriesCountJobId, [ + categoryId, + ]); + const category = logEntryCategoriesById[categoryId]; + + if (category == null) { + throw new UnknownCategoryError(categoryId); + } + + const { + examples, + timing: { spans: fetchLogEntryCategoryExamplesSpans }, + } = await this.fetchLogEntryCategoryExamples( + requestContext, + indices, + timestampField, + startTime, + endTime, + category._source.terms, + exampleCount + ); + + const logEntryCategoryExamplesSpan = finalizeLogEntryCategoryExamplesSpan(); + + return { + data: examples, + timing: { + spans: [ + logEntryCategoryExamplesSpan, + ...fetchMlJobSpans, + ...fetchLogEntryCategoriesSpans, + ...fetchLogEntryCategoryExamplesSpans, + ], + }, + }; + } + private async fetchTopLogEntryCategories( requestContext: RequestHandlerContext, logEntryCategoriesCountJobId: string, @@ -351,6 +439,77 @@ export class LogEntryCategoriesAnalysis { }, }; } + + private async fetchMlJob( + requestContext: RequestHandlerContext, + logEntryCategoriesCountJobId: string + ) { + const finalizeMlGetJobSpan = startTracingSpan('Fetch ml job from ES'); + + const { + jobs: [mlJob], + } = decodeOrThrow(mlJobsResponseRT)( + await this.libs.framework.callWithRequest( + requestContext, + 'ml.getJobs', + createMlJobsQuery([logEntryCategoriesCountJobId]) + ) + ); + + const mlGetJobSpan = finalizeMlGetJobSpan(); + + if (mlJob == null) { + throw new NoLogAnalysisMlJobError(`Failed to find ml job ${logEntryCategoriesCountJobId}.`); + } + + return { + mlJob, + timing: { + spans: [mlGetJobSpan], + }, + }; + } + + private async fetchLogEntryCategoryExamples( + requestContext: RequestHandlerContext, + indices: string, + timestampField: string, + startTime: number, + endTime: number, + categoryQuery: string, + exampleCount: number + ) { + const finalizeEsSearchSpan = startTracingSpan('Fetch examples from ES'); + + const { + hits: { hits }, + } = decodeOrThrow(logEntryCategoryExamplesResponseRT)( + await this.libs.framework.callWithRequest( + requestContext, + 'search', + createLogEntryCategoryExamplesQuery( + indices, + timestampField, + startTime, + endTime, + categoryQuery, + exampleCount + ) + ) + ); + + const esSearchSpan = finalizeEsSearchSpan(); + + return { + examples: hits.map(hit => ({ + timestamp: hit.sort[0], + message: hit._source.message, + })), + timing: { + spans: [esSearchSpan], + }, + }; + } } const parseCategoryId = (rawCategoryId: string) => parseInt(rawCategoryId, 10); diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/common.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/common.ts index 92ef4fb4e35c9..f1e68d34fdae3 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/common.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/common.ts @@ -35,3 +35,11 @@ export const createResultTypeFilters = (resultType: 'model_plot' | 'record') => }, }, ]; + +export const createCategoryIdFilters = (categoryIds: number[]) => [ + { + terms: { + category_id: categoryIds, + }, + }, +]; diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_categories.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_categories.ts index 63b3632f03784..2681a4c037f5d 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_categories.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_categories.ts @@ -7,7 +7,7 @@ import * as rt from 'io-ts'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; -import { defaultRequestParameters, getMlResultIndex } from './common'; +import { defaultRequestParameters, getMlResultIndex, createCategoryIdFilters } from './common'; export const createLogEntryCategoriesQuery = ( logEntryCategoriesJobId: string, @@ -17,16 +17,10 @@ export const createLogEntryCategoriesQuery = ( body: { query: { bool: { - filter: [ - { - terms: { - category_id: categoryIds, - }, - }, - ], + filter: [...createCategoryIdFilters(categoryIds)], }, }, - _source: ['category_id', 'regex'], + _source: ['category_id', 'regex', 'terms'], }, index: getMlResultIndex(logEntryCategoriesJobId), size: categoryIds.length, @@ -36,6 +30,7 @@ export const logEntryCategoryHitRT = rt.type({ _source: rt.type({ category_id: rt.number, regex: rt.string, + terms: rt.string, }), }); diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts new file mode 100644 index 0000000000000..00c3e641bd33e --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as rt from 'io-ts'; + +import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; +import { defaultRequestParameters } from './common'; + +export const createLogEntryCategoryExamplesQuery = ( + indices: string, + timestampField: string, + startTime: number, + endTime: number, + categoryQuery: string, + exampleCount: number +) => ({ + ...defaultRequestParameters, + body: { + query: { + bool: { + filter: [ + { + range: { + [timestampField]: { + gte: startTime, + lte: endTime, + }, + }, + }, + { + match: { + message: { + query: categoryQuery, + operator: 'AND', + }, + }, + }, + ], + }, + }, + _source: ['message'], + }, + index: indices, + size: exampleCount, + sort: [ + { + [timestampField]: { + order: 'asc', + }, + }, + ], +}); + +export const logEntryCategoryExampleHitRT = rt.type({ + _source: rt.type({ + message: rt.string, + }), + sort: rt.tuple([rt.number]), +}); + +export type LogEntryCategoryExampleHit = rt.TypeOf; + +export const logEntryCategoryExamplesResponseRT = rt.intersection([ + commonSearchSuccessResponseFieldsRT, + rt.type({ + hits: rt.type({ + hits: rt.array(logEntryCategoryExampleHitRT), + }), + }), +]); + +export type logEntryCategoryExamplesResponse = rt.TypeOf; diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts new file mode 100644 index 0000000000000..e361305b3686f --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as rt from 'io-ts'; + +export const createMlJobsQuery = (jobIds: string[]) => ({ + job_id: jobIds, + allow_no_jobs: true, +}); + +export const mlJobRT = rt.type({ + job_id: rt.string, + custom_settings: rt.unknown, +}); + +export const mlJobsResponseRT = rt.type({ + jobs: rt.array(mlJobRT), +}); diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/index.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/index.ts index d9ca9a96ffe51..15615046bdd6a 100644 --- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/index.ts +++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/index.ts @@ -6,4 +6,5 @@ export * from './log_entry_categories'; export * from './log_entry_category_datasets'; +export * from './log_entry_category_examples'; export * from './log_entry_rate'; diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts new file mode 100644 index 0000000000000..67c6c9f5b9924 --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import Boom from 'boom'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; + +import { + getLogEntryCategoryExamplesRequestPayloadRT, + getLogEntryCategoryExamplesSuccessReponsePayloadRT, + LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, +} from '../../../../common/http_api/log_analysis'; +import { throwErrors } from '../../../../common/runtime_types'; +import { InfraBackendLibs } from '../../../lib/infra_types'; +import { NoLogAnalysisResultsIndexError } from '../../../lib/log_analysis'; + +const anyObject = schema.object({}, { allowUnknowns: true }); + +export const initGetLogEntryCategoryExamplesRoute = ({ + framework, + logEntryCategoriesAnalysis, +}: InfraBackendLibs) => { + framework.registerRoute( + { + method: 'post', + path: LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, + validate: { + // short-circuit forced @kbn/config-schema validation so we can do io-ts validation + body: anyObject, + }, + }, + async (requestContext, request, response) => { + const { + data: { + categoryId, + exampleCount, + sourceId, + timeRange: { startTime, endTime }, + }, + } = pipe( + getLogEntryCategoryExamplesRequestPayloadRT.decode(request.body), + fold(throwErrors(Boom.badRequest), identity) + ); + + try { + const { + data: logEntryCategoryExamples, + timing, + } = await logEntryCategoriesAnalysis.getLogEntryCategoryExamples( + requestContext, + request, + sourceId, + startTime, + endTime, + categoryId, + exampleCount + ); + + return response.ok({ + body: getLogEntryCategoryExamplesSuccessReponsePayloadRT.encode({ + data: { + examples: logEntryCategoryExamples, + }, + timing, + }), + }); + } catch (e) { + const { statusCode = 500, message = 'Unknown error occurred' } = e; + + if (e instanceof NoLogAnalysisResultsIndexError) { + return response.notFound({ body: { message } }); + } + + return response.customError({ + statusCode, + body: { message }, + }); + } + } + ); +}; From 59b37bc868421e0354373dec4c3f5714594c7b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 10 Jan 2020 20:22:18 +0100 Subject: [PATCH 02/17] Show examples in category table row expansions --- .../public/components/basic_table/index.ts | 7 +++ .../basic_table/row_expansion_button.tsx | 44 ++++++++++++++ .../page_results_content.tsx | 1 + .../top_categories/category_details_row.tsx | 36 +++++++++++ .../top_categories/top_categories_section.tsx | 8 ++- .../top_categories/top_categories_table.tsx | 58 +++++++++++++++++- .../get_log_entry_category_examples.ts | 50 ++++++++++++++++ .../use_log_entry_category_examples.tsx | 59 +++++++++++++++++++ .../sections/anomalies/table.tsx | 59 +++++++++---------- 9 files changed, 289 insertions(+), 33 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/components/basic_table/index.ts create mode 100644 x-pack/legacy/plugins/infra/public/components/basic_table/row_expansion_button.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx diff --git a/x-pack/legacy/plugins/infra/public/components/basic_table/index.ts b/x-pack/legacy/plugins/infra/public/components/basic_table/index.ts new file mode 100644 index 0000000000000..a1d21792d60a4 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/basic_table/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './row_expansion_button'; diff --git a/x-pack/legacy/plugins/infra/public/components/basic_table/row_expansion_button.tsx b/x-pack/legacy/plugins/infra/public/components/basic_table/row_expansion_button.tsx new file mode 100644 index 0000000000000..debde78470953 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/basic_table/row_expansion_button.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useCallback } from 'react'; + +export const RowExpansionButton = ({ + isExpanded, + item, + onCollapse, + onExpand, +}: { + isExpanded: boolean; + item: Item; + onCollapse: (item: Item) => void; + onExpand: (item: Item) => void; +}) => { + const handleClick = useCallback(() => (isExpanded ? onCollapse(item) : onExpand(item)), [ + isExpanded, + item, + onCollapse, + onExpand, + ]); + + return ( + + ); +}; + +const collapseAriaLabel = i18n.translate('xpack.infra.table.collapseRowLabel', { + defaultMessage: 'Collapse', +}); + +const expandAriaLabel = i18n.translate('xpack.infra.table.expandRowLabel', { + defaultMessage: 'Expand', +}); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx index a810ce447d369..6f6e638d7d3e2 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx @@ -197,6 +197,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => { onChangeDatasetSelection={setCategoryQueryDatasets} onRequestRecreateMlJob={viewSetupForReconfiguration} selectedDatasets={categoryQueryDatasets} + sourceId={sourceId} timeRange={categoryQueryTimeRange.timeRange} topCategories={topLogEntryCategories} /> diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx new file mode 100644 index 0000000000000..bb39363513537 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect } from 'react'; + +import { TimeRange } from '../../../../../../common/http_api/shared'; +import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; + +export const CategoryDetailsRow: React.FunctionComponent<{ + categoryId: number; + timeRange: TimeRange; + sourceId: string; +}> = ({ categoryId, timeRange, sourceId }) => { + const { getLogEntryCategoryExamples, logEntryCategoryExamples } = useLogEntryCategoryExamples({ + categoryId, + endTime: timeRange.endTime, + exampleCount: 5, + sourceId, + startTime: timeRange.startTime, + }); + + useEffect(() => { + getLogEntryCategoryExamples(); + }, [getLogEntryCategoryExamples]); + + return ( +
+ {logEntryCategoryExamples.map(categoryExample => ( +
{categoryExample.message}
+ ))} +
+ ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx index 962b506536253..d145a6985ad6f 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx @@ -25,6 +25,7 @@ export const TopCategoriesSection: React.FunctionComponent<{ onChangeDatasetSelection: (datasets: string[]) => void; onRequestRecreateMlJob: () => void; selectedDatasets: string[]; + sourceId: string; timeRange: TimeRange; topCategories: LogEntryCategory[]; }> = ({ @@ -35,6 +36,7 @@ export const TopCategoriesSection: React.FunctionComponent<{ onChangeDatasetSelection, onRequestRecreateMlJob, selectedDatasets, + sourceId, timeRange, topCategories, }) => { @@ -67,7 +69,11 @@ export const TopCategoriesSection: React.FunctionComponent<{ isLoading={isLoadingTopCategories} loadingChildren={} > - + ); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx index 3d20aef03ff15..46ad4f29ac3b5 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx @@ -8,6 +8,7 @@ import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; +import { useSet } from 'react-use'; import euiStyled from '../../../../../../../../common/eui_styled_components'; import { @@ -19,22 +20,55 @@ import { AnomalySeverityIndicator } from './anomaly_severity_indicator'; import { RegularExpressionRepresentation } from './category_expression'; import { DatasetsList } from './datasets_list'; import { LogEntryCountSparkline } from './log_entry_count_sparkline'; +import { RowExpansionButton } from '../../../../../components/basic_table'; +import { CategoryDetailsRow } from './category_details_row'; export const TopCategoriesTable = euiStyled( ({ className, + sourceId, timeRange, topCategories, }: { className?: string; + sourceId: string; timeRange: TimeRange; topCategories: LogEntryCategory[]; }) => { - const columns = useMemo(() => createColumns(timeRange), [timeRange]); + const [expandedCategories, { add: expandCategory, remove: collapseCategory }] = useSet( + new Set() + ); + + const columns = useMemo( + () => createColumns(timeRange, expandedCategories, expandCategory, collapseCategory), + [collapseCategory, expandCategory, expandedCategories, timeRange] + ); + + const expandedRowContentsById = useMemo( + () => + [...expandedCategories].reduce>( + (aggregatedCategoryRows, categoryId) => ({ + ...aggregatedCategoryRows, + [categoryId]: ( +
+ +
+ ), + }), + {} + ), + [expandedCategories, sourceId, timeRange] + ); return ( @@ -46,7 +80,12 @@ export const TopCategoriesTable = euiStyled( } `; -const createColumns = (timeRange: TimeRange): Array> => [ +const createColumns = ( + timeRange: TimeRange, + expandedCategories: Set, + expandCategory: (categoryId: number) => void, + collapseCategory: (categoryId: number) => void +): Array> => [ { align: 'right', field: 'logEntryCount', @@ -103,4 +142,19 @@ const createColumns = (timeRange: TimeRange): Array { + return ( + + ); + }, + width: '40px', + }, ]; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts new file mode 100644 index 0000000000000..4f4917e10a221 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { identity } from 'fp-ts/lib/function'; +import { npStart } from 'ui/new_platform'; + +import { + getLogEntryCategoryExamplesRequestPayloadRT, + getLogEntryCategoryExamplesSuccessReponsePayloadRT, + LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, +} from '../../../../../common/http_api/log_analysis'; +import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; + +export const callGetLogEntryCategoryExamplesAPI = async ( + sourceId: string, + startTime: number, + endTime: number, + categoryId: number, + exampleCount: number +) => { + const response = await npStart.core.http.fetch( + LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, + { + method: 'POST', + body: JSON.stringify( + getLogEntryCategoryExamplesRequestPayloadRT.encode({ + data: { + categoryId, + exampleCount, + sourceId, + timeRange: { + startTime, + endTime, + }, + }, + }) + ), + } + ); + + return pipe( + getLogEntryCategoryExamplesSuccessReponsePayloadRT.decode(response), + fold(throwErrors(createPlainError), identity) + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx new file mode 100644 index 0000000000000..feeb326efc9c8 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useMemo, useState } from 'react'; + +import { LogEntryCategoryExample } from '../../../../common/http_api'; +import { useTrackedPromise } from '../../../utils/use_tracked_promise'; +import { callGetLogEntryCategoryExamplesAPI } from './service_calls/get_log_entry_category_examples'; + +export const useLogEntryCategoryExamples = ({ + categoryId, + endTime, + exampleCount, + sourceId, + startTime, +}: { + categoryId: number; + endTime: number; + exampleCount: number; + sourceId: string; + startTime: number; +}) => { + const [logEntryCategoryExamples, setLogEntryCategoryExamples] = useState< + LogEntryCategoryExample[] + >([]); + + const [getLogEntryCategoryExamplesRequest, getLogEntryCategoryExamples] = useTrackedPromise( + { + cancelPreviousOn: 'creation', + createPromise: async () => { + return await callGetLogEntryCategoryExamplesAPI( + sourceId, + startTime, + endTime, + categoryId, + exampleCount + ); + }, + onResolve: ({ data: { examples } }) => { + setLogEntryCategoryExamples(examples); + }, + }, + [categoryId, endTime, exampleCount, sourceId, startTime] + ); + + const isLoadingLogEntryCategoryExamples = useMemo( + () => getLogEntryCategoryExamplesRequest.state === 'pending', + [getLogEntryCategoryExamplesRequest.state] + ); + + return { + getLogEntryCategoryExamples, + isLoadingLogEntryCategoryExamples, + logEntryCategoryExamples, + }; +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx index 3e86b45fadfdd..99e8bd28a51ae 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiBasicTable, EuiButtonIcon } from '@elastic/eui'; +import { EuiBasicTable } from '@elastic/eui'; import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; import { i18n } from '@kbn/i18n'; import React, { useCallback, useMemo, useState } from 'react'; @@ -15,6 +15,7 @@ import { formatAnomalyScore, getFriendlyNameForPartitionId, } from '../../../../../../common/log_analysis'; +import { RowExpansionButton } from '../../../../../components/basic_table'; import { LogEntryRateResults } from '../../use_log_entry_rate_results'; import { AnomaliesTableExpandedRow } from './expanded_row'; @@ -31,14 +32,6 @@ interface SortingOptions { }; } -const collapseAriaLabel = i18n.translate('xpack.infra.logs.analysis.anomaliesTableCollapseLabel', { - defaultMessage: 'Collapse', -}); - -const expandAriaLabel = i18n.translate('xpack.infra.logs.analysis.anomaliesTableExpandLabel', { - defaultMessage: 'Expand', -}); - const partitionColumnName = i18n.translate( 'xpack.infra.logs.analysis.anomaliesTablePartitionColumnName', { @@ -106,29 +99,34 @@ export const AnomaliesTable: React.FunctionComponent<{ return sorting.sort.direction === 'asc' ? sortedItems : sortedItems.reverse(); }, [tableItems, sorting]); - const toggleExpandedItems = useCallback( + const expandItem = useCallback( + item => { + const newItemIdToExpandedRowMap = { + ...itemIdToExpandedRowMap, + [item.id]: ( + + ), + }; + setItemIdToExpandedRowMap(newItemIdToExpandedRowMap); + }, + [itemIdToExpandedRowMap, jobId, results, setTimeRange, timeRange] + ); + + const collapseItem = useCallback( item => { if (itemIdToExpandedRowMap[item.id]) { const { [item.id]: toggledItem, ...remainingExpandedRowMap } = itemIdToExpandedRowMap; setItemIdToExpandedRowMap(remainingExpandedRowMap); - } else { - const newItemIdToExpandedRowMap = { - ...itemIdToExpandedRowMap, - [item.id]: ( - - ), - }; - setItemIdToExpandedRowMap(newItemIdToExpandedRowMap); } }, - [itemIdToExpandedRowMap, jobId, results, setTimeRange, timeRange] + [itemIdToExpandedRowMap] ); const columns = [ @@ -150,10 +148,11 @@ export const AnomaliesTable: React.FunctionComponent<{ width: '40px', isExpander: true, render: (item: TableItem) => ( - toggleExpandedItems(item)} - aria-label={itemIdToExpandedRowMap[item.id] ? collapseAriaLabel : expandAriaLabel} - iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'} + ), }, From 7d58cd23f4230b4800cbb1af95fe38da30745dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Mon, 3 Feb 2020 20:14:10 +0100 Subject: [PATCH 03/17] Use `transport.request` fallback to query ml jobs --- .../lib/adapters/framework/adapter_types.ts | 2 ++ .../framework/kibana_framework_adapter.ts | 6 +++--- .../log_entry_categories_analysis.ts | 2 +- .../queries/log_entry_category_examples.ts | 16 ++++++++-------- .../server/lib/log_analysis/queries/ml_jobs.ts | 7 +++++-- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts index b14536275cec3..1da1620379bcf 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -36,6 +36,8 @@ export interface CallWithRequestParams extends GenericParams { size?: number; terminate_after?: number; fields?: string | string[]; + path?: string; + query?: string | object; } export type InfraResponse = Lifecycle.ReturnValue; diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 1a6f4e32352c0..cc41f1a8302ec 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -178,9 +178,9 @@ export class KibanaFramework { ): Promise; callWithRequest( requestContext: RequestHandlerContext, - method: 'ml.getJobs', - options?: object - ): Promise; + method: 'transport.request', + options?: CallWithRequestParams + ): Promise; callWithRequest( requestContext: RequestHandlerContext, endpoint: string, diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index f10bdc2f503cf..6779e81a7528f 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -451,7 +451,7 @@ export class LogEntryCategoriesAnalysis { } = decodeOrThrow(mlJobsResponseRT)( await this.libs.framework.callWithRequest( requestContext, - 'ml.getJobs', + 'transport.request', createMlJobsQuery([logEntryCategoriesCountJobId]) ) ); diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts index 00c3e641bd33e..2bf7256ecab62 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts @@ -41,17 +41,17 @@ export const createLogEntryCategoryExamplesQuery = ( ], }, }, - _source: ['message'], + sort: [ + { + [timestampField]: { + order: 'asc', + }, + }, + ], }, + _source: ['message'], index: indices, size: exampleCount, - sort: [ - { - [timestampField]: { - order: 'asc', - }, - }, - ], }); export const logEntryCategoryExampleHitRT = rt.type({ diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts index e361305b3686f..ee4ccbfaeb5a7 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/ml_jobs.ts @@ -7,8 +7,11 @@ import * as rt from 'io-ts'; export const createMlJobsQuery = (jobIds: string[]) => ({ - job_id: jobIds, - allow_no_jobs: true, + method: 'GET', + path: `/_ml/anomaly_detectors/${jobIds.join(',')}`, + query: { + allow_no_jobs: true, + }, }); export const mlJobRT = rt.type({ From fc75abfc6e1e762d97b8f30d4d9a1ed91c780310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 4 Feb 2020 14:12:24 +0100 Subject: [PATCH 04/17] Prepare log rows and columns for re-use --- .../public/components/formatted_time.tsx | 4 +- .../log_text_stream/log_entry_column.tsx | 37 ++++++++++++++++++- .../logging/log_text_stream/log_entry_row.tsx | 8 ++-- .../log_entry_timestamp_column.tsx | 7 ++-- .../scrollable_log_text_stream_view.tsx | 29 +++------------ 5 files changed, 53 insertions(+), 32 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx index 46b505d4fab52..67f4ab5adc597 100644 --- a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx +++ b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx @@ -17,8 +17,10 @@ const getFormattedTime = ( return userFormat ? moment(time).format(userFormat) : moment(time).format(fallbackFormat); }; +export type TimeFormat = 'dateTime' | 'time'; + interface UseFormattedTimeOptions { - format?: 'dateTime' | 'time'; + format?: TimeFormat; fallbackFormat?: string; } diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx index 643f98018cb0a..3fe46cb315e85 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx @@ -4,12 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ +import { useMemo } from 'react'; + import euiStyled from '../../../../../../common/eui_styled_components'; +import { TextScale } from '../../../../common/log_text_scale'; import { - LogColumnConfiguration, isMessageLogColumnConfiguration, isTimestampLogColumnConfiguration, + LogColumnConfiguration, } from '../../../utils/source_configuration'; +import { useFormattedTime, TimeFormat } from '../../formatted_time'; +import { useMeasuredCharacterDimensions } from './text_styles'; const DATE_COLUMN_SLACK_FACTOR = 1.1; const FIELD_COLUMN_MIN_WIDTH_CHARACTERS = 10; @@ -100,3 +105,33 @@ export const getColumnWidths = ( }, } ); + +/** + * This hook calculates the column widths based on the given configuration. It + * depends on the `CharacterDimensionsProbe` it returns being rendered so it can + * measure the monospace character size. + */ +export const useColumnWidths = ({ + columnConfigurations, + scale, + timeFormat = 'time', +}: { + columnConfigurations: LogColumnConfiguration[]; + scale: TextScale; + timeFormat?: TimeFormat; +}) => { + const { CharacterDimensionsProbe, dimensions } = useMeasuredCharacterDimensions(scale); + const referenceTime = useMemo(() => Date.now(), []); + const formattedCurrentDate = useFormattedTime(referenceTime, { format: timeFormat }); + const columnWidths = useMemo( + () => getColumnWidths(columnConfigurations, dimensions.width, formattedCurrentDate.length), + [columnConfigurations, dimensions.width, formattedCurrentDate] + ); + return useMemo( + () => ({ + columnWidths, + CharacterDimensionsProbe, + }), + [columnWidths, CharacterDimensionsProbe] + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx index 0da601ae52088..5bf8acfeb6818 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx @@ -36,8 +36,9 @@ interface LogEntryRowProps { isActiveHighlight: boolean; isHighlighted: boolean; logEntry: LogEntry; - openFlyoutWithItem: (id: string) => void; + openFlyoutWithItem?: (id: string) => void; scale: TextScale; + showActions?: boolean; wrap: boolean; } @@ -51,6 +52,7 @@ export const LogEntryRow = ({ logEntry, openFlyoutWithItem, scale, + showActions = true, wrap, }: LogEntryRowProps) => { const [isHovered, setIsHovered] = useState(false); @@ -63,7 +65,7 @@ export const LogEntryRow = ({ setIsHovered(false); }, []); - const openFlyout = useCallback(() => openFlyoutWithItem(logEntry.gid), [ + const openFlyout = useCallback(() => openFlyoutWithItem?.(logEntry.gid), [ openFlyoutWithItem, logEntry.gid, ]); @@ -195,7 +197,7 @@ interface LogEntryRowWrapperProps { scale: TextScale; } -const LogEntryRowWrapper = euiStyled.div.attrs(() => ({ +export const LogEntryRowWrapper = euiStyled.div.attrs(() => ({ role: 'row', }))` align-items: stretch; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx index 8e161367b428d..65c48c2dc8fca 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx @@ -8,18 +8,19 @@ import { darken, transparentize } from 'polished'; import React, { memo } from 'react'; import euiStyled, { css } from '../../../../../../common/eui_styled_components'; -import { useFormattedTime } from '../../formatted_time'; +import { TimeFormat, useFormattedTime } from '../../formatted_time'; import { LogEntryColumnContent } from './log_entry_column'; interface LogEntryTimestampColumnProps { + format?: TimeFormat; isHighlighted: boolean; isHovered: boolean; time: number; } export const LogEntryTimestampColumn = memo( - ({ isHighlighted, isHovered, time }) => { - const formattedTime = useFormattedTime(time, { format: 'time' }); + ({ format = 'time', isHighlighted, isHovered, time }) => { + const formattedTime = useFormattedTime(time, { format }); return ( diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx index 15d3c83ffebe9..5d01b1137c7e3 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Fragment, useMemo } from 'react'; +import React, { Fragment } from 'react'; import moment from 'moment'; import euiStyled from '../../../../../../common/eui_styled_components'; @@ -16,7 +16,6 @@ import { callWithoutRepeats } from '../../../utils/handlers'; import { LogColumnConfiguration } from '../../../utils/source_configuration'; import { AutoSizer } from '../../auto_sizer'; import { NoData } from '../../empty_states'; -import { useFormattedTime } from '../../formatted_time'; import { InfraLoadingPanel } from '../../loading'; import { getStreamItemBeforeTimeKey, getStreamItemId, parseStreamItemId, StreamItem } from './item'; import { LogColumnHeaders } from './column_headers'; @@ -25,8 +24,7 @@ import { LogTextStreamJumpToTail } from './jump_to_tail'; import { LogEntryRow } from './log_entry_row'; import { MeasurableItemView } from './measurable_item_view'; import { VerticalScrollPanel } from './vertical_scroll_panel'; -import { getColumnWidths, LogEntryColumnWidths } from './log_entry_column'; -import { useMeasuredCharacterDimensions } from './text_styles'; +import { useColumnWidths, LogEntryColumnWidths } from './log_entry_column'; import { LogDateRow } from './log_date_row'; interface ScrollableLogTextStreamViewProps { @@ -330,12 +328,8 @@ export class ScrollableLogTextStreamView extends React.PureComponent< } /** - * This function-as-child component calculates the column widths based on the - * given configuration. It depends on the `CharacterDimensionsProbe` it returns - * being rendered so it can measure the monospace character size. - * - * If the above component wasn't a class component, this would have been - * written as a hook. + * If the above component wasn't a class component, this wouldn't be necessary + * since the `useColumnWidths` hook could have been used directly. */ const WithColumnWidths: React.FunctionComponent<{ children: (params: { @@ -345,20 +339,7 @@ const WithColumnWidths: React.FunctionComponent<{ columnConfigurations: LogColumnConfiguration[]; scale: TextScale; }> = ({ children, columnConfigurations, scale }) => { - const { CharacterDimensionsProbe, dimensions } = useMeasuredCharacterDimensions(scale); - const referenceTime = useMemo(() => Date.now(), []); - const formattedCurrentDate = useFormattedTime(referenceTime, { format: 'time' }); - const columnWidths = useMemo( - () => getColumnWidths(columnConfigurations, dimensions.width, formattedCurrentDate.length), - [columnConfigurations, dimensions.width, formattedCurrentDate] - ); - const childParams = useMemo( - () => ({ - columnWidths, - CharacterDimensionsProbe, - }), - [columnWidths, CharacterDimensionsProbe] - ); + const childParams = useColumnWidths({ columnConfigurations, scale }); return children(childParams); }; From a751fd9b2452a622b0d4fb5c11cefc024e60edac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 4 Feb 2020 14:13:23 +0100 Subject: [PATCH 05/17] Render example message using log stream components --- .../logging/log_text_stream/index.ts | 4 + .../top_categories/category_details_row.tsx | 21 +++-- .../category_example_message.tsx | 76 +++++++++++++++++++ 3 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts index 77781b58a3ccd..8ae7b0796d617 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts @@ -4,4 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +export { LogEntryColumn, LogEntryColumnWidths, useColumnWidths } from './log_entry_column'; +export { LogEntryMessageColumn } from './log_entry_message_column'; +export { LogEntryRowWrapper } from './log_entry_row'; +export { LogEntryTimestampColumn } from './log_entry_timestamp_column'; export { ScrollableLogTextStreamView } from './scrollable_log_text_stream_view'; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index bb39363513537..84d0472f956d1 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -8,6 +8,7 @@ import React, { useEffect } from 'react'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; +import { CategoryExampleMessage, useExampleColumnWidths } from './category_example_message'; export const CategoryDetailsRow: React.FunctionComponent<{ categoryId: number; @@ -26,11 +27,21 @@ export const CategoryDetailsRow: React.FunctionComponent<{ getLogEntryCategoryExamples(); }, [getLogEntryCategoryExamples]); + const { columnWidths, CharacterDimensionsProbe } = useExampleColumnWidths(); + return ( -
- {logEntryCategoryExamples.map(categoryExample => ( -
{categoryExample.message}
- ))} -
+ <> + +
+ {logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( + + ))} +
+ ); }; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx new file mode 100644 index 0000000000000..f55f0fb7c1c4c --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { + LogEntryColumn, + LogEntryColumnWidths, + LogEntryMessageColumn, + LogEntryRowWrapper, + LogEntryTimestampColumn, + useColumnWidths, +} from '../../../../../components/logging/log_text_stream'; +import { LogColumnConfiguration } from '../../../../../utils/source_configuration'; + +export const exampleMessageScale = 'medium' as const; +export const exampleTimestampFormat = 'dateTime' as const; + +export const CategoryExampleMessage: React.FunctionComponent<{ + columnWidths: LogEntryColumnWidths; + message: string; + timestamp: number; +}> = ({ columnWidths, message, timestamp }) => { + return ( + + + + + + + + + ); +}; + +export const useExampleColumnWidths = () => + useColumnWidths({ + columnConfigurations: exampleMessageColumnConfigurations, + scale: exampleMessageScale, + timeFormat: exampleTimestampFormat, + }); + +const timestampColumnId = 'category-example-timestamp-column' as const; +const messageColumnId = 'category-examples-message-column' as const; + +export const exampleMessageColumnConfigurations: LogColumnConfiguration[] = [ + { + __typename: 'InfraSourceTimestampLogColumn', + timestampColumn: { id: timestampColumnId }, + }, + { + __typename: 'InfraSourceMessageLogColumn', + messageColumn: { id: messageColumnId }, + }, +]; From ba2b552fb769c84d1a46d7b4326815eca6f41570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 4 Feb 2020 16:38:20 +0100 Subject: [PATCH 06/17] Introduce a stricter wrapping mode for the examples --- .../log_entry_message_column.tsx | 30 ++++++++++++------- .../logging/log_text_stream/log_entry_row.tsx | 2 +- .../top_categories/category_details_row.tsx | 12 ++++++-- .../category_example_message.tsx | 2 +- .../top_categories/top_categories_table.tsx | 12 ++++---- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx index 11d73736463e2..f3dc2f5835c2c 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx @@ -20,17 +20,19 @@ import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './h import { LogEntryColumnContent } from './log_entry_column'; import { hoveredContentStyle } from './text_styles'; +type WrapMode = 'none' | 'original' | 'long'; + interface LogEntryMessageColumnProps { columnValue: LogEntryColumn; highlights: LogEntryHighlightColumn[]; isActiveHighlight: boolean; isHighlighted: boolean; isHovered: boolean; - isWrapped: boolean; + wrapMode: WrapMode; } export const LogEntryMessageColumn = memo( - ({ columnValue, highlights, isActiveHighlight, isHighlighted, isHovered, isWrapped }) => { + ({ columnValue, highlights, isActiveHighlight, isHighlighted, isHovered, wrapMode }) => { const message = useMemo( () => isMessageColumn(columnValue) @@ -40,32 +42,33 @@ export const LogEntryMessageColumn = memo( ); return ( - + {message} ); } ); -const wrappedContentStyle = css` +const longWrappedContentStyle = css` overflow: visible; white-space: pre-wrap; word-break: break-all; `; -const unwrappedContentStyle = css` +const originalWrappedContentStyle = css` overflow: hidden; white-space: pre; `; +const unwrappedContentStyle = css` + overflow: hidden; + white-space: nowrap; +`; + interface MessageColumnContentProps { isHovered: boolean; isHighlighted: boolean; - isWrapped?: boolean; + wrapMode: WrapMode; } const MessageColumnContent = euiStyled(LogEntryColumnContent)` @@ -73,7 +76,12 @@ const MessageColumnContent = euiStyled(LogEntryColumnContent) (props.isHovered || props.isHighlighted ? hoveredContentStyle : '')}; - ${props => (props.isWrapped ? wrappedContentStyle : unwrappedContentStyle)}; + ${props => + props.wrapMode === 'long' + ? longWrappedContentStyle + : props.wrapMode === 'original' + ? originalWrappedContentStyle + : unwrappedContentStyle}; `; const formatMessageSegments = ( diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx index 5bf8acfeb6818..a374375666c9f 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx @@ -150,7 +150,7 @@ export const LogEntryRow = ({ isHighlighted={isHighlighted} isActiveHighlight={isActiveHighlight} isHovered={isHovered} - isWrapped={wrap} + wrapMode={wrap ? 'long' : 'original'} /> ) : null} diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index 84d0472f956d1..8f7d383ed8ba6 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -9,6 +9,7 @@ import React, { useEffect } from 'react'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; import { CategoryExampleMessage, useExampleColumnWidths } from './category_example_message'; +import euiStyled from '../../../../../../../../common/eui_styled_components'; export const CategoryDetailsRow: React.FunctionComponent<{ categoryId: number; @@ -32,7 +33,7 @@ export const CategoryDetailsRow: React.FunctionComponent<{ return ( <> -
+ {logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( ))} -
+ ); }; + +const CategoryExampleMessages = euiStyled.div` + align-items: stretch; + flex-direction: row; + flex: 1 0 0%; + overflow: hidden; +`; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx index f55f0fb7c1c4c..5d82accd7569b 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -47,7 +47,7 @@ export const CategoryExampleMessage: React.FunctionComponent<{ isHovered={false} isHighlighted={false} isActiveHighlight={false} - isWrapped={false} + wrapMode="none" /> diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx index 46ad4f29ac3b5..0ce7e79f4f22a 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_table.tsx @@ -50,13 +50,11 @@ export const TopCategoriesTable = euiStyled( (aggregatedCategoryRows, categoryId) => ({ ...aggregatedCategoryRows, [categoryId]: ( -
- -
+ ), }), {} From 551df332fbcdf0340a74b3b52c16f78c499af2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 4 Feb 2020 17:20:59 +0100 Subject: [PATCH 07/17] Add example loading indicators --- .../top_categories/category_details_row.tsx | 35 ++++++++++++------- ...ory_example_messages_loading_indicator.tsx | 18 ++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_loading_indicator.tsx diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index 8f7d383ed8ba6..47cb046c3c377 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -6,20 +6,27 @@ import React, { useEffect } from 'react'; +import euiStyled from '../../../../../../../../common/eui_styled_components'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; import { CategoryExampleMessage, useExampleColumnWidths } from './category_example_message'; -import euiStyled from '../../../../../../../../common/eui_styled_components'; +import { CategoryExampleMessagesLoadingIndicator } from './category_example_messages_loading_indicator'; + +const exampleCount = 5; export const CategoryDetailsRow: React.FunctionComponent<{ categoryId: number; timeRange: TimeRange; sourceId: string; }> = ({ categoryId, timeRange, sourceId }) => { - const { getLogEntryCategoryExamples, logEntryCategoryExamples } = useLogEntryCategoryExamples({ + const { + getLogEntryCategoryExamples, + isLoadingLogEntryCategoryExamples, + logEntryCategoryExamples, + } = useLogEntryCategoryExamples({ categoryId, endTime: timeRange.endTime, - exampleCount: 5, + exampleCount, sourceId, startTime: timeRange.startTime, }); @@ -34,14 +41,18 @@ export const CategoryDetailsRow: React.FunctionComponent<{ <> - {logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( - - ))} + {isLoadingLogEntryCategoryExamples ? ( + + ) : ( + logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( + + )) + )} ); @@ -49,7 +60,7 @@ export const CategoryDetailsRow: React.FunctionComponent<{ const CategoryExampleMessages = euiStyled.div` align-items: stretch; - flex-direction: row; + flex-direction: column; flex: 1 0 0%; overflow: hidden; `; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_loading_indicator.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_loading_indicator.tsx new file mode 100644 index 0000000000000..cad87a96a1326 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_loading_indicator.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiLoadingContent } from '@elastic/eui'; +import React from 'react'; + +export const CategoryExampleMessagesLoadingIndicator: React.FunctionComponent<{ + exampleCount: number; +}> = ({ exampleCount }) => ( + <> + {Array.from(new Array(exampleCount), (_value, index) => ( + + ))} + +); From 2645faf41b194dd09c8d4bd0a27593d15cafed7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 4 Feb 2020 21:44:44 +0100 Subject: [PATCH 08/17] Add example loading failure message with retry option --- .../top_categories/category_details_row.tsx | 4 +++ ...ory_example_messages_failure_indicator.tsx | 31 +++++++++++++++++++ .../use_log_entry_category_examples.tsx | 6 ++++ 3 files changed, 41 insertions(+) create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_failure_indicator.tsx diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index 47cb046c3c377..238b6f805cd7b 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -10,6 +10,7 @@ import euiStyled from '../../../../../../../../common/eui_styled_components'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; import { CategoryExampleMessage, useExampleColumnWidths } from './category_example_message'; +import { CategoryExampleMessagesFailureIndicator } from './category_example_messages_failure_indicator'; import { CategoryExampleMessagesLoadingIndicator } from './category_example_messages_loading_indicator'; const exampleCount = 5; @@ -21,6 +22,7 @@ export const CategoryDetailsRow: React.FunctionComponent<{ }> = ({ categoryId, timeRange, sourceId }) => { const { getLogEntryCategoryExamples, + hasFailedLoadingLogEntryCategoryExamples, isLoadingLogEntryCategoryExamples, logEntryCategoryExamples, } = useLogEntryCategoryExamples({ @@ -43,6 +45,8 @@ export const CategoryDetailsRow: React.FunctionComponent<{ {isLoadingLogEntryCategoryExamples ? ( + ) : hasFailedLoadingLogEntryCategoryExamples ? ( + ) : ( logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( void; +}> = ({ onRetry }) => ( + + + + + + + + + + + + +); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx index feeb326efc9c8..cdf3b642a8012 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx @@ -51,8 +51,14 @@ export const useLogEntryCategoryExamples = ({ [getLogEntryCategoryExamplesRequest.state] ); + const hasFailedLoadingLogEntryCategoryExamples = useMemo( + () => getLogEntryCategoryExamplesRequest.state === 'rejected', + [getLogEntryCategoryExamplesRequest.state] + ); + return { getLogEntryCategoryExamples, + hasFailedLoadingLogEntryCategoryExamples, isLoadingLogEntryCategoryExamples, logEntryCategoryExamples, }; From eaceb3969b60c59e39a4e7802293c4d4bf9dfc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 5 Feb 2020 15:36:22 +0100 Subject: [PATCH 09/17] Remove mismatching log message background color --- .../logging/log_text_stream/log_entry_message_column.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx index f3dc2f5835c2c..f5b32f2e87224 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx @@ -72,7 +72,6 @@ interface MessageColumnContentProps { } const MessageColumnContent = euiStyled(LogEntryColumnContent)` - background-color: ${props => props.theme.eui.euiColorEmptyShade}; text-overflow: ellipsis; ${props => (props.isHovered || props.isHighlighted ? hoveredContentStyle : '')}; From 75e4f4c077f9e5fac2b45a088e1e0ea41b533264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 11 Feb 2020 01:15:52 +0100 Subject: [PATCH 10/17] Add dataset column to examples and align columns --- .../results/log_entry_category_examples.ts | 3 +- .../logging/log_text_stream/index.ts | 1 + .../log_entry_field_column.test.tsx | 6 +- .../log_entry_field_column.tsx | 44 +++++----- .../log_entry_message_column.tsx | 28 ++----- .../logging/log_text_stream/log_entry_row.tsx | 4 +- .../logging/log_text_stream/text_styles.tsx | 18 +++++ .../top_categories/category_details_row.tsx | 39 ++++----- .../category_example_message.tsx | 80 +++++++++++++++---- .../log_entry_categories_analysis.ts | 3 +- .../queries/log_entry_category_examples.ts | 3 +- 11 files changed, 136 insertions(+), 93 deletions(-) diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts index 8d1e0d24349c6..d014da8bca262 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_category_examples.ts @@ -42,8 +42,9 @@ export type GetLogEntryCategoryExamplesRequestPayload = rt.TypeOf< */ const logEntryCategoryExampleRT = rt.type({ - timestamp: rt.number, + dataset: rt.string, message: rt.string, + timestamp: rt.number, }); export type LogEntryCategoryExample = rt.TypeOf; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts index 8ae7b0796d617..dbf162171cac3 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/index.ts @@ -5,6 +5,7 @@ */ export { LogEntryColumn, LogEntryColumnWidths, useColumnWidths } from './log_entry_column'; +export { LogEntryFieldColumn } from './log_entry_field_column'; export { LogEntryMessageColumn } from './log_entry_message_column'; export { LogEntryRowWrapper } from './log_entry_row'; export { LogEntryTimestampColumn } from './log_entry_timestamp_column'; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx index f947a0fb1adcd..f4935a4406d61 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx @@ -26,7 +26,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - isWrapped={false} + wrapMode="original" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); @@ -58,7 +58,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - isWrapped={false} + wrapMode="original" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); @@ -80,7 +80,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - isWrapped={false} + wrapMode="original" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx index 6252b3a396d1b..a643556ef2438 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx @@ -5,10 +5,9 @@ */ import stringify from 'json-stable-stringify'; -import { darken, transparentize } from 'polished'; import React, { useMemo } from 'react'; -import euiStyled, { css } from '../../../../../../common/eui_styled_components'; +import euiStyled from '../../../../../../common/eui_styled_components'; import { isFieldColumn, isHighlightFieldColumn, @@ -17,6 +16,13 @@ import { } from '../../../utils/log_entry'; import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './highlighting'; import { LogEntryColumnContent } from './log_entry_column'; +import { + hoveredContentStyle, + longWrappedContentStyle, + originalWrappedContentStyle, + unwrappedContentStyle, + WrapMode, +} from './text_styles'; interface LogEntryFieldColumnProps { columnValue: LogEntryColumn; @@ -24,7 +30,7 @@ interface LogEntryFieldColumnProps { isActiveHighlight: boolean; isHighlighted: boolean; isHovered: boolean; - isWrapped: boolean; + wrapMode: WrapMode; } export const LogEntryFieldColumn: React.FunctionComponent = ({ @@ -33,7 +39,7 @@ export const LogEntryFieldColumn: React.FunctionComponent { const value = useMemo(() => (isFieldColumn(columnValue) ? JSON.parse(columnValue.value) : null), [ columnValue, @@ -59,30 +65,12 @@ export const LogEntryFieldColumn: React.FunctionComponent + {formattedValue} ); }; -const hoveredContentStyle = css` - background-color: ${props => - props.theme.darkMode - ? transparentize(0.9, darken(0.05, props.theme.eui.euiColorHighlight)) - : darken(0.05, props.theme.eui.euiColorHighlight)}; -`; - -const wrappedContentStyle = css` - overflow: visible; - white-space: pre-wrap; - word-break: break-all; -`; - -const unwrappedContentStyle = css` - overflow: hidden; - white-space: pre; -`; - const CommaSeparatedLi = euiStyled.li` display: inline; &:not(:last-child) { @@ -96,13 +84,17 @@ const CommaSeparatedLi = euiStyled.li` interface LogEntryColumnContentProps { isHighlighted: boolean; isHovered: boolean; - isWrapped?: boolean; + wrapMode: WrapMode; } const FieldColumnContent = euiStyled(LogEntryColumnContent)` - background-color: ${props => props.theme.eui.euiColorEmptyShade}; text-overflow: ellipsis; ${props => (props.isHovered || props.isHighlighted ? hoveredContentStyle : '')}; - ${props => (props.isWrapped ? wrappedContentStyle : unwrappedContentStyle)}; + ${props => + props.wrapMode === 'long' + ? longWrappedContentStyle + : props.wrapMode === 'original' + ? originalWrappedContentStyle + : unwrappedContentStyle}; `; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx index f5b32f2e87224..522dfe355c396 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx @@ -6,7 +6,7 @@ import React, { memo, useMemo } from 'react'; -import euiStyled, { css } from '../../../../../../common/eui_styled_components'; +import euiStyled from '../../../../../../common/eui_styled_components'; import { isConstantSegment, isFieldSegment, @@ -18,9 +18,13 @@ import { } from '../../../utils/log_entry'; import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './highlighting'; import { LogEntryColumnContent } from './log_entry_column'; -import { hoveredContentStyle } from './text_styles'; - -type WrapMode = 'none' | 'original' | 'long'; +import { + hoveredContentStyle, + longWrappedContentStyle, + originalWrappedContentStyle, + unwrappedContentStyle, + WrapMode, +} from './text_styles'; interface LogEntryMessageColumnProps { columnValue: LogEntryColumn; @@ -49,22 +53,6 @@ export const LogEntryMessageColumn = memo( } ); -const longWrappedContentStyle = css` - overflow: visible; - white-space: pre-wrap; - word-break: break-all; -`; - -const originalWrappedContentStyle = css` - overflow: hidden; - white-space: pre; -`; - -const unwrappedContentStyle = css` - overflow: hidden; - white-space: nowrap; -`; - interface MessageColumnContentProps { isHovered: boolean; isHighlighted: boolean; diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx index a374375666c9f..ebe31da298ac9 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx @@ -38,7 +38,6 @@ interface LogEntryRowProps { logEntry: LogEntry; openFlyoutWithItem?: (id: string) => void; scale: TextScale; - showActions?: boolean; wrap: boolean; } @@ -52,7 +51,6 @@ export const LogEntryRow = ({ logEntry, openFlyoutWithItem, scale, - showActions = true, wrap, }: LogEntryRowProps) => { const [isHovered, setIsHovered] = useState(false); @@ -172,7 +170,7 @@ export const LogEntryRow = ({ isActiveHighlight={isActiveHighlight} isHighlighted={isHighlighted} isHovered={isHovered} - isWrapped={wrap} + wrapMode={wrap ? 'long' : 'original'} /> ) : null} diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx index e95ac6aa7923b..c614f79e093da 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx @@ -10,6 +10,8 @@ import React, { useMemo, useState, useCallback } from 'react'; import euiStyled, { css } from '../../../../../../common/eui_styled_components'; import { TextScale } from '../../../../common/log_text_scale'; +export type WrapMode = 'none' | 'original' | 'long'; + export const monospaceTextStyle = (scale: TextScale) => css` font-family: ${props => props.theme.eui.euiCodeFontFamily}; font-size: ${props => { @@ -34,6 +36,22 @@ export const hoveredContentStyle = css` : darken(0.05, props.theme.eui.euiColorHighlight)}; `; +export const longWrappedContentStyle = css` + overflow: visible; + white-space: pre-wrap; + word-break: break-all; +`; + +export const originalWrappedContentStyle = css` + overflow: hidden; + white-space: pre; +`; + +export const unwrappedContentStyle = css` + overflow: hidden; + white-space: nowrap; +`; + interface CharacterDimensions { height: number; width: number; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index 238b6f805cd7b..61db494fe0225 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -9,7 +9,7 @@ import React, { useEffect } from 'react'; import euiStyled from '../../../../../../../../common/eui_styled_components'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; -import { CategoryExampleMessage, useExampleColumnWidths } from './category_example_message'; +import { CategoryExampleMessage } from './category_example_message'; import { CategoryExampleMessagesFailureIndicator } from './category_example_messages_failure_indicator'; import { CategoryExampleMessagesLoadingIndicator } from './category_example_messages_loading_indicator'; @@ -37,28 +37,23 @@ export const CategoryDetailsRow: React.FunctionComponent<{ getLogEntryCategoryExamples(); }, [getLogEntryCategoryExamples]); - const { columnWidths, CharacterDimensionsProbe } = useExampleColumnWidths(); - return ( - <> - - - {isLoadingLogEntryCategoryExamples ? ( - - ) : hasFailedLoadingLogEntryCategoryExamples ? ( - - ) : ( - logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( - - )) - )} - - + + {isLoadingLogEntryCategoryExamples ? ( + + ) : hasFailedLoadingLogEntryCategoryExamples ? ( + + ) : ( + logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( + + )) + )} + ); }; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx index 5d82accd7569b..c4738ba2f8599 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useMemo } from 'react'; +import { getFriendlyNameForPartitionId } from '../../../../../../common/log_analysis'; import { LogEntryColumn, - LogEntryColumnWidths, + LogEntryFieldColumn, LogEntryMessageColumn, LogEntryRowWrapper, LogEntryTimestampColumn, - useColumnWidths, } from '../../../../../components/logging/log_text_stream'; import { LogColumnConfiguration } from '../../../../../utils/source_configuration'; @@ -20,10 +20,17 @@ export const exampleMessageScale = 'medium' as const; export const exampleTimestampFormat = 'dateTime' as const; export const CategoryExampleMessage: React.FunctionComponent<{ - columnWidths: LogEntryColumnWidths; + dataset: string; message: string; timestamp: number; -}> = ({ columnWidths, message, timestamp }) => { +}> = ({ dataset, message, timestamp }) => { + // the dataset must be encoded for the field column and the empty value must + // be turned into a user-friendly value + const encodedDatasetFieldValue = useMemo( + () => JSON.stringify(getFriendlyNameForPartitionId(dataset)), + [dataset] + ); + return ( @@ -38,12 +45,27 @@ export const CategoryExampleMessage: React.FunctionComponent<{ + + + - useColumnWidths({ - columnConfigurations: exampleMessageColumnConfigurations, - scale: exampleMessageScale, - timeFormat: exampleTimestampFormat, - }); - +const noHighlights: never[] = []; const timestampColumnId = 'category-example-timestamp-column' as const; const messageColumnId = 'category-examples-message-column' as const; +const datasetColumnId = 'category-examples-dataset-column' as const; + +const columnWidths = { + [timestampColumnId]: { + growWeight: 0, + shrinkWeight: 0, + // w_count + w_trend - w_padding = 120 px + 220 px - 8 px + baseWidth: '332px', + }, + [messageColumnId]: { + growWeight: 1, + shrinkWeight: 0, + baseWidth: '0%', + }, + [datasetColumnId]: { + growWeight: 0, + shrinkWeight: 0, + // w_dataset + w_max_anomaly + w_expand - w_padding = 200 px + 160 px + 40 px - 8 px + baseWidth: '392px', + }, +}; export const exampleMessageColumnConfigurations: LogColumnConfiguration[] = [ { __typename: 'InfraSourceTimestampLogColumn', - timestampColumn: { id: timestampColumnId }, + timestampColumn: { + id: timestampColumnId, + }, }, { __typename: 'InfraSourceMessageLogColumn', - messageColumn: { id: messageColumnId }, + messageColumn: { + id: messageColumnId, + }, + }, + { + __typename: 'InfraSourceFieldLogColumn', + fieldColumn: { + field: 'event.dataset', + id: datasetColumnId, + }, }, ]; diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index 6779e81a7528f..3674338579fd9 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -502,8 +502,9 @@ export class LogEntryCategoriesAnalysis { return { examples: hits.map(hit => ({ - timestamp: hit.sort[0], + dataset: hit._source['event.dataset'] ?? '', message: hit._source.message, + timestamp: hit.sort[0], })), timing: { spans: [esSearchSpan], diff --git a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts index 2bf7256ecab62..680c2193bf4e6 100644 --- a/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts +++ b/x-pack/legacy/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts @@ -49,13 +49,14 @@ export const createLogEntryCategoryExamplesQuery = ( }, ], }, - _source: ['message'], + _source: ['event.dataset', 'message'], index: indices, size: exampleCount, }); export const logEntryCategoryExampleHitRT = rt.type({ _source: rt.type({ + 'event.dataset': rt.union([rt.string, rt.undefined]), message: rt.string, }), sort: rt.tuple([rt.number]), From 704e12381a693bd7c9928a67aabb3ec4df239267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 11 Feb 2020 13:02:43 +0100 Subject: [PATCH 11/17] Remove unused translations via autofix --- .../translations/translations/ja-JP.json | 446 +++++++++--------- .../translations/translations/zh-CN.json | 446 +++++++++--------- 2 files changed, 444 insertions(+), 448 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e9a5d9611c806..d1b149b529a12 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -78,109 +78,6 @@ "messages": { "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント", "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", - "data.search.aggs.aggGroups.bucketsText": "バケット", - "data.search.aggs.aggGroups.metricsText": "メトリック", - "data.search.aggs.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", - "data.search.aggs.buckets.dateHistogramTitle": "日付ヒストグラム", - "data.search.aggs.buckets.dateRangeTitle": "日付範囲", - "data.search.aggs.buckets.filtersTitle": "フィルター", - "data.search.aggs.buckets.filterTitle": "フィルター", - "data.search.aggs.buckets.geohashGridTitle": "ジオハッシュ", - "data.search.aggs.buckets.geotileGridTitle": "ジオタイル", - "data.search.aggs.buckets.histogramTitle": "ヒストグラム", - "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自動", - "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "日ごと", - "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", - "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", - "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分", - "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "月ごと", - "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", - "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "週ごと", - "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", - "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 範囲", - "data.search.aggs.buckets.ipRangeTitle": "IPv4 範囲", - "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", - "data.search.aggs.aggTypesLabel": "{fieldName} の範囲", - "data.search.aggs.buckets.rangeTitle": "範囲", - "data.search.aggs.buckets.significantTerms.excludeLabel": "除外", - "data.search.aggs.buckets.significantTerms.includeLabel": "含める", - "data.search.aggs.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", - "data.search.aggs.buckets.significantTermsTitle": "重要な用語", - "data.search.aggs.buckets.terms.excludeLabel": "除外", - "data.search.aggs.buckets.terms.includeLabel": "含める", - "data.search.aggs.buckets.terms.missingBucketLabel": "欠測値", - "data.search.aggs.buckets.terms.orderAscendingTitle": "昇順", - "data.search.aggs.buckets.terms.orderDescendingTitle": "降順", - "data.search.aggs.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", - "data.search.aggs.buckets.terms.otherBucketLabel": "その他", - "data.search.aggs.buckets.terms.otherBucketTitle": "他のバケット", - "data.search.aggs.buckets.termsTitle": "用語", - "data.search.aggs.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", - "data.search.aggs.metrics.averageBucketTitle": "平均バケット", - "data.search.aggs.metrics.averageLabel": "平均 {field}", - "data.search.aggs.metrics.averageTitle": "平均", - "data.search.aggs.metrics.bucketAggTitle": "バケット集約", - "data.search.aggs.metrics.countLabel": "カウント", - "data.search.aggs.metrics.countTitle": "カウント", - "data.search.aggs.metrics.cumulativeSumLabel": "累積合計", - "data.search.aggs.metrics.cumulativeSumTitle": "累積合計", - "data.search.aggs.metrics.derivativeLabel": "派生", - "data.search.aggs.metrics.derivativeTitle": "派生", - "data.search.aggs.metrics.geoBoundsLabel": "境界", - "data.search.aggs.metrics.geoBoundsTitle": "境界", - "data.search.aggs.metrics.geoCentroidLabel": "ジオセントロイド", - "data.search.aggs.metrics.geoCentroidTitle": "ジオセントロイド", - "data.search.aggs.metrics.maxBucketTitle": "最高バケット", - "data.search.aggs.metrics.maxLabel": "最高 {field}", - "data.search.aggs.metrics.maxTitle": "最高", - "data.search.aggs.metrics.medianLabel": "中央 {field}", - "data.search.aggs.metrics.medianTitle": "中央", - "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "メトリック集約", - "data.search.aggs.metrics.metricAggTitle": "メトリック集約", - "data.search.aggs.metrics.minBucketTitle": "最低バケット", - "data.search.aggs.metrics.minLabel": "最低 {field}", - "data.search.aggs.metrics.minTitle": "最低", - "data.search.aggs.metrics.movingAvgLabel": "移動平均", - "data.search.aggs.metrics.movingAvgTitle": "移動平均", - "data.search.aggs.metrics.overallAverageLabel": "全体平均", - "data.search.aggs.metrics.overallMaxLabel": "全体最高", - "data.search.aggs.metrics.overallMinLabel": "全体最低", - "data.search.aggs.metrics.overallSumLabel": "全体合計", - "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", - "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", - "data.search.aggs.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", - "data.search.aggs.metrics.percentileRanksTitle": "パーセンタイル順位", - "data.search.aggs.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", - "data.search.aggs.metrics.percentilesLabel": "{field} のパーセンタイル", - "data.search.aggs.metrics.percentilesTitle": "パーセンタイル", - "data.search.aggs.metrics.serialDiffLabel": "差分の推移", - "data.search.aggs.metrics.serialDiffTitle": "差分の推移", - "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", - "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", - "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", - "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", - "data.search.aggs.metrics.standardDeviationLabel": "{field} の標準偏差", - "data.search.aggs.metrics.standardDeviationTitle": "標準偏差", - "data.search.aggs.metrics.sumBucketTitle": "合計バケット", - "data.search.aggs.metrics.sumLabel": "{field} の合計", - "data.search.aggs.metrics.sumTitle": "合計", - "data.search.aggs.metrics.topHit.ascendingLabel": "昇順", - "data.search.aggs.metrics.topHit.averageLabel": "平均", - "data.search.aggs.metrics.topHit.concatenateLabel": "連結", - "data.search.aggs.metrics.topHit.descendingLabel": "降順", - "data.search.aggs.metrics.topHit.firstPrefixLabel": "最初", - "data.search.aggs.metrics.topHit.lastPrefixLabel": "最後", - "data.search.aggs.metrics.topHit.maxLabel": "最高", - "data.search.aggs.metrics.topHit.minLabel": "最低", - "data.search.aggs.metrics.topHit.sumLabel": "合計", - "data.search.aggs.metrics.topHitTitle": "トップヒット", - "data.search.aggs.metrics.uniqueCountLabel": "{field} のユニークカウント", - "data.search.aggs.metrics.uniqueCountTitle": "ユニークカウント", - "data.search.aggs.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", - "data.search.aggs.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", - "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", - "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", - "data.search.aggs.string.customLabel": "カスタムラベル", "common.ui.directives.paginate.size.allDropDownOptionLabel": "すべて", "common.ui.dualRangeControl.mustSetBothErrorMessage": "下と上の値の両方を設定する必要があります", "common.ui.dualRangeControl.outsideOfRangeErrorMessage": "値は {min} と {max} の間でなければなりません", @@ -367,10 +264,223 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。", "common.ui.url.replacementFailedErrorMessage": "置換に失敗、未解決の表現式: {expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "保存されたオブジェクトがありません", - "data.search.aggs.percentageOfLabel": "{label} のパーセンテージ", "common.ui.vis.defaultFeedbackMessage": "フィードバックがありますか?{link} で問題を報告してください。", "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "データバウンドを合わせる", "common.ui.vis.kibanaMap.zoomWarning": "ズームレベルが最大に達しました。完全にズームインするには、Elasticsearch と Kibana の {defaultDistribution} にアップグレードしてください。{ems} でより多くのズームレベルが利用できます。または、独自のマップサーバーを構成できます。詳細は { wms } または { configSettings} をご覧ください。", + "data.search.aggs.aggGroups.bucketsText": "バケット", + "data.search.aggs.aggGroups.metricsText": "メトリック", + "data.search.aggs.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", + "data.search.aggs.buckets.dateHistogramTitle": "日付ヒストグラム", + "data.search.aggs.buckets.dateRangeTitle": "日付範囲", + "data.search.aggs.buckets.filtersTitle": "フィルター", + "data.search.aggs.buckets.filterTitle": "フィルター", + "data.search.aggs.buckets.geohashGridTitle": "ジオハッシュ", + "data.search.aggs.buckets.geotileGridTitle": "ジオタイル", + "data.search.aggs.buckets.histogramTitle": "ヒストグラム", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自動", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "日ごと", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "月ごと", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "週ごと", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 範囲", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 範囲", + "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", + "data.search.aggs.aggTypesLabel": "{fieldName} の範囲", + "data.search.aggs.buckets.rangeTitle": "範囲", + "data.search.aggs.buckets.significantTerms.excludeLabel": "除外", + "data.search.aggs.buckets.significantTerms.includeLabel": "含める", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", + "data.search.aggs.buckets.significantTermsTitle": "重要な用語", + "data.search.aggs.buckets.terms.excludeLabel": "除外", + "data.search.aggs.buckets.terms.includeLabel": "含める", + "data.search.aggs.buckets.terms.missingBucketLabel": "欠測値", + "data.search.aggs.buckets.terms.orderAscendingTitle": "昇順", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降順", + "data.search.aggs.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", + "data.search.aggs.buckets.terms.otherBucketLabel": "その他", + "data.search.aggs.buckets.terms.otherBucketTitle": "他のバケット", + "data.search.aggs.buckets.termsTitle": "用語", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", + "data.search.aggs.metrics.averageBucketTitle": "平均バケット", + "data.search.aggs.metrics.averageLabel": "平均 {field}", + "data.search.aggs.metrics.averageTitle": "平均", + "data.search.aggs.metrics.bucketAggTitle": "バケット集約", + "data.search.aggs.metrics.countLabel": "カウント", + "data.search.aggs.metrics.countTitle": "カウント", + "data.search.aggs.metrics.cumulativeSumLabel": "累積合計", + "data.search.aggs.metrics.cumulativeSumTitle": "累積合計", + "data.search.aggs.metrics.derivativeLabel": "派生", + "data.search.aggs.metrics.derivativeTitle": "派生", + "data.search.aggs.metrics.geoBoundsLabel": "境界", + "data.search.aggs.metrics.geoBoundsTitle": "境界", + "data.search.aggs.metrics.geoCentroidLabel": "ジオセントロイド", + "data.search.aggs.metrics.geoCentroidTitle": "ジオセントロイド", + "data.search.aggs.metrics.maxBucketTitle": "最高バケット", + "data.search.aggs.metrics.maxLabel": "最高 {field}", + "data.search.aggs.metrics.maxTitle": "最高", + "data.search.aggs.metrics.medianLabel": "中央 {field}", + "data.search.aggs.metrics.medianTitle": "中央", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "メトリック集約", + "data.search.aggs.metrics.metricAggTitle": "メトリック集約", + "data.search.aggs.metrics.minBucketTitle": "最低バケット", + "data.search.aggs.metrics.minLabel": "最低 {field}", + "data.search.aggs.metrics.minTitle": "最低", + "data.search.aggs.metrics.movingAvgLabel": "移動平均", + "data.search.aggs.metrics.movingAvgTitle": "移動平均", + "data.search.aggs.metrics.overallAverageLabel": "全体平均", + "data.search.aggs.metrics.overallMaxLabel": "全体最高", + "data.search.aggs.metrics.overallMinLabel": "全体最低", + "data.search.aggs.metrics.overallSumLabel": "全体合計", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksTitle": "パーセンタイル順位", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", + "data.search.aggs.metrics.percentilesLabel": "{field} のパーセンタイル", + "data.search.aggs.metrics.percentilesTitle": "パーセンタイル", + "data.search.aggs.metrics.serialDiffLabel": "差分の推移", + "data.search.aggs.metrics.serialDiffTitle": "差分の推移", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", + "data.search.aggs.metrics.standardDeviationLabel": "{field} の標準偏差", + "data.search.aggs.metrics.standardDeviationTitle": "標準偏差", + "data.search.aggs.metrics.sumBucketTitle": "合計バケット", + "data.search.aggs.metrics.sumLabel": "{field} の合計", + "data.search.aggs.metrics.sumTitle": "合計", + "data.search.aggs.metrics.topHit.ascendingLabel": "昇順", + "data.search.aggs.metrics.topHit.averageLabel": "平均", + "data.search.aggs.metrics.topHit.concatenateLabel": "連結", + "data.search.aggs.metrics.topHit.descendingLabel": "降順", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "最初", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最後", + "data.search.aggs.metrics.topHit.maxLabel": "最高", + "data.search.aggs.metrics.topHit.minLabel": "最低", + "data.search.aggs.metrics.topHit.sumLabel": "合計", + "data.search.aggs.metrics.topHitTitle": "トップヒット", + "data.search.aggs.metrics.uniqueCountLabel": "{field} のユニークカウント", + "data.search.aggs.metrics.uniqueCountTitle": "ユニークカウント", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", + "data.search.aggs.string.customLabel": "カスタムラベル", + "data.search.aggs.percentageOfLabel": "{label} のパーセンテージ", + "data.filter.applyFilters.popupHeader": "適用するフィルターの選択", + "data.filter.applyFiltersPopup.cancelButtonLabel": "キャンセル", + "data.filter.applyFiltersPopup.saveButtonLabel": "適用", + "data.filter.filterBar.addFilterButtonLabel": "フィルターを追加します", + "data.filter.filterBar.deleteFilterButtonLabel": "削除", + "data.filter.filterBar.disabledFilterPrefix": "無効", + "data.filter.filterBar.disableFilterButtonLabel": "一時的に無効にする", + "data.filter.filterBar.editFilterButtonLabel": "フィルターを編集", + "data.filter.filterBar.enableFilterButtonLabel": "再度有効にする", + "data.filter.filterBar.excludeFilterButtonLabel": "結果を除外", + "data.filter.filterBar.filterItemBadgeAriaLabel": "フィルターアクション", + "data.filter.filterBar.filterItemBadgeIconAriaLabel": "削除", + "data.filter.filterBar.includeFilterButtonLabel": "結果を含める", + "data.filter.filterBar.indexPatternSelectPlaceholder": "インデックスパターンの選択", + "data.filter.filterBar.moreFilterActionsMessage": "フィルター:{innerText}。他のフィルターアクションを使用するには選択してください。", + "data.filter.filterBar.negatedFilterPrefix": "NOT ", + "data.filter.filterBar.pinFilterButtonLabel": "すべてのアプリにピン付け", + "data.filter.filterBar.pinnedFilterPrefix": "ピン付け済み", + "data.filter.filterBar.unpinFilterButtonLabel": "ピンを外す", + "data.filter.filterEditor.cancelButtonLabel": "キャンセル", + "data.filter.filterEditor.createCustomLabelInputLabel": "カスタムラベル", + "data.filter.filterEditor.createCustomLabelSwitchLabel": "カスタムラベルを作成しますか?", + "data.filter.filterEditor.dateFormatHelpLinkLabel": "対応データフォーマット", + "data.filter.filterEditor.doesNotExistOperatorOptionLabel": "存在しません", + "data.filter.filterEditor.editFilterPopupTitle": "フィルターを編集", + "data.filter.filterEditor.editFilterValuesButtonLabel": "フィルター値を編集", + "data.filter.filterEditor.editQueryDslButtonLabel": "クエリ DSL として編集", + "data.filter.filterEditor.existsOperatorOptionLabel": "存在する", + "data.filter.filterEditor.falseOptionLabel": "False", + "data.filter.filterEditor.fieldSelectLabel": "フィールド", + "data.filter.filterEditor.fieldSelectPlaceholder": "フィールドを選択", + "data.filter.filterEditor.indexPatternSelectLabel": "インデックスパターン", + "data.filter.filterEditor.isBetweenOperatorOptionLabel": "is between", + "data.filter.filterEditor.isNotBetweenOperatorOptionLabel": "is not between", + "data.filter.filterEditor.isNotOneOfOperatorOptionLabel": "is not one of", + "data.filter.filterEditor.isNotOperatorOptionLabel": "is not", + "data.filter.filterEditor.isOneOfOperatorOptionLabel": "is one of", + "data.filter.filterEditor.isOperatorOptionLabel": "が", + "data.filter.filterEditor.operatorSelectLabel": "演算子", + "data.filter.filterEditor.operatorSelectPlaceholderSelect": "選択してください", + "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "待機中", + "data.filter.filterEditor.queryDslLabel": "Elasticsearch クエリ DSL", + "data.filter.filterEditor.rangeEndInputPlaceholder": "範囲の終了値", + "data.filter.filterEditor.rangeInputLabel": "範囲", + "data.filter.filterEditor.rangeStartInputPlaceholder": "範囲の開始値", + "data.filter.filterEditor.saveButtonLabel": "保存", + "data.filter.filterEditor.trueOptionLabel": "True", + "data.filter.filterEditor.valueInputLabel": "値", + "data.filter.filterEditor.valueInputPlaceholder": "値を入力", + "data.filter.filterEditor.valueSelectPlaceholder": "値を選択", + "data.filter.filterEditor.valuesSelectLabel": "値", + "data.filter.filterEditor.valuesSelectPlaceholder": "値を選択", + "data.filter.options.changeAllFiltersButtonLabel": "すべてのフィルターの変更", + "data.filter.options.deleteAllFiltersButtonLabel": "すべて削除", + "data.filter.options.disableAllFiltersButtonLabel": "すべて無効にする", + "data.filter.options.enableAllFiltersButtonLabel": "すべて有効にする", + "data.filter.options.invertDisabledFiltersButtonLabel": "有効・無効を反転", + "data.filter.options.invertNegatedFiltersButtonLabel": "含める・除外を反転", + "data.filter.options.pinAllFiltersButtonLabel": "すべてピン付け", + "data.filter.options.unpinAllFiltersButtonLabel": "すべてのピンを外す", + "data.filter.searchBar.changeAllFiltersTitle": "すべてのフィルターの変更", + "data.indexPatterns.unableWriteLabel": "インデックスパターンを書き込めません!このインデックスパターンへの最新の変更を取得するには、ページを更新してください。", + "data.indexPatterns.unknownFieldErrorMessage": "インデックスパターン「{title}」のフィールド「{name}」が不明なフィールドタイプを使用しています。", + "data.indexPatterns.unknownFieldHeader": "不明なフィールドタイプ {type}", + "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "無効なカレンダー間隔:{interval}、1よりも大きな値が必要です", + "data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "無効な間隔フォーマット:{interval}", + "data.query.queryBar.comboboxAriaLabel": "{pageType} ページの検索とフィルタリング", + "data.query.queryBar.kqlFullLanguageName": "Kibana クエリ言語", + "data.query.queryBar.kqlLanguageName": "KQL", + "data.query.queryBar.kqlOffLabel": "オフ", + "data.query.queryBar.kqlOnLabel": "オン", + "data.query.queryBar.luceneLanguageName": "Lucene", + "data.query.queryBar.luceneSyntaxWarningMessage": "Lucene クエリ構文を使用しているようですが、Kibana クエリ言語 (KQL) が選択されています。KQL ドキュメント {link} を確認してください。", + "data.query.queryBar.luceneSyntaxWarningOptOutText": "今後表示しない", + "data.query.queryBar.luceneSyntaxWarningTitle": "Lucene 構文警告", + "data.query.queryBar.searchInputAriaLabel": "{pageType} ページの検索とフィルタリングを行うには入力を開始してください", + "data.query.queryBar.searchInputPlaceholder": "検索", + "data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) は、シンプルなクエリ構文とスクリプトフィールドのサポートを提供します。また、KQL はベーシックライセンス以上をご利用の場合、自動入力も提供します。KQL をオフにすると、Kibana は Lucene を使用します。", + "data.query.queryBar.syntaxOptionsDescription.docsLinkText": "こちら", + "data.query.queryBar.syntaxOptionsTitle": "構文オプション", + "data.search.searchBar.savedQueryDescriptionLabelText": "説明", + "data.search.searchBar.savedQueryDescriptionText": "再度使用するクエリテキストとフィルターを保存します。", + "data.search.searchBar.savedQueryForm.titleConflictText": "タイトルが既に保存されているクエリに使用されています", + "data.search.searchBar.savedQueryForm.titleMissingText": "名前が必要です", + "data.search.searchBar.savedQueryForm.whitespaceErrorText": "タイトルの始めと終わりにはスペースを使用できません", + "data.search.searchBar.savedQueryFormCancelButtonText": "キャンセル", + "data.search.searchBar.savedQueryFormSaveButtonText": "保存", + "data.search.searchBar.savedQueryFormTitle": "クエリを保存", + "data.search.searchBar.savedQueryIncludeFiltersLabelText": "フィルターを含める", + "data.search.searchBar.savedQueryIncludeTimeFilterLabelText": "時間フィルターを含める", + "data.search.searchBar.savedQueryNameHelpText": "名前が必要です。タイトルの始めと終わりにはスペースを使用できません。名前は固有でなければなりません。", + "data.search.searchBar.savedQueryNameLabelText": "名前", + "data.search.searchBar.savedQueryNoSavedQueriesText": "保存されたクエリがありません。", + "data.search.searchBar.savedQueryPopoverButtonText": "保存されたクエリを表示", + "data.search.searchBar.savedQueryPopoverClearButtonAriaLabel": "現在保存されているクエリを消去", + "data.search.searchBar.savedQueryPopoverClearButtonText": "消去", + "data.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "キャンセル", + "data.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "削除", + "data.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "「{savedQueryName}」を削除しますか?", + "data.search.searchBar.savedQueryPopoverDeleteButtonAriaLabel": "保存されたクエリ {savedQueryName} を削除", + "data.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "新規保存クエリを保存", + "data.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "新規保存", + "data.search.searchBar.savedQueryPopoverSaveButtonAriaLabel": "新規保存クエリを保存", + "data.search.searchBar.savedQueryPopoverSaveButtonText": "現在のクエリを保存", + "data.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "{title} への変更を保存", + "data.search.searchBar.savedQueryPopoverSaveChangesButtonText": "変更を保存", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemButtonAriaLabel": "保存クエリボタン {savedQueryName}", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} の説明", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "選択されたクエリボタン {savedQueryName} を保存しました。変更を破棄するには押してください。", + "data.search.searchBar.savedQueryPopoverTitleText": "保存されたクエリ", "charts.colormaps.bluesText": "青", "charts.colormaps.greensText": "緑", "charts.colormaps.greenToRedText": "緑から赤", @@ -526,116 +636,6 @@ "dashboardEmbeddableContainer.actions.toggleExpandPanelMenuItem.notExpandedDisplayName": "全画面", "dashboardEmbeddableContainer.dashboardGrid.toast.unableToLoadDashboardDangerMessage": "ダッシュボードが読み込めません。", "dashboardEmbeddableContainer.factory.displayName": "ダッシュボード", - "data.filter.applyFilters.popupHeader": "適用するフィルターの選択", - "data.filter.applyFiltersPopup.cancelButtonLabel": "キャンセル", - "data.filter.applyFiltersPopup.saveButtonLabel": "適用", - "data.filter.filterBar.addFilterButtonLabel": "フィルターを追加します", - "data.filter.filterBar.deleteFilterButtonLabel": "削除", - "data.filter.filterBar.disabledFilterPrefix": "無効", - "data.filter.filterBar.disableFilterButtonLabel": "一時的に無効にする", - "data.filter.filterBar.editFilterButtonLabel": "フィルターを編集", - "data.filter.filterBar.enableFilterButtonLabel": "再度有効にする", - "data.filter.filterBar.excludeFilterButtonLabel": "結果を除外", - "data.filter.filterBar.filterItemBadgeAriaLabel": "フィルターアクション", - "data.filter.filterBar.filterItemBadgeIconAriaLabel": "削除", - "data.filter.filterBar.includeFilterButtonLabel": "結果を含める", - "data.filter.filterBar.indexPatternSelectPlaceholder": "インデックスパターンの選択", - "data.filter.filterBar.moreFilterActionsMessage": "フィルター:{innerText}。他のフィルターアクションを使用するには選択してください。", - "data.filter.filterBar.negatedFilterPrefix": "NOT ", - "data.filter.filterBar.pinFilterButtonLabel": "すべてのアプリにピン付け", - "data.filter.filterBar.pinnedFilterPrefix": "ピン付け済み", - "data.filter.filterBar.unpinFilterButtonLabel": "ピンを外す", - "data.filter.filterEditor.cancelButtonLabel": "キャンセル", - "data.filter.filterEditor.createCustomLabelInputLabel": "カスタムラベル", - "data.filter.filterEditor.createCustomLabelSwitchLabel": "カスタムラベルを作成しますか?", - "data.filter.filterEditor.dateFormatHelpLinkLabel": "対応データフォーマット", - "data.filter.filterEditor.doesNotExistOperatorOptionLabel": "存在しません", - "data.filter.filterEditor.editFilterPopupTitle": "フィルターを編集", - "data.filter.filterEditor.editFilterValuesButtonLabel": "フィルター値を編集", - "data.filter.filterEditor.editQueryDslButtonLabel": "クエリ DSL として編集", - "data.filter.filterEditor.existsOperatorOptionLabel": "存在する", - "data.filter.filterEditor.falseOptionLabel": "False", - "data.filter.filterEditor.fieldSelectLabel": "フィールド", - "data.filter.filterEditor.fieldSelectPlaceholder": "フィールドを選択", - "data.filter.filterEditor.indexPatternSelectLabel": "インデックスパターン", - "data.filter.filterEditor.isBetweenOperatorOptionLabel": "is between", - "data.filter.filterEditor.isNotBetweenOperatorOptionLabel": "is not between", - "data.filter.filterEditor.isNotOneOfOperatorOptionLabel": "is not one of", - "data.filter.filterEditor.isNotOperatorOptionLabel": "is not", - "data.filter.filterEditor.isOneOfOperatorOptionLabel": "is one of", - "data.filter.filterEditor.isOperatorOptionLabel": "が", - "data.filter.filterEditor.operatorSelectLabel": "演算子", - "data.filter.filterEditor.operatorSelectPlaceholderSelect": "選択してください", - "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "待機中", - "data.filter.filterEditor.queryDslLabel": "Elasticsearch クエリ DSL", - "data.filter.filterEditor.rangeEndInputPlaceholder": "範囲の終了値", - "data.filter.filterEditor.rangeInputLabel": "範囲", - "data.filter.filterEditor.rangeStartInputPlaceholder": "範囲の開始値", - "data.filter.filterEditor.saveButtonLabel": "保存", - "data.filter.filterEditor.trueOptionLabel": "True", - "data.filter.filterEditor.valueInputLabel": "値", - "data.filter.filterEditor.valueInputPlaceholder": "値を入力", - "data.filter.filterEditor.valueSelectPlaceholder": "値を選択", - "data.filter.filterEditor.valuesSelectLabel": "値", - "data.filter.filterEditor.valuesSelectPlaceholder": "値を選択", - "data.filter.options.changeAllFiltersButtonLabel": "すべてのフィルターの変更", - "data.filter.options.deleteAllFiltersButtonLabel": "すべて削除", - "data.filter.options.disableAllFiltersButtonLabel": "すべて無効にする", - "data.filter.options.enableAllFiltersButtonLabel": "すべて有効にする", - "data.filter.options.invertDisabledFiltersButtonLabel": "有効・無効を反転", - "data.filter.options.invertNegatedFiltersButtonLabel": "含める・除外を反転", - "data.filter.options.pinAllFiltersButtonLabel": "すべてピン付け", - "data.filter.options.unpinAllFiltersButtonLabel": "すべてのピンを外す", - "data.filter.searchBar.changeAllFiltersTitle": "すべてのフィルターの変更", - "data.indexPatterns.unableWriteLabel": "インデックスパターンを書き込めません!このインデックスパターンへの最新の変更を取得するには、ページを更新してください。", - "data.indexPatterns.unknownFieldErrorMessage": "インデックスパターン「{title}」のフィールド「{name}」が不明なフィールドタイプを使用しています。", - "data.indexPatterns.unknownFieldHeader": "不明なフィールドタイプ {type}", - "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "無効なカレンダー間隔:{interval}、1よりも大きな値が必要です", - "data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "無効な間隔フォーマット:{interval}", - "data.query.queryBar.comboboxAriaLabel": "{pageType} ページの検索とフィルタリング", - "data.query.queryBar.kqlFullLanguageName": "Kibana クエリ言語", - "data.query.queryBar.kqlLanguageName": "KQL", - "data.query.queryBar.kqlOffLabel": "オフ", - "data.query.queryBar.kqlOnLabel": "オン", - "data.query.queryBar.luceneLanguageName": "Lucene", - "data.query.queryBar.luceneSyntaxWarningMessage": "Lucene クエリ構文を使用しているようですが、Kibana クエリ言語 (KQL) が選択されています。KQL ドキュメント {link} を確認してください。", - "data.query.queryBar.luceneSyntaxWarningOptOutText": "今後表示しない", - "data.query.queryBar.luceneSyntaxWarningTitle": "Lucene 構文警告", - "data.query.queryBar.searchInputAriaLabel": "{pageType} ページの検索とフィルタリングを行うには入力を開始してください", - "data.query.queryBar.searchInputPlaceholder": "検索", - "data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) は、シンプルなクエリ構文とスクリプトフィールドのサポートを提供します。また、KQL はベーシックライセンス以上をご利用の場合、自動入力も提供します。KQL をオフにすると、Kibana は Lucene を使用します。", - "data.query.queryBar.syntaxOptionsDescription.docsLinkText": "こちら", - "data.query.queryBar.syntaxOptionsTitle": "構文オプション", - "data.search.searchBar.savedQueryDescriptionLabelText": "説明", - "data.search.searchBar.savedQueryDescriptionText": "再度使用するクエリテキストとフィルターを保存します。", - "data.search.searchBar.savedQueryForm.titleConflictText": "タイトルが既に保存されているクエリに使用されています", - "data.search.searchBar.savedQueryForm.titleMissingText": "名前が必要です", - "data.search.searchBar.savedQueryForm.whitespaceErrorText": "タイトルの始めと終わりにはスペースを使用できません", - "data.search.searchBar.savedQueryFormCancelButtonText": "キャンセル", - "data.search.searchBar.savedQueryFormSaveButtonText": "保存", - "data.search.searchBar.savedQueryFormTitle": "クエリを保存", - "data.search.searchBar.savedQueryIncludeFiltersLabelText": "フィルターを含める", - "data.search.searchBar.savedQueryIncludeTimeFilterLabelText": "時間フィルターを含める", - "data.search.searchBar.savedQueryNameHelpText": "名前が必要です。タイトルの始めと終わりにはスペースを使用できません。名前は固有でなければなりません。", - "data.search.searchBar.savedQueryNameLabelText": "名前", - "data.search.searchBar.savedQueryNoSavedQueriesText": "保存されたクエリがありません。", - "data.search.searchBar.savedQueryPopoverButtonText": "保存されたクエリを表示", - "data.search.searchBar.savedQueryPopoverClearButtonAriaLabel": "現在保存されているクエリを消去", - "data.search.searchBar.savedQueryPopoverClearButtonText": "消去", - "data.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "キャンセル", - "data.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "削除", - "data.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "「{savedQueryName}」を削除しますか?", - "data.search.searchBar.savedQueryPopoverDeleteButtonAriaLabel": "保存されたクエリ {savedQueryName} を削除", - "data.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "新規保存クエリを保存", - "data.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "新規保存", - "data.search.searchBar.savedQueryPopoverSaveButtonAriaLabel": "新規保存クエリを保存", - "data.search.searchBar.savedQueryPopoverSaveButtonText": "現在のクエリを保存", - "data.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "{title} への変更を保存", - "data.search.searchBar.savedQueryPopoverSaveChangesButtonText": "変更を保存", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemButtonAriaLabel": "保存クエリボタン {savedQueryName}", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} の説明", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "選択されたクエリボタン {savedQueryName} を保存しました。変更を破棄するには押してください。", - "data.search.searchBar.savedQueryPopoverTitleText": "保存されたクエリ", "embeddableApi.actions.applyFilterActionTitle": "現在のビューにフィルターを適用", "embeddableApi.addPanel.createNewDefaultOption": "新規作成...", "embeddableApi.addPanel.displayName": "パネルの追加", @@ -1435,8 +1435,6 @@ "kbn.management.indexPattern.confirmOverwriteTitle": "{type} を上書きしますか?", "kbn.management.indexPattern.sectionsHeader": "インデックスパターン", "kbn.management.indexPattern.titleExistsLabel": "「{title}」というタイトルのインデックスパターンが既に存在します。", - "management.indexPatternHeader": "インデックスパターン", - "management.indexPatternLabel": "Elasticsearch からのデータの取得に役立つインデックスパターンを管理します。", "kbn.management.indexPatternList.createButton.betaLabel": "ベータ", "kbn.management.indexPatternPrompt.exampleOne": "チャートを作成したりコンテンツを素早くクエリできるように log-west-001 という名前の単一のデータソースをインデックスします。", "kbn.management.indexPatternPrompt.exampleOneTitle": "単一のデータソース", @@ -1555,9 +1553,7 @@ "kbn.management.objects.objectsTable.table.typeFilterName": "タイプ", "kbn.management.objects.objectsTable.unableFindSavedObjectsNotificationMessage": "保存されたオブジェクトが見つかりません", "kbn.management.objects.parsingFieldErrorMessage": "{fieldName} をインデックスパターン {indexName} 用にパース中にエラーが発生しました: {errorMessage}", - "management.objects.savedObjectsDescription": "保存された検索、ビジュアライゼーション、ダッシュボードのインポート、エクスポート、管理を行います", "kbn.management.objects.savedObjectsSectionLabel": "保存されたオブジェクト", - "management.objects.savedObjectsTitle": "保存されたオブジェクト", "kbn.management.objects.view.cancelButtonAriaLabel": "キャンセル", "kbn.management.objects.view.cancelButtonLabel": "キャンセル", "kbn.management.objects.view.deleteItemButtonLabel": "{title} を削除", @@ -1575,8 +1571,6 @@ "kbn.management.objects.view.viewItemTitle": "{title} を表示", "kbn.management.savedObjects.editBreadcrumb": "{savedObjectType} を編集", "kbn.management.savedObjects.indexBreadcrumb": "保存されたオブジェクト", - "advancedSettings.advancedSettingsDescription": "Kibana の動作を管理する設定を直接変更します。", - "advancedSettings.advancedSettingsLabel": "高度な設定", "kbn.management.settings.breadcrumb": "高度な設定", "kbn.management.settings.callOutCautionDescription": "これらの設定は非常に上級ユーザー向けなのでご注意ください。ここでの変更は Kibana の重要な部分に不具合を生じさせる可能性があります。これらの設定はドキュメントに記載されていなかったり、サポートされていなかったり、実験的であったりします。フィールドにデフォルトの値が設定されている場合、そのフィールドを未入力のままにするとデフォルトに戻り、他の構成により利用できない可能性があります。カスタム設定を削除すると、Kibana の構成から永久に削除されます。", "kbn.management.settings.callOutCautionTitle": "注意:不具合が起こる可能性があります", @@ -1616,7 +1610,6 @@ "kbn.management.settings.form.clearSearchResultText": "(検索結果を消去)", "kbn.management.settings.form.noSearchResultText": "設定が見つかりませんでした {clearSearch}", "kbn.management.settings.form.searchResultText": "検索用語により {settingsCount} 件の設定が非表示になっています {clearSearch}", - "advancedSettings.pageTitle": "設定", "kbn.management.settings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", "kbn.management.settings.searchBarAriaLabel": "高度な設定を検索", "kbn.management.settings.sectionLabel": "高度な設定", @@ -1664,6 +1657,13 @@ "kbn.visualize.wizard.step1Breadcrumb": "作成", "kbn.visualize.wizard.step2Breadcrumb": "作成", "kbn.visualizeTitle": "可視化", + "management.indexPatternHeader": "インデックスパターン", + "management.indexPatternLabel": "Elasticsearch からのデータの取得に役立つインデックスパターンを管理します。", + "management.objects.savedObjectsDescription": "保存された検索、ビジュアライゼーション、ダッシュボードのインポート、エクスポート、管理を行います", + "management.objects.savedObjectsTitle": "保存されたオブジェクト", + "advancedSettings.advancedSettingsDescription": "Kibana の動作を管理する設定を直接変更します。", + "advancedSettings.advancedSettingsLabel": "高度な設定", + "advancedSettings.pageTitle": "設定", "kibana_legacy.bigUrlWarningNotificationMessage": "{advancedSettingsLink}で{storeInSessionStorageParam}オプションを有効にするか、オンスクリーンビジュアルを簡素化してください。", "kibana_legacy.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高度な設定", "kibana_legacy.bigUrlWarningNotificationTitle": "URLが大きく、Kibanaの動作が停止する可能性があります", @@ -6435,8 +6435,6 @@ "xpack.infra.logs.analysis.anomaliesSectionLineSeriesName": "15 分ごとのログエントリー (平均)", "xpack.infra.logs.analysis.anomaliesSectionLoadingAriaLabel": "異常を読み込み中", "xpack.infra.logs.analysis.anomaliesSectionTitle": "異常", - "xpack.infra.logs.analysis.anomaliesTableCollapseLabel": "縮小", - "xpack.infra.logs.analysis.anomaliesTableExpandLabel": "拡張", "xpack.infra.logs.analysis.anomaliesTableMaxAnomalyScoreColumnName": "最高異常スコア", "xpack.infra.logs.analysis.anomaliesTablePartitionColumnName": "パーティション", "xpack.infra.logs.analysis.anomalySectionNoAnomaliesTitle": "異常が検出されませんでした。", @@ -13190,4 +13188,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "フィールドを選択してください。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 201e3c35ee282..94414e3172614 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -78,109 +78,6 @@ "messages": { "common.ui.aggResponse.allDocsTitle": "所有文档", "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", - "data.search.aggs.aggGroups.bucketsText": "存储桶", - "data.search.aggs.aggGroups.metricsText": "指标", - "data.search.aggs.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", - "data.search.aggs.buckets.dateHistogramTitle": "Date Histogram", - "data.search.aggs.buckets.dateRangeTitle": "日期范围", - "data.search.aggs.buckets.filtersTitle": "筛选", - "data.search.aggs.buckets.filterTitle": "筛选", - "data.search.aggs.buckets.geohashGridTitle": "Geohash", - "data.search.aggs.buckets.geotileGridTitle": "地理磁贴", - "data.search.aggs.buckets.histogramTitle": "Histogram", - "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自动", - "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "每日", - "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "每小时", - "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "毫秒", - "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分钟", - "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "每月", - "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", - "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "每周", - "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "每年", - "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 范围", - "data.search.aggs.buckets.ipRangeTitle": "IPv4 范围", - "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", - "data.search.aggs.aggTypesLabel": "{fieldName} 范围", - "data.search.aggs.buckets.rangeTitle": "范围", - "data.search.aggs.buckets.significantTerms.excludeLabel": "排除", - "data.search.aggs.buckets.significantTerms.includeLabel": "包括", - "data.search.aggs.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", - "data.search.aggs.buckets.significantTermsTitle": "重要词", - "data.search.aggs.buckets.terms.excludeLabel": "排除", - "data.search.aggs.buckets.terms.includeLabel": "包括", - "data.search.aggs.buckets.terms.missingBucketLabel": "缺失", - "data.search.aggs.buckets.terms.orderAscendingTitle": "升序", - "data.search.aggs.buckets.terms.orderDescendingTitle": "降序", - "data.search.aggs.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", - "data.search.aggs.buckets.terms.otherBucketLabel": "其他", - "data.search.aggs.buckets.terms.otherBucketTitle": "其他存储桶", - "data.search.aggs.buckets.termsTitle": "词", - "data.search.aggs.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", - "data.search.aggs.metrics.averageBucketTitle": "平均存储桶", - "data.search.aggs.metrics.averageLabel": "{field}平均值", - "data.search.aggs.metrics.averageTitle": "平均值", - "data.search.aggs.metrics.bucketAggTitle": "存储桶聚合", - "data.search.aggs.metrics.countLabel": "计数", - "data.search.aggs.metrics.countTitle": "计数", - "data.search.aggs.metrics.cumulativeSumLabel": "累计和", - "data.search.aggs.metrics.cumulativeSumTitle": "累计和", - "data.search.aggs.metrics.derivativeLabel": "导数", - "data.search.aggs.metrics.derivativeTitle": "导数", - "data.search.aggs.metrics.geoBoundsLabel": "地理边界", - "data.search.aggs.metrics.geoBoundsTitle": "地理边界", - "data.search.aggs.metrics.geoCentroidLabel": "地理重心", - "data.search.aggs.metrics.geoCentroidTitle": "地理重心", - "data.search.aggs.metrics.maxBucketTitle": "最大存储桶", - "data.search.aggs.metrics.maxLabel": "{field}最大值", - "data.search.aggs.metrics.maxTitle": "最大值", - "data.search.aggs.metrics.medianLabel": "{field}中值", - "data.search.aggs.metrics.medianTitle": "中值", - "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "指标聚合", - "data.search.aggs.metrics.metricAggTitle": "指标聚合", - "data.search.aggs.metrics.minBucketTitle": "最小存储桶", - "data.search.aggs.metrics.minLabel": "{field}最小值", - "data.search.aggs.metrics.minTitle": "最小值", - "data.search.aggs.metrics.movingAvgLabel": "移动平均值", - "data.search.aggs.metrics.movingAvgTitle": "移动平均值", - "data.search.aggs.metrics.overallAverageLabel": "总体平均值", - "data.search.aggs.metrics.overallMaxLabel": "总体最大值", - "data.search.aggs.metrics.overallMinLabel": "总体最大值", - "data.search.aggs.metrics.overallSumLabel": "总和", - "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", - "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", - "data.search.aggs.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", - "data.search.aggs.metrics.percentileRanksTitle": "百分位数排名", - "data.search.aggs.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", - "data.search.aggs.metrics.percentilesLabel": "“{field}” 的百分位数", - "data.search.aggs.metrics.percentilesTitle": "百分位数", - "data.search.aggs.metrics.serialDiffLabel": "序列差异", - "data.search.aggs.metrics.serialDiffTitle": "序列差异", - "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", - "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", - "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", - "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", - "data.search.aggs.metrics.standardDeviationLabel": "“{field}” 的标准偏差", - "data.search.aggs.metrics.standardDeviationTitle": "标准偏差", - "data.search.aggs.metrics.sumBucketTitle": "求和存储桶", - "data.search.aggs.metrics.sumLabel": "“{field}” 的和", - "data.search.aggs.metrics.sumTitle": "和", - "data.search.aggs.metrics.topHit.ascendingLabel": "升序", - "data.search.aggs.metrics.topHit.averageLabel": "平均值", - "data.search.aggs.metrics.topHit.concatenateLabel": "连接", - "data.search.aggs.metrics.topHit.descendingLabel": "降序", - "data.search.aggs.metrics.topHit.firstPrefixLabel": "第一", - "data.search.aggs.metrics.topHit.lastPrefixLabel": "最后", - "data.search.aggs.metrics.topHit.maxLabel": "最大值", - "data.search.aggs.metrics.topHit.minLabel": "最小值", - "data.search.aggs.metrics.topHit.sumLabel": "和", - "data.search.aggs.metrics.topHitTitle": "最高命中结果", - "data.search.aggs.metrics.uniqueCountLabel": "“{field}” 的唯一计数", - "data.search.aggs.metrics.uniqueCountTitle": "唯一计数", - "data.search.aggs.otherBucket.labelForMissingValuesLabel": "缺失值的标签", - "data.search.aggs.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", - "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", - "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", - "data.search.aggs.string.customLabel": "定制标签", "common.ui.directives.paginate.size.allDropDownOptionLabel": "全部", "common.ui.dualRangeControl.mustSetBothErrorMessage": "下限值和上限值都须设置", "common.ui.dualRangeControl.outsideOfRangeErrorMessage": "值必须是在 {min} 到 {max} 的范围内", @@ -367,10 +264,223 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,并且似乎没有任何可安全删除的项。\n\n通常可通过移至新的标签页来解决此问题,但这会导致更大的问题。如果您有规律地看到此消息,请在 {gitHubIssuesUrl} 提交问题。", "common.ui.url.replacementFailedErrorMessage": "替换失败,未解析的表达式:{expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "已保存对象缺失", - "data.search.aggs.percentageOfLabel": "{label} 的百分比", "common.ui.vis.defaultFeedbackMessage": "想反馈?请在“{link}中创建问题。", "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "适应数据边界", "common.ui.vis.kibanaMap.zoomWarning": "已达到缩放级别最大数目。要一直放大,请升级到 Elasticsearch 和 Kibana 的 {defaultDistribution}。您可以通过 {ems} 免费使用其他缩放级别。或者,您可以配置自己的地图服务器。请前往 { wms } 或 { configSettings} 以获取详细信息。", + "data.search.aggs.aggGroups.bucketsText": "存储桶", + "data.search.aggs.aggGroups.metricsText": "指标", + "data.search.aggs.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", + "data.search.aggs.buckets.dateHistogramTitle": "Date Histogram", + "data.search.aggs.buckets.dateRangeTitle": "日期范围", + "data.search.aggs.buckets.filtersTitle": "筛选", + "data.search.aggs.buckets.filterTitle": "筛选", + "data.search.aggs.buckets.geohashGridTitle": "Geohash", + "data.search.aggs.buckets.geotileGridTitle": "地理磁贴", + "data.search.aggs.buckets.histogramTitle": "Histogram", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自动", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "每日", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "每小时", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "毫秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分钟", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "每月", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "每周", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "每年", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 范围", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 范围", + "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", + "data.search.aggs.aggTypesLabel": "{fieldName} 范围", + "data.search.aggs.buckets.rangeTitle": "范围", + "data.search.aggs.buckets.significantTerms.excludeLabel": "排除", + "data.search.aggs.buckets.significantTerms.includeLabel": "包括", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", + "data.search.aggs.buckets.significantTermsTitle": "重要词", + "data.search.aggs.buckets.terms.excludeLabel": "排除", + "data.search.aggs.buckets.terms.includeLabel": "包括", + "data.search.aggs.buckets.terms.missingBucketLabel": "缺失", + "data.search.aggs.buckets.terms.orderAscendingTitle": "升序", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降序", + "data.search.aggs.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", + "data.search.aggs.buckets.terms.otherBucketLabel": "其他", + "data.search.aggs.buckets.terms.otherBucketTitle": "其他存储桶", + "data.search.aggs.buckets.termsTitle": "词", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", + "data.search.aggs.metrics.averageBucketTitle": "平均存储桶", + "data.search.aggs.metrics.averageLabel": "{field}平均值", + "data.search.aggs.metrics.averageTitle": "平均值", + "data.search.aggs.metrics.bucketAggTitle": "存储桶聚合", + "data.search.aggs.metrics.countLabel": "计数", + "data.search.aggs.metrics.countTitle": "计数", + "data.search.aggs.metrics.cumulativeSumLabel": "累计和", + "data.search.aggs.metrics.cumulativeSumTitle": "累计和", + "data.search.aggs.metrics.derivativeLabel": "导数", + "data.search.aggs.metrics.derivativeTitle": "导数", + "data.search.aggs.metrics.geoBoundsLabel": "地理边界", + "data.search.aggs.metrics.geoBoundsTitle": "地理边界", + "data.search.aggs.metrics.geoCentroidLabel": "地理重心", + "data.search.aggs.metrics.geoCentroidTitle": "地理重心", + "data.search.aggs.metrics.maxBucketTitle": "最大存储桶", + "data.search.aggs.metrics.maxLabel": "{field}最大值", + "data.search.aggs.metrics.maxTitle": "最大值", + "data.search.aggs.metrics.medianLabel": "{field}中值", + "data.search.aggs.metrics.medianTitle": "中值", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "指标聚合", + "data.search.aggs.metrics.metricAggTitle": "指标聚合", + "data.search.aggs.metrics.minBucketTitle": "最小存储桶", + "data.search.aggs.metrics.minLabel": "{field}最小值", + "data.search.aggs.metrics.minTitle": "最小值", + "data.search.aggs.metrics.movingAvgLabel": "移动平均值", + "data.search.aggs.metrics.movingAvgTitle": "移动平均值", + "data.search.aggs.metrics.overallAverageLabel": "总体平均值", + "data.search.aggs.metrics.overallMaxLabel": "总体最大值", + "data.search.aggs.metrics.overallMinLabel": "总体最大值", + "data.search.aggs.metrics.overallSumLabel": "总和", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", + "data.search.aggs.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", + "data.search.aggs.metrics.percentileRanksTitle": "百分位数排名", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", + "data.search.aggs.metrics.percentilesLabel": "“{field}” 的百分位数", + "data.search.aggs.metrics.percentilesTitle": "百分位数", + "data.search.aggs.metrics.serialDiffLabel": "序列差异", + "data.search.aggs.metrics.serialDiffTitle": "序列差异", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", + "data.search.aggs.metrics.standardDeviationLabel": "“{field}” 的标准偏差", + "data.search.aggs.metrics.standardDeviationTitle": "标准偏差", + "data.search.aggs.metrics.sumBucketTitle": "求和存储桶", + "data.search.aggs.metrics.sumLabel": "“{field}” 的和", + "data.search.aggs.metrics.sumTitle": "和", + "data.search.aggs.metrics.topHit.ascendingLabel": "升序", + "data.search.aggs.metrics.topHit.averageLabel": "平均值", + "data.search.aggs.metrics.topHit.concatenateLabel": "连接", + "data.search.aggs.metrics.topHit.descendingLabel": "降序", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "第一", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最后", + "data.search.aggs.metrics.topHit.maxLabel": "最大值", + "data.search.aggs.metrics.topHit.minLabel": "最小值", + "data.search.aggs.metrics.topHit.sumLabel": "和", + "data.search.aggs.metrics.topHitTitle": "最高命中结果", + "data.search.aggs.metrics.uniqueCountLabel": "“{field}” 的唯一计数", + "data.search.aggs.metrics.uniqueCountTitle": "唯一计数", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "缺失值的标签", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", + "data.search.aggs.string.customLabel": "定制标签", + "data.search.aggs.percentageOfLabel": "{label} 的百分比", + "data.filter.applyFilters.popupHeader": "选择要应用的筛选", + "data.filter.applyFiltersPopup.cancelButtonLabel": "取消", + "data.filter.applyFiltersPopup.saveButtonLabel": "应用", + "data.filter.filterBar.addFilterButtonLabel": "添加筛选", + "data.filter.filterBar.deleteFilterButtonLabel": "删除", + "data.filter.filterBar.disabledFilterPrefix": "已禁用", + "data.filter.filterBar.disableFilterButtonLabel": "暂时禁用", + "data.filter.filterBar.editFilterButtonLabel": "编辑筛选", + "data.filter.filterBar.enableFilterButtonLabel": "重新启用", + "data.filter.filterBar.excludeFilterButtonLabel": "排除结果", + "data.filter.filterBar.filterItemBadgeAriaLabel": "筛选操作", + "data.filter.filterBar.filterItemBadgeIconAriaLabel": "删除", + "data.filter.filterBar.includeFilterButtonLabel": "包括结果", + "data.filter.filterBar.indexPatternSelectPlaceholder": "选择索引模式", + "data.filter.filterBar.moreFilterActionsMessage": "筛选:{innerText}。选择以获取更多筛选操作。", + "data.filter.filterBar.negatedFilterPrefix": "非 ", + "data.filter.filterBar.pinFilterButtonLabel": "在所有应用上固定", + "data.filter.filterBar.pinnedFilterPrefix": "已固定", + "data.filter.filterBar.unpinFilterButtonLabel": "取消固定", + "data.filter.filterEditor.cancelButtonLabel": "取消", + "data.filter.filterEditor.createCustomLabelInputLabel": "定制标签", + "data.filter.filterEditor.createCustomLabelSwitchLabel": "创建定制标签?", + "data.filter.filterEditor.dateFormatHelpLinkLabel": "已接受日期格式", + "data.filter.filterEditor.doesNotExistOperatorOptionLabel": "不存在", + "data.filter.filterEditor.editFilterPopupTitle": "编辑筛选", + "data.filter.filterEditor.editFilterValuesButtonLabel": "编辑筛选值", + "data.filter.filterEditor.editQueryDslButtonLabel": "编辑为查询 DSL", + "data.filter.filterEditor.existsOperatorOptionLabel": "存在", + "data.filter.filterEditor.falseOptionLabel": "false", + "data.filter.filterEditor.fieldSelectLabel": "字段", + "data.filter.filterEditor.fieldSelectPlaceholder": "首先选择字段", + "data.filter.filterEditor.indexPatternSelectLabel": "索引模式", + "data.filter.filterEditor.isBetweenOperatorOptionLabel": "介于", + "data.filter.filterEditor.isNotBetweenOperatorOptionLabel": "不介于", + "data.filter.filterEditor.isNotOneOfOperatorOptionLabel": "不属于", + "data.filter.filterEditor.isNotOperatorOptionLabel": "不是", + "data.filter.filterEditor.isOneOfOperatorOptionLabel": "属于", + "data.filter.filterEditor.isOperatorOptionLabel": "是", + "data.filter.filterEditor.operatorSelectLabel": "运算符", + "data.filter.filterEditor.operatorSelectPlaceholderSelect": "选择", + "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "正在等候", + "data.filter.filterEditor.queryDslLabel": "Elasticsearch 查询 DSL", + "data.filter.filterEditor.rangeEndInputPlaceholder": "范围结束", + "data.filter.filterEditor.rangeInputLabel": "范围", + "data.filter.filterEditor.rangeStartInputPlaceholder": "范围开始", + "data.filter.filterEditor.saveButtonLabel": "保存", + "data.filter.filterEditor.trueOptionLabel": "true", + "data.filter.filterEditor.valueInputLabel": "值", + "data.filter.filterEditor.valueInputPlaceholder": "输入值", + "data.filter.filterEditor.valueSelectPlaceholder": "选择值", + "data.filter.filterEditor.valuesSelectLabel": "值", + "data.filter.filterEditor.valuesSelectPlaceholder": "选择值", + "data.filter.options.changeAllFiltersButtonLabel": "更改所有筛选", + "data.filter.options.deleteAllFiltersButtonLabel": "全部删除", + "data.filter.options.disableAllFiltersButtonLabel": "全部禁用", + "data.filter.options.enableAllFiltersButtonLabel": "全部启用", + "data.filter.options.invertDisabledFiltersButtonLabel": "反向已启用/已禁用", + "data.filter.options.invertNegatedFiltersButtonLabel": "反向包括", + "data.filter.options.pinAllFiltersButtonLabel": "全部固定", + "data.filter.options.unpinAllFiltersButtonLabel": "全部取消固定", + "data.filter.searchBar.changeAllFiltersTitle": "更改所有筛选", + "data.indexPatterns.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。", + "data.indexPatterns.unknownFieldErrorMessage": "indexPattern “{title}” 中的字段 “{name}” 使用未知字段类型。", + "data.indexPatterns.unknownFieldHeader": "未知字段类型 {type}", + "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "无效的日历时间间隔:{interval},值必须为 1", + "data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "时间间隔格式无效:{interval}", + "data.query.queryBar.comboboxAriaLabel": "搜索并筛选 {pageType} 页面", + "data.query.queryBar.kqlFullLanguageName": "Kibana 查询语言", + "data.query.queryBar.kqlLanguageName": "KQL", + "data.query.queryBar.kqlOffLabel": "关闭", + "data.query.queryBar.kqlOnLabel": "开启", + "data.query.queryBar.luceneLanguageName": "Lucene", + "data.query.queryBar.luceneSyntaxWarningMessage": "尽管您选择了 Kibana 查询语言 (KQL),但似乎您正在尝试使用 Lucene 查询语法。请查看 KQL 文档 {link}。", + "data.query.queryBar.luceneSyntaxWarningOptOutText": "不再显示", + "data.query.queryBar.luceneSyntaxWarningTitle": "Lucene 语法警告", + "data.query.queryBar.searchInputAriaLabel": "开始键入内容,以搜索并筛选 {pageType} 页面", + "data.query.queryBar.searchInputPlaceholder": "搜索", + "data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) 提供简化查询语法并支持脚本字段。如果您具有基本许可或更高级别的许可,KQL 还提供自动填充功能。如果关闭 KQL,Kibana 将使用 Lucene。", + "data.query.queryBar.syntaxOptionsDescription.docsLinkText": "此处", + "data.query.queryBar.syntaxOptionsTitle": "语法选项", + "data.search.searchBar.savedQueryDescriptionLabelText": "描述", + "data.search.searchBar.savedQueryDescriptionText": "保存想要再次使用的查询文本和筛选。", + "data.search.searchBar.savedQueryForm.titleConflictText": "标题与现有已保存查询有冲突", + "data.search.searchBar.savedQueryForm.titleMissingText": "“名称”必填", + "data.search.searchBar.savedQueryForm.whitespaceErrorText": "标题不能包含前导或尾随空格", + "data.search.searchBar.savedQueryFormCancelButtonText": "取消", + "data.search.searchBar.savedQueryFormSaveButtonText": "保存", + "data.search.searchBar.savedQueryFormTitle": "保存查询", + "data.search.searchBar.savedQueryIncludeFiltersLabelText": "包括筛选", + "data.search.searchBar.savedQueryIncludeTimeFilterLabelText": "包括时间筛选", + "data.search.searchBar.savedQueryNameHelpText": "“名称”必填。标题不能包含前导或尾随空格。名称必须唯一。", + "data.search.searchBar.savedQueryNameLabelText": "名称", + "data.search.searchBar.savedQueryNoSavedQueriesText": "没有已保存查询。", + "data.search.searchBar.savedQueryPopoverButtonText": "查看已保存查询", + "data.search.searchBar.savedQueryPopoverClearButtonAriaLabel": "清除当前已保存查询", + "data.search.searchBar.savedQueryPopoverClearButtonText": "清除", + "data.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "取消", + "data.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "删除", + "data.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "删除“{savedQueryName}”?", + "data.search.searchBar.savedQueryPopoverDeleteButtonAriaLabel": "删除已保存查询 {savedQueryName}", + "data.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "另存为新的已保存查询", + "data.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "另存为新的", + "data.search.searchBar.savedQueryPopoverSaveButtonAriaLabel": "保存新的已保存查询", + "data.search.searchBar.savedQueryPopoverSaveButtonText": "保存当前查询", + "data.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "将更改保存到 {title}", + "data.search.searchBar.savedQueryPopoverSaveChangesButtonText": "保存更改", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemButtonAriaLabel": "已保存查询按钮 {savedQueryName}", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} 描述", + "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "已保存查询按钮已选择 {savedQueryName}。按下可清除任何更改。", + "data.search.searchBar.savedQueryPopoverTitleText": "已保存查询", "charts.colormaps.bluesText": "蓝色", "charts.colormaps.greensText": "绿色", "charts.colormaps.greenToRedText": "绿到红", @@ -526,116 +636,6 @@ "dashboardEmbeddableContainer.actions.toggleExpandPanelMenuItem.notExpandedDisplayName": "全屏", "dashboardEmbeddableContainer.dashboardGrid.toast.unableToLoadDashboardDangerMessage": "无法加载仪表板。", "dashboardEmbeddableContainer.factory.displayName": "仪表板", - "data.filter.applyFilters.popupHeader": "选择要应用的筛选", - "data.filter.applyFiltersPopup.cancelButtonLabel": "取消", - "data.filter.applyFiltersPopup.saveButtonLabel": "应用", - "data.filter.filterBar.addFilterButtonLabel": "添加筛选", - "data.filter.filterBar.deleteFilterButtonLabel": "删除", - "data.filter.filterBar.disabledFilterPrefix": "已禁用", - "data.filter.filterBar.disableFilterButtonLabel": "暂时禁用", - "data.filter.filterBar.editFilterButtonLabel": "编辑筛选", - "data.filter.filterBar.enableFilterButtonLabel": "重新启用", - "data.filter.filterBar.excludeFilterButtonLabel": "排除结果", - "data.filter.filterBar.filterItemBadgeAriaLabel": "筛选操作", - "data.filter.filterBar.filterItemBadgeIconAriaLabel": "删除", - "data.filter.filterBar.includeFilterButtonLabel": "包括结果", - "data.filter.filterBar.indexPatternSelectPlaceholder": "选择索引模式", - "data.filter.filterBar.moreFilterActionsMessage": "筛选:{innerText}。选择以获取更多筛选操作。", - "data.filter.filterBar.negatedFilterPrefix": "非 ", - "data.filter.filterBar.pinFilterButtonLabel": "在所有应用上固定", - "data.filter.filterBar.pinnedFilterPrefix": "已固定", - "data.filter.filterBar.unpinFilterButtonLabel": "取消固定", - "data.filter.filterEditor.cancelButtonLabel": "取消", - "data.filter.filterEditor.createCustomLabelInputLabel": "定制标签", - "data.filter.filterEditor.createCustomLabelSwitchLabel": "创建定制标签?", - "data.filter.filterEditor.dateFormatHelpLinkLabel": "已接受日期格式", - "data.filter.filterEditor.doesNotExistOperatorOptionLabel": "不存在", - "data.filter.filterEditor.editFilterPopupTitle": "编辑筛选", - "data.filter.filterEditor.editFilterValuesButtonLabel": "编辑筛选值", - "data.filter.filterEditor.editQueryDslButtonLabel": "编辑为查询 DSL", - "data.filter.filterEditor.existsOperatorOptionLabel": "存在", - "data.filter.filterEditor.falseOptionLabel": "false", - "data.filter.filterEditor.fieldSelectLabel": "字段", - "data.filter.filterEditor.fieldSelectPlaceholder": "首先选择字段", - "data.filter.filterEditor.indexPatternSelectLabel": "索引模式", - "data.filter.filterEditor.isBetweenOperatorOptionLabel": "介于", - "data.filter.filterEditor.isNotBetweenOperatorOptionLabel": "不介于", - "data.filter.filterEditor.isNotOneOfOperatorOptionLabel": "不属于", - "data.filter.filterEditor.isNotOperatorOptionLabel": "不是", - "data.filter.filterEditor.isOneOfOperatorOptionLabel": "属于", - "data.filter.filterEditor.isOperatorOptionLabel": "是", - "data.filter.filterEditor.operatorSelectLabel": "运算符", - "data.filter.filterEditor.operatorSelectPlaceholderSelect": "选择", - "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "正在等候", - "data.filter.filterEditor.queryDslLabel": "Elasticsearch 查询 DSL", - "data.filter.filterEditor.rangeEndInputPlaceholder": "范围结束", - "data.filter.filterEditor.rangeInputLabel": "范围", - "data.filter.filterEditor.rangeStartInputPlaceholder": "范围开始", - "data.filter.filterEditor.saveButtonLabel": "保存", - "data.filter.filterEditor.trueOptionLabel": "true", - "data.filter.filterEditor.valueInputLabel": "值", - "data.filter.filterEditor.valueInputPlaceholder": "输入值", - "data.filter.filterEditor.valueSelectPlaceholder": "选择值", - "data.filter.filterEditor.valuesSelectLabel": "值", - "data.filter.filterEditor.valuesSelectPlaceholder": "选择值", - "data.filter.options.changeAllFiltersButtonLabel": "更改所有筛选", - "data.filter.options.deleteAllFiltersButtonLabel": "全部删除", - "data.filter.options.disableAllFiltersButtonLabel": "全部禁用", - "data.filter.options.enableAllFiltersButtonLabel": "全部启用", - "data.filter.options.invertDisabledFiltersButtonLabel": "反向已启用/已禁用", - "data.filter.options.invertNegatedFiltersButtonLabel": "反向包括", - "data.filter.options.pinAllFiltersButtonLabel": "全部固定", - "data.filter.options.unpinAllFiltersButtonLabel": "全部取消固定", - "data.filter.searchBar.changeAllFiltersTitle": "更改所有筛选", - "data.indexPatterns.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。", - "data.indexPatterns.unknownFieldErrorMessage": "indexPattern “{title}” 中的字段 “{name}” 使用未知字段类型。", - "data.indexPatterns.unknownFieldHeader": "未知字段类型 {type}", - "data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "无效的日历时间间隔:{interval},值必须为 1", - "data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "时间间隔格式无效:{interval}", - "data.query.queryBar.comboboxAriaLabel": "搜索并筛选 {pageType} 页面", - "data.query.queryBar.kqlFullLanguageName": "Kibana 查询语言", - "data.query.queryBar.kqlLanguageName": "KQL", - "data.query.queryBar.kqlOffLabel": "关闭", - "data.query.queryBar.kqlOnLabel": "开启", - "data.query.queryBar.luceneLanguageName": "Lucene", - "data.query.queryBar.luceneSyntaxWarningMessage": "尽管您选择了 Kibana 查询语言 (KQL),但似乎您正在尝试使用 Lucene 查询语法。请查看 KQL 文档 {link}。", - "data.query.queryBar.luceneSyntaxWarningOptOutText": "不再显示", - "data.query.queryBar.luceneSyntaxWarningTitle": "Lucene 语法警告", - "data.query.queryBar.searchInputAriaLabel": "开始键入内容,以搜索并筛选 {pageType} 页面", - "data.query.queryBar.searchInputPlaceholder": "搜索", - "data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) 提供简化查询语法并支持脚本字段。如果您具有基本许可或更高级别的许可,KQL 还提供自动填充功能。如果关闭 KQL,Kibana 将使用 Lucene。", - "data.query.queryBar.syntaxOptionsDescription.docsLinkText": "此处", - "data.query.queryBar.syntaxOptionsTitle": "语法选项", - "data.search.searchBar.savedQueryDescriptionLabelText": "描述", - "data.search.searchBar.savedQueryDescriptionText": "保存想要再次使用的查询文本和筛选。", - "data.search.searchBar.savedQueryForm.titleConflictText": "标题与现有已保存查询有冲突", - "data.search.searchBar.savedQueryForm.titleMissingText": "“名称”必填", - "data.search.searchBar.savedQueryForm.whitespaceErrorText": "标题不能包含前导或尾随空格", - "data.search.searchBar.savedQueryFormCancelButtonText": "取消", - "data.search.searchBar.savedQueryFormSaveButtonText": "保存", - "data.search.searchBar.savedQueryFormTitle": "保存查询", - "data.search.searchBar.savedQueryIncludeFiltersLabelText": "包括筛选", - "data.search.searchBar.savedQueryIncludeTimeFilterLabelText": "包括时间筛选", - "data.search.searchBar.savedQueryNameHelpText": "“名称”必填。标题不能包含前导或尾随空格。名称必须唯一。", - "data.search.searchBar.savedQueryNameLabelText": "名称", - "data.search.searchBar.savedQueryNoSavedQueriesText": "没有已保存查询。", - "data.search.searchBar.savedQueryPopoverButtonText": "查看已保存查询", - "data.search.searchBar.savedQueryPopoverClearButtonAriaLabel": "清除当前已保存查询", - "data.search.searchBar.savedQueryPopoverClearButtonText": "清除", - "data.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "取消", - "data.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "删除", - "data.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "删除“{savedQueryName}”?", - "data.search.searchBar.savedQueryPopoverDeleteButtonAriaLabel": "删除已保存查询 {savedQueryName}", - "data.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "另存为新的已保存查询", - "data.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "另存为新的", - "data.search.searchBar.savedQueryPopoverSaveButtonAriaLabel": "保存新的已保存查询", - "data.search.searchBar.savedQueryPopoverSaveButtonText": "保存当前查询", - "data.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "将更改保存到 {title}", - "data.search.searchBar.savedQueryPopoverSaveChangesButtonText": "保存更改", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemButtonAriaLabel": "已保存查询按钮 {savedQueryName}", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} 描述", - "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "已保存查询按钮已选择 {savedQueryName}。按下可清除任何更改。", - "data.search.searchBar.savedQueryPopoverTitleText": "已保存查询", "embeddableApi.actions.applyFilterActionTitle": "将筛选应用于当前视图", "embeddableApi.addPanel.createNewDefaultOption": "创建新的......", "embeddableApi.addPanel.displayName": "添加面板", @@ -1435,8 +1435,6 @@ "kbn.management.indexPattern.confirmOverwriteTitle": "覆盖“{type}”?", "kbn.management.indexPattern.sectionsHeader": "索引模式", "kbn.management.indexPattern.titleExistsLabel": "具有标题 “{title}” 的索引模式已存在。", - "management.indexPatternHeader": "索引模式", - "management.indexPatternLabel": "管理帮助从 Elasticsearch 检索数据的索引模式。", "kbn.management.indexPatternList.createButton.betaLabel": "公测版", "kbn.management.indexPatternPrompt.exampleOne": "索引单个称作 log-west-001 的数据源,以便可以快速地构建图表或查询其内容。", "kbn.management.indexPatternPrompt.exampleOneTitle": "单数据源", @@ -1555,9 +1553,7 @@ "kbn.management.objects.objectsTable.table.typeFilterName": "类型", "kbn.management.objects.objectsTable.unableFindSavedObjectsNotificationMessage": "找不到已保存对象", "kbn.management.objects.parsingFieldErrorMessage": "为索引模式 “{indexName}” 解析 “{fieldName}” 时发生错误:{errorMessage}", - "management.objects.savedObjectsDescription": "导入、导出和管理您的已保存搜索、可视化和仪表板。", "kbn.management.objects.savedObjectsSectionLabel": "已保存对象", - "management.objects.savedObjectsTitle": "已保存对象", "kbn.management.objects.view.cancelButtonAriaLabel": "取消", "kbn.management.objects.view.cancelButtonLabel": "取消", "kbn.management.objects.view.deleteItemButtonLabel": "删除“{title}”", @@ -1575,8 +1571,6 @@ "kbn.management.objects.view.viewItemTitle": "查看“{title}”", "kbn.management.savedObjects.editBreadcrumb": "编辑 {savedObjectType}", "kbn.management.savedObjects.indexBreadcrumb": "已保存对象", - "advancedSettings.advancedSettingsDescription": "直接编辑在 Kibana 中控制行为的设置。", - "advancedSettings.advancedSettingsLabel": "高级设置", "kbn.management.settings.breadcrumb": "高级设置", "kbn.management.settings.callOutCautionDescription": "此处请谨慎操作,这些设置仅供高级用户使用。您在这里所做的更改可能使 Kibana 的大部分功能出现问题。这些设置有一部分可能未在文档中说明、不受支持或是实验性设置。如果字段有默认值,将字段留空会将其设置为默认值,其他配置指令可能不接受其默认值。删除定制设置会将其从 Kibana 的配置中永久删除。", "kbn.management.settings.callOutCautionTitle": "注意:在这里您可能会使问题出现", @@ -1616,7 +1610,6 @@ "kbn.management.settings.form.clearSearchResultText": "(清除搜索)", "kbn.management.settings.form.noSearchResultText": "未找到设置{clearSearch}", "kbn.management.settings.form.searchResultText": "搜索词隐藏了 {settingsCount} 个设置{clearSearch}", - "advancedSettings.pageTitle": "设置", "kbn.management.settings.searchBar.unableToParseQueryErrorMessage": "无法解析查询", "kbn.management.settings.searchBarAriaLabel": "搜索高级设置", "kbn.management.settings.sectionLabel": "高级设置", @@ -1664,6 +1657,13 @@ "kbn.visualize.wizard.step1Breadcrumb": "创建", "kbn.visualize.wizard.step2Breadcrumb": "创建", "kbn.visualizeTitle": "可视化", + "management.indexPatternHeader": "索引模式", + "management.indexPatternLabel": "管理帮助从 Elasticsearch 检索数据的索引模式。", + "management.objects.savedObjectsDescription": "导入、导出和管理您的已保存搜索、可视化和仪表板。", + "management.objects.savedObjectsTitle": "已保存对象", + "advancedSettings.advancedSettingsDescription": "直接编辑在 Kibana 中控制行为的设置。", + "advancedSettings.advancedSettingsLabel": "高级设置", + "advancedSettings.pageTitle": "设置", "kibana_legacy.bigUrlWarningNotificationMessage": "在{advancedSettingsLink}中启用“{storeInSessionStorageParam}”选项或简化屏幕视觉效果。", "kibana_legacy.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高级设置", "kibana_legacy.bigUrlWarningNotificationTitle": "URL 过长,Kibana 可能无法工作", @@ -6434,8 +6434,6 @@ "xpack.infra.logs.analysis.anomaliesSectionLineSeriesName": "每 15 分钟日志条目数(平均值)", "xpack.infra.logs.analysis.anomaliesSectionLoadingAriaLabel": "正在加载异常", "xpack.infra.logs.analysis.anomaliesSectionTitle": "异常", - "xpack.infra.logs.analysis.anomaliesTableCollapseLabel": "折叠", - "xpack.infra.logs.analysis.anomaliesTableExpandLabel": "展开", "xpack.infra.logs.analysis.anomaliesTableMaxAnomalyScoreColumnName": "最大异常分数", "xpack.infra.logs.analysis.anomaliesTablePartitionColumnName": "分区", "xpack.infra.logs.analysis.anomalySectionNoAnomaliesTitle": "未检测到任何异常。", @@ -13189,4 +13187,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "此字段必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} +} \ No newline at end of file From 422dfea987d5a93226a26d02feca726ce42d6198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Mar 2020 01:33:07 +0100 Subject: [PATCH 12/17] Display per-dataset anomaly scores and ML links --- .../results/log_entry_categories.ts | 9 ++- .../log_analysis/log_analysis_results.ts | 7 +++ .../analyze_in_ml_button.tsx | 12 ++-- .../analyze_dataset_in_ml_action.tsx | 57 +++++++++++++++++++ .../anomaly_severity_indicator_list.tsx | 26 +++++++++ .../top_categories/datasets_action_list.tsx | 35 ++++++++++++ .../sections/top_categories/datasets_list.tsx | 24 ++++++-- .../top_categories/top_categories_section.tsx | 1 + .../top_categories/top_categories_table.tsx | 44 +++++++++++--- .../log_entry_categories_analysis.ts | 49 ++++++++++------ .../queries/top_log_entry_categories.ts | 22 +++++++ 11 files changed, 252 insertions(+), 34 deletions(-) create mode 100644 x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx create mode 100644 x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/anomaly_severity_indicator_list.tsx create mode 100644 x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_action_list.tsx diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_categories.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_categories.ts index 66823c25237ac..f56462012d2e9 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_categories.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_categories.ts @@ -72,9 +72,16 @@ export const logEntryCategoryHistogramRT = rt.type({ export type LogEntryCategoryHistogram = rt.TypeOf; +export const logEntryCategoryDatasetRT = rt.type({ + name: rt.string, + maximumAnomalyScore: rt.number, +}); + +export type LogEntryCategoryDataset = rt.TypeOf; + export const logEntryCategoryRT = rt.type({ categoryId: rt.number, - datasets: rt.array(rt.string), + datasets: rt.array(logEntryCategoryDatasetRT), histograms: rt.array(logEntryCategoryHistogramRT), logEntryCount: rt.number, maximumAnomalyScore: rt.number, diff --git a/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts b/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts index 1dcd4a10fc4e3..19c92cb381104 100644 --- a/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts +++ b/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts @@ -44,3 +44,10 @@ export const formatAnomalyScore = (score: number) => { export const getFriendlyNameForPartitionId = (partitionId: string) => { return partitionId !== '' ? partitionId : 'unknown'; }; + +export const compareDatasetsByMaximumAnomalyScore = < + Dataset extends { maximumAnomalyScore: number } +>( + firstDataset: Dataset, + secondDataset: Dataset +) => firstDataset.maximumAnomalyScore - secondDataset.maximumAnomalyScore; diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx index 6b946898f6330..b7dd6bda8a49d 100644 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx @@ -34,7 +34,9 @@ export const AnalyzeInMlButton: React.FunctionComponent<{ {buttonLabel} @@ -70,11 +72,11 @@ const getOverallAnomalyExplorerLink = (pathname: string, jobId: string, timeRang }); }; -const getPartitionSpecificSingleMetricViewerLink = ( +export const getEntitySpecificSingleMetricViewerLink = ( pathname: string, jobId: string, - partition: string, - timeRange: TimeRange + timeRange: TimeRange, + entities: Record ) => { const { from, to } = convertTimeRangeToParams(timeRange); @@ -91,7 +93,7 @@ const getPartitionSpecificSingleMetricViewerLink = ( const _a = encode({ mlTimeSeriesExplorer: { - entities: { 'event.dataset': partition }, + entities, }, }); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx new file mode 100644 index 0000000000000..b78e18d547bfd --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { identity } from 'fp-ts/lib/function'; +import React, { useMemo } from 'react'; + +import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { TimeRange } from '../../../../../../common/http_api/shared'; +import { getEntitySpecificSingleMetricViewerLink } from '../../../../../components/logging/log_analysis_results'; + +export const AnalyzeCategoryDatasetInMlAction: React.FunctionComponent<{ + categorizationJobId: string; + categoryId: number; + dataset: string; + timeRange: TimeRange; +}> = ({ categorizationJobId, categoryId, dataset, timeRange }) => { + const prependBasePath = useKibana().services.http?.basePath?.prepend ?? identity; + const href = useMemo( + () => + getEntitySpecificSingleMetricViewerLink( + prependBasePath('/app/ml'), + categorizationJobId, + timeRange, + { + 'event.dataset': dataset, + mlcategory: `${categoryId}`, + } + ), + [categorizationJobId, categoryId, dataset, prependBasePath, timeRange] + ); + + return ( + + + + ); +}; + +const analyseCategoryDatasetInMlButtonLabel = i18n.translate( + 'xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel', + { defaultMessage: 'Analyze in ML' } +); + +const analyseCategoryDatasetInMlTooltipDescription = i18n.translate( + 'xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription', + { defaultMessage: 'Analyze this category in the ML app.' } +); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/anomaly_severity_indicator_list.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/anomaly_severity_indicator_list.tsx new file mode 100644 index 0000000000000..6035c032bdece --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/anomaly_severity_indicator_list.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { LogEntryCategoryDataset } from '../../../../../../common/http_api/log_analysis'; +import { getFriendlyNameForPartitionId } from '../../../../../../common/log_analysis'; +import { AnomalySeverityIndicator } from './anomaly_severity_indicator'; + +export const AnomalySeverityIndicatorList: React.FunctionComponent<{ + datasets: LogEntryCategoryDataset[]; +}> = ({ datasets }) => ( +
    + {datasets.map(dataset => { + const datasetLabel = getFriendlyNameForPartitionId(dataset.name); + return ( +
  • + +
  • + ); + })} +
+); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_action_list.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_action_list.tsx new file mode 100644 index 0000000000000..a3705cb28ed05 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_action_list.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { LogEntryCategoryDataset } from '../../../../../../common/http_api/log_analysis'; +import { TimeRange } from '../../../../../../common/http_api/shared'; +import { getFriendlyNameForPartitionId } from '../../../../../../common/log_analysis'; +import { AnalyzeCategoryDatasetInMlAction } from './analyze_dataset_in_ml_action'; + +export const DatasetActionsList: React.FunctionComponent<{ + categorizationJobId: string; + categoryId: number; + datasets: LogEntryCategoryDataset[]; + timeRange: TimeRange; +}> = ({ categorizationJobId, categoryId, datasets, timeRange }) => ( +
    + {datasets.map(dataset => { + const datasetLabel = getFriendlyNameForPartitionId(dataset.name); + return ( +
  • + +
  • + ); + })} +
+); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_list.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_list.tsx index c30612f54be00..6918ae0914cc6 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_list.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/datasets_list.tsx @@ -6,15 +6,31 @@ import React from 'react'; +import { euiStyled } from '../../../../../../../observability/public'; +import { LogEntryCategoryDataset } from '../../../../../../common/http_api/log_analysis'; import { getFriendlyNameForPartitionId } from '../../../../../../common/log_analysis'; export const DatasetsList: React.FunctionComponent<{ - datasets: string[]; + datasets: LogEntryCategoryDataset[]; }> = ({ datasets }) => (
    - {datasets.sort().map(dataset => { - const datasetLabel = getFriendlyNameForPartitionId(dataset); - return
  • {datasetLabel}
  • ; + {datasets.map(dataset => { + const datasetLabel = getFriendlyNameForPartitionId(dataset.name); + return ( +
  • + {datasetLabel} +
  • + ); })}
); + +/* + * These aim at aligning the list with the EuiHealth list in the neighboring + * column. + */ +const DatasetLabel = euiStyled.div` + display: inline-block; + margin-bottom: 2.5px; + margin-top: 1px; +`; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx index d145a6985ad6f..37d26de6fce70 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/top_categories_section.tsx @@ -70,6 +70,7 @@ export const TopCategoriesSection: React.FunctionComponent<{ loadingChildren={} > createColumns(timeRange, expandedCategories, expandCategory, collapseCategory), - [collapseCategory, expandCategory, expandedCategories, timeRange] + () => + createColumns( + timeRange, + categorizationJobId, + expandedCategories, + expandCategory, + collapseCategory + ), + [categorizationJobId, collapseCategory, expandCategory, expandedCategories, timeRange] ); const expandedRowContentsById = useMemo( @@ -80,6 +91,7 @@ export const TopCategoriesTable = euiStyled( const createColumns = ( timeRange: TimeRange, + categorizationJobId: string, expandedCategories: Set, expandCategory: (categoryId: number) => void, collapseCategory: (categoryId: number) => void @@ -126,7 +138,7 @@ const createColumns = ( name: i18n.translate('xpack.infra.logs.logEntryCategories.datasetColumnTitle', { defaultMessage: 'Datasets', }), - render: (datasets: string[]) => , + render: (datasets: LogEntryCategoryDataset[]) => , width: '200px', }, { @@ -135,11 +147,27 @@ const createColumns = ( name: i18n.translate('xpack.infra.logs.logEntryCategories.maximumAnomalyScoreColumnTitle', { defaultMessage: 'Maximum anomaly score', }), - render: (maximumAnomalyScore: number) => ( - + render: (_maximumAnomalyScore: number, item) => ( + ), width: '160px', }, + { + actions: [ + { + render: category => ( + + ), + }, + ], + width: '40px', + }, + { align: 'right', isExpander: true, diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index 9b10d6ea7d402..5a6194f01c40e 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -6,17 +6,18 @@ import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; import { + compareDatasetsByMaximumAnomalyScore, getJobId, - logEntryCategoriesJobTypes, jobCustomSettingsRT, + logEntryCategoriesJobTypes, } from '../../../common/log_analysis'; import { startTracingSpan, TracingSpan } from '../../../common/performance_tracing'; import { decodeOrThrow } from '../../../common/runtime_types'; import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; import { - NoLogAnalysisResultsIndexError, - NoLogAnalysisMlJobError, InsufficientLogAnalysisMlJobConfigurationError, + NoLogAnalysisMlJobError, + NoLogAnalysisResultsIndexError, UnknownCategoryError, } from './errors'; import { @@ -24,6 +25,10 @@ import { logEntryCategoriesResponseRT, LogEntryCategoryHit, } from './queries/log_entry_categories'; +import { + createLogEntryCategoryExamplesQuery, + logEntryCategoryExamplesResponseRT, +} from './queries/log_entry_category_examples'; import { createLogEntryCategoryHistogramsQuery, logEntryCategoryHistogramsResponseRT, @@ -34,15 +39,11 @@ import { LogEntryDatasetBucket, logEntryDatasetsResponseRT, } from './queries/log_entry_data_sets'; -import { mlJobsResponseRT, createMlJobsQuery } from './queries/ml_jobs'; +import { createMlJobsQuery, mlJobsResponseRT } from './queries/ml_jobs'; import { createTopLogEntryCategoriesQuery, topLogEntryCategoriesResponseRT, } from './queries/top_log_entry_categories'; -import { - createLogEntryCategoryExamplesQuery, - logEntryCategoryExamplesResponseRT, -} from './queries/log_entry_category_examples'; const COMPOSITE_AGGREGATION_BATCH_SIZE = 1000; @@ -296,14 +297,30 @@ export class LogEntryCategoriesAnalysis { } const topLogEntryCategories = topLogEntryCategoriesResponse.aggregations.terms_category_id.buckets.map( - topCategoryBucket => ({ - categoryId: parseCategoryId(topCategoryBucket.key), - logEntryCount: topCategoryBucket.filter_model_plot.sum_actual.value ?? 0, - datasets: topCategoryBucket.filter_model_plot.terms_dataset.buckets.map( - datasetBucket => datasetBucket.key - ), - maximumAnomalyScore: topCategoryBucket.filter_record.maximum_record_score.value ?? 0, - }) + topCategoryBucket => { + const maximumAnomalyScoresByDataset = topCategoryBucket.filter_record.terms_dataset.buckets.reduce< + Record + >( + (accumulatedMaximumAnomalyScores, datasetFromRecord) => ({ + ...accumulatedMaximumAnomalyScores, + [datasetFromRecord.key]: datasetFromRecord.maximum_record_score.value ?? 0, + }), + {} + ); + + return { + categoryId: parseCategoryId(topCategoryBucket.key), + logEntryCount: topCategoryBucket.filter_model_plot.sum_actual.value ?? 0, + datasets: topCategoryBucket.filter_model_plot.terms_dataset.buckets + .map(datasetBucket => ({ + name: datasetBucket.key, + maximumAnomalyScore: maximumAnomalyScoresByDataset[datasetBucket.key] ?? 0, + })) + .sort(compareDatasetsByMaximumAnomalyScore) + .reverse(), + maximumAnomalyScore: topCategoryBucket.filter_record.maximum_record_score.value ?? 0, + }; + } ); return { diff --git a/x-pack/plugins/infra/server/lib/log_analysis/queries/top_log_entry_categories.ts b/x-pack/plugins/infra/server/lib/log_analysis/queries/top_log_entry_categories.ts index 22b0ef748f5f8..517d31865e358 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/queries/top_log_entry_categories.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/queries/top_log_entry_categories.ts @@ -100,6 +100,19 @@ export const createTopLogEntryCategoriesQuery = ( field: 'record_score', }, }, + terms_dataset: { + terms: { + field: 'partition_field_value', + size: 1000, + }, + aggs: { + maximum_record_score: { + max: { + field: 'record_score', + }, + }, + }, + }, }, }, }, @@ -130,6 +143,15 @@ export const logEntryCategoryBucketRT = rt.type({ doc_count: rt.number, filter_record: rt.type({ maximum_record_score: metricAggregationRT, + terms_dataset: rt.type({ + buckets: rt.array( + rt.type({ + key: rt.string, + doc_count: rt.number, + maximum_record_score: metricAggregationRT, + }) + ), + }), }), filter_model_plot: rt.type({ sum_actual: metricAggregationRT, From 182098da40ad8bc8df3e07446b04657f6eb2b2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Mar 2020 01:38:03 +0100 Subject: [PATCH 13/17] Adjust dataset column width in example rows --- .../sections/top_categories/category_example_message.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx index c4738ba2f8599..54609bcf8e2c2 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -96,8 +96,8 @@ const columnWidths = { [datasetColumnId]: { growWeight: 0, shrinkWeight: 0, - // w_dataset + w_max_anomaly + w_expand - w_padding = 200 px + 160 px + 40 px - 8 px - baseWidth: '392px', + // w_dataset + w_max_anomaly + w_expand - w_padding = 200 px + 160 px + 40 px + 40 px - 8 px + baseWidth: '432px', }, }; From 55db708b90bdf07083c5dcfa172a2eac5a8365a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Mar 2020 13:32:40 +0100 Subject: [PATCH 14/17] Add message for empty example response --- .../top_categories/category_details_row.tsx | 3 ++ ...egory_example_messages_empty_indicator.tsx | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_messages_empty_indicator.tsx diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx index 8e6dbd8967135..c0728c0a55483 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_details_row.tsx @@ -10,6 +10,7 @@ import { euiStyled } from '../../../../../../../observability/public'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { useLogEntryCategoryExamples } from '../../use_log_entry_category_examples'; import { CategoryExampleMessage } from './category_example_message'; +import { CategoryExampleMessagesEmptyIndicator } from './category_example_messages_empty_indicator'; import { CategoryExampleMessagesFailureIndicator } from './category_example_messages_failure_indicator'; import { CategoryExampleMessagesLoadingIndicator } from './category_example_messages_loading_indicator'; @@ -43,6 +44,8 @@ export const CategoryDetailsRow: React.FunctionComponent<{ ) : hasFailedLoadingLogEntryCategoryExamples ? ( + ) : logEntryCategoryExamples.length === 0 ? ( + ) : ( logEntryCategoryExamples.map((categoryExample, categoryExampleIndex) => ( void; +}> = ({ onReload }) => ( + + + + + + + + + + +); From aea5ece83edf0a8951b0addf7250e9f7b71672e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 11 Mar 2020 12:42:19 +0100 Subject: [PATCH 15/17] Use new link helper hook for dataset ml link --- .../analyze_dataset_in_ml_action.tsx | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx index b78e18d547bfd..3e1398c804686 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx @@ -6,12 +6,11 @@ import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { identity } from 'fp-ts/lib/function'; -import React, { useMemo } from 'react'; +import React from 'react'; -import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; import { TimeRange } from '../../../../../../common/http_api/shared'; import { getEntitySpecificSingleMetricViewerLink } from '../../../../../components/logging/log_analysis_results'; +import { useLinkProps } from '../../../../../hooks/use_link_props'; export const AnalyzeCategoryDatasetInMlAction: React.FunctionComponent<{ categorizationJobId: string; @@ -19,19 +18,11 @@ export const AnalyzeCategoryDatasetInMlAction: React.FunctionComponent<{ dataset: string; timeRange: TimeRange; }> = ({ categorizationJobId, categoryId, dataset, timeRange }) => { - const prependBasePath = useKibana().services.http?.basePath?.prepend ?? identity; - const href = useMemo( - () => - getEntitySpecificSingleMetricViewerLink( - prependBasePath('/app/ml'), - categorizationJobId, - timeRange, - { - 'event.dataset': dataset, - mlcategory: `${categoryId}`, - } - ), - [categorizationJobId, categoryId, dataset, prependBasePath, timeRange] + const linkProps = useLinkProps( + getEntitySpecificSingleMetricViewerLink(categorizationJobId, timeRange, { + 'event.dataset': dataset, + mlcategory: `${categoryId}`, + }) ); return ( @@ -39,8 +30,8 @@ export const AnalyzeCategoryDatasetInMlAction: React.FunctionComponent<{ ); From e283dc83e4989c22c12bc6d7ad94388e2b6a083f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 11 Mar 2020 12:43:04 +0100 Subject: [PATCH 16/17] Correctly read dataset from sample message documents --- .../lib/log_analysis/log_entry_categories_analysis.ts | 4 ++-- .../lib/log_analysis/queries/log_entry_category_examples.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index 5a6194f01c40e..f17d665e209ec 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -519,8 +519,8 @@ export class LogEntryCategoriesAnalysis { return { examples: hits.map(hit => ({ - dataset: hit._source['event.dataset'] ?? '', - message: hit._source.message, + dataset: hit._source.event?.dataset ?? '', + message: hit._source.message ?? '', timestamp: hit.sort[0], })), timing: { diff --git a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts index 680c2193bf4e6..c4c7efcfc4ff0 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/queries/log_entry_category_examples.ts @@ -55,8 +55,10 @@ export const createLogEntryCategoryExamplesQuery = ( }); export const logEntryCategoryExampleHitRT = rt.type({ - _source: rt.type({ - 'event.dataset': rt.union([rt.string, rt.undefined]), + _source: rt.partial({ + event: rt.partial({ + dataset: rt.string, + }), message: rt.string, }), sort: rt.tuple([rt.number]), From 1b0e3ee1cc06a07f2765877ca6d317bf3287510a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 11 Mar 2020 12:55:22 +0100 Subject: [PATCH 17/17] Rename 'original' to 'pre-wrapped' wrap mode --- .../logging/log_text_stream/log_entry_field_column.test.tsx | 6 +++--- .../logging/log_text_stream/log_entry_field_column.tsx | 6 +++--- .../logging/log_text_stream/log_entry_message_column.tsx | 6 +++--- .../components/logging/log_text_stream/log_entry_row.tsx | 4 ++-- .../components/logging/log_text_stream/text_styles.tsx | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx index 3ecb4222a022a..5d295ca7e4817 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx @@ -26,7 +26,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - wrapMode="original" + wrapMode="pre-wrapped" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); @@ -58,7 +58,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - wrapMode="original" + wrapMode="pre-wrapped" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); @@ -80,7 +80,7 @@ describe('LogEntryFieldColumn', () => { isActiveHighlight={false} isHighlighted={false} isHovered={false} - wrapMode="original" + wrapMode="pre-wrapped" />, { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 ); diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx index a5e9acd63b5d2..c6584f2fdbb6d 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx @@ -19,7 +19,7 @@ import { LogEntryColumnContent } from './log_entry_column'; import { hoveredContentStyle, longWrappedContentStyle, - originalWrappedContentStyle, + preWrappedContentStyle, unwrappedContentStyle, WrapMode, } from './text_styles'; @@ -94,7 +94,7 @@ const FieldColumnContent = euiStyled(LogEntryColumnContent) props.wrapMode === 'long' ? longWrappedContentStyle - : props.wrapMode === 'original' - ? originalWrappedContentStyle + : props.wrapMode === 'pre-wrapped' + ? preWrappedContentStyle : unwrappedContentStyle}; `; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx index 488de905cddcc..122f0fe472c6e 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx @@ -21,7 +21,7 @@ import { LogEntryColumnContent } from './log_entry_column'; import { hoveredContentStyle, longWrappedContentStyle, - originalWrappedContentStyle, + preWrappedContentStyle, unwrappedContentStyle, WrapMode, } from './text_styles'; @@ -66,8 +66,8 @@ const MessageColumnContent = euiStyled(LogEntryColumnContent) props.wrapMode === 'long' ? longWrappedContentStyle - : props.wrapMode === 'original' - ? originalWrappedContentStyle + : props.wrapMode === 'pre-wrapped' + ? preWrappedContentStyle : unwrappedContentStyle}; `; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx index ee9623bc07da5..e5e3740f420e8 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx @@ -148,7 +148,7 @@ export const LogEntryRow = memo( isHighlighted={isHighlighted} isActiveHighlight={isActiveHighlight} isHovered={isHovered} - wrapMode={wrap ? 'long' : 'original'} + wrapMode={wrap ? 'long' : 'pre-wrapped'} /> ) : null}
@@ -170,7 +170,7 @@ export const LogEntryRow = memo( isActiveHighlight={isActiveHighlight} isHighlighted={isHighlighted} isHovered={isHovered} - wrapMode={wrap ? 'long' : 'original'} + wrapMode={wrap ? 'long' : 'pre-wrapped'} /> ) : null} diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx index c99eda30db011..434258343eefb 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx @@ -10,7 +10,7 @@ import React, { useMemo, useState, useCallback } from 'react'; import { euiStyled, css } from '../../../../../observability/public'; import { TextScale } from '../../../../common/log_text_scale'; -export type WrapMode = 'none' | 'original' | 'long'; +export type WrapMode = 'none' | 'pre-wrapped' | 'long'; export const monospaceTextStyle = (scale: TextScale) => css` font-family: ${props => props.theme.eui.euiCodeFontFamily}; @@ -42,7 +42,7 @@ export const longWrappedContentStyle = css` word-break: break-all; `; -export const originalWrappedContentStyle = css` +export const preWrappedContentStyle = css` overflow: hidden; white-space: pre; `;