From 3fae351d2b8b78a3f85ddfd5f76b395ff7c10e1b Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Wed, 1 Mar 2023 17:29:31 -0700 Subject: [PATCH 01/11] Prepares usage-collection plugin for versioned HTTP APIs --- .../common/types/stats/index.ts | 10 +++ .../common/types/stats/latest.ts | 9 +++ .../usage_collection/common/types/stats/v1.ts | 69 +++++++++++++++++++ .../server/routes/stats/stats.ts | 27 +++++--- 4 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 src/plugins/usage_collection/common/types/stats/index.ts create mode 100644 src/plugins/usage_collection/common/types/stats/latest.ts create mode 100644 src/plugins/usage_collection/common/types/stats/v1.ts diff --git a/src/plugins/usage_collection/common/types/stats/index.ts b/src/plugins/usage_collection/common/types/stats/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/stats/latest.ts b/src/plugins/usage_collection/common/types/stats/latest.ts new file mode 100644 index 0000000000000..e9c79f0f50f93 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './v1'; diff --git a/src/plugins/usage_collection/common/types/stats/v1.ts b/src/plugins/usage_collection/common/types/stats/v1.ts new file mode 100644 index 0000000000000..490507f38b72e --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/v1.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** v1 types Start */ + +/** + * stats query v1 + */ +export interface StatsHTTPQuery { + extended?: boolean | ''; + legacy?: boolean | ''; + exclude_usage?: boolean | ''; +} +/** unused, for demonstration only */ +type MaybeRecord = + | { + [key: string]: Record; + } + | unknown; + +/** unused, for demonstration only */ +interface StatsHTTPBodyPartiallyTyped { + // lastMetrics + elasticsearch_client: unknown; + process: unknown; + processes: unknown[]; + os: unknown; + response_times: MaybeRecord; + requests: MaybeRecord; + concurrent_connections: number; + // stats added + lastUpdated: number; + collectionInterval: number; + // kibana + kibana: { + uuid: string; + name: string; + index: string; + host: string; + locale: string; + transport_address: string; + version: string; + snapshot: boolean; + status: string; + }; + // others + [key: string]: unknown; +} +/** unused, for demonstration only */ +export type StatsHTTPBodyTyped = StatsHTTPBodyUntyped | StatsHTTPBodyPartiallyTyped; + +/** + * stats body v1 + * Used for telemetry purposes, not used to integrate with other Kibana clients. + * Response body verification handled elsewhere + */ +type StatsHTTPBodyUntyped = unknown; + +/** + * generic type for api response body + */ +export interface StatsHTTPBody { + [key: string]: unknown; +} diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index 242e93a7554e3..f014111d00aaf 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -9,7 +9,6 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { firstValueFrom, Observable } from 'rxjs'; - import { ElasticsearchClient, IRouter, @@ -17,6 +16,8 @@ import { ServiceStatus, ServiceStatusLevels, } from '@kbn/core/server'; +import { v1 } from '../../../common/types/stats'; + import { CollectorSet } from '../../collector'; const SNAPSHOT_REGEX = /-snapshot/i; @@ -73,8 +74,10 @@ export function registerStatsRoute({ }, }, async (context, req, res) => { - const isExtended = req.query.extended === '' || req.query.extended; - const isLegacy = req.query.legacy === '' || req.query.legacy; + const requestQuery: v1.StatsHTTPQuery = req.query; + + const isExtended = requestQuery.extended === '' || requestQuery.extended; + const isLegacy = requestQuery.legacy === '' || requestQuery.legacy; let extended; if (isExtended) { @@ -119,12 +122,12 @@ export function registerStatsRoute({ last_updated: collectedAt.toISOString(), collection_interval_in_millis: metrics.collectionInterval, }); - + const body: v1.StatsHTTPBody = { + ...kibanaStats, + ...extended, + }; return res.ok({ - body: { - ...kibanaStats, - ...extended, - }, + body, }); } ); @@ -136,3 +139,11 @@ const ServiceStatusToLegacyState: Record = { [ServiceStatusLevels.degraded.toString()]: 'yellow', [ServiceStatusLevels.available.toString()]: 'green', }; + +export interface Extended { + kibanaStats: Record | unknown[]; +} + +export interface KibanaStats { + extended: Record | unknown[] | undefined; +} From 8323d200d97269b1ab4d10e5318c3aabf431caf5 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Fri, 3 Mar 2023 17:12:59 -0700 Subject: [PATCH 02/11] Duplicates OpsMetrics in usage_collection stats types, cleans up remnants of reporting usage as empty object --- .../core-custom-branding-common/index.d.ts | 23 ++ .../core-custom-branding-common/index.js | 9 + .../usage_collection/common/types/index.ts | 9 + .../types/stats/core_metrics_duplicated.ts | 207 ++++++++++++++++++ .../common/types/stats/latest.ts | 2 +- .../usage_collection/common/types/stats/v1.ts | 56 +++-- .../server/routes/stats/stats.ts | 29 +-- src/plugins/usage_collection/tsconfig.json | 2 +- .../management/cypress_endpoint.config.d.ts | 3 + .../management/cypress_endpoint.config.js | 41 ++++ 10 files changed, 329 insertions(+), 52 deletions(-) create mode 100644 packages/core/custom-branding/core-custom-branding-common/index.d.ts create mode 100644 packages/core/custom-branding/core-custom-branding-common/index.js create mode 100644 src/plugins/usage_collection/common/types/index.ts create mode 100644 src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts create mode 100644 x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts create mode 100644 x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js diff --git a/packages/core/custom-branding/core-custom-branding-common/index.d.ts b/packages/core/custom-branding/core-custom-branding-common/index.d.ts new file mode 100644 index 0000000000000..46aea984b1f00 --- /dev/null +++ b/packages/core/custom-branding/core-custom-branding-common/index.d.ts @@ -0,0 +1,23 @@ +export interface CustomBranding { + /** + * Custom replacement for the Elastic logo in the top lef * + * */ + logo?: string; + /** + * Custom replacement for favicon in SVG format + */ + faviconSVG?: string; + /** + * Custom page title + */ + pageTitle?: string; + /** + * Custom replacement for Elastic Mark + * @link packages/core/chrome/core-chrome-browser-internal/src/ui/header/elastic_mark.tsx + */ + customizedLogo?: string; + /** + * Custom replacement for favicon in PNG format + */ + faviconPNG?: string; +} diff --git a/packages/core/custom-branding/core-custom-branding-common/index.js b/packages/core/custom-branding/core-custom-branding-common/index.js new file mode 100644 index 0000000000000..4e90e66b8247a --- /dev/null +++ b/packages/core/custom-branding/core-custom-branding-common/index.js @@ -0,0 +1,9 @@ +"use strict"; +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/src/plugins/usage_collection/common/types/index.ts b/src/plugins/usage_collection/common/types/index.ts new file mode 100644 index 0000000000000..54e29b1dcba85 --- /dev/null +++ b/src/plugins/usage_collection/common/types/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './stats'; diff --git a/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts b/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts new file mode 100644 index 0000000000000..63a80dde1c371 --- /dev/null +++ b/src/plugins/usage_collection/common/types/stats/core_metrics_duplicated.ts @@ -0,0 +1,207 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * an IntervalHistogram object that samples and reports the event loop delay over time. + * The delays will be reported in milliseconds. + * + * @public + */ +export interface IntervalHistogram { + // The first timestamp the interval timer kicked in for collecting data points. + fromTimestamp: string; + // Last timestamp the interval timer kicked in for collecting data points. + lastUpdatedAt: string; + // The minimum recorded event loop delay. + min: number; + // The maximum recorded event loop delay. + max: number; + // The mean of the recorded event loop delays. + mean: number; + // The number of times the event loop delay exceeded the maximum 1 hour event loop delay threshold. + exceeds: number; + // The standard deviation of the recorded event loop delays. + stddev: number; + // An object detailing the accumulated percentile distribution. + percentiles: { + // 50th percentile of delays of the collected data points. + 50: number; + // 75th percentile of delays of the collected data points. + 75: number; + // 95th percentile of delays of the collected data points. + 95: number; + // 99th percentile of delays of the collected data points. + 99: number; + }; +} + +/** + * Protocol(s) used by the Elasticsearch Client + * @public + */ + +export type ElasticsearchClientProtocol = 'none' | 'http' | 'https' | 'mixed'; + +/** + * Metrics related to the elasticsearch clients + * @public + */ +export interface ElasticsearchClientsMetrics { + /** Total number of active sockets (all nodes, all connections) */ + totalActiveSockets: number; + /** Total number of available sockets (alive but idle, all nodes, all connections) */ + totalIdleSockets: number; + /** Total number of queued requests (all nodes, all connections) */ + totalQueuedRequests: number; +} + +/** + * Process related metrics + * @public + */ +export interface OpsProcessMetrics { + /** pid of the kibana process */ + pid: number; + /** process memory usage */ + memory: { + /** heap memory usage */ + heap: { + /** total heap available */ + total_in_bytes: number; + /** used heap */ + used_in_bytes: number; + /** v8 heap size limit */ + size_limit: number; + }; + /** node rss */ + resident_set_size_in_bytes: number; + }; + /** mean event loop delay since last collection*/ + event_loop_delay: number; + /** node event loop delay histogram since last collection */ + event_loop_delay_histogram: IntervalHistogram; + /** uptime of the kibana process */ + uptime_in_millis: number; +} + +/** + * OS related metrics + * @public + */ +export interface OpsOsMetrics { + /** The os platform */ + platform: NodeJS.Platform; + /** The os platform release, prefixed by the platform name */ + platformRelease: string; + /** The os distrib. Only present for linux platforms */ + distro?: string; + /** The os distrib release, prefixed by the os distrib. Only present for linux platforms */ + distroRelease?: string; + /** cpu load metrics */ + load: { + /** load for last minute */ + '1m': number; + /** load for last 5 minutes */ + '5m': number; + /** load for last 15 minutes */ + '15m': number; + }; + /** system memory usage metrics */ + memory: { + /** total memory available */ + total_in_bytes: number; + /** current free memory */ + free_in_bytes: number; + /** current used memory */ + used_in_bytes: number; + }; + /** the OS uptime */ + uptime_in_millis: number; + + /** cpu accounting metrics, undefined when not running in a cgroup */ + cpuacct?: { + /** name of this process's cgroup */ + control_group: string; + /** cpu time used by this process's cgroup */ + usage_nanos: number; + }; + + /** cpu cgroup metrics, undefined when not running in a cgroup */ + cpu?: { + /** name of this process's cgroup */ + control_group: string; + /** the length of the cfs period */ + cfs_period_micros: number; + /** total available run-time within a cfs period */ + cfs_quota_micros: number; + /** current stats on the cfs periods */ + stat: { + /** number of cfs periods that elapsed */ + number_of_elapsed_periods: number; + /** number of times the cgroup has been throttled */ + number_of_times_throttled: number; + /** total amount of time the cgroup has been throttled for */ + time_throttled_nanos: number; + }; + }; +} + +/** + * server related metrics + * @public + */ +export interface OpsServerMetrics { + /** server response time stats */ + response_times: { + /** average response time */ + avg_in_millis: number; + /** maximum response time */ + max_in_millis: number; + }; + /** server requests stats */ + requests: { + /** number of disconnected requests since startup */ + disconnects: number; + /** total number of requests handled since startup */ + total: number; + /** number of request handled per response status code */ + statusCodes: Record; + }; + /** number of current concurrent connections to the server */ + concurrent_connections: number; +} + +/** + * Regroups metrics gathered by all the collectors. + * This contains metrics about the os/runtime, the kibana process and the http server. + * + * @public + */ +export interface OpsMetrics { + /** Time metrics were recorded at. */ + collected_at: Date; + /** + * Metrics related to the elasticsearch client + */ + elasticsearch_client: ElasticsearchClientsMetrics; + /** + * Process related metrics. + * @remarks processes field preferred + */ + process: OpsProcessMetrics; + /** Process related metrics. Reports an array of objects for each kibana pid.*/ + processes: OpsProcessMetrics[]; + /** OS related metrics */ + os: OpsOsMetrics; + /** server response time stats */ + response_times: OpsServerMetrics['response_times']; + /** server requests stats */ + requests: OpsServerMetrics['requests']; + /** number of current concurrent connections to the server */ + concurrent_connections: OpsServerMetrics['concurrent_connections']; +} diff --git a/src/plugins/usage_collection/common/types/stats/latest.ts b/src/plugins/usage_collection/common/types/stats/latest.ts index e9c79f0f50f93..ff21a8ea323e3 100644 --- a/src/plugins/usage_collection/common/types/stats/latest.ts +++ b/src/plugins/usage_collection/common/types/stats/latest.ts @@ -5,5 +5,5 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +export * as OpsMetricsCopy from './core_metrics_duplicated'; export * from './v1'; diff --git a/src/plugins/usage_collection/common/types/stats/v1.ts b/src/plugins/usage_collection/common/types/stats/v1.ts index 490507f38b72e..ceac7ccc9b102 100644 --- a/src/plugins/usage_collection/common/types/stats/v1.ts +++ b/src/plugins/usage_collection/common/types/stats/v1.ts @@ -6,36 +6,41 @@ * Side Public License, v 1. */ +import * as OpsMetricsCopy from './core_metrics_duplicated'; /** v1 types Start */ /** * stats query v1 + * @remarks exclude_usage is always interpreted as true. query param retained to prevent breaking changes to existing consumers. */ export interface StatsHTTPQuery { extended?: boolean | ''; legacy?: boolean | ''; exclude_usage?: boolean | ''; } -/** unused, for demonstration only */ -type MaybeRecord = - | { - [key: string]: Record; - } - | unknown; +export interface UsageObject { + kibana?: UsageObject; + xpack?: UsageObject; + [key: string]: unknown | UsageObject; +} +/** + * Extended usage stats. + * Legacy implementation used to conditionally include kibana usage metrics + * as of https://github.com/elastic/kibana/pull/151082, usage is no longer reported + * and set to an empty object to prevent breaking changes to existing consumers. + */ +export interface ExtendedStats { + [key: string]: unknown; + clusterUuid?: string; // camel case if legacy === true + cluster_uuid?: string; // snake_case if legacy === false +} +/** + * OpsMetrics: partially typed to avoid duplicating core's OpsMetrics types + */ +export type LastOpsMetrics = OpsMetricsCopy.OpsMetrics; /** unused, for demonstration only */ -interface StatsHTTPBodyPartiallyTyped { - // lastMetrics - elasticsearch_client: unknown; - process: unknown; - processes: unknown[]; - os: unknown; - response_times: MaybeRecord; - requests: MaybeRecord; - concurrent_connections: number; - // stats added - lastUpdated: number; - collectionInterval: number; +export interface KibanaStats { // kibana kibana: { uuid: string; @@ -48,18 +53,11 @@ interface StatsHTTPBodyPartiallyTyped { snapshot: boolean; status: string; }; - // others - [key: string]: unknown; + // // others + // [key: string]: unknown; } -/** unused, for demonstration only */ -export type StatsHTTPBodyTyped = StatsHTTPBodyUntyped | StatsHTTPBodyPartiallyTyped; - -/** - * stats body v1 - * Used for telemetry purposes, not used to integrate with other Kibana clients. - * Response body verification handled elsewhere - */ -type StatsHTTPBodyUntyped = unknown; +/** Stats response body */ +export type StatsHTTPBodyTyped = LastOpsMetrics | KibanaStats | ExtendedStats; /** * generic type for api response body diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index f014111d00aaf..f652c290a2b4d 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -21,12 +21,6 @@ import { v1 } from '../../../common/types/stats'; import { CollectorSet } from '../../collector'; const SNAPSHOT_REGEX = /-snapshot/i; -interface UsageObject { - kibana?: UsageObject; - xpack?: UsageObject; - [key: string]: unknown | UsageObject; -} - export function registerStatsRoute({ router, config, @@ -80,24 +74,17 @@ export function registerStatsRoute({ const isLegacy = requestQuery.legacy === '' || requestQuery.legacy; let extended; + if (isExtended) { const core = await context.core; const { asCurrentUser } = core.elasticsearch.client; - - const usage = {} as UsageObject; + // as of https://github.com/elastic/kibana/pull/151082, usage will always be an empty object. const clusterUuid = await getClusterUuid(asCurrentUser); - - // In an effort to make telemetry more easily augmented, we need to ensure - // we can passthrough the data without every part of the process needing - // to know about the change; however, to support legacy use cases where this - // wasn't true, we need to be backwards compatible with how the legacy data - // looked and support those use cases here. - extended = isLegacy - ? { usage, clusterUuid } - : collectorSet.toApiFieldNames({ - usage, - clusterUuid, - }); + const extendedClusterUuid = isLegacy ? { clusterUuid } : { cluster_uuid: clusterUuid }; + extended = { + usage: {}, + extendedClusterUuid, + }; } // Guaranteed to resolve immediately due to replay effect on getOpsMetrics$ @@ -122,7 +109,7 @@ export function registerStatsRoute({ last_updated: collectedAt.toISOString(), collection_interval_in_millis: metrics.collectionInterval, }); - const body: v1.StatsHTTPBody = { + const body: v1.StatsHTTPBodyTyped = { ...kibanaStats, ...extended, }; diff --git a/src/plugins/usage_collection/tsconfig.json b/src/plugins/usage_collection/tsconfig.json index f6e360d80b3ad..becc176c0451e 100644 --- a/src/plugins/usage_collection/tsconfig.json +++ b/src/plugins/usage_collection/tsconfig.json @@ -7,7 +7,7 @@ "include": [ "public/**/*", "server/**/*", - "common/*", + "common/**/*", "../../../typings/**/*" ], "kbn_references": [ diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts new file mode 100644 index 0000000000000..42cd75f66e3c9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts @@ -0,0 +1,3 @@ +/// +declare const _default: Cypress.ConfigOptions; +export default _default; diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js new file mode 100644 index 0000000000000..68de0e34de7e6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js @@ -0,0 +1,41 @@ +"use strict"; +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const cypress_config_1 = require("@kbn/cypress-config"); +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +const data_loaders_1 = require("./cypress/support/data_loaders"); +// eslint-disable-next-line import/no-default-export +exports.default = (0, cypress_config_1.defineCypressConfig)({ + defaultCommandTimeout: 60000, + execTimeout: 120000, + pageLoadTimeout: 12000, + retries: { + runMode: 1, + openMode: 0, + }, + screenshotsFolder: '../../../target/kibana-security-solution/public/management/cypress/screenshots', + trashAssetsBeforeRuns: false, + video: false, + viewportHeight: 900, + viewportWidth: 1440, + experimentalStudio: true, + env: { + 'cypress-react-selector': { + root: '#security-solution-app', + }, + }, + e2e: { + baseUrl: 'http://localhost:5620', + supportFile: 'public/management/cypress/support/e2e.ts', + specPattern: 'public/management/cypress/e2e/endpoint/*.cy.{js,jsx,ts,tsx}', + experimentalRunAllSpecs: true, + setupNodeEvents(on, config) { + (0, data_loaders_1.dataLoaders)(on, config); + }, + }, +}); From 9fd189149d2d545e7db7ea216d1412c675a497ae Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Sun, 5 Mar 2023 16:45:58 -0700 Subject: [PATCH 03/11] Versions ui_counters API: --- .../common/types/ui_counters/index.ts | 10 ++++++ .../common/types/ui_counters/latest.ts | 9 +++++ .../common/types/ui_counters/v1.ts | 36 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/plugins/usage_collection/common/types/ui_counters/index.ts create mode 100644 src/plugins/usage_collection/common/types/ui_counters/latest.ts create mode 100644 src/plugins/usage_collection/common/types/ui_counters/v1.ts diff --git a/src/plugins/usage_collection/common/types/ui_counters/index.ts b/src/plugins/usage_collection/common/types/ui_counters/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/latest.ts b/src/plugins/usage_collection/common/types/ui_counters/latest.ts new file mode 100644 index 0000000000000..f966e698fb59e --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/v1.ts b/src/plugins/usage_collection/common/types/ui_counters/v1.ts new file mode 100644 index 0000000000000..05d3e5b1b44ce --- /dev/null +++ b/src/plugins/usage_collection/common/types/ui_counters/v1.ts @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * ui_counters query v1 + * @remarks + */ +export interface UiCountersHTTPRequestBody { + report: { + reportVersion?: 3; + userAgent?: { + key: string; + type: string; + appName: string; + userAgent: string; + }; + uiCounter?: { + key: string; + type: string; + appName: string; + eventName: string; + total: number; + }; + application_usage?: { + minutesOnScreen: number; + numberOfClicks: number; + appId: string; + viewId: string; + }; + }; +} From 04b4f40d81a8dfaf458db608d86ddb6403295c6d Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 13:04:03 -0700 Subject: [PATCH 04/11] WIP: ui_counters --- .../usage_collection/common/types/index.ts | 3 +- .../common/types/ui_counters/v1.ts | 59 +++++++++++++------ .../server/routes/ui_counters.ts | 6 +- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/plugins/usage_collection/common/types/index.ts b/src/plugins/usage_collection/common/types/index.ts index 54e29b1dcba85..9593f08b004d0 100644 --- a/src/plugins/usage_collection/common/types/index.ts +++ b/src/plugins/usage_collection/common/types/index.ts @@ -6,4 +6,5 @@ * Side Public License, v 1. */ -export * as v1 from './stats'; +export * as v1Stats from './stats'; +export * as v1UiCounters from './ui_counters'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/v1.ts b/src/plugins/usage_collection/common/types/ui_counters/v1.ts index 05d3e5b1b44ce..218e991027816 100644 --- a/src/plugins/usage_collection/common/types/ui_counters/v1.ts +++ b/src/plugins/usage_collection/common/types/ui_counters/v1.ts @@ -13,24 +13,45 @@ export interface UiCountersHTTPRequestBody { report: { reportVersion?: 3; - userAgent?: { - key: string; - type: string; - appName: string; - userAgent: string; - }; - uiCounter?: { - key: string; - type: string; - appName: string; - eventName: string; - total: number; - }; - application_usage?: { - minutesOnScreen: number; - numberOfClicks: number; - appId: string; - viewId: string; - }; + userAgent?: Record< + string, + Readonly< + {} & { + key: string; + type: string; + appName: string; + userAgent: string; + } + > + >; + uiCounter?: Record< + string, + Readonly< + {} & { + key: string; + type: string; + appName: string; + eventName: string; + total: number; + } + > + >; + application_usage?: Record< + string, + Readonly<{ + minutesOnScreen: number; + numberOfClicks: number; + appId: string; + viewId: string; + }> + >; }; } + +export enum UiCountersHTTPResponseStatus { + ok = 'ok', + fail = 'fail', +} +export interface UiCountersHTTPResponseBody { + status: UiCountersHTTPResponseStatus; +} diff --git a/src/plugins/usage_collection/server/routes/ui_counters.ts b/src/plugins/usage_collection/server/routes/ui_counters.ts index f4d7385195012..d72064bd3b90e 100644 --- a/src/plugins/usage_collection/server/routes/ui_counters.ts +++ b/src/plugins/usage_collection/server/routes/ui_counters.ts @@ -10,6 +10,7 @@ import { schema } from '@kbn/config-schema'; import { IRouter, ISavedObjectsRepository } from '@kbn/core/server'; import { storeReport, reportSchema } from '../report'; import { UsageCounter } from '../usage_counters'; +import { v1 } from '../../common/types/ui_counters'; export function registerUiCountersRoute( router: IRouter, @@ -26,13 +27,14 @@ export function registerUiCountersRoute( }, }, async (context, req, res) => { - const { report } = req.body; + const requestBody: v1.UiCountersHTTPRequestBody = req.body; + // const { report } = req.body; try { const internalRepository = getSavedObjects(); if (!internalRepository) { throw Error(`The saved objects client hasn't been initialised yet`); } - await storeReport(internalRepository, uiCountersUsageCounter, report); + await storeReport(internalRepository, uiCountersUsageCounter, requestBody.report); return res.ok({ body: { status: 'ok' } }); } catch (error) { return res.ok({ body: { status: 'fail' } }); From 86b6ef85c71a36400bc8f6f01ba83d83100ff1cd Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 14:48:26 -0700 Subject: [PATCH 05/11] Creates new types for ui_counters ok and fail response --- .../usage_collection/common/types/ui_counters/v1.ts | 9 ++++----- .../usage_collection/server/routes/ui_counters.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/plugins/usage_collection/common/types/ui_counters/v1.ts b/src/plugins/usage_collection/common/types/ui_counters/v1.ts index 218e991027816..a40acacf50143 100644 --- a/src/plugins/usage_collection/common/types/ui_counters/v1.ts +++ b/src/plugins/usage_collection/common/types/ui_counters/v1.ts @@ -48,10 +48,9 @@ export interface UiCountersHTTPRequestBody { }; } -export enum UiCountersHTTPResponseStatus { - ok = 'ok', - fail = 'fail', +export interface UiCountersResponseOk { + status: 'ok'; } -export interface UiCountersHTTPResponseBody { - status: UiCountersHTTPResponseStatus; +export interface UiCountersResponseFail { + status: 'fail'; } diff --git a/src/plugins/usage_collection/server/routes/ui_counters.ts b/src/plugins/usage_collection/server/routes/ui_counters.ts index d72064bd3b90e..8c137a1dbc1ef 100644 --- a/src/plugins/usage_collection/server/routes/ui_counters.ts +++ b/src/plugins/usage_collection/server/routes/ui_counters.ts @@ -35,9 +35,15 @@ export function registerUiCountersRoute( throw Error(`The saved objects client hasn't been initialised yet`); } await storeReport(internalRepository, uiCountersUsageCounter, requestBody.report); - return res.ok({ body: { status: 'ok' } }); + const bodyOk: v1.UiCountersResponseOk = { + status: 'ok', + }; + return res.ok({ body: bodyOk }); } catch (error) { - return res.ok({ body: { status: 'fail' } }); + const bodyFail: v1.UiCountersResponseFail = { + status: 'fail', + }; + return res.ok({ body: bodyFail }); } } ); From 5ac0a19c300de2b4d8e7d6537481efc73483e2c5 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 16:07:57 -0700 Subject: [PATCH 06/11] Explicitly type ui_counter saved objects mapping --- .../usage_collection/common/types/index.ts | 1 + .../common/types/ui_counters/v1.ts | 4 ++- .../common/types/usage_counters/index.ts | 10 +++++++ .../common/types/usage_counters/latest.ts | 9 ++++++ .../common/types/usage_counters/v1.ts | 26 +++++++++++++++++ .../server/routes/ui_counters.ts | 1 - .../server/usage_counters/saved_objects.ts | 4 +-- .../server/usage_counters/usage_counter.ts | 29 ++++--------------- .../usage_counters/usage_counters_service.ts | 13 +++++---- 9 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 src/plugins/usage_collection/common/types/usage_counters/index.ts create mode 100644 src/plugins/usage_collection/common/types/usage_counters/latest.ts create mode 100644 src/plugins/usage_collection/common/types/usage_counters/v1.ts diff --git a/src/plugins/usage_collection/common/types/index.ts b/src/plugins/usage_collection/common/types/index.ts index 9593f08b004d0..423bde69accdb 100644 --- a/src/plugins/usage_collection/common/types/index.ts +++ b/src/plugins/usage_collection/common/types/index.ts @@ -8,3 +8,4 @@ export * as v1Stats from './stats'; export * as v1UiCounters from './ui_counters'; +export * as v1UsageCounters from './usage_counters'; diff --git a/src/plugins/usage_collection/common/types/ui_counters/v1.ts b/src/plugins/usage_collection/common/types/ui_counters/v1.ts index a40acacf50143..0f110aee5a4e9 100644 --- a/src/plugins/usage_collection/common/types/ui_counters/v1.ts +++ b/src/plugins/usage_collection/common/types/ui_counters/v1.ts @@ -47,10 +47,12 @@ export interface UiCountersHTTPRequestBody { >; }; } - +/** explicit response type for store report success. The status value is hardcoded. */ export interface UiCountersResponseOk { status: 'ok'; } + +/** explicit response type for store report fail. The status value is hardcoded. */ export interface UiCountersResponseFail { status: 'fail'; } diff --git a/src/plugins/usage_collection/common/types/usage_counters/index.ts b/src/plugins/usage_collection/common/types/usage_counters/index.ts new file mode 100644 index 0000000000000..f14c7c0580841 --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; +export * from './latest'; diff --git a/src/plugins/usage_collection/common/types/usage_counters/latest.ts b/src/plugins/usage_collection/common/types/usage_counters/latest.ts new file mode 100644 index 0000000000000..f966e698fb59e --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * as v1 from './v1'; diff --git a/src/plugins/usage_collection/common/types/usage_counters/v1.ts b/src/plugins/usage_collection/common/types/usage_counters/v1.ts new file mode 100644 index 0000000000000..fa53a9d9e93b0 --- /dev/null +++ b/src/plugins/usage_collection/common/types/usage_counters/v1.ts @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface CounterMetric { + domainId: string; + counterName: string; + counterType: string; + incrementBy: number; +} + +/** + * Details about the counter to be incremented + */ +export interface IncrementCounterParams { + /** The name of the counter **/ + counterName: string; + /** The counter type ("count" by default) **/ + counterType?: string; + /** Increment the counter by this number (1 if not specified) **/ + incrementBy?: number; +} diff --git a/src/plugins/usage_collection/server/routes/ui_counters.ts b/src/plugins/usage_collection/server/routes/ui_counters.ts index 8c137a1dbc1ef..d87fb50b124a0 100644 --- a/src/plugins/usage_collection/server/routes/ui_counters.ts +++ b/src/plugins/usage_collection/server/routes/ui_counters.ts @@ -28,7 +28,6 @@ export function registerUiCountersRoute( }, async (context, req, res) => { const requestBody: v1.UiCountersHTTPRequestBody = req.body; - // const { report } = req.body; try { const internalRepository = getSavedObjects(); if (!internalRepository) { diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts index 701bbba404c49..615321a004a44 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.ts @@ -12,7 +12,7 @@ import type { SavedObjectsServiceSetup, } from '@kbn/core/server'; import moment from 'moment'; -import type { CounterMetric } from './usage_counter'; +import { v1 } from '../../common/types/usage_counters'; /** * The attributes stored in the UsageCounters' SavedObjects @@ -83,7 +83,7 @@ export const serializeCounterKey = ({ }; export const storeCounter = async ( - counterMetric: CounterMetric, + counterMetric: v1.CounterMetric, internalRepository: Pick ) => { const { counterName, counterType, domainId, incrementBy } = counterMetric; diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counter.ts b/src/plugins/usage_collection/server/usage_counters/usage_counter.ts index b8057fdda8eb6..8ec006abb7553 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counter.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counter.ts @@ -7,29 +7,10 @@ */ import * as Rx from 'rxjs'; - -export interface CounterMetric { - domainId: string; - counterName: string; - counterType: string; - incrementBy: number; -} - +import { v1 } from '../../common/types/usage_counters'; export interface UsageCounterDeps { domainId: string; - counter$: Rx.Subject; -} - -/** - * Details about the counter to be incremented - */ -export interface IncrementCounterParams { - /** The name of the counter **/ - counterName: string; - /** The counter type ("count" by default) **/ - counterType?: string; - /** Increment the counter by this number (1 if not specified) **/ - incrementBy?: number; + counter$: Rx.Subject; } /** @@ -42,19 +23,19 @@ export interface IUsageCounter { * Notifies the counter about a new event happening so it can increase the count internally. * @param params {@link IncrementCounterParams} */ - incrementCounter: (params: IncrementCounterParams) => void; + incrementCounter: (params: v1.IncrementCounterParams) => void; } export class UsageCounter implements IUsageCounter { private domainId: string; - private counter$: Rx.Subject; + private counter$: Rx.Subject; constructor({ domainId, counter$ }: UsageCounterDeps) { this.domainId = domainId; this.counter$ = counter$; } - public incrementCounter = (params: IncrementCounterParams) => { + public incrementCounter = (params: v1.IncrementCounterParams) => { const { counterName, counterType = 'count', incrementBy = 1 } = params; this.counter$.next({ diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts index 095f314a8e80b..6e283a0715ed0 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts @@ -16,7 +16,8 @@ import { import type { Logger, LogMeta } from '@kbn/core/server'; import moment from 'moment'; -import { CounterMetric, UsageCounter } from './usage_counter'; +import { UsageCounter } from './usage_counter'; +import { v1 } from '../../common/types/usage_counters'; import { registerUsageCountersSavedObjectType, storeCounter, @@ -54,7 +55,7 @@ export class UsageCountersService { private readonly bufferDurationMs: number; private readonly counterSets = new Map(); - private readonly source$ = new Rx.Subject(); + private readonly source$ = new Rx.Subject(); private readonly counter$ = this.source$.pipe(rxOp.multicast(new Rx.Subject()), rxOp.refCount()); private readonly flushCache$ = new Rx.Subject(); @@ -69,7 +70,7 @@ export class UsageCountersService { } public setup = (core: UsageCountersServiceSetupDeps): UsageCountersServiceSetup => { - const cache$ = new Rx.ReplaySubject(); + const cache$ = new Rx.ReplaySubject(); const storingCache$ = new Rx.BehaviorSubject(false); // flush cache data from cache -> source this.flushCache$ @@ -135,7 +136,7 @@ export class UsageCountersService { }; private storeDate$( - counters: CounterMetric[], + counters: v1.CounterMetric[], internalRepository: Pick ) { return Rx.forkJoin( @@ -170,7 +171,7 @@ export class UsageCountersService { return this.counterSets.get(type); }; - private mergeCounters = (counters: CounterMetric[]): Record => { + private mergeCounters = (counters: v1.CounterMetric[]): Record => { const date = moment.now(); return counters.reduce((acc, counter) => { const { counterName, domainId, counterType } = counter; @@ -188,6 +189,6 @@ export class UsageCountersService { incrementBy: existingCounter.incrementBy + counter.incrementBy, }, }; - }, {} as Record); + }, {} as Record); }; } From bf5ed2bf845c4c0499d03b22811d18d615f67217 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 16:24:18 -0700 Subject: [PATCH 07/11] Explcitly type CounterMetric --- .../usage_counters/usage_counters_service.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts index 6e283a0715ed0..f1ad4e40e4e26 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts @@ -17,7 +17,7 @@ import type { Logger, LogMeta } from '@kbn/core/server'; import moment from 'moment'; import { UsageCounter } from './usage_counter'; -import { v1 } from '../../common/types/usage_counters'; +import { v1UsageCounters } from '../../common/types'; import { registerUsageCountersSavedObjectType, storeCounter, @@ -55,7 +55,7 @@ export class UsageCountersService { private readonly bufferDurationMs: number; private readonly counterSets = new Map(); - private readonly source$ = new Rx.Subject(); + private readonly source$ = new Rx.Subject(); private readonly counter$ = this.source$.pipe(rxOp.multicast(new Rx.Subject()), rxOp.refCount()); private readonly flushCache$ = new Rx.Subject(); @@ -70,7 +70,7 @@ export class UsageCountersService { } public setup = (core: UsageCountersServiceSetupDeps): UsageCountersServiceSetup => { - const cache$ = new Rx.ReplaySubject(); + const cache$ = new Rx.ReplaySubject(); const storingCache$ = new Rx.BehaviorSubject(false); // flush cache data from cache -> source this.flushCache$ @@ -136,7 +136,7 @@ export class UsageCountersService { }; private storeDate$( - counters: v1.CounterMetric[], + counters: v1UsageCounters.v1.CounterMetric[], internalRepository: Pick ) { return Rx.forkJoin( @@ -171,7 +171,9 @@ export class UsageCountersService { return this.counterSets.get(type); }; - private mergeCounters = (counters: v1.CounterMetric[]): Record => { + private mergeCounters = ( + counters: v1UsageCounters.v1.CounterMetric[] + ): Record => { const date = moment.now(); return counters.reduce((acc, counter) => { const { counterName, domainId, counterType } = counter; @@ -189,6 +191,6 @@ export class UsageCountersService { incrementBy: existingCounter.incrementBy + counter.incrementBy, }, }; - }, {} as Record); + }, {} as Record); }; } From 677eb64a52d9e023b698d67031fb613443845514 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 16:53:22 -0700 Subject: [PATCH 08/11] Update createReporter fetch types --- .../usage_collection/public/services/create_reporter.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/usage_collection/public/services/create_reporter.ts b/src/plugins/usage_collection/public/services/create_reporter.ts index 95d5fff9cc943..8641b934d8514 100644 --- a/src/plugins/usage_collection/public/services/create_reporter.ts +++ b/src/plugins/usage_collection/public/services/create_reporter.ts @@ -8,6 +8,7 @@ import { Reporter, Storage } from '@kbn/analytics'; import { HttpSetup } from '@kbn/core/public'; +import { v1 } from '../../common/types/ui_counters'; interface AnalyicsReporterConfig { localStorage: Storage; @@ -21,14 +22,14 @@ export function createReporter(config: AnalyicsReporterConfig): Reporter { return new Reporter({ debug, storage: localStorage, - async http(report) { + async http(report: v1.UiCountersHTTPRequestBody['report']) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const response = await fetch.post('/api/ui_counters/_report', { body: JSON.stringify({ report }), asSystemRequest: true, }); - - if (response.status !== 'ok') { + const okStatus: v1.UiCountersResponseOk = response.status; + if (response.status !== okStatus) { throw Error('Unable to store report.'); } return response; From 6068f6aad514c597f7a1e20b192561d4a43d732f Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 17:20:39 -0700 Subject: [PATCH 09/11] Adds code comments to share for discussing --- .../usage_collection/common/types/stats/v1.ts | 22 ++++++++++++++----- .../public/services/create_reporter.ts | 1 + .../usage_collection/server/report/schema.ts | 1 + .../server/routes/stats/stats.ts | 8 ------- .../usage_counters/usage_counters_service.ts | 6 +++-- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/plugins/usage_collection/common/types/stats/v1.ts b/src/plugins/usage_collection/common/types/stats/v1.ts index ceac7ccc9b102..e3881d19aec19 100644 --- a/src/plugins/usage_collection/common/types/stats/v1.ts +++ b/src/plugins/usage_collection/common/types/stats/v1.ts @@ -36,10 +36,13 @@ export interface ExtendedStats { cluster_uuid?: string; // snake_case if legacy === false } /** - * OpsMetrics: partially typed to avoid duplicating core's OpsMetrics types + * OpsMetrics: aliased from a duplicate of core's OpsMetrics types + * @remarks the alternative to creating a local copy of the OpsMetrics types is to declare them as `unknown` and assume validation happens elsewhere. + * The disadvantage is that any changes made to the original OpsMetrics will be passed through without needing to update the API types. */ export type LastOpsMetrics = OpsMetricsCopy.OpsMetrics; -/** unused, for demonstration only */ + +/** explicitly typed stats for kibana */ export interface KibanaStats { // kibana kibana: { @@ -53,15 +56,22 @@ export interface KibanaStats { snapshot: boolean; status: string; }; - // // others - // [key: string]: unknown; } /** Stats response body */ export type StatsHTTPBodyTyped = LastOpsMetrics | KibanaStats | ExtendedStats; /** - * generic type for api response body + * unused, for demonstration purposes only. + * alternative generic type for api response body + */ +export interface LastOpsMetricsUnknown { + [key: string]: unknown; +} + +/** + * unused, for demonstration purposes only. + * alternative generic type for api response body */ -export interface StatsHTTPBody { +export interface StatsHTTPBodyUnknown { [key: string]: unknown; } diff --git a/src/plugins/usage_collection/public/services/create_reporter.ts b/src/plugins/usage_collection/public/services/create_reporter.ts index 8641b934d8514..685e3063e0a95 100644 --- a/src/plugins/usage_collection/public/services/create_reporter.ts +++ b/src/plugins/usage_collection/public/services/create_reporter.ts @@ -22,6 +22,7 @@ export function createReporter(config: AnalyicsReporterConfig): Reporter { return new Reporter({ debug, storage: localStorage, + // not sure if these versioned-type related changes are strictly needed for defining the Reporter. async http(report: v1.UiCountersHTTPRequestBody['report']) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const response = await fetch.post('/api/ui_counters/_report', { diff --git a/src/plugins/usage_collection/server/report/schema.ts b/src/plugins/usage_collection/server/report/schema.ts index 1f76d3a4db76d..259f893d5eaa5 100644 --- a/src/plugins/usage_collection/server/report/schema.ts +++ b/src/plugins/usage_collection/server/report/schema.ts @@ -43,5 +43,6 @@ export const reportSchema = schema.object({ application_usage: schema.maybe(schema.recordOf(schema.string(), applicationUsageReportSchema)), }); +// should the schema types also be versioned explicitly? export type ReportSchemaType = TypeOf; export type ApplicationUsageReport = TypeOf; diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index f652c290a2b4d..cb745768abe9f 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -126,11 +126,3 @@ const ServiceStatusToLegacyState: Record = { [ServiceStatusLevels.degraded.toString()]: 'yellow', [ServiceStatusLevels.available.toString()]: 'green', }; - -export interface Extended { - kibanaStats: Record | unknown[]; -} - -export interface KibanaStats { - extended: Record | unknown[] | undefined; -} diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts index f1ad4e40e4e26..84326586732f4 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counters_service.ts @@ -55,7 +55,7 @@ export class UsageCountersService { private readonly bufferDurationMs: number; private readonly counterSets = new Map(); - private readonly source$ = new Rx.Subject(); + private readonly source$ = new Rx.Subject(); // updates the types to specifically target what the HTTP API's require private readonly counter$ = this.source$.pipe(rxOp.multicast(new Rx.Subject()), rxOp.refCount()); private readonly flushCache$ = new Rx.Subject(); @@ -70,7 +70,7 @@ export class UsageCountersService { } public setup = (core: UsageCountersServiceSetupDeps): UsageCountersServiceSetup => { - const cache$ = new Rx.ReplaySubject(); + const cache$ = new Rx.ReplaySubject(); // updates the types to specifically target what the HTTP API's require const storingCache$ = new Rx.BehaviorSubject(false); // flush cache data from cache -> source this.flushCache$ @@ -135,6 +135,7 @@ export class UsageCountersService { this.stop$.next(); }; + // using updated types from the ones the HTTP API requires private storeDate$( counters: v1UsageCounters.v1.CounterMetric[], internalRepository: Pick @@ -171,6 +172,7 @@ export class UsageCountersService { return this.counterSets.get(type); }; + // using updated types from the ones the HTTP API requires private mergeCounters = ( counters: v1UsageCounters.v1.CounterMetric[] ): Record => { From aae570bc9b659307b8c95bfde4558a9f8eb5ad64 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 6 Mar 2023 18:36:08 -0700 Subject: [PATCH 10/11] update type imports --- src/plugins/usage_collection/server/usage_counters/index.ts | 5 ++++- .../server/usage_counters/saved_objects.test.ts | 4 ++-- .../server/usage_counters/usage_counter.test.ts | 5 +++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/usage_collection/server/usage_counters/index.ts b/src/plugins/usage_collection/server/usage_counters/index.ts index cc1ee77ef3ea4..3ff122d8509de 100644 --- a/src/plugins/usage_collection/server/usage_counters/index.ts +++ b/src/plugins/usage_collection/server/usage_counters/index.ts @@ -8,7 +8,10 @@ export type { UsageCountersServiceSetup } from './usage_counters_service'; export type { UsageCountersSavedObjectAttributes, UsageCountersSavedObject } from './saved_objects'; -export type { IUsageCounter as UsageCounter, IncrementCounterParams } from './usage_counter'; +export type { IUsageCounter as UsageCounter } from './usage_counter'; + +import { v1 } from '../../common/types/usage_counters'; +export type IncrementCounterParams = v1.IncrementCounterParams; export { UsageCountersService } from './usage_counters_service'; export type { SerializeCounterParams } from './saved_objects'; diff --git a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts index cb3c5e7683b16..40f92ea3a5e3a 100644 --- a/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/saved_objects.test.ts @@ -8,7 +8,7 @@ import { serializeCounterKey, storeCounter } from './saved_objects'; import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; -import { CounterMetric } from './usage_counter'; +import { v1 } from '../../common/types/usage_counters'; import moment from 'moment'; describe('counterKey', () => { @@ -38,7 +38,7 @@ describe('storeCounter', () => { }); it('stores counter in a saved object', async () => { - const counterMetric: CounterMetric = { + const counterMetric: v1.CounterMetric = { domainId: 'a', counterName: 'b', counterType: 'c', diff --git a/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts b/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts index 3602ff1a29376..8bd35b85edc21 100644 --- a/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts +++ b/src/plugins/usage_collection/server/usage_counters/usage_counter.test.ts @@ -5,13 +5,14 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { UsageCounter, CounterMetric } from './usage_counter'; +import { UsageCounter } from './usage_counter'; import * as Rx from 'rxjs'; import * as rxOp from 'rxjs/operators'; +import { v1 } from '../../common/types/usage_counters'; describe('UsageCounter', () => { const domainId = 'test-domain-id'; - const counter$ = new Rx.Subject(); + const counter$ = new Rx.Subject(); const usageCounter = new UsageCounter({ domainId, counter$ }); afterAll(() => { From d16c06801c05317b1f5d1de0324327c9fbd965f8 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 7 Mar 2023 02:32:00 +0000 Subject: [PATCH 11/11] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../core-custom-branding-common/index.d.ts | 50 +++++++++------- .../core-custom-branding-common/index.js | 3 +- .../management/cypress_endpoint.config.d.ts | 9 ++- .../management/cypress_endpoint.config.js | 58 +++++++++---------- 4 files changed, 67 insertions(+), 53 deletions(-) diff --git a/packages/core/custom-branding/core-custom-branding-common/index.d.ts b/packages/core/custom-branding/core-custom-branding-common/index.d.ts index 46aea984b1f00..88b1cd0a20335 100644 --- a/packages/core/custom-branding/core-custom-branding-common/index.d.ts +++ b/packages/core/custom-branding/core-custom-branding-common/index.d.ts @@ -1,23 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + export interface CustomBranding { - /** - * Custom replacement for the Elastic logo in the top lef * - * */ - logo?: string; - /** - * Custom replacement for favicon in SVG format - */ - faviconSVG?: string; - /** - * Custom page title - */ - pageTitle?: string; - /** - * Custom replacement for Elastic Mark - * @link packages/core/chrome/core-chrome-browser-internal/src/ui/header/elastic_mark.tsx - */ - customizedLogo?: string; - /** - * Custom replacement for favicon in PNG format - */ - faviconPNG?: string; + /** + * Custom replacement for the Elastic logo in the top lef * + * */ + logo?: string; + /** + * Custom replacement for favicon in SVG format + */ + faviconSVG?: string; + /** + * Custom page title + */ + pageTitle?: string; + /** + * Custom replacement for Elastic Mark + * @link packages/core/chrome/core-chrome-browser-internal/src/ui/header/elastic_mark.tsx + */ + customizedLogo?: string; + /** + * Custom replacement for favicon in PNG format + */ + faviconPNG?: string; } diff --git a/packages/core/custom-branding/core-custom-branding-common/index.js b/packages/core/custom-branding/core-custom-branding-common/index.js index 4e90e66b8247a..d92515c8edb6f 100644 --- a/packages/core/custom-branding/core-custom-branding-common/index.js +++ b/packages/core/custom-branding/core-custom-branding-common/index.js @@ -1,4 +1,3 @@ -"use strict"; /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -6,4 +5,4 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -Object.defineProperty(exports, "__esModule", { value: true }); +Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts index 42cd75f66e3c9..1167766e6ab8c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.d.ts @@ -1,3 +1,10 @@ -/// +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// / declare const _default: Cypress.ConfigOptions; export default _default; diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js index 68de0e34de7e6..4450c3f136a59 100644 --- a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.js @@ -1,41 +1,41 @@ -"use strict"; /* * 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. */ -Object.defineProperty(exports, "__esModule", { value: true }); -const cypress_config_1 = require("@kbn/cypress-config"); +Object.defineProperty(exports, '__esModule', { value: true }); +const cypress_config_1 = require('@kbn/cypress-config'); // eslint-disable-next-line @kbn/imports/no_boundary_crossing -const data_loaders_1 = require("./cypress/support/data_loaders"); +const data_loaders_1 = require('./cypress/support/data_loaders'); // eslint-disable-next-line import/no-default-export exports.default = (0, cypress_config_1.defineCypressConfig)({ - defaultCommandTimeout: 60000, - execTimeout: 120000, - pageLoadTimeout: 12000, - retries: { - runMode: 1, - openMode: 0, + defaultCommandTimeout: 60000, + execTimeout: 120000, + pageLoadTimeout: 12000, + retries: { + runMode: 1, + openMode: 0, + }, + screenshotsFolder: + '../../../target/kibana-security-solution/public/management/cypress/screenshots', + trashAssetsBeforeRuns: false, + video: false, + viewportHeight: 900, + viewportWidth: 1440, + experimentalStudio: true, + env: { + 'cypress-react-selector': { + root: '#security-solution-app', }, - screenshotsFolder: '../../../target/kibana-security-solution/public/management/cypress/screenshots', - trashAssetsBeforeRuns: false, - video: false, - viewportHeight: 900, - viewportWidth: 1440, - experimentalStudio: true, - env: { - 'cypress-react-selector': { - root: '#security-solution-app', - }, - }, - e2e: { - baseUrl: 'http://localhost:5620', - supportFile: 'public/management/cypress/support/e2e.ts', - specPattern: 'public/management/cypress/e2e/endpoint/*.cy.{js,jsx,ts,tsx}', - experimentalRunAllSpecs: true, - setupNodeEvents(on, config) { - (0, data_loaders_1.dataLoaders)(on, config); - }, + }, + e2e: { + baseUrl: 'http://localhost:5620', + supportFile: 'public/management/cypress/support/e2e.ts', + specPattern: 'public/management/cypress/e2e/endpoint/*.cy.{js,jsx,ts,tsx}', + experimentalRunAllSpecs: true, + setupNodeEvents(on, config) { + (0, data_loaders_1.dataLoaders)(on, config); }, + }, });