Skip to content

Commit

Permalink
add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Bamieh committed Apr 12, 2021
1 parent df928a9 commit 204134e
Showing 1 changed file with 102 additions and 3 deletions.
105 changes: 102 additions & 3 deletions src/plugins/usage_collection/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The way to report the usage of any feature depends on whether the actions to tra

In any case, to use any of these APIs, the plugin must optionally require the plugin `usageCollection`:


```json
// plugin/kibana.json
{
Expand Down Expand Up @@ -112,6 +113,104 @@ Not an API as such. However, Data Telemetry collects the usage of known patterns

This collector does not report the name of the indices nor any content. It only provides stats about usage of known shippers/ingest tools.

#### Usage Counters

Usage counters allows plugins to report user triggered events from the server. This api has feature parity with UI Counters on the `public` plugin side of usage_collection.

Usage counters provide instrumentation on the server to count triggered events such as "api called", "threshold reached", and miscellaneous events count.

It is useful for gathering _semi-aggregated_ events with a per day granularity.
This allows tracking trends in usage and provides enough granularity for this type of telemetry to provide insights such as
- "How many times this threshold has been reached"
- "What is the trend in usage of this api"
- "How frequent are users hitting this error per day"
- "What is the success rate of this operation"
- "Which option is being selected the most/least"

##### How to use it

To create a usage counter for your plugin, use the API `usageCollection.createUsageCounter` as follows:

```ts
// server/plugin.ts
import { Plugin, CoreStart } from '../../../core/public';
import { UsageCollectionSetup, UsageCounter } from '../../../plugins/usage_collection/server';

export class MyPlugin implements Plugin {
private usageCounter?: UsageCounter;
public setup(
core: CoreStart,
{ usageCollection }: { usageCollection?: UsageCollectionSetup }
) {

/**
* Create a usage counter for this plugin. Domain ID must be unique.
* It is advised to use the plugin name as the domain ID for most cases.
*/
this.usageCounter = usageCollection?.createUsageCounter('<Domain ID>');
try {
doSomeOperation();
this.usageCounter?.incrementCounter({
counterName: 'doSomeOperation_success',
incrementBy: 1,
});
} catch (err) {
this.usageCounter?.incrementCounter({
counterName: 'doSomeOperation_error',
counterType: 'error',
incrementBy: 1,
});
logger.error(err);
}
}
}
```

Pass the created `usageCounter` around in your service to instrument usage.

That's all you need to do! The Usage counters service will handle piping these counters all the way to the telemetry service.

##### Telemetry reported usage

Usage counters are reported inside the telemetry usage payload under `stack_stats.kibana.plugins.usage_counters`.

```ts
{
usage_counters: {
dailyEvents: [
{
domainId: '<Domain ID>',
counterName: 'doSomeOperation_success',
counterType: 'count',
lastUpdatedAt: '2021-11-20T11:43:00.961Z',
fromTimestamp: '2021-11-20T00:00:00Z',
total: 3,
},
{
domainId: '<Domain ID>',
counterName: 'doSomeOperation_success',
counterType: 'count',
lastUpdatedAt: '2021-11-21T10:30:00.961Z',
fromTimestamp: '2021-11-21T00:00:00Z',
total: 5,
},
{
domainId: '<Domain ID>',
counterName: 'doSomeOperation_error',
counterType: 'error',
lastUpdatedAt: '2021-11-20T11:43:00.961Z',
fromTimestamp: '2021-11-20T00:00:00Z',
total: 1,
},
],
},
}
```

##### Disallowed characters

The colon character (`:`) should not be used in the `counterType`. Colons play a special role for `counterType` in how metrics are stored as saved objects.

#### Custom collector

In many cases, plugins need to report the custom usage of a feature. In this cases, the plugins must complete the following 2 steps in the `setup` lifecycle step:
Expand Down Expand Up @@ -202,7 +301,7 @@ Some background:

- `isReady` (added in v7.2.0 and v6.8.4) is a way for a usage collector to announce that some async process must finish first before it can return data in the `fetch` method (e.g. a client needs to ne initialized, or the task manager needs to run a task first). If any collector reports that it is not ready when we call its `fetch` method, we reset a flag to try again and, after a set amount of time, collect data from those collectors that are ready and skip any that are not. This means that if a collector returns `true` for `isReady` and it actually isn't ready to return data, there won't be telemetry data from that collector in that telemetry report (usually once per day). You should consider what it means if your collector doesn't return data in the first few documents when Kibana starts or, if we should wait for any other reason (e.g. the task manager needs to run your task first). If you need to tell telemetry collection to wait, you should implement this function with custom logic. If your `fetch` method can run without the need of any previous dependencies, then you can return true for `isReady` as shown in the example below.

- The `fetch` method needs to support multiple contexts in which it is called. For example, when a user requests the example of what we collect in the **Kibana>Advanced Settings>Usage data** section, the clients provided in the context of the function (`CollectorFetchContext`) are scoped to that user's privileges. The reason is to avoid exposing via telemetry any data that user should not have access to (i.e.: if the user does not have access to certain indices, they shouldn't be allowed to see the number of documents that exists in it). In this case, the `fetch` method receives the clients `esClient` and `soClient` scoped to the user who performed the HTTP API request. Alternatively, when requesting the usage data to be reported to the Remote Telemetry Service, the clients are scoped to the internal Kibana user (`kibana_system`). Please, mind it might have lower-level access than the default super-admin `elastic` test user.
- The `fetch` method needs to support multiple contexts in which it is called. For example, when a user requests the example of what we collect in the **Kibana>Advanced Settings>Usage data** section, the clients provided in the context of the function (`CollectorFetchContext`) are scoped to that user's privileges. The reason is to avoid exposing via telemetry any data that user should not have access to (i.e.: if the user does not have access to certain indices, they shouldn't be allowed to see the number of documents that exists in it). In this case, the `fetch` method receives the clients `esClient` and `soClient` scoped to the user who performed the HTTP API request. Alternatively, when requesting the usage data to be reported to the Remote Telemetry Service, the clients are scoped to the internal Kibana user (`kibana_system`). Please, mind it might have lower-level access than the default super-admin `elastic` test user.
In some scenarios, your collector might need to maintain its own client. An example of that is the `monitoring` plugin, that maintains a connection to the Remote Monitoring Cluster to push its monitoring data. If that's the case, your plugin can opt-in to receive the additional `kibanaRequest` parameter by adding `extendFetchContext.kibanaRequest: true` to the collector's config: it will be appended to the context of the `fetch` method only if the request needs to be scoped to a user other than Kibana Internal, so beware that your collector will need to work for both scenarios (especially for the scenario when `kibanaRequest` is missing).

Note: there will be many cases where you won't need to use the `esClient` or `soClient` function that gets passed in to your `fetch` method at all. Your feature might have an accumulating value in server memory, or read something from the OS.
Expand Down Expand Up @@ -403,9 +502,9 @@ There are a few ways you can test that your usage collector is working properly.

## FAQ

1. **How should I design my data model?**
1. **How should I design my data model?**
Keep it simple, and keep it to a model that Kibana will be able to understand. Bear in mind the number of keys you are reporting as it may result in fields mapping explosion. Flat arrays, such as arrays of strings are fine.
2. **If I accumulate an event counter in server memory, which my fetch method returns, won't it reset when the Kibana server restarts?**
2. **If I accumulate an event counter in server memory, which my fetch method returns, won't it reset when the Kibana server restarts?**
Yes, but that is not a major concern. A visualization on such info might be a date histogram that gets events-per-second or something, which would be impacted by server restarts, so we'll have to offset the beginning of the time range when we detect that the latest metric is smaller than the earliest metric. That would be a pretty custom visualization, but perhaps future Kibana enhancements will be able to support that.

# Routes registered by this plugin
Expand Down

0 comments on commit 204134e

Please sign in to comment.