mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Spaces] Telemetry for space solution property (#184192)
## Summary Added telemetry for space solution property. ### How to test ``` # Create a couple of spaces with solution POST kbn:/api/spaces/space { "name": "space with solution", "id": "my-space-solution-1", "description": "a description", "color": "#5c5959", "solution": "search", "disabledFeatures": [] } POST kbn:/api/spaces/space { "name": "space with solution", "id": "my-space-solution-2", "description": "a description", "color": "#5c5959", "solution": "search", "disabledFeatures": [] } POST kbn:/api/spaces/space { "name": "space with solution", "id": "my-space-solution-3", "description": "a description", "color": "#5c5959", "solution": "security", "disabledFeatures": [] } # Get stats data POST kbn:/internal/telemetry/clusters/_stats { "unencrypted": true, "refreshCache": true } ``` ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Fixes: https://github.com/elastic/kibana/issues/183641__ ## Release Note Added telemetry for space solution property. --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
10f61743ad
commit
b4238544ae
5 changed files with 132 additions and 5 deletions
|
@ -10410,7 +10410,7 @@
|
|||
"description": "Non-default value of setting."
|
||||
}
|
||||
},
|
||||
"observability:enableInfrastructureContainerAssetView":{
|
||||
"observability:enableInfrastructureContainerAssetView": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "Non-default value of setting."
|
||||
|
|
|
@ -112,6 +112,14 @@ const getMockedEsClient = () => {
|
|||
},
|
||||
],
|
||||
},
|
||||
solution: {
|
||||
buckets: [
|
||||
{
|
||||
key: 'search',
|
||||
doc_count: 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
return esClient;
|
||||
|
@ -161,6 +169,7 @@ describe('with a basic license', () => {
|
|||
disabledFeatures: {
|
||||
terms: { field: 'space.disabledFeatures', include: ['feature1', 'feature2'], size: 2 },
|
||||
},
|
||||
solution: { terms: { field: 'space.solution', missing: 'unset', size: 5 } },
|
||||
},
|
||||
query: { term: { type: { value: 'space' } } },
|
||||
size: 0,
|
||||
|
|
|
@ -46,6 +46,8 @@ async function getSpacesUsage(
|
|||
}
|
||||
|
||||
const knownFeatureIds = features.getKibanaFeatures().map((feature) => feature.id);
|
||||
const knownSolutions = ['classic', 'search', 'observability', 'security', 'unset'];
|
||||
|
||||
const resp = (await esClient.search({
|
||||
index: kibanaIndex,
|
||||
body: {
|
||||
|
@ -65,6 +67,13 @@ async function getSpacesUsage(
|
|||
size: knownFeatureIds.length,
|
||||
},
|
||||
},
|
||||
solution: {
|
||||
terms: {
|
||||
field: 'space.solution',
|
||||
size: knownSolutions.length,
|
||||
missing: 'unset',
|
||||
},
|
||||
},
|
||||
},
|
||||
size: 0,
|
||||
},
|
||||
|
@ -74,11 +83,17 @@ async function getSpacesUsage(
|
|||
|
||||
const count = hits?.total?.value ?? 0;
|
||||
const disabledFeatureBuckets = aggregations?.disabledFeatures?.buckets ?? [];
|
||||
const solutionBuckets = aggregations?.solution?.buckets ?? [];
|
||||
|
||||
const initialCounts = knownFeatureIds.reduce((acc, featureId) => {
|
||||
const initialCounts = knownFeatureIds.reduce<Record<string, number>>((acc, featureId) => {
|
||||
acc[featureId] = 0;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
}, {});
|
||||
|
||||
const initialSolutionCounts = knownSolutions.reduce<Record<string, number>>((acc, solution) => {
|
||||
acc[solution] = 0;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const disabledFeatures: Record<string, number> = disabledFeatureBuckets.reduce(
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
@ -89,6 +104,15 @@ async function getSpacesUsage(
|
|||
initialCounts
|
||||
);
|
||||
|
||||
const solutions = solutionBuckets.reduce<Record<string, number>>(
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
(acc, { key, doc_count }) => {
|
||||
acc[key] = doc_count;
|
||||
return acc;
|
||||
},
|
||||
initialSolutionCounts
|
||||
);
|
||||
|
||||
const usesFeatureControls = Object.values(disabledFeatures).some(
|
||||
(disabledSpaceCount) => disabledSpaceCount > 0
|
||||
);
|
||||
|
@ -97,6 +121,7 @@ async function getSpacesUsage(
|
|||
count,
|
||||
usesFeatureControls,
|
||||
disabledFeatures,
|
||||
solutions,
|
||||
} as UsageData;
|
||||
}
|
||||
|
||||
|
@ -117,6 +142,7 @@ export interface UsageData extends UsageStats {
|
|||
enabled: boolean;
|
||||
count?: number;
|
||||
usesFeatureControls?: boolean;
|
||||
solutions: Record<string, number>;
|
||||
disabledFeatures: {
|
||||
// "feature": number;
|
||||
[key: string]: number | undefined;
|
||||
|
@ -172,6 +198,38 @@ export function getSpacesUsageCollector(
|
|||
'Indicates if at least one feature is disabled in at least one space. This is a signal that space-level feature controls are in use. This does not account for role-based (security) feature controls.',
|
||||
},
|
||||
},
|
||||
solutions: {
|
||||
classic: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of spaces which have solution set to classic.',
|
||||
},
|
||||
},
|
||||
search: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of spaces which have solution set to search.',
|
||||
},
|
||||
},
|
||||
observability: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of spaces which have solution set to observability.',
|
||||
},
|
||||
},
|
||||
security: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of spaces which have solution set to security.',
|
||||
},
|
||||
},
|
||||
unset: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of spaces without solution set.',
|
||||
},
|
||||
},
|
||||
},
|
||||
disabledFeatures: {
|
||||
// "feature": number;
|
||||
DYNAMIC_KEY: {
|
||||
|
|
|
@ -15113,6 +15113,40 @@
|
|||
"description": "Indicates if at least one feature is disabled in at least one space. This is a signal that space-level feature controls are in use. This does not account for role-based (security) feature controls."
|
||||
}
|
||||
},
|
||||
"solutions": {
|
||||
"properties": {
|
||||
"classic": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of spaces which have solution set to classic."
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of spaces which have solution set to search."
|
||||
}
|
||||
},
|
||||
"observability": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of spaces which have solution set to observability."
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of spaces which have solution set to security."
|
||||
}
|
||||
},
|
||||
"unset": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of spaces without solution set."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"disabledFeatures": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
|
|
|
@ -14,7 +14,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const usageAPI = getService('usageAPI');
|
||||
|
||||
describe('Verify disabledFeatures telemetry payloads', async () => {
|
||||
beforeEach(async () => {
|
||||
before(async () => {
|
||||
await spacesService.create({
|
||||
id: 'space-1',
|
||||
name: 'space-1',
|
||||
|
@ -28,13 +28,24 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
name: 'space-2',
|
||||
description: 'This is your space-2!',
|
||||
color: '#00bfb3',
|
||||
solution: 'security',
|
||||
disabledFeatures: ['savedObjectsManagement', 'canvas', 'maps'],
|
||||
});
|
||||
|
||||
await spacesService.create({
|
||||
id: 'space-3',
|
||||
name: 'space-3',
|
||||
description: 'This is your space-3!',
|
||||
color: '#00bfb3',
|
||||
disabledFeatures: [],
|
||||
solution: 'search',
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
after(async () => {
|
||||
await spacesService.delete('space-1');
|
||||
await spacesService.delete('space-2');
|
||||
await spacesService.delete('space-3');
|
||||
});
|
||||
|
||||
it('includes only disabledFeatures findings', async () => {
|
||||
|
@ -83,5 +94,20 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
savedQueryManagement: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('includes only solution findings', async () => {
|
||||
const [{ stats }] = await usageAPI.getTelemetryStats({
|
||||
unencrypted: true,
|
||||
refreshCache: true,
|
||||
});
|
||||
|
||||
expect(stats.stack_stats.kibana.plugins.spaces.solutions).to.eql({
|
||||
security: 1,
|
||||
search: 1,
|
||||
observability: 0,
|
||||
classic: 0,
|
||||
unset: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue