[Osquery] Remove osquery-manager-usage-metric SO type (#154100)

## Summary

Remove unused `osquery-manager-usage-metric` SO type

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Patryk Kopyciński 2023-05-23 13:42:11 +02:00 committed by GitHub
parent 3db3709eb4
commit 7a62628bd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 5 additions and 967 deletions

View file

@ -97,6 +97,11 @@ export const initialExcludeOnUpgradeQueryMock = {
type: 'ml-telemetry',
},
},
{
term: {
type: 'osquery-manager-usage-metric',
},
},
{
term: {
type: 'osquery-usage-metric',

View file

@ -9,10 +9,6 @@ export const savedQuerySavedObjectType = 'osquery-saved-query';
export const packSavedObjectType = 'osquery-pack';
export const packAssetSavedObjectType = 'osquery-pack-asset';
export const usageMetricSavedObjectType = 'osquery-manager-usage-metric';
export type SavedObjectType =
| 'osquery-saved-query'
| 'osquery-pack'
| 'osquery-manager-usage-metric';
/**
* This makes any optional property the same as Required<T> would but also has the

View file

@ -26,7 +26,6 @@
"optionalPlugins": [
"fleet",
"home",
"usageCollection",
"lens",
"telemetry",
"cases"

View file

@ -27,7 +27,6 @@ import type { OsqueryPluginSetup, OsqueryPluginStart, SetupPlugins, StartPlugins
import { defineRoutes } from './routes';
import { osquerySearchStrategyProvider } from './search_strategy/osquery';
import { initSavedObjects } from './saved_objects';
import { initUsageCollectors } from './usage';
import type { OsqueryAppContext } from './lib/osquery_app_context_services';
import { OsqueryAppContextService } from './lib/osquery_app_context_services';
import type { ConfigType } from '../common/config';
@ -78,11 +77,6 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
};
initSavedObjects(core.savedObjects);
initUsageCollectors({
core,
osqueryContext,
usageCollection: plugins.usageCollection,
});
this.createActionService = createActionService(osqueryContext);

View file

@ -1,8 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export * from './recorder';

View file

@ -1,121 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
import { usageMetricSavedObjectType } from '../../../common/types';
import type { CounterValue, RouteString } from './recorder';
import { getOrCreateMetricObject, getRouteMetric, incrementCount, routeStrings } from './recorder';
const savedObjectsClient = savedObjectsClientMock.create();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function checkGetCalls(calls: any[]) {
expect(calls.length).toEqual(routeStrings.length);
for (let i = 0; i < routeStrings.length; ++i) {
expect(calls[i]).toEqual([usageMetricSavedObjectType, routeStrings[i]]);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function checkCreateCalls(calls: any[], expectedCallRoutes: string[] = routeStrings) {
expect(calls.length).toEqual(expectedCallRoutes.length);
for (let i = 0; i < expectedCallRoutes.length; ++i) {
expect(calls[i][0]).toEqual(usageMetricSavedObjectType);
expect(calls[i][2].id).toEqual(expectedCallRoutes[i]);
}
}
describe('Usage metric recorder', () => {
describe('Metric initalizer', () => {
const get = savedObjectsClient.get as jest.Mock;
const create = savedObjectsClient.create as jest.Mock;
afterEach(() => {
get.mockClear();
create.mockClear();
});
it('should create metrics that do not exist', async () => {
get.mockRejectedValueOnce('stub value');
create.mockReturnValueOnce('stub value');
const result = await getOrCreateMetricObject(savedObjectsClient, 'live_query');
checkGetCalls(get.mock.calls);
checkCreateCalls(create.mock.calls);
expect(result).toBe('stub value');
});
it('should handle previously created objects properly', async () => {
get.mockReturnValueOnce('stub value');
create.mockRejectedValueOnce('stub value');
const result = await getOrCreateMetricObject(savedObjectsClient, 'live_query');
checkGetCalls(get.mock.calls);
checkCreateCalls(create.mock.calls, []);
expect(result).toBe('stub value');
});
});
describe('Incrementation', () => {
let counterMap: { [key: string]: CounterValue };
const get = savedObjectsClient.get as jest.Mock;
const update = savedObjectsClient.update as jest.Mock;
update.mockImplementation(
async (objectType: string, route: RouteString, newVal: CounterValue) => {
counterMap[`${objectType}-${route}`] = newVal;
}
);
get.mockImplementation(async (objectType: string, route: RouteString) => ({
attributes: counterMap[`${objectType}-${route}`],
}));
beforeEach(() => {
counterMap = routeStrings.reduce((acc, route) => {
acc[`${usageMetricSavedObjectType}-${route}`] = {
count: 0,
errors: 0,
};
return acc;
}, {} as { [key: string]: CounterValue });
get.mockClear();
update.mockClear();
});
it('should increment the route counter', async () => {
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 0,
errors: 0,
});
await incrementCount(savedObjectsClient, 'live_query');
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 1,
errors: 0,
});
});
it('should allow incrementing the error counter', async () => {
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 0,
errors: 0,
});
await incrementCount(savedObjectsClient, 'live_query', 'errors');
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 0,
errors: 1,
});
});
it('should allow adjustment of the increment', async () => {
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 0,
errors: 0,
});
await incrementCount(savedObjectsClient, 'live_query', 'count', 2);
expect(await getRouteMetric(savedObjectsClient, 'live_query')).toEqual({
count: 2,
errors: 0,
});
});
});
});

View file

@ -1,63 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { SavedObjectsClientContract } from '@kbn/core/server';
import { usageMetricSavedObjectType } from '../../../common/types';
import type { LiveQuerySessionUsage } from '../../usage/types';
export interface RouteUsageMetric {
queries: number;
errors: number;
}
export type RouteString = 'live_query';
export const routeStrings: RouteString[] = ['live_query'];
export async function getOrCreateMetricObject<T>(
soClient: SavedObjectsClientContract,
route: string
) {
try {
return await soClient.get<T>(usageMetricSavedObjectType, route);
} catch (e) {
return await soClient.create(
usageMetricSavedObjectType,
{
errors: 0,
count: 0,
},
{
id: route,
}
);
}
}
export async function getCount(soClient: SavedObjectsClientContract, route: RouteString) {
return await getOrCreateMetricObject<LiveQuerySessionUsage>(soClient, route);
}
export interface CounterValue {
count: number;
errors: number;
}
export async function incrementCount(
soClient: SavedObjectsClientContract,
route: RouteString,
key: keyof CounterValue = 'count',
increment = 1
) {
const metric = await getOrCreateMetricObject<CounterValue>(soClient, route);
metric.attributes[key] += increment;
await soClient.update(usageMetricSavedObjectType, route, metric.attributes);
}
export async function getRouteMetric(soClient: SavedObjectsClientContract, route: RouteString) {
return (await getCount(soClient, route)).attributes;
}

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { SavedObjectsType } from '@kbn/core/server';
import { usageMetricSavedObjectType } from '../../../common/types';
export const usageMetricSavedObjectMappings: SavedObjectsType['mappings'] = {
properties: {
count: {
type: 'long',
},
errors: {
type: 'long',
},
},
};
export const usageMetricType: SavedObjectsType = {
name: usageMetricSavedObjectType,
hidden: false,
namespaceType: 'agnostic',
mappings: usageMetricSavedObjectMappings,
};

View file

@ -13,7 +13,6 @@ import type {
} from '@kbn/data-plugin/server';
import type { FleetStartContract } from '@kbn/fleet-plugin/server';
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import type { PluginSetupContract } from '@kbn/features-plugin/server';
import type { SecurityPluginStart } from '@kbn/security-plugin/server';
import type {
@ -34,7 +33,6 @@ export interface OsqueryPluginSetup {
export interface OsqueryPluginStart {}
export interface SetupPlugins {
usageCollection?: UsageCollectionSetup;
actions: ActionsPlugin['setup'];
cases: CasesSetup;
data: DataPluginSetup;

View file

@ -1,51 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { CoreSetup } from '@kbn/core/server';
import { SavedObjectsClient } from '@kbn/core/server';
import type { CollectorFetchContext } from '@kbn/usage-collection-plugin/server';
import { getBeatUsage, getLiveQueryUsage, getPolicyLevelUsage } from './fetchers';
import type { CollectorDependencies, UsageData } from './types';
import { usageSchema } from './types';
export type RegisterCollector = (deps: CollectorDependencies) => void;
export const getInternalSavedObjectsClient = async (
getStartServices: CoreSetup['getStartServices']
) => {
const [coreStart] = await getStartServices();
return new SavedObjectsClient(coreStart.savedObjects.createInternalRepository());
};
export const registerCollector: RegisterCollector = ({ core, osqueryContext, usageCollection }) => {
if (!usageCollection) {
return;
}
const collector = usageCollection.makeUsageCollector<UsageData>({
type: 'osquery',
schema: usageSchema,
isReady: () => true,
fetch: async ({ esClient }: CollectorFetchContext): Promise<UsageData> => {
const savedObjectsClient = await getInternalSavedObjectsClient(core.getStartServices);
return {
beat_metrics: {
usage: await getBeatUsage(esClient),
},
live_query_usage: await getLiveQueryUsage(savedObjectsClient, esClient),
...(await getPolicyLevelUsage(
esClient,
savedObjectsClient,
osqueryContext.service.getPackagePolicyService()
)),
};
},
});
usageCollection.registerCollector(collector);
};

View file

@ -1,8 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const METRICS_INDICES = 'logs-elastic_agent.osquerybeat*';

View file

@ -1,105 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { extractBeatUsageMetrics } from './fetchers';
describe('extractBeatUsageMetrics', () => {
it('should not blow when no values are supplied for the aggregations', () => {
expect(extractBeatUsageMetrics({})).toEqual({
memory: {
rss: {},
},
cpu: {},
});
});
it('should not blow when some values are missing from the aggregations', () => {
expect(
extractBeatUsageMetrics({
aggregations: {
lastDay: {
max_rss: {
value: 1,
},
},
},
})
).toEqual({
memory: {
rss: {
max: 1,
},
},
cpu: {},
});
});
it('should pick out all the max/avg/latest for memory/cpu', () => {
expect(
extractBeatUsageMetrics({
aggregations: {
lastDay: {
max_rss: {
value: 1,
},
avg_rss: {
value: 1,
},
max_cpu: {
value: 2,
},
avg_cpu: {
value: 2,
},
latest: {
hits: {
total: 1,
hits: [
{
_index: '',
_id: '',
_source: {
monitoring: {
metrics: {
beat: {
cpu: {
total: {
time: {
ms: 2,
},
},
},
memstats: {
rss: 1,
},
},
},
},
},
},
],
},
},
},
},
})
).toEqual({
memory: {
rss: {
max: 1,
avg: 1,
latest: 1,
},
},
cpu: {
max: 2,
avg: 2,
latest: 2,
},
});
});
});

View file

@ -1,274 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type {
AggregationsSingleBucketAggregateBase,
AggregationsTopHitsAggregate,
AggregationsRateAggregate,
SearchResponse,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { PackagePolicyClient } from '@kbn/fleet-plugin/server';
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import type { ListResult, PackagePolicy } from '@kbn/fleet-plugin/common';
import {
AGENTS_INDEX,
AGENT_ACTIONS_INDEX,
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
} from '@kbn/fleet-plugin/common';
import { getRouteMetric } from '../routes/usage';
import { OSQUERY_INTEGRATION_NAME } from '../../common';
import { METRICS_INDICES } from './constants';
import type { AgentInfo, BeatMetricsUsage, LiveQueryUsage } from './types';
interface PolicyLevelUsage {
scheduled_queries?: ScheduledQueryUsageMetrics;
agent_info?: AgentInfo;
}
export async function getPolicyLevelUsage(
esClient: ElasticsearchClient,
soClient: SavedObjectsClientContract,
packagePolicyService?: PackagePolicyClient
): Promise<PolicyLevelUsage> {
if (!packagePolicyService) {
return {};
}
const packagePolicies = await packagePolicyService.list(soClient, {
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${OSQUERY_INTEGRATION_NAME}`,
perPage: 10_000,
});
const result: PolicyLevelUsage = {
scheduled_queries: getScheduledQueryUsage(packagePolicies),
// TODO: figure out how to support dynamic keys in metrics
// packageVersions: getPackageVersions(packagePolicies),
};
const agentResponse = await esClient.search<
unknown,
{
policied: AggregationsSingleBucketAggregateBase;
}
>({
body: {
size: 0,
query: {
match: {
active: true,
},
},
aggs: {
policied: {
filter: {
terms: {
policy_id: packagePolicies.items.map((p) => p.policy_id),
},
},
},
},
},
index: AGENTS_INDEX,
ignore_unavailable: true,
});
const policied = agentResponse.aggregations?.policied;
if (policied && typeof policied.doc_count === 'number') {
result.agent_info = {
enrolled: policied.doc_count,
};
}
return result;
}
export function getPackageVersions(packagePolicies: ListResult<PackagePolicy>) {
return packagePolicies.items.reduce((acc, item) => {
if (item.package) {
acc[item.package.version] = (acc[item.package.version] ?? 0) + 1;
}
return acc;
}, {} as { [version: string]: number });
}
interface ScheduledQueryUsageMetrics {
queryGroups: {
total: number;
empty: number;
};
}
export function getScheduledQueryUsage(packagePolicies: ListResult<PackagePolicy>) {
return packagePolicies.items.reduce(
(acc, item) => {
++acc.queryGroups.total;
const policyAgents = item.inputs.reduce((sum, input) => sum + input.streams.length, 0);
if (policyAgents === 0) {
++acc.queryGroups.empty;
}
return acc;
},
{
queryGroups: {
total: 0,
empty: 0,
},
} as ScheduledQueryUsageMetrics
);
}
export async function getLiveQueryUsage(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient
) {
const metricResponse = await esClient.search<
unknown,
{
queries: AggregationsSingleBucketAggregateBase;
}
>({
body: {
size: 0,
aggs: {
queries: {
filter: {
term: {
input_type: 'osquery',
},
},
},
},
},
index: AGENT_ACTIONS_INDEX,
ignore_unavailable: true,
});
const result: LiveQueryUsage = {
session: await getRouteMetric(soClient, 'live_query'),
};
const esQueries = metricResponse.aggregations?.queries;
if (esQueries && typeof esQueries.doc_count === 'number') {
// getting error stats out of ES is difficult due to a lack of error info on .fleet-actions
// and a lack of indexable osquery specific info on .fleet-actions-results
result.cumulative = {
queries: esQueries.doc_count,
};
}
return result;
}
interface BeatUsageAggs {
lastDay: {
max_rss?: AggregationsRateAggregate;
max_cpu?: AggregationsRateAggregate;
latest?: AggregationsTopHitsAggregate;
// not used in code, declared to satisfy type
avg_rss?: AggregationsRateAggregate;
avg_cpu?: AggregationsRateAggregate;
};
}
export function extractBeatUsageMetrics(
metricResponse: Pick<SearchResponse<unknown, BeatUsageAggs>, 'aggregations'>
) {
const lastDayAggs = metricResponse.aggregations?.lastDay;
const result: BeatMetricsUsage = {
memory: {
rss: {},
},
cpu: {},
};
if (lastDayAggs) {
if (lastDayAggs.max_rss !== undefined) {
result.memory.rss.max = lastDayAggs.max_rss.value;
}
if (lastDayAggs.avg_rss !== undefined) {
// @ts-expect-error condition check another property, not idea why. consider fixing
result.memory.rss.avg = lastDayAggs.max_rss.value;
}
if (lastDayAggs.max_cpu !== undefined) {
result.cpu.max = lastDayAggs.max_cpu.value;
}
if (lastDayAggs.avg_cpu !== undefined) {
// @ts-expect-error condition check another property, not idea why. consider fixing
result.cpu.avg = lastDayAggs.max_cpu.value;
}
if (lastDayAggs.latest !== undefined) {
const latest = lastDayAggs.latest.hits.hits[0]?._source?.monitoring.metrics.beat;
if (latest) {
result.cpu.latest = latest.cpu.total.time.ms;
result.memory.rss.latest = latest.memstats.rss;
}
}
}
return result;
}
export async function getBeatUsage(esClient: ElasticsearchClient) {
const metricResponse = await esClient.search<unknown, BeatUsageAggs>({
body: {
size: 0,
aggs: {
lastDay: {
filter: {
range: {
'@timestamp': {
gte: 'now-24h',
lte: 'now',
},
},
},
aggs: {
latest: {
top_hits: {
sort: [
{
'@timestamp': {
order: 'desc',
},
},
],
size: 1,
},
},
max_rss: {
max: {
field: 'monitoring.metrics.beat.memstats.rss',
},
},
avg_rss: {
avg: {
field: 'monitoring.metrics.beat.memstats.rss',
},
},
max_cpu: {
max: {
field: 'monitoring.metrics.beat.cpu.total.time.ms',
},
},
avg_cpu: {
avg: {
field: 'monitoring.metrics.beat.cpu.total.time.ms',
},
},
},
},
},
},
index: METRICS_INDICES,
ignore_unavailable: true,
});
return extractBeatUsageMetrics(metricResponse);
}

View file

@ -1,15 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { CollectorDependencies } from './types';
import { registerCollector } from './collector';
export type InitUsageCollectors = (deps: CollectorDependencies) => void;
export const initUsageCollectors: InitUsageCollectors = (dependencies) => {
registerCollector(dependencies);
};

View file

@ -1,160 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { CoreSetup } from '@kbn/core/server';
import type { MakeSchemaFrom } from '@kbn/usage-collection-plugin/server';
import type { OsqueryAppContext } from '../lib/osquery_app_context_services';
import type { SetupPlugins } from '../types';
export type CollectorDependencies = {
osqueryContext: OsqueryAppContext;
core: CoreSetup;
} & Pick<SetupPlugins, 'usageCollection'>;
export interface LiveQuerySessionUsage {
count: number;
errors: number;
}
export interface LiveQueryCumulativeUsage {
queries: number;
}
export interface LiveQueryUsage {
session: LiveQuerySessionUsage;
cumulative?: LiveQueryCumulativeUsage;
}
export interface ScheduledQueryUsage {
queryGroups: {
total: number;
empty: number;
};
}
export interface AgentInfo {
enrolled: number;
}
export interface MetricEntry {
max?: number;
latest?: number;
avg?: number;
}
export interface BeatMetricsUsage {
cpu: MetricEntry;
memory: {
rss: MetricEntry;
};
}
export interface BeatMetrics {
usage: BeatMetricsUsage;
}
export interface UsageData {
live_query_usage?: LiveQueryUsage;
scheduled_queries?: ScheduledQueryUsage;
agent_info?: AgentInfo;
beat_metrics?: BeatMetrics;
}
export const usageSchema: MakeSchemaFrom<UsageData> = {
live_query_usage: {
session: {
count: {
type: 'long',
_meta: {
description: 'Number of osquery action requests',
},
},
errors: {
type: 'long',
_meta: {
description: 'Number of osquery action requests that resulted in errors',
},
},
},
cumulative: {
queries: {
type: 'long',
_meta: {
description: 'Number of osquery actions stored in Elasticsearch',
},
},
},
},
scheduled_queries: {
queryGroups: {
total: {
type: 'long',
_meta: {
description: 'Number of osquery policies/query groups',
},
},
empty: {
type: 'long',
_meta: {
description: 'Number of empty osquery policies/query groups',
},
},
},
},
agent_info: {
enrolled: {
type: 'long',
_meta: {
description: 'Number of agents enrolled in a policy with an osquery integration',
},
},
},
beat_metrics: {
usage: {
cpu: {
latest: {
type: 'long',
_meta: {
description: 'Latest cpu usage sample in ms',
},
},
max: {
type: 'long',
_meta: {
description: 'Max cpu usage sample over 24 hours in ms',
},
},
avg: {
type: 'long',
_meta: {
description: 'Mean cpu usage over 24 hours in ms',
},
},
},
memory: {
rss: {
latest: {
type: 'long',
_meta: {
description: 'Latest resident set size sample',
},
},
max: {
type: 'long',
_meta: {
description: 'Max resident set size sample over 24 hours',
},
},
avg: {
type: 'long',
_meta: {
description: 'Mean resident set size sample over 24 hours',
},
},
},
},
},
},
};

View file

@ -57,7 +57,6 @@
"@kbn/dev-cli-runner",
"@kbn/telemetry-plugin",
"@kbn/actions-plugin",
"@kbn/usage-collection-plugin",
"@kbn/features-plugin",
"@kbn/task-manager-plugin",
"@kbn/data-views-plugin",

View file

@ -6940,126 +6940,6 @@
}
}
},
"osquery": {
"properties": {
"live_query_usage": {
"properties": {
"session": {
"properties": {
"count": {
"type": "long",
"_meta": {
"description": "Number of osquery action requests"
}
},
"errors": {
"type": "long",
"_meta": {
"description": "Number of osquery action requests that resulted in errors"
}
}
}
},
"cumulative": {
"properties": {
"queries": {
"type": "long",
"_meta": {
"description": "Number of osquery actions stored in Elasticsearch"
}
}
}
}
}
},
"scheduled_queries": {
"properties": {
"queryGroups": {
"properties": {
"total": {
"type": "long",
"_meta": {
"description": "Number of osquery policies/query groups"
}
},
"empty": {
"type": "long",
"_meta": {
"description": "Number of empty osquery policies/query groups"
}
}
}
}
}
},
"agent_info": {
"properties": {
"enrolled": {
"type": "long",
"_meta": {
"description": "Number of agents enrolled in a policy with an osquery integration"
}
}
}
},
"beat_metrics": {
"properties": {
"usage": {
"properties": {
"cpu": {
"properties": {
"latest": {
"type": "long",
"_meta": {
"description": "Latest cpu usage sample in ms"
}
},
"max": {
"type": "long",
"_meta": {
"description": "Max cpu usage sample over 24 hours in ms"
}
},
"avg": {
"type": "long",
"_meta": {
"description": "Mean cpu usage over 24 hours in ms"
}
}
}
},
"memory": {
"properties": {
"rss": {
"properties": {
"latest": {
"type": "long",
"_meta": {
"description": "Latest resident set size sample"
}
},
"max": {
"type": "long",
"_meta": {
"description": "Max resident set size sample over 24 hours"
}
},
"avg": {
"type": "long",
"_meta": {
"description": "Mean resident set size sample over 24 hours"
}
}
}
}
}
}
}
}
}
}
}
},
"reporting": {
"properties": {
"csv_searchsource": {