diff --git a/package.json b/package.json index e2c19700b73e7..d96dab6423a87 100644 --- a/package.json +++ b/package.json @@ -266,7 +266,7 @@ "@mapbox/vector-tile": "1.3.1", "@opentelemetry/api-metrics": "0.29.2", "@opentelemetry/exporter-metrics-otlp-grpc": "^0.29.2", - "@opentelemetry/exporter-prometheus": "^0.29.2", + "@opentelemetry/exporter-prometheus": "^0.30.0", "@opentelemetry/resources": "^1.3.1", "@opentelemetry/sdk-metrics-base": "^0.29.2", "@opentelemetry/semantic-conventions": "^1.3.1", diff --git a/x-pack/plugins/alerting/server/monitoring/index.ts b/x-pack/plugins/alerting/server/monitoring/index.ts index 3040758f6a4d7..5f298456554f0 100644 --- a/x-pack/plugins/alerting/server/monitoring/index.ts +++ b/x-pack/plugins/alerting/server/monitoring/index.ts @@ -8,4 +8,3 @@ export { registerNodeCollector } from './register_node_collector'; export { registerClusterCollector } from './register_cluster_collector'; export * from './types'; export * from './in_memory_metrics'; -export * from './metrics'; diff --git a/x-pack/plugins/alerting/server/monitoring/metrics.ts b/x-pack/plugins/alerting/server/monitoring/metrics.ts deleted file mode 100644 index b13fefa65b5c6..0000000000000 --- a/x-pack/plugins/alerting/server/monitoring/metrics.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Counter, Histogram, Meter } from '@opentelemetry/api-metrics'; - -export class Metrics { - ruleExecutionsTotal: Counter; - ruleExecutions: Counter; - ruleFailures: Counter; - ruleDuration: Histogram; - - constructor(meter: Meter) { - this.ruleExecutionsTotal = meter.createCounter('ruleExecutionsTotal'); - this.ruleExecutions = meter.createCounter('ruleExecutions'); - this.ruleFailures = meter.createCounter('ruleFailures'); - this.ruleDuration = meter.createHistogram('ruleDuration'); - } -} diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 3fe87ddae3344..83d9c4f99ded8 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -49,7 +49,6 @@ import { import { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; import { PluginStart as DataPluginStart } from '@kbn/data-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; -import { metrics } from '@opentelemetry/api-metrics'; import { RuleTypeRegistry } from './rule_type_registry'; import { TaskRunnerFactory } from './task_runner'; import { RulesClientFactory } from './rules_client_factory'; @@ -78,12 +77,7 @@ import { getHealth } from './health/get_health'; import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory'; import { AlertingAuthorization } from './authorization'; import { getSecurityHealth, SecurityHealth } from './lib/get_security_health'; -import { - registerNodeCollector, - registerClusterCollector, - InMemoryMetrics, - Metrics, -} from './monitoring'; +import { registerNodeCollector, registerClusterCollector, InMemoryMetrics } from './monitoring'; import { getRuleTaskTimeout } from './lib/get_rule_task_timeout'; import { getActionsConfigMap } from './lib/get_actions_config_map'; @@ -179,7 +173,6 @@ export class AlertingPlugin { private kibanaBaseUrl: string | undefined; private usageCounter: UsageCounter | undefined; private inMemoryMetrics: InMemoryMetrics; - private metrics: Metrics; constructor(initializerContext: PluginInitializerContext) { this.config = initializerContext.config.get(); @@ -190,7 +183,6 @@ export class AlertingPlugin { this.telemetryLogger = initializerContext.logger.get('usage'); this.kibanaVersion = initializerContext.env.packageInfo.version; this.inMemoryMetrics = new InMemoryMetrics(initializerContext.logger.get('in_memory_metrics')); - this.metrics = new Metrics(metrics.getMeter('kibana.alerting')); } public setup( @@ -235,7 +227,6 @@ export class AlertingPlugin { licensing: plugins.licensing, minimumScheduleInterval: this.config.rules.minimumScheduleInterval, inMemoryMetrics: this.inMemoryMetrics, - metrics: this.metrics, }); this.ruleTypeRegistry = ruleTypeRegistry; diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index daf8bd69332cc..ed52ebf8b04da 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -14,7 +14,6 @@ import { licenseStateMock } from './lib/license_state.mock'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { inMemoryMetricsMock } from './monitoring/in_memory_metrics.mock'; -import { metricsMock } from './monitoring/metrics.mock'; const logger = loggingSystemMock.create().get(); let mockedLicenseState: jest.Mocked; @@ -22,7 +21,6 @@ let ruleTypeRegistryParams: ConstructorOptions; const taskManager = taskManagerMock.createSetup(); const inMemoryMetrics = inMemoryMetricsMock.create(); -const metrics = metricsMock.create(); beforeEach(() => { jest.resetAllMocks(); @@ -35,7 +33,6 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, - metrics, }; }); diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index f6a164b423727..338450746781b 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -31,7 +31,7 @@ import { } from '../common'; import { ILicenseState } from './lib/license_state'; import { getRuleTypeFeatureUsageName } from './lib/get_rule_type_feature_usage_name'; -import { InMemoryMetrics, Metrics } from './monitoring'; +import { InMemoryMetrics } from './monitoring'; import { AlertingRulesConfig } from '.'; export interface ConstructorOptions { @@ -42,7 +42,6 @@ export interface ConstructorOptions { licensing: LicensingPluginSetup; minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval']; inMemoryMetrics: InMemoryMetrics; - metrics: Metrics; } export interface RegistryRuleType @@ -140,7 +139,6 @@ export class RuleTypeRegistry { private readonly minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval']; private readonly licensing: LicensingPluginSetup; private readonly inMemoryMetrics: InMemoryMetrics; - private readonly metrics: Metrics; constructor({ logger, @@ -150,7 +148,6 @@ export class RuleTypeRegistry { licensing, minimumScheduleInterval, inMemoryMetrics, - metrics, }: ConstructorOptions) { this.logger = logger; this.taskManager = taskManager; @@ -159,7 +156,6 @@ export class RuleTypeRegistry { this.licensing = licensing; this.minimumScheduleInterval = minimumScheduleInterval; this.inMemoryMetrics = inMemoryMetrics; - this.metrics = metrics; } public has(id: string) { @@ -278,7 +274,7 @@ export class RuleTypeRegistry { InstanceContext, ActionGroupIds, RecoveryActionGroupId | RecoveredActionGroupId - >(normalizedRuleType, context, this.inMemoryMetrics, this.metrics), + >(normalizedRuleType, context, this.inMemoryMetrics), }, }); // No need to notify usage on basic alert types diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts index 81992e1a50510..0f2677dc49751 100644 --- a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -15,14 +15,12 @@ import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { isRuleExportable } from './is_rule_exportable'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { metricsMock } from '../monitoring/metrics.mock'; let ruleTypeRegistryParams: ConstructorOptions; let logger: MockedLogger; let mockedLicenseState: jest.Mocked; const taskManager = taskManagerMock.createSetup(); const inMemoryMetrics = inMemoryMetricsMock.create(); -const metrics = metricsMock.create(); beforeEach(() => { jest.resetAllMocks(); @@ -36,7 +34,6 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, - metrics, }; }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index d142cc385d035..5d2f6d7c1f659 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -43,7 +43,6 @@ import { omit } from 'lodash'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { ExecuteOptions } from '@kbn/actions-plugin/server/create_execute_function'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; -import { metricsMock } from '../monitoring/metrics.mock'; import moment from 'moment'; import { generateAlertOpts, @@ -124,7 +123,6 @@ describe('Task Runner', () => { const dataPlugin = dataPluginMock.createStartContract(); const uiSettingsService = uiSettingsServiceMock.createStartContract(); const inMemoryMetrics = inMemoryMetricsMock.create(); - const metrics = metricsMock.create(); type TaskRunnerFactoryInitializerParamsType = jest.Mocked & { actionsPlugin: jest.Mocked; @@ -222,8 +220,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -324,8 +321,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -406,8 +402,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -528,8 +523,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -582,8 +576,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -662,8 +655,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -707,8 +699,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -765,8 +756,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -834,8 +824,7 @@ describe('Task Runner', () => { }, }, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -916,8 +905,7 @@ describe('Task Runner', () => { }, }, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -982,8 +970,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1095,8 +1082,7 @@ describe('Task Runner', () => { }, }, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1208,8 +1194,7 @@ describe('Task Runner', () => { }, }, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1300,8 +1285,7 @@ describe('Task Runner', () => { }, }, customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1392,8 +1376,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1456,8 +1439,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1480,8 +1462,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1511,8 +1492,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1544,8 +1524,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1582,8 +1561,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1618,8 +1596,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1648,8 +1625,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1678,8 +1654,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1709,8 +1684,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1743,8 +1717,7 @@ describe('Task Runner', () => { ruleType, legacyTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1782,8 +1755,7 @@ describe('Task Runner', () => { state: originalAlertSate, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1813,8 +1785,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1846,8 +1817,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1871,8 +1841,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1898,8 +1867,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -1948,8 +1916,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2055,8 +2022,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2130,8 +2096,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2200,8 +2165,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2275,8 +2239,7 @@ describe('Task Runner', () => { }, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2328,8 +2291,7 @@ describe('Task Runner', () => { ...taskRunnerFactoryInitializerParams, supportsEphemeralTasks: true, }, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2400,8 +2362,7 @@ describe('Task Runner', () => { state, }, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2430,8 +2391,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2446,8 +2406,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2475,8 +2434,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2511,8 +2469,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2597,8 +2554,7 @@ describe('Task Runner', () => { ...taskRunnerFactoryInitializerParams, actionsConfigMap, }, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2750,8 +2706,7 @@ describe('Task Runner', () => { ...taskRunnerFactoryInitializerParams, actionsConfigMap, }, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); @@ -2821,8 +2776,7 @@ describe('Task Runner', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalled(); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 6a87822940a9f..5f7e1299f7698 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -55,7 +55,7 @@ import { } from '../../common'; import { NormalizedRuleType, UntypedNormalizedRuleType } from '../rule_type_registry'; import { getEsErrorMessage } from '../lib/errors'; -import { InMemoryMetrics, IN_MEMORY_METRICS, Metrics } from '../monitoring'; +import { InMemoryMetrics, IN_MEMORY_METRICS } from '../monitoring'; import { GenerateNewAndRecoveredAlertEventsParams, LogActiveAndRecoveredAlertsParams, @@ -111,7 +111,6 @@ export class TaskRunner< private readonly executionId: string; private readonly ruleTypeRegistry: RuleTypeRegistry; private readonly inMemoryMetrics: InMemoryMetrics; - private readonly metrics: Metrics; private alertingEventLogger: AlertingEventLogger; private usageCounter?: UsageCounter; private searchAbortController: AbortController; @@ -129,8 +128,7 @@ export class TaskRunner< >, taskInstance: ConcreteTaskInstance, context: TaskRunnerContext, - inMemoryMetrics: InMemoryMetrics, - metrics: Metrics + inMemoryMetrics: InMemoryMetrics ) { this.context = context; this.logger = context.logger; @@ -143,7 +141,6 @@ export class TaskRunner< this.cancelled = false; this.executionId = uuid.v4(); this.inMemoryMetrics = inMemoryMetrics; - this.metrics = metrics; this.alertingEventLogger = new AlertingEventLogger(this.context.eventLogger); } @@ -679,7 +676,6 @@ export class TaskRunner< if (null != duration) { executionStatus.lastDuration = nanosToMillis(duration); monitoringHistory.duration = executionStatus.lastDuration; - this.metrics.ruleDuration.record(executionStatus.lastDuration); } // if executionStatus indicates an error, fill in fields in @@ -696,12 +692,8 @@ export class TaskRunner< if (!this.cancelled) { this.inMemoryMetrics.increment(IN_MEMORY_METRICS.RULE_EXECUTIONS); - // NOTE: Using the typesafe opentelemetry counter here directly - this.metrics.ruleExecutionsTotal.add(1); - this.metrics.ruleExecutions.add(1, { ruleType: this.ruleType.id }); if (executionStatus.error) { this.inMemoryMetrics.increment(IN_MEMORY_METRICS.RULE_FAILURES); - this.metrics.ruleFailures.add(1); } this.logger.debug( `Updating rule task for ${this.ruleType.id} rule with id ${ruleId} - ${JSON.stringify( diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index f2d4578689f32..fb2d1be3a3872 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -35,7 +35,6 @@ import { IEventLogger } from '@kbn/event-log-plugin/server'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; -import { metricsMock } from '../monitoring/metrics.mock'; import { AlertingEventLogger, RuleContextOpts, @@ -96,7 +95,6 @@ describe('Task Runner Cancel', () => { const uiSettingsService = uiSettingsServiceMock.createStartContract(); const dataPlugin = dataPluginMock.createStartContract(); const inMemoryMetrics = inMemoryMetricsMock.create(); - const metrics = metricsMock.create(); type TaskRunnerFactoryInitializerParamsType = jest.Mocked & { actionsPlugin: jest.Mocked; @@ -178,8 +176,7 @@ describe('Task Runner Cancel', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -247,8 +244,7 @@ describe('Task Runner Cancel', () => { ...taskRunnerFactoryInitializerParams, cancelAlertsOnRuleTimeout: false, }, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -312,8 +308,7 @@ describe('Task Runner Cancel', () => { updatedRuleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); @@ -373,8 +368,7 @@ describe('Task Runner Cancel', () => { ruleType, mockedTaskInstance, taskRunnerFactoryInitializerParams, - inMemoryMetrics, - metrics + inMemoryMetrics ); expect(AlertingEventLogger).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index ea6c1a0c63d81..e787617800356 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -26,10 +26,8 @@ import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { executionContextServiceMock } from '@kbn/core/server/mocks'; import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; -import { metricsMock } from '../monitoring/metrics.mock'; const inMemoryMetrics = inMemoryMetricsMock.create(); -const metrics = metricsMock.create(); const executionContext = executionContextServiceMock.createSetupContract(); const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); @@ -117,7 +115,7 @@ describe('Task Runner Factory', () => { test(`throws an error if factory isn't initialized`, () => { const factory = new TaskRunnerFactory(); expect(() => - factory.create(ruleType, { taskInstance: mockedTaskInstance }, inMemoryMetrics, metrics) + factory.create(ruleType, { taskInstance: mockedTaskInstance }, inMemoryMetrics) ).toThrowErrorMatchingInlineSnapshot(`"TaskRunnerFactory not initialized"`); }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts index 8fae29b098345..09fe8cb030c40 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts @@ -32,7 +32,7 @@ import { } from '../types'; import { TaskRunner } from './task_runner'; import { NormalizedRuleType } from '../rule_type_registry'; -import { InMemoryMetrics, Metrics } from '../monitoring'; +import { InMemoryMetrics } from '../monitoring'; import { ActionsConfigMap } from '../lib/get_actions_config_map'; export interface TaskRunnerContext { @@ -89,8 +89,7 @@ export class TaskRunnerFactory { RecoveryActionGroupId >, { taskInstance }: RunContext, - inMemoryMetrics: InMemoryMetrics, - metrics: Metrics + inMemoryMetrics: InMemoryMetrics ) { if (!this.isInitialized) { throw new Error('TaskRunnerFactory not initialized'); @@ -104,6 +103,6 @@ export class TaskRunnerFactory { InstanceContext, ActionGroupIds, RecoveryActionGroupId - >(ruleType, taskInstance, this.taskRunnerContext!, inMemoryMetrics, metrics); + >(ruleType, taskInstance, this.taskRunnerContext!, inMemoryMetrics); } } diff --git a/x-pack/plugins/monitoring_collection/README.md b/x-pack/plugins/monitoring_collection/README.md index 1f2d2984af886..cdd12b0701f77 100644 --- a/x-pack/plugins/monitoring_collection/README.md +++ b/x-pack/plugins/monitoring_collection/README.md @@ -2,4 +2,45 @@ ## Plugin -This plugin allows for other plugins to add data to Kibana stack monitoring documents. \ No newline at end of file +This plugin allows for other plugins to add data to Kibana stack monitoring documents. + +## OpenTelemetry Metrics + +TODO: explain how to instrument the code with `@opentelemetry/api-metrics` so that the steps below will work with metrics + +### Enable Prometheus endpoint with Elastic Agent Prometheus input + +1. Start [local setup with fleet](../fleet/README.md#running-fleet-server-locally-in-a-container) or a cloud cluster +2. Start Kibana +3. Set up a new agent policy and enroll a new agent in your local machine +4. Install the Prometheus Metrics package + a. Set **Hosts** with `localhost:5601` + b. Set **Metrics Path** with `/(BASEPATH)/api/monitoring_collection/v1/prometheus` + c. Remove the values from **Bearer Token File** and **SSL Certificate Authorities** + d. Set **Username** and **Password** with `elastic` and `changeme` +5. Add the following configuration to `kibana.dev.yml` + + ```yml + # Enable the prometheus exporter + monitoring_collection.opentelemetry.metrics: + prometheus.enabled: true + + ``` + +6. Set up a rule (I use "Create default rules" in the top "Alerts and rules" menu of Stack Monitoring UI) + +### Enable OpenTelemetry Metrics API exported as OpenTelemetry Protocol + +1. Start [local setup with fleet](../fleet/README.md#running-fleet-server-locally-in-a-container) or a cloud cluster +2. Start Kibana +3. Set up a new agent policy and enroll a new agent in your local machine +4. Install Elastic APM package listening on `localhost:8200` without authentication +5. Add the following configuration to `kibana.dev.yml` + + ```yml + # Enable the OTLP exporter + monitoring_collection.opentelemetry.metrics: + otlp.url: "http://127.0.0.1:8200" + ``` + +6. Set up a rule (I use "Create default rules" in the top "Alerts and rules" menu of Stack Monitoring UI) diff --git a/x-pack/plugins/monitoring_collection/server/constants.ts b/x-pack/plugins/monitoring_collection/server/constants.ts index 4a698aa26f29b..92b43a9d80e48 100644 --- a/x-pack/plugins/monitoring_collection/server/constants.ts +++ b/x-pack/plugins/monitoring_collection/server/constants.ts @@ -6,4 +6,4 @@ */ export const TYPE_ALLOWLIST = ['node_rules', 'cluster_rules', 'node_actions', 'cluster_actions']; -export const PROMETHEUS_ROUTE = '/api/monitoring_collection/v1/prometheus'; +export const MONITORING_COLLECTION_BASE_PATH = '/api/monitoring_collection'; diff --git a/x-pack/plugins/monitoring_collection/server/lib/index.ts b/x-pack/plugins/monitoring_collection/server/lib/index.ts index 0c39a62ab359c..34c1fce763bdc 100644 --- a/x-pack/plugins/monitoring_collection/server/lib/index.ts +++ b/x-pack/plugins/monitoring_collection/server/lib/index.ts @@ -7,3 +7,4 @@ export { getKibanaStats } from './get_kibana_stats'; export { getESClusterUuid } from './get_es_cluster_uuid'; +export { PrometheusExporter } from './prometheus_exporter'; diff --git a/x-pack/plugins/monitoring_collection/server/lib/prometheus_exporter.ts b/x-pack/plugins/monitoring_collection/server/lib/prometheus_exporter.ts index d4b21fbd9641f..f1d2d1ffd4fb3 100644 --- a/x-pack/plugins/monitoring_collection/server/lib/prometheus_exporter.ts +++ b/x-pack/plugins/monitoring_collection/server/lib/prometheus_exporter.ts @@ -5,21 +5,20 @@ * 2.0. */ -// Adapted from https://github.com/open-telemetry/opentelemetry-js/blob/aabc5f6b89e3d9af6640fb854967212ca5b1a3b8/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts - import { AggregationTemporality, MetricReader } from '@opentelemetry/sdk-metrics-base'; -import { PrometheusExporter as OpenTelemetryPrometheusExporter } from '@opentelemetry/exporter-prometheus'; -import { ExporterConfig } from '@opentelemetry/exporter-prometheus'; +import { + PrometheusExporter as OpenTelemetryPrometheusExporter, + ExporterConfig, + PrometheusSerializer, +} from '@opentelemetry/exporter-prometheus'; import { KibanaResponseFactory } from '@kbn/core/server'; -import { Logger } from '@kbn/core/server'; -import { PrometheusSerializer } from './prometheus_serializer'; export class PrometheusExporter extends MetricReader { private readonly _prefix?: string; private readonly _appendTimestamp: boolean; private _serializer: PrometheusSerializer; - constructor(logger: Logger, config: ExporterConfig = {}) { + constructor(config: ExporterConfig = {}) { super(); this._prefix = config.prefix || OpenTelemetryPrometheusExporter.DEFAULT_OPTIONS.prefix; this._appendTimestamp = @@ -27,7 +26,7 @@ export class PrometheusExporter extends MetricReader { ? config.appendTimestamp : OpenTelemetryPrometheusExporter.DEFAULT_OPTIONS.appendTimestamp; - this._serializer = new PrometheusSerializer(logger, this._prefix, this._appendTimestamp); + this._serializer = new PrometheusSerializer(this._prefix, this._appendTimestamp); } selectAggregationTemporality(): AggregationTemporality { @@ -45,31 +44,30 @@ export class PrometheusExporter extends MetricReader { /** * Responds to incoming message with current state of all metrics. */ - public exportMetrics(res: KibanaResponseFactory) { - // TODO: How can I type this return without requiring (forbidden path) KibanaReponse? - return this.collect().then( - (collectionResult) => { - const { resourceMetrics, errors } = collectionResult; - if (errors.length) { - return res.customError({ - statusCode: 500, - body: `PrometheusExporter: metrics collection errors ${errors}`, - }); - } - const result = this._serializer.serialize(resourceMetrics); - if (result === '') { - return res.noContent(); - } - return res.ok({ - body: result, - }); - }, - (err) => { + public async exportMetrics(res: KibanaResponseFactory) { + try { + const collectionResult = await this.collect(); + const { resourceMetrics, errors } = collectionResult; + if (errors.length) { return res.customError({ statusCode: 500, - body: `# Failed to export metrics ${err}`, + body: `PrometheusExporter: Metrics collection errors ${errors}`, }); } - ); + const result = this._serializer.serialize(resourceMetrics); + if (result === '') { + return res.noContent(); + } + return res.ok({ + body: result, + }); + } catch (error) { + return res.customError({ + statusCode: 500, + body: { + message: `PrometheusExporter: Failed to export metrics ${error}`, + }, + }); + } } } diff --git a/x-pack/plugins/monitoring_collection/server/lib/prometheus_serializer.ts b/x-pack/plugins/monitoring_collection/server/lib/prometheus_serializer.ts deleted file mode 100644 index d036a31673700..0000000000000 --- a/x-pack/plugins/monitoring_collection/server/lib/prometheus_serializer.ts +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// From https://github.com/open-telemetry/opentelemetry-js/blob/97bc6321c0fe4da7414afb83038279b735a5ba65/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusSerializer.ts -// Can be removed once https://github.com/open-telemetry/opentelemetry-js/issues/3033 is merged/released - -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Logger } from '@kbn/core/server'; -import { - ResourceMetrics, - InstrumentType, - DataPointType, - ScopeMetrics, - MetricData, - DataPoint, - Histogram, -} from '@opentelemetry/sdk-metrics-base'; -import type { MetricAttributes } from '@opentelemetry/api-metrics'; - -// From https://github.com/open-telemetry/opentelemetry-js/blob/28c9e8829488a7fa131803447b0511195ae1fdf0/packages/opentelemetry-core/src/common/time.ts#L148 -export function hrTimeToMilliseconds(time: [number, number]): number { - return Math.round(time[0] * 1e3 + time[1] / 1e6); -} - -type PrometheusDataTypeLiteral = 'counter' | 'gauge' | 'histogram' | 'summary' | 'untyped'; - -function escapeString(str: string) { - return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n'); -} - -function escapeAttributeValue(str: string) { - if (typeof str !== 'string') { - str = String(str); - } - return escapeString(str).replace(/"/g, '\\"'); -} - -const invalidCharacterRegex = /[^a-z0-9_]/gi; -/** - * Ensures metric names are valid Prometheus metric names by removing - * characters allowed by OpenTelemetry but disallowed by Prometheus. - * - * https://prometheus.io/docs/concepts/data_model/#metric-names-and-attributes - * - * 1. Names must match `[a-zA-Z_:][a-zA-Z0-9_:]*` - * - * 2. Colons are reserved for user defined recording rules. - * They should not be used by exporters or direct instrumentation. - * - * OpenTelemetry metric names are already validated in the Meter when they are created, - * and they match the format `[a-zA-Z][a-zA-Z0-9_.\-]*` which is very close to a valid - * prometheus metric name, so we only need to strip characters valid in OpenTelemetry - * but not valid in prometheus and replace them with '_'. - * - * @param name name to be sanitized - */ -function sanitizePrometheusMetricName(name: string): string { - return name.replace(invalidCharacterRegex, '_'); // replace all invalid characters with '_' -} - -/** - * @private - * - * Helper method which assists in enforcing the naming conventions for metric - * names in Prometheus - * @param name the name of the metric - * @param type the kind of metric - * @returns string - */ -function enforcePrometheusNamingConvention(name: string, type: InstrumentType): string { - // Prometheus requires that metrics of the Counter kind have "_total" suffix - if (!name.endsWith('_total') && type === InstrumentType.COUNTER) { - name = name + '_total'; - } - - return name; -} - -function valueString(value: number) { - if (Number.isNaN(value)) { - return 'Nan'; - } else if (!Number.isFinite(value)) { - if (value < 0) { - return '-Inf'; - } else { - return '+Inf'; - } - } else { - return `${value}`; - } -} - -function toPrometheusType( - instrumentType: InstrumentType, - dataPointType: DataPointType -): PrometheusDataTypeLiteral { - switch (dataPointType) { - case DataPointType.SINGULAR: - if ( - instrumentType === InstrumentType.COUNTER || - instrumentType === InstrumentType.OBSERVABLE_COUNTER - ) { - return 'counter'; - } - /** - * - HISTOGRAM - * - UP_DOWN_COUNTER - * - OBSERVABLE_GAUGE - * - OBSERVABLE_UP_DOWN_COUNTER - */ - return 'gauge'; - case DataPointType.HISTOGRAM: - return 'histogram'; - default: - return 'untyped'; - } -} - -function stringify( - metricName: string, - attributes: MetricAttributes, - value: number, - timestamp?: number, - additionalAttributes?: MetricAttributes -) { - let hasAttribute = false; - let attributesStr = ''; - - for (const [key, val] of Object.entries(attributes)) { - const sanitizedAttributeName = sanitizePrometheusMetricName(key); - hasAttribute = true; - attributesStr += `${ - attributesStr.length > 0 ? ',' : '' - }${sanitizedAttributeName}="${escapeAttributeValue(val)}"`; - } - if (additionalAttributes) { - for (const [key, val] of Object.entries(additionalAttributes)) { - const sanitizedAttributeName = sanitizePrometheusMetricName(key); - hasAttribute = true; - attributesStr += `${ - attributesStr.length > 0 ? ',' : '' - }${sanitizedAttributeName}="${escapeAttributeValue(val)}"`; - } - } - - if (hasAttribute) { - metricName += `{${attributesStr}}`; - } - - return `${metricName} ${valueString(value)}${ - timestamp !== undefined ? ' ' + String(timestamp) : '' - }\n`; -} - -export class PrometheusSerializer { - private logger: Logger; - private _prefix: string | undefined; - private _appendTimestamp: boolean; - - constructor(logger: Logger, prefix?: string, appendTimestamp = true) { - if (prefix) { - this._prefix = prefix + '_'; - } - this._appendTimestamp = appendTimestamp; - this.logger = logger; - } - - serialize(resourceMetrics: ResourceMetrics): string { - let str = ''; - for (const scopeMetrics of resourceMetrics.scopeMetrics) { - str += this.serializeScopeMetrics(scopeMetrics); - } - return str; - } - - serializeScopeMetrics(scopeMetrics: ScopeMetrics) { - let str = ''; - for (const metric of scopeMetrics.metrics) { - str += this.serializeMetricData(metric) + '\n'; - } - return str; - } - - serializeMetricData(metricData: MetricData) { - let name = sanitizePrometheusMetricName(escapeString(metricData.descriptor.name)); - if (this._prefix) { - name = `${this._prefix}${name}`; - } - const dataPointType = metricData.dataPointType; - - name = enforcePrometheusNamingConvention(name, metricData.descriptor.type); - - const help = `# HELP ${name} ${escapeString( - metricData.descriptor.description || 'description missing' - )}`; - const type = `# TYPE ${name} ${toPrometheusType(metricData.descriptor.type, dataPointType)}`; - - let results = ''; - switch (dataPointType) { - case DataPointType.SINGULAR: { - results = metricData.dataPoints - .map((it) => this.serializeSingularDataPoint(name, metricData.descriptor.type, it)) - .join(''); - break; - } - case DataPointType.HISTOGRAM: { - results = metricData.dataPoints - .map((it) => this.serializeHistogramDataPoint(name, metricData.descriptor.type, it)) - .join(''); - break; - } - default: { - this.logger.error(`Unrecognizable DataPointType: ${dataPointType} for metric "${name}"`); - } - } - - return `${help}\n${type}\n${results}`.trim(); - } - - serializeSingularDataPoint( - name: string, - type: InstrumentType, - dataPoint: DataPoint - ): string { - let results = ''; - - name = enforcePrometheusNamingConvention(name, type); - const { value, attributes } = dataPoint; - const timestamp = hrTimeToMilliseconds(dataPoint.endTime); - results += stringify( - name, - attributes, - value, - this._appendTimestamp ? timestamp : undefined, - undefined - ); - return results; - } - - serializeHistogramDataPoint( - name: string, - type: InstrumentType, - dataPoint: DataPoint - ): string { - let results = ''; - - name = enforcePrometheusNamingConvention(name, type); - const { value, attributes } = dataPoint; - const timestamp = hrTimeToMilliseconds(dataPoint.endTime); - /** Histogram["bucket"] is not typed with `number` */ - for (const key of ['count', 'sum'] as Array<'count' | 'sum'>) { - results += stringify( - name + '_' + key, - attributes, - value[key], - this._appendTimestamp ? timestamp : undefined, - undefined - ); - } - - let cumulativeSum = 0; - const countEntries = value.buckets.counts.entries(); - let infiniteBoundaryDefined = false; - for (const [idx, val] of countEntries) { - cumulativeSum += val; - const upperBound = value.buckets.boundaries[idx]; - /** HistogramAggregator is producing different boundary output - - * in one case not including infinity values, in other - - * full, e.g. [0, 100] and [0, 100, Infinity] - * we should consider that in export, if Infinity is defined, use it - * as boundary - */ - if (upperBound === undefined && infiniteBoundaryDefined) { - break; - } - if (upperBound === Infinity) { - infiniteBoundaryDefined = true; - } - results += stringify( - name + '_bucket', - attributes, - cumulativeSum, - this._appendTimestamp ? timestamp : undefined, - { - le: upperBound === undefined || upperBound === Infinity ? '+Inf' : String(upperBound), - } - ); - } - - return results; - } -} diff --git a/x-pack/plugins/monitoring_collection/server/plugin.ts b/x-pack/plugins/monitoring_collection/server/plugin.ts index 7f42f99c5d95f..433b5a3d22e63 100644 --- a/x-pack/plugins/monitoring_collection/server/plugin.ts +++ b/x-pack/plugins/monitoring_collection/server/plugin.ts @@ -6,9 +6,14 @@ */ import { JsonObject } from '@kbn/utility-types'; -import { CoreSetup, Plugin, PluginInitializerContext, Logger } from '@kbn/core/server'; +import { + CoreSetup, + Plugin, + PluginInitializerContext, + Logger, + ServiceStatus, +} from '@kbn/core/server'; import { MakeSchemaFrom } from '@kbn/usage-collection-plugin/server'; -import { ServiceStatus } from '@kbn/core/server'; import { metrics } from '@opentelemetry/api-metrics'; import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics-base'; @@ -17,8 +22,8 @@ import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' import * as grpc from '@grpc/grpc-js'; import { PrometheusExporter } from './lib/prometheus_exporter'; import { MonitoringCollectionConfig } from './config'; -import { registerDynamicRoute, registerV1PrometheusRoute } from './routes'; -import { PROMETHEUS_ROUTE, TYPE_ALLOWLIST } from './constants'; +import { registerDynamicRoute, registerV1PrometheusRoute, PROMETHEUS_PATH } from './routes'; +import { TYPE_ALLOWLIST } from './constants'; export interface MonitoringCollectionSetup { registerMetric: (metric: Metric) => void; @@ -126,14 +131,9 @@ export class MonitoringCollectionPlugin implements Plugin { jest.resetAllMocks(); }); -jest.mock('../lib', () => ({ +jest.mock('../../../../lib', () => ({ getESClusterUuid: () => 'clusterA', getKibanaStats: () => ({ name: 'myKibana' }), })); @@ -42,7 +42,7 @@ describe('dynamic route', () => { const router = httpServiceMock.createRouter(); const getMetric = async () => { - return { foo: 1 }; + return Promise.resolve({ foo: 1 }); }; registerDynamicRoute({ router, @@ -81,7 +81,7 @@ describe('dynamic route', () => { const router = httpServiceMock.createRouter(); const getMetric = async () => { - return {}; + return Promise.resolve({}); }; registerDynamicRoute({ router, config: kibanaStatsConfig, getStatus, getMetric }); diff --git a/x-pack/plugins/monitoring_collection/server/routes/dynamic_route.ts b/x-pack/plugins/monitoring_collection/server/routes/api/v1/dynamic_route/index.ts similarity index 86% rename from x-pack/plugins/monitoring_collection/server/routes/dynamic_route.ts rename to x-pack/plugins/monitoring_collection/server/routes/api/v1/dynamic_route/index.ts index 944037dd17a7b..4d18eeb6ec922 100644 --- a/x-pack/plugins/monitoring_collection/server/routes/dynamic_route.ts +++ b/x-pack/plugins/monitoring_collection/server/routes/api/v1/dynamic_route/index.ts @@ -7,8 +7,9 @@ import { JsonObject } from '@kbn/utility-types'; import { schema } from '@kbn/config-schema'; import { IRouter, ServiceStatus } from '@kbn/core/server'; -import { getESClusterUuid, getKibanaStats } from '../lib'; -import { MetricResult } from '../plugin'; +import { getESClusterUuid, getKibanaStats } from '../../../../lib'; +import { MetricResult } from '../../../../plugin'; +import { MONITORING_COLLECTION_BASE_PATH } from '../../../../constants'; export function registerDynamicRoute({ router, @@ -34,7 +35,7 @@ export function registerDynamicRoute({ }) { router.get( { - path: `/api/monitoring_collection/{type}`, + path: `${MONITORING_COLLECTION_BASE_PATH}/{type}`, options: { authRequired: true, tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page diff --git a/x-pack/plugins/alerting/server/monitoring/metrics.mock.ts b/x-pack/plugins/monitoring_collection/server/routes/api/v1/index.ts similarity index 55% rename from x-pack/plugins/alerting/server/monitoring/metrics.mock.ts rename to x-pack/plugins/monitoring_collection/server/routes/api/v1/index.ts index 129298e63e90f..e5a70f3f79abc 100644 --- a/x-pack/plugins/alerting/server/monitoring/metrics.mock.ts +++ b/x-pack/plugins/monitoring_collection/server/routes/api/v1/index.ts @@ -4,10 +4,5 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { metrics } from '@opentelemetry/api-metrics'; -import { Metrics } from './metrics'; - -export const metricsMock = { - create: () => new Metrics(metrics.getMeter('kibana.alerting.metrics.mock')), -}; +export { registerDynamicRoute } from './dynamic_route'; +export { registerV1PrometheusRoute, PROMETHEUS_PATH } from './prometheus'; diff --git a/x-pack/plugins/monitoring_collection/server/routes/prometheus.test.ts b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.test.ts similarity index 58% rename from x-pack/plugins/monitoring_collection/server/routes/prometheus.test.ts rename to x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.test.ts index ec5d6d7bb44a4..b136d982992c4 100644 --- a/x-pack/plugins/monitoring_collection/server/routes/prometheus.test.ts +++ b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.test.ts @@ -5,22 +5,25 @@ * 2.0. */ +import { RequestHandlerContext } from '@kbn/core/server'; import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks'; -import { registerV1PrometheusRoute } from './prometheus'; -import { KibanaRequest, KibanaResponseFactory } from '@kbn/core/server'; -import { PrometheusExporter } from '../lib/prometheus_exporter'; +import { registerV1PrometheusRoute } from '.'; +import { PrometheusExporter } from '../../../../lib'; -describe('prometheus route', () => { +describe('Prometheus route', () => { it('forwards the request to the prometheus exporter', async () => { const router = httpServiceMock.createRouter(); - const prometheusExporter = { exportMetrics: jest.fn() } as unknown as PrometheusExporter; + const prometheusExporter = { + exportMetrics: jest.fn(), + } as Partial as PrometheusExporter; + registerV1PrometheusRoute({ router, prometheusExporter }); const [, handler] = router.get.mock.calls[0]; - const context = {}; - const req = { params: {} } as KibanaRequest; - const factory: jest.Mocked = httpServerMock.createResponseFactory(); + const context = {} as jest.Mocked; + const req = httpServerMock.createKibanaRequest(); + const factory = httpServerMock.createResponseFactory(); await handler(context, req, factory); diff --git a/x-pack/plugins/monitoring_collection/server/routes/prometheus.ts b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.ts similarity index 72% rename from x-pack/plugins/monitoring_collection/server/routes/prometheus.ts rename to x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.ts index 40e783c3d8b46..6977be155a4fb 100644 --- a/x-pack/plugins/monitoring_collection/server/routes/prometheus.ts +++ b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/get_metrics.ts @@ -6,9 +6,10 @@ */ import { IRouter } from '@kbn/core/server'; -import { PROMETHEUS_ROUTE } from '../constants'; -import { PrometheusExporter } from '../lib/prometheus_exporter'; +import { MONITORING_COLLECTION_BASE_PATH } from '../../../../constants'; +import { PrometheusExporter } from '../../../../lib'; +export const PROMETHEUS_PATH = `${MONITORING_COLLECTION_BASE_PATH}/v1/prometheus`; export function registerV1PrometheusRoute({ router, prometheusExporter, @@ -18,14 +19,14 @@ export function registerV1PrometheusRoute({ }) { router.get( { - path: PROMETHEUS_ROUTE, + path: PROMETHEUS_PATH, options: { authRequired: true, tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page }, validate: {}, }, - async (context, req, res) => { + async (_context, _req, res) => { return prometheusExporter.exportMetrics(res); } ); diff --git a/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/index.ts b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/index.ts new file mode 100644 index 0000000000000..5b99f51c94511 --- /dev/null +++ b/x-pack/plugins/monitoring_collection/server/routes/api/v1/prometheus/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export * from './get_metrics'; diff --git a/x-pack/plugins/monitoring_collection/server/routes/index.ts b/x-pack/plugins/monitoring_collection/server/routes/index.ts index c4a116cb3f84c..29cd177990593 100644 --- a/x-pack/plugins/monitoring_collection/server/routes/index.ts +++ b/x-pack/plugins/monitoring_collection/server/routes/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export { registerDynamicRoute } from './dynamic_route'; -export { registerV1PrometheusRoute } from './prometheus'; +export { registerV1PrometheusRoute, PROMETHEUS_PATH, registerDynamicRoute } from './api/v1'; diff --git a/yarn.lock b/yarn.lock index 0b94a0b7cf9a8..916e1d03d341e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4384,6 +4384,13 @@ dependencies: "@opentelemetry/api" "^1.0.0" +"@opentelemetry/api-metrics@0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.30.0.tgz#b5defd10756e81d1c7ce8669ff8a8d2465ba0be8" + integrity sha512-jSb7iiYPY+DSUKIyzfGt0a5K1QGzWY5fSWtUB8Alfi27NhQGHBeuYYC5n9MaBP/HNWw5GpEIhXGEYCF9Pf8IEg== + dependencies: + "@opentelemetry/api" "^1.0.0" + "@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.1.0.tgz#563539048255bbe1a5f4f586a4a10a1bb737f44a" @@ -4396,6 +4403,13 @@ dependencies: "@opentelemetry/semantic-conventions" "1.3.1" +"@opentelemetry/core@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.4.0.tgz#26839ab9e36583a174273a1e1c5b33336c163725" + integrity sha512-faq50VFEdyC7ICAOlhSi+yYZ+peznnGjTJToha9R63i9fVopzpKrkZt7AIdXUmz2+L2OqXrcJs7EIdN/oDyr5w== + dependencies: + "@opentelemetry/semantic-conventions" "1.4.0" + "@opentelemetry/exporter-metrics-otlp-grpc@^0.29.2": version "0.29.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.29.2.tgz#d51352a703363237621d22793949cab4d69e1b01" @@ -4422,14 +4436,14 @@ "@opentelemetry/resources" "1.3.1" "@opentelemetry/sdk-metrics-base" "0.29.2" -"@opentelemetry/exporter-prometheus@^0.29.2": - version "0.29.2" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.29.2.tgz#70ca7fb37655ca57a580387607d5465b47e27ac3" - integrity sha512-E5sRfUM4rzbvjxdpL1H6YRtjr8wY8+/2R4NjfxPEwrENLeeQk87V1E+YFLqAS7TfFLW7Zr4lmmamunwn5THvQA== +"@opentelemetry/exporter-prometheus@^0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.30.0.tgz#f81322d3cb000170e716bc76820600d5649be538" + integrity sha512-y0SXvpzoKR+Tk/UL6F1f7vAcCzqpCDP/cTEa+Z7sX57aEG0HDXLQiLmAgK/BHqcEN5MFQMZ+MDVDsUrvpa6/Jw== dependencies: - "@opentelemetry/api-metrics" "0.29.2" - "@opentelemetry/core" "1.3.1" - "@opentelemetry/sdk-metrics-base" "0.29.2" + "@opentelemetry/api-metrics" "0.30.0" + "@opentelemetry/core" "1.4.0" + "@opentelemetry/sdk-metrics-base" "0.30.0" "@opentelemetry/otlp-exporter-base@0.29.2": version "0.29.2" @@ -4467,6 +4481,14 @@ "@opentelemetry/core" "1.3.1" "@opentelemetry/semantic-conventions" "1.3.1" +"@opentelemetry/resources@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.4.0.tgz#5e23b0d7976158861059dec17e0ee36a35a5ab85" + integrity sha512-Q3pI5+pCM+Ur7YwK9GbG89UBipwJbfmuzSPAXTw964ZHFzSrz+JAgrETC9rqsUOYdUlj/V7LbRMG5bo72xE0Xw== + dependencies: + "@opentelemetry/core" "1.4.0" + "@opentelemetry/semantic-conventions" "1.4.0" + "@opentelemetry/sdk-metrics-base@0.29.2", "@opentelemetry/sdk-metrics-base@^0.29.2": version "0.29.2" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.29.2.tgz#bd515455f1d90e211458dcf957f0ae937772b155" @@ -4477,6 +4499,16 @@ "@opentelemetry/resources" "1.3.1" lodash.merge "4.6.2" +"@opentelemetry/sdk-metrics-base@0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.30.0.tgz#242d9260a89a1ac2bf1e167b3fda758f3883c769" + integrity sha512-3BDg1MYDInDyGvy+bSH8OuCX5nsue7omH6Y2eidCGTTDYRPxDmq9tsRJxnTUepoMAvWX+1sTwZ4JqTFmc1z8Mw== + dependencies: + "@opentelemetry/api-metrics" "0.30.0" + "@opentelemetry/core" "1.4.0" + "@opentelemetry/resources" "1.4.0" + lodash.merge "4.6.2" + "@opentelemetry/sdk-trace-base@1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.3.1.tgz#958083dbab928eefd17848959ac8810c787bec7f" @@ -4491,6 +4523,11 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.1.tgz#ba07b864a3c955f061aa30ea3ef7f4ae4449794a" integrity sha512-wU5J8rUoo32oSef/rFpOT1HIjLjAv3qIDHkw1QIhODV3OpAVHi5oVzlouozg9obUmZKtbZ0qUe/m7FP0y0yBzA== +"@opentelemetry/semantic-conventions@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.4.0.tgz#facf2c67d6063b9918d5a5e3fdf25f3a30d547b6" + integrity sha512-Hzl8soGpmyzja9w3kiFFcYJ7n5HNETpplY6cb67KR4QPlxp4FTTresO06qXHgHDhyIInmbLJXuwARjjpsKYGuQ== + "@percy/agent@^0.28.6": version "0.28.6" resolved "https://registry.yarnpkg.com/@percy/agent/-/agent-0.28.6.tgz#b220fab6ddcf63ae4e6c343108ba6955a772ce1c" @@ -7506,7 +7543,7 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.41", "@types/node@>= 8", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31": +"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.41", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31": version "16.11.41" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.41.tgz#88eb485b1bfdb4c224d878b7832239536aa2f813" integrity sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==