From fe9985b5669b55f6c4792a9c4de8dc8ada25a64c Mon Sep 17 00:00:00 2001
From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com>
Date: Thu, 13 Apr 2023 08:23:02 -0400
Subject: [PATCH] [Cases] Adding mime type telemetry (#154679)
This PR adds telemetry for collecting statistics for the mimetypes of
the files uploaded to cases.
It only looks for the top 20 mime types using a terms aggregation. It
does this across all cases and broken down by owner. On the telemetry
server we'll need to create a single document per entry in the array
here so we can do filtering for the visualizations.
Example
```
"topMimeTypes": [
{
"count": 2,
"name": "image/png"
},
{
"count": 1,
"name": "application/json"
},
{
"count": 1,
"name": "text/plain"
}
]
```
Example telemetry result
"cases": {
"cases": {
"all": {
"total": 1,
"daily": 1,
"weekly": 1,
"monthly": 1,
"status": {
"open": 1,
"inProgress": 0,
"closed": 0
},
"syncAlertsOn": 1,
"syncAlertsOff": 0,
"totalUsers": 1,
"totalParticipants": 1,
"totalTags": 1,
"totalWithAlerts": 0,
"totalWithConnectors": 0,
"latestDates": {
"createdAt": "2023-04-11T16:07:00.565Z",
"updatedAt": "2023-04-11T16:07:17.712Z",
"closedAt": ""
},
"assignees": {
"total": 0,
"totalWithZero": 1,
"totalWithAtLeastOne": 0
},
"attachmentFramework": {
"externalAttachments": [
{
"type": ".files",
"average": 4,
"maxOnACase": 4,
"total": 4
}
],
"persistableAttachments": [],
"files": {
"averageSize": 3,
"average": 4,
"maxOnACase": 4,
"total": 4,
"topMimeTypes": [
{
"count": 2,
"name": "image/png"
},
{
"count": 1,
"name": "application/json"
},
{
"count": 1,
"name": "text/plain"
}
]
}
}
},
"sec": {
"total": 0,
"daily": 0,
"weekly": 0,
"monthly": 0,
"attachmentFramework": {
"externalAttachments": [],
"persistableAttachments": [],
"files": {
"averageSize": 0,
"average": 0,
"maxOnACase": 0,
"total": 0,
"topMimeTypes": []
}
},
"assignees": {
"total": 0,
"totalWithZero": 0,
"totalWithAtLeastOne": 0
}
},
"obs": {
"total": 0,
"daily": 0,
"weekly": 0,
"monthly": 0,
"attachmentFramework": {
"externalAttachments": [],
"persistableAttachments": [],
"files": {
"averageSize": 0,
"average": 0,
"maxOnACase": 0,
"total": 0,
"topMimeTypes": []
}
},
"assignees": {
"total": 0,
"totalWithZero": 0,
"totalWithAtLeastOne": 0
}
},
"main": {
"total": 1,
"daily": 1,
"weekly": 1,
"monthly": 1,
"attachmentFramework": {
"externalAttachments": [
{
"type": ".files",
"average": 4,
"maxOnACase": 4,
"total": 4
}
],
"persistableAttachments": [],
"files": {
"averageSize": 3,
"average": 4,
"maxOnACase": 4,
"total": 4,
"topMimeTypes": [
{
"count": 2,
"name": "image/png"
},
{
"count": 1,
"name": "application/json"
},
{
"count": 1,
"name": "text/plain"
}
]
}
},
"assignees": {
"total": 0,
"totalWithZero": 1,
"totalWithAtLeastOne": 0
}
}
},
"userActions": {
"all": {
"total": 5,
"daily": 5,
"weekly": 5,
"monthly": 5,
"maxOnACase": 5
}
},
"comments": {
"all": {
"total": 0,
"daily": 0,
"weekly": 0,
"monthly": 0,
"maxOnACase": 0
}
},
"alerts": {
"all": {
"total": 0,
"daily": 0,
"weekly": 0,
"monthly": 0,
"maxOnACase": 0
}
},
"connectors": {
"all": {
"all": {
"totalAttached": 0
},
"itsm": {
"totalAttached": 0
},
"sir": {
"totalAttached": 0
},
"jira": {
"totalAttached": 0
},
"resilient": {
"totalAttached": 0
},
"swimlane": {
"totalAttached": 0
},
"maxAttachedToACase": 0
}
},
"pushes": {
"all": {
"total": 0,
"maxOnACase": 0
}
},
"configuration": {
"all": {
"closure": {
"manually": 0,
"automatic": 0
}
}
}
}
## Testing
To test modify this file:
https://github.com/elastic/kibana/blob/main/x-pack/plugins/cases/server/telemetry/schedule_telemetry_task.ts
With:
```
export const scheduleCasesTelemetryTask = (
taskManager: TaskManagerStartContract,
logger: Logger
) => {
(async () => {
await taskManager
.ensureScheduled({
id: CASES_TELEMETRY_TASK_NAME,
taskType: CASES_TELEMETRY_TASK_NAME,
schedule: {
interval: `${MINUTES_ON_HALF_DAY}m`,
},
scope: ['cases'],
params: {},
state: {},
})
.catch((err) => {
logger.debug(
`Error scheduling cases task with ID ${CASES_TELEMETRY_TASK_NAME} and type ${CASES_TELEMETRY_TASK_NAME}. Received ${err.message}`
);
});
await taskManager.runSoon(CASES_TELEMETRY_TASK_NAME);
})();
};
```
This will cause the telemetry to be sent as soon as the server is
restarted.
To generate files and attachments to add stats to the telemetry I
created this python script:
https://github.com/elastic/cases-files-generator
To retrieve the telemetry:
```
POST http://localhost:5601/api/telemetry/v2/clusters/_stats
{
"refreshCache": true,
"unencrypted": true
}
```
---
.../server/telemetry/queries/cases.test.ts | 104 +++++++++-
.../cases/server/telemetry/queries/cases.ts | 22 ++-
.../server/telemetry/queries/utils.test.ts | 179 +++++++++++++++++-
.../cases/server/telemetry/queries/utils.ts | 37 ++--
.../plugins/cases/server/telemetry/schema.ts | 7 +
.../plugins/cases/server/telemetry/types.ts | 29 ++-
.../schema/xpack_plugins.json | 52 +++++
7 files changed, 385 insertions(+), 45 deletions(-)
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 ca6049885b298..b97235ff82247 100644
--- a/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts
+++ b/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts
@@ -12,7 +12,7 @@ import type {
AttachmentAggregationResult,
AttachmentFrameworkAggsResult,
CaseAggregationResult,
- FileAttachmentAggregationResult,
+ FileAttachmentAggregationResults,
} from '../types';
import { getCasesTelemetryData } from './cases';
@@ -187,17 +187,65 @@ describe('getCasesTelemetryData', () => {
...attachmentFramework,
};
- const filesRes: FileAttachmentAggregationResult = {
+ const filesRes: FileAttachmentAggregationResults = {
securitySolution: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
},
observability: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
},
cases: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
+ },
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
},
- averageSize: 500,
};
mockFind(caseAggsResult);
@@ -259,6 +307,16 @@ describe('getCasesTelemetryData', () => {
average,
maxOnACase: 10,
total,
+ topMimeTypes: [
+ {
+ count: 5,
+ name: 'image/png',
+ },
+ {
+ count: 1,
+ name: 'application/json',
+ },
+ ],
},
},
};
@@ -644,6 +702,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.externalReferenceAttachmentTypeId",
+ "size": 10,
},
},
"persistableReferenceTypes": Object {
@@ -677,6 +736,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.persistableStateAttachmentTypeId",
+ "size": 10,
},
},
},
@@ -717,6 +777,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.externalReferenceAttachmentTypeId",
+ "size": 10,
},
},
"observability": Object {
@@ -752,6 +813,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.externalReferenceAttachmentTypeId",
+ "size": 10,
},
},
"persistableReferenceTypes": Object {
@@ -785,6 +847,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.persistableStateAttachmentTypeId",
+ "size": 10,
},
},
},
@@ -830,6 +893,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.persistableStateAttachmentTypeId",
+ "size": 10,
},
},
"securitySolution": Object {
@@ -865,6 +929,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.externalReferenceAttachmentTypeId",
+ "size": 10,
},
},
"persistableReferenceTypes": Object {
@@ -898,6 +963,7 @@ describe('getCasesTelemetryData', () => {
},
"terms": Object {
"field": "cases-comments.attributes.persistableStateAttachmentTypeId",
+ "size": 10,
},
},
},
@@ -1031,6 +1097,12 @@ describe('getCasesTelemetryData', () => {
"field": "file.attributes.size",
},
},
+ "topMimeTypes": Object {
+ "terms": Object {
+ "field": "file.attributes.mime_type",
+ "size": 20,
+ },
+ },
},
"filter": Object {
"term": Object {
@@ -1045,6 +1117,12 @@ describe('getCasesTelemetryData', () => {
"field": "file.attributes.size",
},
},
+ "topMimeTypes": Object {
+ "terms": Object {
+ "field": "file.attributes.mime_type",
+ "size": 20,
+ },
+ },
},
"filter": Object {
"term": Object {
@@ -1059,6 +1137,12 @@ describe('getCasesTelemetryData', () => {
"field": "file.attributes.size",
},
},
+ "topMimeTypes": Object {
+ "terms": Object {
+ "field": "file.attributes.mime_type",
+ "size": 20,
+ },
+ },
},
"filter": Object {
"term": Object {
@@ -1066,13 +1150,19 @@ describe('getCasesTelemetryData', () => {
},
},
},
+ "topMimeTypes": Object {
+ "terms": Object {
+ "field": "file.attributes.mime_type",
+ "size": 20,
+ },
+ },
},
"filter": Object {
"arguments": Array [
Object {
"isQuoted": false,
"type": "literal",
- "value": "file.attributes.Meta.caseId",
+ "value": "file.attributes.Meta.caseIds",
},
Object {
"type": "wildcard",
diff --git a/x-pack/plugins/cases/server/telemetry/queries/cases.ts b/x-pack/plugins/cases/server/telemetry/queries/cases.ts
index 0e999721ae105..59576fa1f45c0 100644
--- a/x-pack/plugins/cases/server/telemetry/queries/cases.ts
+++ b/x-pack/plugins/cases/server/telemetry/queries/cases.ts
@@ -23,7 +23,7 @@ import type {
LatestDates,
CaseAggregationResult,
AttachmentAggregationResult,
- FileAttachmentAggregationResult,
+ FileAttachmentAggregationResults,
} from '../types';
import {
findValueInBuckets,
@@ -234,6 +234,7 @@ const getCommentsSavedObjectTelemetry = async (
externalReferenceTypes: {
terms: {
field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.externalReferenceAttachmentTypeId`,
+ size: 10,
},
aggs: {
...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT),
@@ -242,6 +243,7 @@ const getCommentsSavedObjectTelemetry = async (
persistableReferenceTypes: {
terms: {
field: `${CASE_COMMENT_SAVED_OBJECT}.attributes.persistableStateAttachmentTypeId`,
+ size: 10,
},
aggs: {
...getMaxBucketOnCaseAggregationQuery(CASE_COMMENT_SAVED_OBJECT),
@@ -284,7 +286,7 @@ const getCommentsSavedObjectTelemetry = async (
const getFilesTelemetry = async (
savedObjectsClient: ISavedObjectsRepository
-): Promise> => {
+): Promise> => {
const averageSize = () => ({
averageSize: {
avg: {
@@ -293,6 +295,15 @@ const getFilesTelemetry = async (
},
});
+ const top20MimeTypes = () => ({
+ topMimeTypes: {
+ terms: {
+ field: `${FILE_SO_TYPE}.attributes.mime_type`,
+ size: 20,
+ },
+ },
+ });
+
const filesByOwnerAggregationQuery = OWNERS.reduce(
(aggQuery, owner) => ({
...aggQuery,
@@ -304,20 +315,21 @@ const getFilesTelemetry = async (
},
aggs: {
...averageSize(),
+ ...top20MimeTypes(),
},
},
}),
{}
);
- const filterCaseIdExists = fromKueryExpression(`${FILE_SO_TYPE}.attributes.Meta.caseId: *`);
+ const filterCaseIdExists = fromKueryExpression(`${FILE_SO_TYPE}.attributes.Meta.caseIds: *`);
- return savedObjectsClient.find({
+ return savedObjectsClient.find({
page: 0,
perPage: 0,
type: FILE_SO_TYPE,
filter: filterCaseIdExists,
- aggs: { ...filesByOwnerAggregationQuery, ...averageSize() },
+ aggs: { ...filesByOwnerAggregationQuery, ...averageSize(), ...top20MimeTypes() },
});
};
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 d7c6a0e9bf7b9..359aa621798f0 100644
--- a/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts
+++ b/x-pack/plugins/cases/server/telemetry/queries/utils.test.ts
@@ -10,7 +10,7 @@ import type {
AttachmentAggregationResult,
AttachmentFrameworkAggsResult,
CaseAggregationResult,
- FileAttachmentAggregationResult,
+ FileAttachmentAggregationResults,
} from '../types';
import {
findValueInBuckets,
@@ -168,17 +168,65 @@ describe('utils', () => {
...attachmentFramework,
};
- const filesRes: FileAttachmentAggregationResult = {
+ const filesRes: FileAttachmentAggregationResults = {
securitySolution: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
},
observability: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
},
cases: {
- averageSize: 500,
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
+ },
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
},
- averageSize: 500,
};
it('constructs the solution values correctly', () => {
@@ -215,6 +263,16 @@ describe('utils', () => {
"average": 1,
"averageSize": 500,
"maxOnACase": 10,
+ "topMimeTypes": Array [
+ Object {
+ "count": 5,
+ "name": "image/png",
+ },
+ Object {
+ "count": 1,
+ "name": "application/json",
+ },
+ ],
"total": 5,
},
"persistableAttachments": Array [
@@ -271,6 +329,16 @@ describe('utils', () => {
"average": 5,
"averageSize": 500,
"maxOnACase": 10,
+ "topMimeTypes": Array [
+ Object {
+ "count": 5,
+ "name": "image/png",
+ },
+ Object {
+ "count": 1,
+ "name": "application/json",
+ },
+ ],
"total": 5,
},
"persistableAttachments": Array [
@@ -327,6 +395,16 @@ describe('utils', () => {
"average": 5,
"averageSize": 500,
"maxOnACase": 10,
+ "topMimeTypes": Array [
+ Object {
+ "count": 5,
+ "name": "image/png",
+ },
+ Object {
+ "count": 1,
+ "name": "application/json",
+ },
+ ],
"total": 5,
},
"persistableAttachments": Array [
@@ -363,6 +441,7 @@ describe('utils', () => {
"average": 0,
"averageSize": 0,
"maxOnACase": 0,
+ "topMimeTypes": Array [],
"total": 0,
},
"persistableAttachments": Array [],
@@ -486,7 +565,7 @@ describe('utils', () => {
});
describe('files', () => {
- it('sets the files stats to empty when it cannot find a files entry', () => {
+ it('sets the files stats to empty when the file aggregation results is the empty version', () => {
const attachmentFramework: AttachmentFrameworkAggsResult = {
externalReferenceTypes: {
buckets: [
@@ -512,19 +591,25 @@ describe('utils', () => {
getAttachmentsFrameworkStats({
attachmentAggregations: attachmentFramework,
totalCasesForOwner: 5,
- filesAggregations: { averageSize: 500 },
+ filesAggregations: {
+ averageSize: { value: 0 },
+ topMimeTypes: {
+ buckets: [],
+ },
+ },
}).attachmentFramework.files
).toMatchInlineSnapshot(`
Object {
"average": 0,
"averageSize": 0,
"maxOnACase": 0,
+ "topMimeTypes": Array [],
"total": 0,
}
`);
});
- it('sets the files stats when it finds a files entry', () => {
+ it('sets the files stats using the file aggregation result', () => {
const attachmentFramework: AttachmentFrameworkAggsResult = {
externalReferenceTypes: {
buckets: [
@@ -549,7 +634,21 @@ describe('utils', () => {
expect(
getAttachmentsFrameworkStats({
attachmentAggregations: attachmentFramework,
- filesAggregations: { averageSize: 500 },
+ filesAggregations: {
+ averageSize: { value: 500 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
+ },
totalCasesForOwner: 5,
}).attachmentFramework.files
).toMatchInlineSnapshot(`
@@ -557,10 +656,70 @@ describe('utils', () => {
"average": 1,
"averageSize": 500,
"maxOnACase": 10,
+ "topMimeTypes": Array [
+ Object {
+ "count": 5,
+ "name": "image/png",
+ },
+ Object {
+ "count": 1,
+ "name": "application/json",
+ },
+ ],
"total": 5,
}
`);
});
+
+ it('sets the top mime types when a file entry is not found', () => {
+ const attachmentFramework: AttachmentFrameworkAggsResult = {
+ externalReferenceTypes: {
+ buckets: [],
+ },
+ persistableReferenceTypes: {
+ buckets: [],
+ },
+ };
+
+ expect(
+ getAttachmentsFrameworkStats({
+ attachmentAggregations: attachmentFramework,
+ filesAggregations: {
+ averageSize: { value: 0 },
+ topMimeTypes: {
+ buckets: [
+ {
+ doc_count: 5,
+ key: 'image/png',
+ },
+ {
+ doc_count: 1,
+ key: 'application/json',
+ },
+ ],
+ },
+ },
+ totalCasesForOwner: 5,
+ }).attachmentFramework.files
+ ).toMatchInlineSnapshot(`
+ Object {
+ "average": 0,
+ "averageSize": 0,
+ "maxOnACase": 0,
+ "topMimeTypes": Array [
+ Object {
+ "count": 5,
+ "name": "image/png",
+ },
+ Object {
+ "count": 1,
+ "name": "application/json",
+ },
+ ],
+ "total": 0,
+ }
+ `);
+ });
});
});
diff --git a/x-pack/plugins/cases/server/telemetry/queries/utils.ts b/x-pack/plugins/cases/server/telemetry/queries/utils.ts
index 0c0a4f7bbf87d..7896c2bdac760 100644
--- a/x-pack/plugins/cases/server/telemetry/queries/utils.ts
+++ b/x-pack/plugins/cases/server/telemetry/queries/utils.ts
@@ -23,8 +23,8 @@ import type {
BucketsWithMaxOnCase,
AttachmentStats,
FileAttachmentStats,
- FileAttachmentAggregationResult,
- FileAttachmentAverageSize,
+ FileAttachmentAggregationResults,
+ FileAttachmentAggsResult,
AttachmentFrameworkAggsResult,
} from '../types';
import { buildFilter } from '../../client/utils';
@@ -170,7 +170,7 @@ export const getSolutionValues = ({
}: {
caseAggregations?: CaseAggregationResult;
attachmentAggregations?: AttachmentAggregationResult;
- filesAggregations?: FileAttachmentAggregationResult;
+ filesAggregations?: FileAttachmentAggregationResults;
owner: Owner;
}): SolutionTelemetry => {
const aggregationsBuckets = getAggregationsBuckets({
@@ -223,13 +223,15 @@ export const getAttachmentsFrameworkStats = ({
totalCasesForOwner,
}: {
attachmentAggregations?: AttachmentFrameworkAggsResult;
- filesAggregations?: FileAttachmentAverageSize;
+ filesAggregations?: FileAttachmentAggsResult;
totalCasesForOwner: number;
}): AttachmentFramework => {
if (!attachmentAggregations) {
return emptyAttachmentFramework();
}
- const averageFileSize = filesAggregations?.averageSize;
+
+ const averageFileSize = filesAggregations?.averageSize?.value;
+ const topMimeTypes = filesAggregations?.topMimeTypes;
return {
attachmentFramework: {
@@ -245,6 +247,7 @@ export const getAttachmentsFrameworkStats = ({
registryResults: attachmentAggregations.externalReferenceTypes,
averageFileSize,
totalCasesForOwner,
+ topMimeTypes,
}),
},
};
@@ -272,8 +275,8 @@ const getAttachmentRegistryStats = (
return stats;
};
-const calculateTypePerCaseAverage = (typeDocCount: number, totalCases: number) => {
- if (totalCases === 0) {
+const calculateTypePerCaseAverage = (typeDocCount: number | undefined, totalCases: number) => {
+ if (typeDocCount == null || totalCases === 0) {
return 0;
}
@@ -284,22 +287,27 @@ const getFileAttachmentStats = ({
registryResults,
averageFileSize,
totalCasesForOwner,
+ topMimeTypes,
}: {
registryResults: BucketsWithMaxOnCase;
averageFileSize?: number;
totalCasesForOwner: number;
+ topMimeTypes?: Buckets;
}): FileAttachmentStats => {
const fileBucket = registryResults.buckets.find((bucket) => bucket.key === FILE_ATTACHMENT_TYPE);
- if (!fileBucket || averageFileSize == null) {
- return emptyFileAttachment();
- }
+ const mimeTypes =
+ topMimeTypes?.buckets.map((mimeType) => ({
+ count: mimeType.doc_count,
+ name: mimeType.key,
+ })) ?? [];
return {
- averageSize: averageFileSize,
- average: calculateTypePerCaseAverage(fileBucket.doc_count, totalCasesForOwner),
- maxOnACase: fileBucket.references.cases.max.value,
- total: fileBucket.doc_count,
+ averageSize: averageFileSize ?? 0,
+ average: calculateTypePerCaseAverage(fileBucket?.doc_count, totalCasesForOwner),
+ maxOnACase: fileBucket?.references.cases.max.value ?? 0,
+ total: fileBucket?.doc_count ?? 0,
+ topMimeTypes: mimeTypes,
};
};
@@ -332,4 +340,5 @@ const emptyFileAttachment = (): FileAttachmentStats => ({
averageSize: 0,
maxOnACase: 0,
total: 0,
+ topMimeTypes: [],
});
diff --git a/x-pack/plugins/cases/server/telemetry/schema.ts b/x-pack/plugins/cases/server/telemetry/schema.ts
index 59506c932a51f..33d44101c5a6d 100644
--- a/x-pack/plugins/cases/server/telemetry/schema.ts
+++ b/x-pack/plugins/cases/server/telemetry/schema.ts
@@ -51,6 +51,13 @@ const attachmentFrameworkSchema: AttachmentFrameworkSchema = {
averageSize: long,
maxOnACase: long,
total: long,
+ topMimeTypes: {
+ type: 'array',
+ items: {
+ count: long,
+ name: string,
+ },
+ },
},
};
diff --git a/x-pack/plugins/cases/server/telemetry/types.ts b/x-pack/plugins/cases/server/telemetry/types.ts
index e28c3abaf4d52..b38d46d04283b 100644
--- a/x-pack/plugins/cases/server/telemetry/types.ts
+++ b/x-pack/plugins/cases/server/telemetry/types.ts
@@ -9,11 +9,15 @@ import type { ISavedObjectsRepository, Logger } from '@kbn/core/server';
import type { MakeSchemaFrom } from '@kbn/usage-collection-plugin/server';
import type { Owner } from '../../common/constants/types';
-export interface Buckets {
- buckets: Array<{
- doc_count: number;
- key: number | string;
- }>;
+export type BucketKeyString = Omit & { key: string };
+
+interface Bucket {
+ doc_count: number;
+ key: T;
+}
+
+export interface Buckets {
+ buckets: Array>;
}
export interface Cardinality {
@@ -57,12 +61,15 @@ export interface AssigneesFilters {
};
}
-export interface FileAttachmentAverageSize {
- averageSize: number;
+export interface FileAttachmentAggsResult {
+ averageSize: {
+ value: number;
+ };
+ topMimeTypes: Buckets;
}
-export type FileAttachmentAggregationResult = Record &
- FileAttachmentAverageSize;
+export type FileAttachmentAggregationResults = Record &
+ FileAttachmentAggsResult;
export interface BucketsWithMaxOnCase {
buckets: Array<
@@ -118,6 +125,10 @@ export interface AttachmentStats extends CommonAttachmentStats {
export interface FileAttachmentStats extends CommonAttachmentStats {
averageSize: number;
+ topMimeTypes: Array<{
+ name: string;
+ count: number;
+ }>;
}
export interface AttachmentFramework {
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 517c52ed4fb71..594373a71e188 100644
--- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json
+++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json
@@ -4839,6 +4839,19 @@
},
"total": {
"type": "long"
+ },
+ "topMimeTypes": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "name": {
+ "type": "keyword"
+ }
+ }
+ }
}
}
}
@@ -4986,6 +4999,19 @@
},
"total": {
"type": "long"
+ },
+ "topMimeTypes": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "name": {
+ "type": "keyword"
+ }
+ }
+ }
}
}
}
@@ -5073,6 +5099,19 @@
},
"total": {
"type": "long"
+ },
+ "topMimeTypes": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "name": {
+ "type": "keyword"
+ }
+ }
+ }
}
}
}
@@ -5160,6 +5199,19 @@
},
"total": {
"type": "long"
+ },
+ "topMimeTypes": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "count": {
+ "type": "long"
+ },
+ "name": {
+ "type": "keyword"
+ }
+ }
+ }
}
}
}