Skip to content

Commit

Permalink
[EBT] Use UI/Usage Counters to report success telemetry about EBT (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
afharo authored May 9, 2022
1 parent dc38f08 commit 7f07d24
Show file tree
Hide file tree
Showing 17 changed files with 295 additions and 17 deletions.
3 changes: 2 additions & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pageLoadAssetSize:
fieldFormats: 65209
kibanaReact: 74422
share: 71239
uiActions: 35121
uiActions: 35121
embeddable: 87309
embeddableEnhanced: 22107
uiActionsEnhanced: 38494
Expand All @@ -128,3 +128,4 @@ pageLoadAssetSize:
screenshotting: 22870
synthetics: 40958
expressionXY: 29000
kibanaUsageCollection: 16463
29 changes: 15 additions & 14 deletions src/plugins/kibana_usage_collection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

This plugin registers the Platform Usage Collectors in Kibana.

| Collector name | Description | Extended documentation |
|----------------|:------------|:----------------------:|
| **Application Usage** | Measures how popular an App in Kibana is by reporting the on-screen time and the number of general clicks that happen in it. | [Link](./server/collectors/application_usage/README.md) |
| **Core Metrics** | Collects the usage reported by the core APIs | - |
| **Config Usage** | Reports the non-default values set via `kibana.yml` config file or CLI options. It `[redacts]` any potential PII-sensitive values. | [Link](./server/collectors/config_usage/README.md) |
| **User-changed UI Settings** | Reports all the UI Settings that have been overwritten by the user. It `[redacts]` any potential PII-sensitive values. | [Link](./server/collectors/management/README.md) |
| **CSP configuration** | Reports the key values regarding the CSP configuration. | - |
| **Kibana** | It reports the number of Saved Objects per type. It is limited to `dashboard`, `visualization`, `search`, `index-pattern`, `graph-workspace`.<br> It exists for legacy purposes, and may still be used by Monitoring via Metricbeat. | - |
| **Saved Objects Counts** | Number of Saved Objects per type. | - |
| **Localization data** | Localization settings: setup locale and installed translation files. | - |
| **Ops stats** | Operation metrics from the system. | - |
| **UI Counters** | Daily aggregation of the number of times an event occurs in the UI. | [Link](../usage_collection/README.mdx#ui-counters) |
| **UI Metrics** | Deprecated. Old form of UI Counters. It reports the _count of the repetitions since the cluster's first start_ of any UI events that may have happened. | - |
| **Usage Counters** | Daily aggregation of the number of times an event occurs on the Server. | [Link](../usage_collection/README.mdx#usage-counters) |
| Collector name | Description | Extended documentation |
|--------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------:|
| **Application Usage** | Measures how popular an App in Kibana is by reporting the on-screen time and the number of general clicks that happen in it. | [Link](./server/collectors/application_usage/README.md) |
| **Core Metrics** | Collects the usage reported by the core APIs | - |
| **Config Usage** | Reports the non-default values set via `kibana.yml` config file or CLI options. It `[redacts]` any potential PII-sensitive values. | [Link](./server/collectors/config_usage/README.md) |
| **User-changed UI Settings** | Reports all the UI Settings that have been overwritten by the user. It `[redacts]` any potential PII-sensitive values. | [Link](./server/collectors/management/README.md) |
| **CSP configuration** | Reports the key values regarding the CSP configuration. | - |
| **Kibana** | It reports the number of Saved Objects per type. It is limited to `dashboard`, `visualization`, `search`, `index-pattern`, `graph-workspace`.<br> It exists for legacy purposes, and may still be used by Monitoring via Metricbeat. | - |
| **Saved Objects Counts** | Number of Saved Objects per type. | - |
| **Localization data** | Localization settings: setup locale and installed translation files. | - |
| **Ops stats** | Operation metrics from the system. | - |
| **UI Counters** | Daily aggregation of the number of times an event occurs in the UI. | [Link](../usage_collection/README.mdx#ui-counters) |
| **UI Metrics** | Deprecated. Old form of UI Counters. It reports the _count of the repetitions since the cluster's first start_ of any UI events that may have happened. | - |
| **Usage Counters** | Daily aggregation of the number of times an event occurs on the Server. | [Link](../usage_collection/README.mdx#usage-counters) |
| **Event-based Telemetry Success Counters** | Using the UI and Usage Counters APIs, it reports the stats coming out of the `core.analytics.telemetryCounters$` observable. | [Browser](./public/ebt_counters/README.md) and [Server](./server/ebt_counters/README.md) |
2 changes: 1 addition & 1 deletion src/plugins/kibana_usage_collection/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"version": "kibana",
"server": true,
"ui": false,
"ui": true,
"requiredPlugins": [
"usageCollection"
],
Expand Down
14 changes: 14 additions & 0 deletions src/plugins/kibana_usage_collection/public/ebt_counters/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Event-based Telemetry Success Counters (browser-side)

Using the UI Counters API, it reports the stats coming from the `core.analytics.telemetryCounters$` observable. It allows us to track the success of the EBT client on the browser.

## Field mappings

As the number of fields available in the Usage API is reduced, this collection merges some fields to be able to report it.

| UI Counter field | Telemetry Counter fields |
|------------------|--------------------------------------------------------------------------------------------------|
| `appName` | Concatenation of the string `'ebt_counters.'` and the `source` (`'client'` or the shipper name). |
| `eventName` | Matches the `eventType`. |
| `counterType` | Concatenation of the `type` and the `code` (i.e.: `'succeeded_200'`). |
| `total` | Matches the value in `count`. |
Original file line number Diff line number Diff line change
@@ -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 { registerEbtCounters } from './register_ebt_counters';
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.
*/

import type { TelemetryCounter } from '@kbn/analytics-client';
import { TelemetryCounterType } from '@kbn/analytics-client';
import { coreMock } from '@kbn/core/public/mocks';
import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/public/mocks';
import { registerEbtCounters } from './register_ebt_counters';

describe('registerEbtCounters', () => {
let core: ReturnType<typeof coreMock.createSetup>;
let usageCollection: ReturnType<typeof usageCollectionPluginMock.createSetupContract>;
let internalListener: (counter: TelemetryCounter) => void;
let telemetryCounter$Spy: jest.SpyInstance;

beforeEach(() => {
core = coreMock.createSetup();
usageCollection = usageCollectionPluginMock.createSetupContract();
telemetryCounter$Spy = jest
.spyOn(core.analytics.telemetryCounter$, 'subscribe')
.mockImplementation(((listener) => {
internalListener = listener as (counter: TelemetryCounter) => void;
}) as typeof core.analytics.telemetryCounter$['subscribe']);
});

test('it subscribes to `analytics.telemetryCounters$`', () => {
registerEbtCounters(core.analytics, usageCollection);
expect(telemetryCounter$Spy).toHaveBeenCalledTimes(1);
});

test('it reports a UI counter whenever a counter is emitted', () => {
registerEbtCounters(core.analytics, usageCollection);
expect(telemetryCounter$Spy).toHaveBeenCalledTimes(1);
internalListener({
type: TelemetryCounterType.succeeded,
source: 'test-shipper',
event_type: 'test-event',
code: 'test-code',
count: 1,
});
expect(usageCollection.reportUiCounter).toHaveBeenCalledTimes(1);
expect(usageCollection.reportUiCounter).toHaveBeenCalledWith(
'ebt_counters.test-shipper',
'succeeded_test-code',
'test-event',
1
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.
*/

import type { AnalyticsServiceSetup } from '@kbn/core/public';
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';

export function registerEbtCounters(
analytics: AnalyticsServiceSetup,
usageCollection: UsageCollectionSetup
) {
// The client should complete telemetryCounter$ when shutting down. We shouldn't need to pipe(takeUntil(stop$)).
analytics.telemetryCounter$.subscribe(({ type, source, event_type: eventType, code, count }) => {
usageCollection.reportUiCounter(`ebt_counters.${source}`, `${type}_${code}`, eventType, count);
});
}
13 changes: 13 additions & 0 deletions src/plugins/kibana_usage_collection/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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.
*/

import { KibanaUsageCollectionPlugin } from './plugin';

export function plugin() {
return new KibanaUsageCollectionPlugin();
}
25 changes: 25 additions & 0 deletions src/plugins/kibana_usage_collection/public/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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.
*/

import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
import type { CoreSetup, Plugin } from '@kbn/core/public';
import { registerEbtCounters } from './ebt_counters';

interface KibanaUsageCollectionPluginsDepsSetup {
usageCollection: UsageCollectionSetup;
}

export class KibanaUsageCollectionPlugin implements Plugin {
public setup(coreSetup: CoreSetup, { usageCollection }: KibanaUsageCollectionPluginsDepsSetup) {
registerEbtCounters(coreSetup.analytics, usageCollection);
}

public start() {}

public stop() {}
}
14 changes: 14 additions & 0 deletions src/plugins/kibana_usage_collection/server/ebt_counters/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Event-based Telemetry Success Counters (server-side)

Using the Usage Counters API, it reports the stats coming from the `core.analytics.telemetryCounters$` observable. It allows us to track the success of the EBT client on the server side.

## Field mappings

As the number of fields available in the Usage API is reduced, this collection merges some fields to be able to report it.

| Usage Counter field | Telemetry Counter fields |
|---------------------|--------------------------------------------------------------------------------------------------|
| `domainId` | Concatenation of the string `'ebt_counters.'` and the `source` (`'client'` or the shipper name). |
| `counterName` | Matches the `eventType`. |
| `counterType` | Concatenation of the `type` and the `code` (i.e.: `'succeeded_200'`). |
| `total` | Matches the value in `count`. |
Original file line number Diff line number Diff line change
@@ -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 { registerEbtCounters } from './register_ebt_counters';
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 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.
*/

import type { TelemetryCounter } from '@kbn/analytics-client';
import { TelemetryCounterType } from '@kbn/analytics-client';
import { coreMock } from '@kbn/core/server/mocks';
import { createUsageCollectionSetupMock } from '@kbn/usage-collection-plugin/server/mocks';
import { registerEbtCounters } from './register_ebt_counters';

describe('registerEbtCounters', () => {
let core: ReturnType<typeof coreMock.createSetup>;
let usageCollection: ReturnType<typeof createUsageCollectionSetupMock>;
let internalListener: (counter: TelemetryCounter) => void;
let telemetryCounter$Spy: jest.SpyInstance;

beforeEach(() => {
core = coreMock.createSetup();
usageCollection = createUsageCollectionSetupMock();
telemetryCounter$Spy = jest
.spyOn(core.analytics.telemetryCounter$, 'subscribe')
.mockImplementation(((listener) => {
internalListener = listener as (counter: TelemetryCounter) => void;
}) as typeof core.analytics.telemetryCounter$['subscribe']);
});

test('it subscribes to `analytics.telemetryCounters$`', () => {
registerEbtCounters(core.analytics, usageCollection);
expect(telemetryCounter$Spy).toHaveBeenCalledTimes(1);
});

test('it creates a new usageCounter when it does not exist', () => {
registerEbtCounters(core.analytics, usageCollection);
expect(telemetryCounter$Spy).toHaveBeenCalledTimes(1);
internalListener({
type: TelemetryCounterType.succeeded,
source: 'test-shipper',
event_type: 'test-event',
code: 'test-code',
count: 1,
});
expect(usageCollection.getUsageCounterByType).toHaveBeenCalledTimes(1);
expect(usageCollection.getUsageCounterByType).toHaveBeenCalledWith('ebt_counters.test-shipper');
expect(usageCollection.createUsageCounter).toHaveBeenCalledTimes(1);
expect(usageCollection.createUsageCounter).toHaveBeenCalledWith('ebt_counters.test-shipper');
});

test('it reuses the usageCounter when it already exists', () => {
const incrementCounterMock = jest.fn();
usageCollection.getUsageCounterByType.mockReturnValue({
incrementCounter: incrementCounterMock,
});
registerEbtCounters(core.analytics, usageCollection);
expect(telemetryCounter$Spy).toHaveBeenCalledTimes(1);
internalListener({
type: TelemetryCounterType.succeeded,
source: 'test-shipper',
event_type: 'test-event',
code: 'test-code',
count: 1,
});
expect(usageCollection.getUsageCounterByType).toHaveBeenCalledTimes(1);
expect(usageCollection.getUsageCounterByType).toHaveBeenCalledWith('ebt_counters.test-shipper');
expect(usageCollection.createUsageCounter).toHaveBeenCalledTimes(0);
expect(incrementCounterMock).toHaveBeenCalledTimes(1);
expect(incrementCounterMock).toHaveBeenCalledWith({
counterName: 'test-event',
counterType: `succeeded_test-code`,
incrementBy: 1,
});
});
});
Loading

0 comments on commit 7f07d24

Please sign in to comment.