Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: remove usage for stats endpoint #151082

Merged
merged 13 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ describe('Files usage telemetry', () => {
request.post(root, `/api/files/shares/${fileKind}/${file3.id}`).send({}).expect(200),
]);

const { body } = await request.get(root, `/api/stats?extended=true&legacy=true`);
const { body } = await request
.post(root, '/api/telemetry/v2/clusters/_stats')
.send({ unencrypted: true });

expect(body.usage.files).toMatchInlineSnapshot(`
afharo marked this conversation as resolved.
Show resolved Hide resolved
expect(body[0].stats.stack_stats.kibana.plugins.files).toMatchInlineSnapshot(`
Object {
"countByExtension": Array [
Object {
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/usage_collection/server/routes/stats/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ However, the information detailed above can be extended, with the combination of

| Query Parameter | Default value | Description |
|:----------------|:-------------:|:------------|
|`extended`|`false`|When `true`, it adds `clusterUuid` and `usage`. The latter contains the information reported by all the Usage Collectors registered in the Kibana server. It may throw `503 Stats not ready` if any of the collectors is not fully initialized yet.|
|`legacy`|`false`|By default, when `extended=true`, the key names of the data in `usage` are transformed into API-friendlier `snake_case` format (i.e.: `clusterUuid` is transformed to `cluster_uuid`). When this parameter is `true`, the data is returned as-is.|
|`exclude_usage`|`false`|When `true`, and `extended=true`, it will report `clusterUuid` but no `usage`.|
|`extended`|`false`|When `true`, it adds `clusterUuid`.|
|`legacy`|`false`|By default, when `extended=true`, the key names are transformed into API-friendlier `snake_case` format (i.e.: `clusterUuid` is transformed to `cluster_uuid`). When this parameter is `true`, the data is returned as-is.|
|`exclude_usage`|`true`| Deprecated. Only kept for backward-compatibility. Setting this to `false` has no effect. Usage is always excluded. |

## Known use cases

Expand Down
73 changes: 14 additions & 59 deletions src/plugins/usage_collection/server/routes/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@

import { schema } from '@kbn/config-schema';
import { i18n } from '@kbn/i18n';
import defaultsDeep from 'lodash/defaultsDeep';
import { firstValueFrom, Observable } from 'rxjs';

import {
ElasticsearchClient,
IRouter,
type MetricsServiceSetup,
SavedObjectsClientContract,
ServiceStatus,
ServiceStatusLevels,
} from '@kbn/core/server';
Expand Down Expand Up @@ -51,14 +49,6 @@ export function registerStatsRoute({
metrics: MetricsServiceSetup;
overallStatus$: Observable<ServiceStatus>;
}) {
const getUsage = async (
esClient: ElasticsearchClient,
savedObjectsClient: SavedObjectsClientContract
): Promise<UsageObject> => {
const usage = await collectorSet.bulkFetchUsage(esClient, savedObjectsClient);
return collectorSet.toObject(usage);
};

const getClusterUuid = async (asCurrentUser: ElasticsearchClient): Promise<string> => {
const body = await asCurrentUser.info({ filter_path: 'cluster_uuid' });
const { cluster_uuid: uuid } = body;
Expand All @@ -77,69 +67,34 @@ export function registerStatsRoute({
extended: schema.oneOf([schema.literal(''), schema.boolean()], { defaultValue: false }),
legacy: schema.oneOf([schema.literal(''), schema.boolean()], { defaultValue: false }),
exclude_usage: schema.oneOf([schema.literal(''), schema.boolean()], {
defaultValue: false,
defaultValue: true,
}),
}),
},
},
async (context, req, res) => {
const isExtended = req.query.extended === '' || req.query.extended;
const isLegacy = req.query.legacy === '' || req.query.legacy;
const shouldGetUsage = req.query.exclude_usage === false;

let extended;
if (isExtended) {
const core = await context.core;
const { asCurrentUser } = core.elasticsearch.client;
const savedObjectsClient = core.savedObjects.client;

const [usage, clusterUuid] = await Promise.all([
shouldGetUsage
? getUsage(asCurrentUser, savedObjectsClient)
: Promise.resolve<UsageObject>({}),
getClusterUuid(asCurrentUser),
]);

let modifiedUsage = usage;
if (isLegacy) {
// 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.
modifiedUsage = Object.keys(usage).reduce((accum, usageKey) => {
if (usageKey === 'kibana') {
accum = {
...accum,
...usage[usageKey],
};
} else if (usageKey === 'reporting') {
accum = {
...accum,
xpack: {
...accum.xpack,
reporting: usage[usageKey],
},
};
} else {
// I don't think we need to it this for the above conditions, but do it for most as it will
// match the behavior done in monitoring/bulk_uploader
defaultsDeep(accum, { [usageKey]: usage[usageKey] });
}

return accum;
}, {} as UsageObject);
const usage = {} as UsageObject;
const clusterUuid = await getClusterUuid(asCurrentUser);

extended = {
usage: modifiedUsage,
clusterUuid,
};
} else {
extended = collectorSet.toApiFieldNames({
usage: modifiedUsage,
clusterUuid,
});
}
// 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,
});
}

// Guaranteed to resolve immediately due to replay effect on getOpsMetrics$
Expand Down
3 changes: 3 additions & 0 deletions test/api_integration/apis/stats/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default function ({ getService }) {
.then(({ body }) => {
expect(body.cluster_uuid).to.be.a('string');
expect(body.usage).to.be.an('object'); // no usage collectors have been registered so usage is an empty object
expect(body.usage).to.eql({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧡

assertStatsAndMetrics(body);
});
});
Expand All @@ -103,6 +104,7 @@ export default function ({ getService }) {
.then(({ body }) => {
expect(body.cluster_uuid).to.be.a('string');
expect(body.usage).to.be.an('object');
expect(body.usage).to.eql({});
assertStatsAndMetrics(body);
});
});
Expand All @@ -116,6 +118,7 @@ export default function ({ getService }) {
.then(({ body }) => {
expect(body.clusterUuid).to.be.a('string');
expect(body.usage).to.be.an('object'); // no usage collectors have been registered so usage is an empty object
expect(body.usage).to.eql({});
assertStatsAndMetrics(body, true);
});
});
Expand Down