[ML] Add telemetry for Anomaly detection alert rules (#97727)

* [ML] register usage collection

* [ML] fix telemetry

* [ML] fix definition schema for collector

* [ML] get kibana config synchronously
This commit is contained in:
Dima Arnautov 2021-04-21 13:34:15 +02:00 committed by GitHub
parent f1747733f5
commit 7405a22cf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 155 additions and 1 deletions

View file

@ -28,7 +28,8 @@
"management",
"licenseManagement",
"maps",
"lens"
"lens",
"usageCollection"
],
"server": true,
"ui": true,

View file

@ -16,6 +16,7 @@ import {
CapabilitiesStart,
IClusterClient,
SavedObjectsServiceStart,
SharedGlobalConfig,
} from 'kibana/server';
import type { SecurityPluginSetup } from '../../security/server';
import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server';
@ -59,6 +60,7 @@ import { RouteGuard } from './lib/route_guard';
import { registerMlAlerts } from './lib/alerts/register_ml_alerts';
import { ML_ALERT_TYPES } from '../common/constants/alerts';
import { alertingRoutes } from './routes/alerting';
import { registerCollector } from './usage';
export type MlPluginSetup = SharedServices;
export type MlPluginStart = void;
@ -74,11 +76,14 @@ export class MlServerPlugin
private security: SecurityPluginSetup | undefined;
private isMlReady: Promise<void>;
private setMlReady: () => void = () => {};
private readonly kibanaIndexConfig: SharedGlobalConfig;
constructor(ctx: PluginInitializerContext) {
this.log = ctx.logger.get();
this.mlLicense = new MlLicense();
this.isMlReady = new Promise((resolve) => (this.setMlReady = resolve));
this.kibanaIndexConfig = ctx.config.legacy.get();
}
public setup(coreSetup: CoreSetup<PluginsStart>, plugins: PluginsSetup): MlPluginSetup {
@ -212,6 +217,10 @@ export class MlServerPlugin
});
}
if (plugins.usageCollection) {
registerCollector(plugins.usageCollection, this.kibanaIndexConfig.kibana.index);
}
return { ...sharedServices };
}

View file

@ -17,6 +17,7 @@ import type { ResolveMlCapabilities } from '../common/types/capabilities';
import type { RouteGuard } from './lib/route_guard';
import type { AlertingPlugin } from '../../alerting/server';
import type { ActionsPlugin } from '../../actions/server';
import type { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server';
export interface LicenseCheckResult {
isAvailable: boolean;
@ -47,6 +48,7 @@ export interface PluginsSetup {
spaces?: SpacesPluginSetup;
alerting?: AlertingPlugin['setup'];
actions?: ActionsPlugin['setup'];
usageCollection?: UsageCollectionSetup;
}
export interface PluginsStart {

View file

@ -0,0 +1,100 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/server';
import { ML_ALERT_TYPES } from '../../common/constants/alerts';
import { AnomalyResultType } from '../../common/types/anomalies';
export interface MlUsageData {
alertRules: {
'xpack.ml.anomaly_detection_alert': {
count_by_result_type: {
record: number;
bucket: number;
influencer: number;
};
};
};
}
export function registerCollector(usageCollection: UsageCollectionSetup, kibanaIndex: string) {
const collector = usageCollection.makeUsageCollector<MlUsageData>({
type: 'ml',
schema: {
alertRules: {
'xpack.ml.anomaly_detection_alert': {
count_by_result_type: {
record: {
type: 'long',
_meta: { description: 'total number of alerting rules using record result type' },
},
influencer: {
type: 'long',
_meta: { description: 'total number of alerting rules using influencer result type' },
},
bucket: {
type: 'long',
_meta: { description: 'total number of alerting rules using bucket result type' },
},
},
},
},
},
isReady: () => !!kibanaIndex,
fetch: async ({ esClient }) => {
const result = await esClient.search({
index: kibanaIndex,
size: 0,
body: {
query: {
bool: {
filter: [
{ term: { type: 'alert' } },
{
term: {
'alert.alertTypeId': ML_ALERT_TYPES.ANOMALY_DETECTION,
},
},
],
},
},
aggs: {
count_by_result_type: {
terms: {
field: 'alert.params.resultType',
size: 3,
},
},
},
},
});
const aggResponse = result.body.aggregations as {
count_by_result_type: {
buckets: Array<{
key: AnomalyResultType;
doc_count: number;
}>;
};
};
const countByResultType = aggResponse.count_by_result_type.buckets.reduce((acc, curr) => {
acc[curr.key] = curr.doc_count;
return acc;
}, {} as MlUsageData['alertRules'][typeof ML_ALERT_TYPES.ANOMALY_DETECTION]['count_by_result_type']);
return {
alertRules: {
[ML_ALERT_TYPES.ANOMALY_DETECTION]: {
count_by_result_type: countByResultType,
},
},
};
},
});
usageCollection.registerCollector(collector);
}

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { registerCollector } from './collector';

View file

@ -3430,6 +3430,40 @@
}
}
},
"ml": {
"properties": {
"alertRules": {
"properties": {
"xpack.ml.anomaly_detection_alert": {
"properties": {
"count_by_result_type": {
"properties": {
"record": {
"type": "long",
"_meta": {
"description": "total number of alerting rules using record result type"
}
},
"influencer": {
"type": "long",
"_meta": {
"description": "total number of alerting rules using influencer result type"
}
},
"bucket": {
"type": "long",
"_meta": {
"description": "total number of alerting rules using bucket result type"
}
}
}
}
}
}
}
}
}
},
"kibana_settings": {
"properties": {
"xpack": {