diff --git a/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts b/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts index 41cbfc2a12000..ca6049885b298 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts @@ -8,20 +8,25 @@ import type { SavedObjectsFindResponse } from '@kbn/core/server'; import { savedObjectsRepositoryMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { ESCaseStatus } from '../../services/cases/types'; -import type { CaseAggregationResult } from '../types'; +import type { + AttachmentAggregationResult, + AttachmentFrameworkAggsResult, + CaseAggregationResult, + FileAttachmentAggregationResult, +} from '../types'; import { getCasesTelemetryData } from './cases'; +const MOCK_FIND_TOTAL = 5; +const SOLUTION_TOTAL = 1; + describe('getCasesTelemetryData', () => { describe('getCasesTelemetryData', () => { const logger = loggingSystemMock.createLogger(); const savedObjectsClient = savedObjectsRepositoryMock.create(); - const mockFind = ( - aggs: Record = {}, - so: SavedObjectsFindResponse['saved_objects'] = [] - ) => { + const mockFind = (aggs: object, so: SavedObjectsFindResponse['saved_objects'] = []) => { savedObjectsClient.find.mockResolvedValueOnce({ - total: 5, + total: MOCK_FIND_TOTAL, saved_objects: so, per_page: 1, page: 1, @@ -103,22 +108,100 @@ describe('getCasesTelemetryData', () => { buckets: [ { key: 'observability', - doc_count: 1, + doc_count: SOLUTION_TOTAL, }, { key: 'securitySolution', - doc_count: 1, + doc_count: SOLUTION_TOTAL, }, { key: 'cases', - doc_count: 1, + doc_count: SOLUTION_TOTAL, }, ], }, }; + const attachmentFramework: AttachmentFrameworkAggsResult = { + externalReferenceTypes: { + buckets: [ + { + doc_count: 5, + key: '.osquery', + references: { + cases: { + max: { + value: 10, + }, + }, + }, + }, + { + doc_count: 5, + key: '.files', + references: { + cases: { + max: { + value: 10, + }, + }, + }, + }, + ], + }, + persistableReferenceTypes: { + buckets: [ + { + doc_count: 5, + key: '.ml', + references: { + cases: { + max: { + value: 10, + }, + }, + }, + }, + { + doc_count: 5, + key: '.files', + references: { + cases: { + max: { + value: 10, + }, + }, + }, + }, + ], + }, + }; + + const attachmentAggsResult: AttachmentAggregationResult = { + securitySolution: { ...attachmentFramework }, + observability: { ...attachmentFramework }, + cases: { ...attachmentFramework }, + participants: { + value: 2, + }, + ...attachmentFramework, + }; + + const filesRes: FileAttachmentAggregationResult = { + securitySolution: { + averageSize: 500, + }, + observability: { + averageSize: 500, + }, + cases: { + averageSize: 500, + }, + averageSize: 500, + }; + mockFind(caseAggsResult); - mockFind({ participants: { value: 2 } }); + mockFind(attachmentAggsResult); mockFind({ references: { referenceType: { referenceAgg: { value: 3 } } } }); mockFind({ references: { referenceType: { referenceAgg: { value: 4 } } } }); mockSavedObjectResponse({ @@ -130,6 +213,7 @@ describe('getCasesTelemetryData', () => { mockSavedObjectResponse({ closed_at: '2022-03-08T12:24:11.429Z', }); + mockFind(filesRes); }; beforeEach(() => { @@ -139,10 +223,62 @@ describe('getCasesTelemetryData', () => { it('it returns the correct res', async () => { mockResponse(); + const attachmentFramework = (total: number, average: number) => { + return { + attachmentFramework: { + externalAttachments: [ + { + average, + maxOnACase: 10, + total, + type: '.osquery', + }, + { + average, + maxOnACase: 10, + total, + type: '.files', + }, + ], + persistableAttachments: [ + { + average, + maxOnACase: 10, + total, + type: '.ml', + }, + { + average, + maxOnACase: 10, + total, + type: '.files', + }, + ], + files: { + averageSize: 500, + average, + maxOnACase: 10, + total, + }, + }, + }; + }; + const res = await getCasesTelemetryData({ savedObjectsClient, logger }); + + const allAttachmentsTotal = 5; + const allAttachmentsAverage = allAttachmentsTotal / MOCK_FIND_TOTAL; + + const solutionAttachmentsTotal = 5; + const solutionAttachmentsAverage = solutionAttachmentsTotal / SOLUTION_TOTAL; + const solutionAttachmentFrameworkStats = attachmentFramework( + solutionAttachmentsTotal, + solutionAttachmentsAverage + ); + expect(res).toEqual({ all: { - total: 5, + total: MOCK_FIND_TOTAL, daily: 3, weekly: 2, monthly: 1, @@ -168,6 +304,7 @@ describe('getCasesTelemetryData', () => { totalWithZero: 100, totalWithAtLeastOne: 0, }, + ...attachmentFramework(allAttachmentsTotal, allAttachmentsAverage), }, main: { assignees: { @@ -175,6 +312,7 @@ describe('getCasesTelemetryData', () => { totalWithZero: 100, totalWithAtLeastOne: 0, }, + ...solutionAttachmentFrameworkStats, total: 1, daily: 3, weekly: 2, @@ -186,6 +324,7 @@ describe('getCasesTelemetryData', () => { totalWithZero: 100, totalWithAtLeastOne: 0, }, + ...solutionAttachmentFrameworkStats, total: 1, daily: 3, weekly: 2, @@ -197,6 +336,7 @@ describe('getCasesTelemetryData', () => { totalWithZero: 100, totalWithAtLeastOne: 0, }, + ...solutionAttachmentFrameworkStats, total: 1, daily: 3, weekly: 2, @@ -468,18 +608,311 @@ describe('getCasesTelemetryData', () => { } `); - expect(savedObjectsClient.find.mock.calls[1][0]).toEqual({ - aggs: { - participants: { - cardinality: { - field: 'cases-comments.attributes.created_by.username', + expect(savedObjectsClient.find.mock.calls[1][0]).toMatchInlineSnapshot(` + Object { + "aggs": Object { + "cases": Object { + "aggs": Object { + "externalReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.externalReferenceAttachmentTypeId", + }, + }, + "persistableReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.persistableStateAttachmentTypeId", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.attributes.owner": "cases", + }, + }, + }, + "externalReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.externalReferenceAttachmentTypeId", + }, + }, + "observability": Object { + "aggs": Object { + "externalReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.externalReferenceAttachmentTypeId", + }, + }, + "persistableReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.persistableStateAttachmentTypeId", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.attributes.owner": "observability", + }, + }, + }, + "participants": Object { + "cardinality": Object { + "field": "cases-comments.attributes.created_by.username", + }, + }, + "persistableReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.persistableStateAttachmentTypeId", + }, + }, + "securitySolution": Object { + "aggs": Object { + "externalReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.externalReferenceAttachmentTypeId", + }, + }, + "persistableReferenceTypes": Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "cases": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-comments.references.id", + }, + }, + "max": Object { + "max_bucket": Object { + "buckets_path": "ids._count", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.references.type": "cases", + }, + }, + }, + }, + "nested": Object { + "path": "cases-comments.references", + }, + }, + }, + "terms": Object { + "field": "cases-comments.attributes.persistableStateAttachmentTypeId", + }, + }, + }, + "filter": Object { + "term": Object { + "cases-comments.attributes.owner": "securitySolution", + }, + }, }, }, - }, - page: 0, - perPage: 0, - type: 'cases-comments', - }); + "page": 0, + "perPage": 0, + "type": "cases-comments", + } + `); expect(savedObjectsClient.find.mock.calls[2][0]).toEqual({ aggs: { @@ -582,6 +1015,78 @@ describe('getCasesTelemetryData', () => { type: 'cases', }); } + + expect(savedObjectsClient.find.mock.calls[7][0]).toMatchInlineSnapshot(` + Object { + "aggs": Object { + "averageSize": Object { + "avg": Object { + "field": "file.attributes.size", + }, + }, + "cases": Object { + "aggs": Object { + "averageSize": Object { + "avg": Object { + "field": "file.attributes.size", + }, + }, + }, + "filter": Object { + "term": Object { + "file.attributes.Meta.owner": "cases", + }, + }, + }, + "observability": Object { + "aggs": Object { + "averageSize": Object { + "avg": Object { + "field": "file.attributes.size", + }, + }, + }, + "filter": Object { + "term": Object { + "file.attributes.Meta.owner": "observability", + }, + }, + }, + "securitySolution": Object { + "aggs": Object { + "averageSize": Object { + "avg": Object { + "field": "file.attributes.size", + }, + }, + }, + "filter": Object { + "term": Object { + "file.attributes.Meta.owner": "securitySolution", + }, + }, + }, + }, + "filter": Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "file.attributes.Meta.caseId", + }, + Object { + "type": "wildcard", + "value": "@kuery-wildcard@", + }, + ], + "function": "is", + "type": "function", + }, + "page": 0, + "perPage": 0, + "type": "file", + } + `); }); }); }); diff --git a/x-pack/plugins/cases/server/telemetry/queries/cases.ts b/x-pack/plugins/cases/server/telemetry/queries/cases.ts index 29868c5129cdb..a918089cbe0e6 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/cases.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/cases.ts @@ -28,6 +28,7 @@ import type { import { findValueInBuckets, getAggregationsBuckets, + getAttachmentsFrameworkStats, getCountsAggregationQuery, getCountsFromBuckets, getMaxBucketOnCaseAggregationQuery, @@ -56,9 +57,9 @@ export const getLatestCasesDates = async ({ ]); return { - createdAt: savedObjects?.[0].saved_objects?.[0].attributes?.created_at ?? null, - updatedAt: savedObjects?.[1].saved_objects?.[0].attributes?.updated_at ?? null, - closedAt: savedObjects?.[2].saved_objects?.[0].attributes?.closed_at ?? null, + createdAt: savedObjects?.[0]?.saved_objects?.[0]?.attributes?.created_at ?? null, + updatedAt: savedObjects?.[1]?.saved_objects?.[0]?.attributes?.updated_at ?? null, + closedAt: savedObjects?.[2]?.saved_objects?.[0]?.attributes?.closed_at ?? null, }; }; @@ -66,8 +67,6 @@ export const getCasesTelemetryData = async ({ savedObjectsClient, logger, }: CollectTelemetryDataParams): Promise => { - console.log('*****collecting telemetry'); - try { const [casesRes, commentsRes, totalAlertsRes, totalConnectorsRes, latestDates, filesRes] = await Promise.all([ @@ -79,15 +78,17 @@ export const getCasesTelemetryData = async ({ getFilesTelemetry(savedObjectsClient), ]); - console.log('****finished collection telemetry'); - console.log('casesRes ', JSON.stringify(casesRes, null, 2)); - console.log('filesRes ', JSON.stringify(filesRes, null, 2)); - const aggregationsBuckets = getAggregationsBuckets({ aggs: casesRes.aggregations, keys: ['counts', 'syncAlerts', 'status', 'users', 'totalAssignees'], }); + const allAttachmentFrameworkStats = getAttachmentsFrameworkStats({ + attachmentAggregations: commentsRes.aggregations, + totalCasesForOwner: casesRes.total, + filesAggregations: filesRes.aggregations, + }); + return { all: { total: casesRes.total, @@ -113,6 +114,7 @@ export const getCasesTelemetryData = async ({ totalWithAtLeastOne: casesRes.aggregations?.assigneeFilters.buckets.atLeastOne.doc_count ?? 0, }, + ...allAttachmentFrameworkStats, }, sec: getSolutionValues({ caseAggregations: casesRes.aggregations, @@ -228,6 +230,25 @@ const getAssigneesAggregations = () => ({ const getCommentsSavedObjectTelemetry = async ( savedObjectsClient: ISavedObjectsRepository ): Promise> => { + const attachmentRegistries = () => ({ + externalReferenceTypes: { + terms: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.externalReferenceAttachmentTypeId`, + }, + aggs: { + ...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT), + }, + }, + persistableReferenceTypes: { + terms: { + field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.persistableStateAttachmentTypeId`, + }, + aggs: { + ...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT), + }, + }, + }); + const attachmentsByOwnerAggregationQuery = OWNERS.reduce( (aggQuery, owner) => ({ ...aggQuery, @@ -238,36 +259,20 @@ const getCommentsSavedObjectTelemetry = async ( }, }, aggs: { - externalReferenceTypes: { - terms: { - field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.externalReferenceAttachmentTypeId`, - }, - aggs: { - ...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT), - }, - }, - persistableReferenceTypes: { - terms: { - field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.persistableStateAttachmentTypeId`, - }, - aggs: { - ...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT), - }, - }, + ...attachmentRegistries(), }, }, }), {} ); - console.log('****collecting attachments telemetry'); - return savedObjectsClient.find({ page: 0, perPage: 0, type: CASE_COMMENT_SAVED_OBJECT, aggs: { ...attachmentsByOwnerAggregationQuery, + ...attachmentRegistries(), participants: { cardinality: { field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.created_by.username`, @@ -280,6 +285,14 @@ const getCommentsSavedObjectTelemetry = async ( const getFilesTelemetry = async ( savedObjectsClient: ISavedObjectsRepository ): Promise> => { + const averageSize = () => ({ + averageSize: { + avg: { + field: `${FILE_SO_TYPE}.attributes.size`, + }, + }, + }); + const filesByOwnerAggregationQuery = OWNERS.reduce( (aggQuery, owner) => ({ ...aggQuery, @@ -290,11 +303,7 @@ const getFilesTelemetry = async ( }, }, aggs: { - averageSize: { - avg: { - field: `${FILE_SO_TYPE}.attributes.size`, - }, - }, + ...averageSize(), }, }, }), @@ -307,8 +316,8 @@ const getFilesTelemetry = async ( page: 0, perPage: 0, type: FILE_SO_TYPE, - // filter: filterCaseIdExists, - aggs: filesByOwnerAggregationQuery, + filter: filterCaseIdExists, + aggs: { ...filesByOwnerAggregationQuery, ...averageSize() }, }); }; diff --git a/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts b/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts index a9a8732bd8982..d7c6a0e9bf7b9 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts @@ -165,6 +165,7 @@ describe('utils', () => { participants: { value: 5, }, + ...attachmentFramework, }; const filesRes: FileAttachmentAggregationResult = { @@ -177,6 +178,7 @@ describe('utils', () => { cases: { averageSize: 500, }, + averageSize: 500, }; it('constructs the solution values correctly', () => { @@ -353,8 +355,7 @@ describe('utils', () => { describe('getAttachmentsFrameworkStats', () => { it('returns empty stats if the aggregation is undefined', () => { - expect(getAttachmentsFrameworkStats({ totalCasesForOwner: 0, owner: 'securitySolution' })) - .toMatchInlineSnapshot(` + expect(getAttachmentsFrameworkStats({ totalCasesForOwner: 0 })).toMatchInlineSnapshot(` Object { "attachmentFramework": Object { "externalAttachments": Array [], @@ -403,20 +404,10 @@ describe('utils', () => { }, }; - const aggs: AttachmentAggregationResult = { - securitySolution: { ...attachmentFramework }, - observability: { ...attachmentFramework }, - cases: { ...attachmentFramework }, - participants: { - value: 1, - }, - }; - it('populates the externalAttachments array', () => { const stats = getAttachmentsFrameworkStats({ - attachmentAggregations: aggs, + attachmentAggregations: attachmentFramework, totalCasesForOwner: 5, - owner: 'securitySolution', }); expect(stats.attachmentFramework.externalAttachments[0]).toEqual({ @@ -470,20 +461,10 @@ describe('utils', () => { }, }; - const aggs: AttachmentAggregationResult = { - securitySolution: { ...attachmentFramework }, - observability: { ...attachmentFramework }, - cases: { ...attachmentFramework }, - participants: { - value: 1, - }, - }; - it('populates the externalAttachments array', () => { const stats = getAttachmentsFrameworkStats({ - attachmentAggregations: aggs, + attachmentAggregations: attachmentFramework, totalCasesForOwner: 5, - owner: 'securitySolution', }); expect(stats.attachmentFramework.persistableAttachments[0]).toEqual({ @@ -527,33 +508,11 @@ describe('utils', () => { }, }; - const aggs: AttachmentAggregationResult = { - securitySolution: { ...attachmentFramework }, - observability: { ...attachmentFramework }, - cases: { ...attachmentFramework }, - participants: { - value: 1, - }, - }; - - const filesRes: FileAttachmentAggregationResult = { - securitySolution: { - averageSize: 500, - }, - observability: { - averageSize: 500, - }, - cases: { - averageSize: 500, - }, - }; - expect( getAttachmentsFrameworkStats({ - attachmentAggregations: aggs, + attachmentAggregations: attachmentFramework, totalCasesForOwner: 5, - filesAggregations: filesRes, - owner: 'securitySolution', + filesAggregations: { averageSize: 500 }, }).attachmentFramework.files ).toMatchInlineSnapshot(` Object { @@ -587,33 +546,11 @@ describe('utils', () => { }, }; - const aggs: AttachmentAggregationResult = { - securitySolution: { ...attachmentFramework }, - observability: { ...attachmentFramework }, - cases: { ...attachmentFramework }, - participants: { - value: 1, - }, - }; - - const filesRes: FileAttachmentAggregationResult = { - securitySolution: { - averageSize: 500, - }, - observability: { - averageSize: 500, - }, - cases: { - averageSize: 500, - }, - }; - expect( getAttachmentsFrameworkStats({ - attachmentAggregations: aggs, - filesAggregations: filesRes, + attachmentAggregations: attachmentFramework, + filesAggregations: { averageSize: 500 }, totalCasesForOwner: 5, - owner: 'securitySolution', }).attachmentFramework.files ).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/cases/server/telemetry/queries/utils.ts b/x-pack/plugins/cases/server/telemetry/queries/utils.ts index de578cc27013c..43b5149e6333d 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/utils.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/utils.ts @@ -25,6 +25,8 @@ import type { AttachmentStats, FileAttachmentStats, FileAttachmentAggregationResult, + FileAttachmentAverageSize, + AttachmentFrameworkAggsResult, } from '../types'; import { buildFilter } from '../../client/utils'; import type { Owner } from '../../../common/constants/types'; @@ -178,15 +180,16 @@ export const getSolutionValues = ({ }); const totalCasesForOwner = findValueInBuckets(aggregationsBuckets.totalsByOwner, owner); + const attachmentsAggsForOwner = attachmentAggregations?.[owner]; + const fileAttachmentsForOwner = filesAggregations?.[owner]; return { total: totalCasesForOwner, ...getCountsFromBuckets(aggregationsBuckets[`${owner}.counts`]), ...getAttachmentsFrameworkStats({ - attachmentAggregations, - filesAggregations, + attachmentAggregations: attachmentsAggsForOwner, + filesAggregations: fileAttachmentsForOwner, totalCasesForOwner, - owner, }), assignees: { total: caseAggregations?.[owner].totalAssignees.value ?? 0, @@ -219,31 +222,28 @@ export const getAttachmentsFrameworkStats = ({ attachmentAggregations, filesAggregations, totalCasesForOwner, - owner, }: { - attachmentAggregations?: AttachmentAggregationResult; - filesAggregations?: FileAttachmentAggregationResult; + attachmentAggregations?: AttachmentFrameworkAggsResult; + filesAggregations?: FileAttachmentAverageSize; totalCasesForOwner: number; - owner: Owner; }): AttachmentFramework => { if (!attachmentAggregations) { return emptyAttachmentFramework(); } - const attachmentOwnerStats = attachmentAggregations[owner]; - const averageFileSize = filesAggregations?.[owner]?.averageSize; + const averageFileSize = filesAggregations?.averageSize; return { attachmentFramework: { externalAttachments: getAttachmentRegistryStats( - attachmentOwnerStats.externalReferenceTypes, + attachmentAggregations.externalReferenceTypes, totalCasesForOwner ), persistableAttachments: getAttachmentRegistryStats( - attachmentOwnerStats.persistableReferenceTypes, + attachmentAggregations.persistableReferenceTypes, totalCasesForOwner ), files: getFileAttachmentStats({ - registryResults: attachmentOwnerStats.externalReferenceTypes, + registryResults: attachmentAggregations.externalReferenceTypes, averageFileSize, totalCasesForOwner, }), @@ -349,6 +349,7 @@ export const getTelemetryDataEmptyState = (): CasesTelemetry => ({ updatedAt: null, closedAt: null, }, + ...emptyAttachmentFramework(), }, sec: { total: 0, diff --git a/x-pack/plugins/cases/server/telemetry/schema.ts b/x-pack/plugins/cases/server/telemetry/schema.ts index f21599e298237..7e04c070ac3aa 100644 --- a/x-pack/plugins/cases/server/telemetry/schema.ts +++ b/x-pack/plugins/cases/server/telemetry/schema.ts @@ -76,6 +76,7 @@ export const casesSchema: CasesTelemetrySchema = { cases: { all: { ...countSchema, + attachmentFramework: attachmentFrameworkSchema, assignees: assigneesSchema, status: statusSchema, syncAlertsOn: long, diff --git a/x-pack/plugins/cases/server/telemetry/types.ts b/x-pack/plugins/cases/server/telemetry/types.ts index 59a57d6fd655c..e2af2519b1e95 100644 --- a/x-pack/plugins/cases/server/telemetry/types.ts +++ b/x-pack/plugins/cases/server/telemetry/types.ts @@ -61,7 +61,8 @@ export interface FileAttachmentAverageSize { averageSize: number; } -export type FileAttachmentAggregationResult = Record; +export type FileAttachmentAggregationResult = Record & + FileAttachmentAverageSize; export interface BucketsWithMaxOnCase { buckets: Array< @@ -79,7 +80,7 @@ export interface AttachmentFrameworkAggsResult { export type AttachmentAggregationResult = Record & { participants: Cardinality; -}; +} & AttachmentFrameworkAggsResult; export type CaseAggregationResult = Record< Owner, @@ -145,18 +146,19 @@ export interface LatestDates { export interface CasesTelemetry { cases: { - all: Count & { - assignees: Assignees; - status: Status; - syncAlertsOn: number; - syncAlertsOff: number; - totalUsers: number; - totalParticipants: number; - totalTags: number; - totalWithAlerts: number; - totalWithConnectors: number; - latestDates: LatestDates; - }; + all: Count & + AttachmentFramework & { + assignees: Assignees; + status: Status; + syncAlertsOn: number; + syncAlertsOff: number; + totalUsers: number; + totalParticipants: number; + totalTags: number; + totalWithAlerts: number; + totalWithConnectors: number; + latestDates: LatestDates; + }; sec: SolutionTelemetry; obs: SolutionTelemetry; main: SolutionTelemetry; diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 99e466ebbb357..5a08e6af7930a 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4796,6 +4796,36 @@ } } }, + "attachmentFramework": { + "properties": { + "persistableAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "externalAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "files": { + "properties": { + "average": "long", + "averageSize": "long", + "maxOnACase": "long", + "total": "long" + } + } + } + }, "status": { "properties": { "open": { @@ -4871,6 +4901,36 @@ "type": "long" } } + }, + "attachmentFramework": { + "properties": { + "persistableAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "externalAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "files": { + "properties": { + "average": "long", + "averageSize": "long", + "maxOnACase": "long", + "total": "long" + } + } + } } } }, @@ -4900,6 +4960,36 @@ "type": "long" } } + }, + "attachmentFramework": { + "properties": { + "persistableAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "externalAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "files": { + "properties": { + "average": "long", + "averageSize": "long", + "maxOnACase": "long", + "total": "long" + } + } + } } } }, @@ -4929,6 +5019,36 @@ "type": "long" } } + }, + "attachmentFramework": { + "properties": { + "persistableAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "externalAttachments": { + "type": "array", + "items": { + "average": "long", + "maxOnACase": "long", + "total": "long", + "type": "string" + } + }, + "files": { + "properties": { + "average": "long", + "averageSize": "long", + "maxOnACase": "long", + "total": "long" + } + } + } } } }