diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts index f6e0946299fed..39075710b8c51 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts @@ -77,8 +77,7 @@ export function getTransformHealthRuleType(): RuleTypeModel; + issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: number }>; } export interface BaseTransformAlertResponse { transform_id: string; description?: string; health_status: TransformHealth['status']; - issues?: TransformHealth['issues']; -} - -export interface NotStartedTransformResponse extends BaseTransformAlertResponse { - transform_state: string; - node_name?: string; + issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: string }>; } -export interface UnhealthyTransformResponse extends BaseTransformAlertResponse { +export interface TransformStateReportResponse extends BaseTransformAlertResponse { transform_state: string; node_name?: string; } @@ -45,7 +41,7 @@ export interface ErrorMessagesTransformResponse extends BaseTransformAlertRespon error_messages: Array<{ message: string; timestamp: number; node_name?: string }>; } -export type TransformHealthResult = NotStartedTransformResponse | ErrorMessagesTransformResponse; +export type TransformHealthResult = TransformStateReportResponse | ErrorMessagesTransformResponse; export type TransformHealthAlertContext = { results: TransformHealthResult[]; @@ -66,14 +62,17 @@ export const TRANSFORM_ISSUE_DETECTED: ActionGroup = { interface RegisterParams { logger: Logger; alerting: AlertingSetup; + getFieldFormatsStart: () => FieldFormatsStart; } export function registerTransformHealthRuleType(params: RegisterParams) { const { alerting } = params; - alerting.registerType(getTransformHealthRuleType()); + alerting.registerType(getTransformHealthRuleType(params.getFieldFormatsStart)); } -export function getTransformHealthRuleType(): RuleType< +export function getTransformHealthRuleType( + getFieldFormatsStart: () => FieldFormatsStart +): RuleType< TransformHealthRuleParams, never, RuleTypeState, @@ -117,14 +116,19 @@ export function getTransformHealthRuleType(): RuleType< doesSetRecoveryContext: true, async executor(options) { const { - services: { scopedClusterClient, alertFactory }, + services: { scopedClusterClient, alertFactory, uiSettingsClient }, params, } = options; - const transformHealthService = transformHealthServiceProvider( - scopedClusterClient.asCurrentUser + const fieldFormatsRegistry = await getFieldFormatsStart().fieldFormatServiceFactory( + uiSettingsClient ); + const transformHealthService = transformHealthServiceProvider({ + esClient: scopedClusterClient.asCurrentUser, + fieldFormatsRegistry, + }); + const executionResult = await transformHealthService.getHealthChecksResults(params); const unhealthyTests = executionResult.filter(({ isHealthy }) => !isHealthy); diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts index f5b06a2b81453..72eb8981aadd6 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts @@ -11,6 +11,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { keyBy, memoize, partition } from 'lodash'; import type { RulesClient } from '@kbn/alerting-plugin/server'; import { type TransformGetTransformStatsTransformStats } from '@elastic/elasticsearch/lib/api/types'; +import { FIELD_FORMAT_IDS, FieldFormatsRegistry } from '@kbn/field-formats-plugin/common'; import { TransformHealthRuleParams } from './schema'; import { ALL_TRANSFORMS_SELECTION, @@ -21,10 +22,9 @@ import { import { getResultTestConfig } from '../../../../common/utils/alerts'; import type { ErrorMessagesTransformResponse, - NotStartedTransformResponse, + TransformStateReportResponse, TransformHealth, TransformHealthAlertContext, - UnhealthyTransformResponse, } from './register_transform_health_rule_type'; import type { TransformHealthAlertRule } from '../../../../common/types/alerting'; import { isContinuousTransform } from '../../../../common/types/transform'; @@ -51,10 +51,15 @@ type TransformGetTransformStats = TransformGetTransformStatsTransformStats & { health: TransformHealth; }; -export function transformHealthServiceProvider( - esClient: ElasticsearchClient, - rulesClient?: RulesClient -) { +export function transformHealthServiceProvider({ + esClient, + rulesClient, + fieldFormatsRegistry, +}: { + esClient: ElasticsearchClient; + rulesClient?: RulesClient; + fieldFormatsRegistry?: FieldFormatsRegistry; +}) { const transformsDict = new Map(); /** @@ -110,6 +115,34 @@ export function transformHealthServiceProvider( } ); + function baseTransformAlertResponseFormatter( + transformStats: TransformGetTransformStats + ): TransformStateReportResponse { + const dateFormatter = fieldFormatsRegistry!.deserialize({ id: FIELD_FORMAT_IDS.DATE }); + + return { + transform_id: transformStats.id, + description: transformsDict.get(transformStats.id)?.description, + transform_state: transformStats.state, + node_name: transformStats.node?.name, + health_status: transformStats.health.status, + ...(transformStats.health.issues + ? { + issues: transformStats.health.issues.map((issue) => { + return { + issue: issue.issue, + details: issue.details, + count: issue.count, + ...(issue.first_occurrence + ? { first_occurrence: dateFormatter.convert(issue.first_occurrence) } + : {}), + }; + }), + } + : {}), + }; + } + return { /** * Returns report about not started transforms @@ -119,18 +152,11 @@ export function transformHealthServiceProvider( */ async getTransformsStateReport( transformIds: string[] - ): Promise<[NotStartedTransformResponse[], NotStartedTransformResponse[]]> { + ): Promise<[TransformStateReportResponse[], TransformStateReportResponse[]]> { const transformsStats = await getTransformStats(transformIds); return partition( - transformsStats.map((t) => ({ - transform_id: t.id, - description: transformsDict.get(t.id)?.description, - transform_state: t.state, - node_name: t.node?.name, - health_status: t.health.status, - issues: t.health.issues, - })), + transformsStats.map(baseTransformAlertResponseFormatter), (t) => t.transform_state !== TRANSFORM_STATE.STARTED && t.transform_state !== TRANSFORM_STATE.INDEXING @@ -216,21 +242,12 @@ export function transformHealthServiceProvider( */ async getUnhealthyTransformsReport( transformIds: string[] - ): Promise { + ): Promise { const transformsStats = await getTransformStats(transformIds); return transformsStats .filter((t) => t.health.status !== 'green') - .map((t) => { - return { - transform_id: t.id, - transform_state: t.state, - node_name: t.node?.name, - description: transformsDict.get(t.id)?.description, - health_status: t.health.status, - issues: t.health.issues, - }; - }); + .map(baseTransformAlertResponseFormatter); }, /** * Returns results of the transform health checks diff --git a/x-pack/plugins/transform/server/plugin.ts b/x-pack/plugins/transform/server/plugin.ts index 3eab84ca0b5fc..fdcc4d606a25e 100644 --- a/x-pack/plugins/transform/server/plugin.ts +++ b/x-pack/plugins/transform/server/plugin.ts @@ -31,6 +31,8 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { private readonly license: License; private readonly logger: Logger; + private fieldFormatsStart: PluginStartDependencies['fieldFormats'] | null = null; + constructor(initContext: PluginInitializerContext) { this.logger = initContext.logger.get(); this.apiRoutes = new ApiRoutes(); @@ -78,13 +80,19 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { }); if (alerting) { - registerTransformHealthRuleType({ alerting, logger: this.logger }); + registerTransformHealthRuleType({ + alerting, + logger: this.logger, + getFieldFormatsStart: () => this.fieldFormatsStart!, + }); } return {}; } - start(core: CoreStart, plugins: PluginStartDependencies) {} + start(core: CoreStart, plugins: PluginStartDependencies) { + this.fieldFormatsStart = plugins.fieldFormats; + } stop() {} } diff --git a/x-pack/plugins/transform/server/routes/api/transforms.ts b/x-pack/plugins/transform/server/routes/api/transforms.ts index 580f0f54aabf7..36db7b9a03e3a 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms.ts @@ -97,10 +97,10 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) { const alerting = await ctx.alerting; if (alerting) { - const transformHealthService = transformHealthServiceProvider( - esClient.asCurrentUser, - alerting.getRulesClient() - ); + const transformHealthService = transformHealthServiceProvider({ + esClient: esClient.asCurrentUser, + rulesClient: alerting.getRulesClient(), + }); // @ts-ignore await transformHealthService.populateTransformsWithAssignedRules(body.transforms); diff --git a/x-pack/plugins/transform/server/types.ts b/x-pack/plugins/transform/server/types.ts index 26bdf02acb5c0..3a748314521a7 100644 --- a/x-pack/plugins/transform/server/types.ts +++ b/x-pack/plugins/transform/server/types.ts @@ -10,16 +10,19 @@ import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugi import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { AlertingPlugin } from '@kbn/alerting-plugin/server'; +import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import { License } from './services'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; features: FeaturesPluginSetup; alerting?: AlertingPlugin['setup']; + fieldFormats: FieldFormatsSetup; } export interface PluginStartDependencies { dataViews: DataViewsServerPluginStart; + fieldFormats: FieldFormatsStart; } export interface RouteDependencies {