Skip to content

Commit

Permalink
Fix agent config indicator when applied through fleet integration (el…
Browse files Browse the repository at this point in the history
…astic#131820)

* Fix agent config indicator when applied through fleet integration

* Add synthrace scenario

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
2 people authored and emilioalvap committed May 23, 2022
1 parent dcb9fc4 commit fe6190f
Show file tree
Hide file tree
Showing 17 changed files with 363 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/elastic-apm-synthtrace/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
export { timerange } from './lib/timerange';
export { apm } from './lib/apm';
export { stackMonitoring } from './lib/stack_monitoring';
export { observer } from './lib/agent_config';
export { cleanWriteTargets } from './lib/utils/clean_write_targets';
export { createLogger, LogLevel } from './lib/utils/create_logger';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { AgentConfigFields } from './agent_config_fields';
import { Metricset } from '../apm/metricset';

export class AgentConfig extends Metricset<AgentConfigFields> {
constructor() {
super({
'metricset.name': 'agent_config',
agent_config_applied: 1,
});
}

etag(etag: string) {
this.fields['labels.etag'] = etag;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { ApmFields } from '../apm/apm_fields';

export type AgentConfigFields = Pick<
ApmFields,
| '@timestamp'
| 'processor.event'
| 'processor.name'
| 'metricset.name'
| 'observer'
| 'ecs.version'
| 'event.ingested'
> &
Partial<{
'labels.etag': string;
agent_config_applied: number;
'event.agent_id_status': string;
}>;
9 changes: 9 additions & 0 deletions packages/elastic-apm-synthtrace/src/lib/agent_config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { observer } from './observer';
21 changes: 21 additions & 0 deletions packages/elastic-apm-synthtrace/src/lib/agent_config/observer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { AgentConfigFields } from './agent_config_fields';
import { AgentConfig } from './agent_config';
import { Entity } from '../entity';

export class Observer extends Entity<AgentConfigFields> {
agentConfig() {
return new AgentConfig();
}
}

export function observer() {
return new Observer({});
}
2 changes: 1 addition & 1 deletion packages/elastic-apm-synthtrace/src/lib/apm/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Instance extends Entity<ApmFields> {
}

appMetrics(metrics: ApmApplicationMetricFields) {
return new Metricset({
return new Metricset<ApmFields>({
...this.fields,
'metricset.name': 'app',
...metrics,
Expand Down
6 changes: 3 additions & 3 deletions packages/elastic-apm-synthtrace/src/lib/apm/metricset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
*/

import { Serializable } from '../serializable';
import { ApmFields } from './apm_fields';
import { Fields } from '../entity';

export class Metricset extends Serializable<ApmFields> {
constructor(fields: ApmFields) {
export class Metricset<TFields extends Fields> extends Serializable<TFields> {
constructor(fields: TFields) {
super({
'processor.event': 'metric',
'processor.name': 'metric',
Expand Down
4 changes: 3 additions & 1 deletion packages/elastic-apm-synthtrace/src/lib/stream_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ export class StreamProcessor<TFields extends Fields = ApmFields> {
const eventType = d.processor.event as keyof ApmElasticsearchOutputWriteTargets;
let dataStream = writeTargets[eventType];
if (eventType === 'metric') {
if (!d.service?.name) {
if (d.metricset?.name === 'agent_config') {
dataStream = 'metrics-apm.internal-default';
} else if (!d.service?.name) {
dataStream = 'metrics-apm.app-default';
} else {
if (!d.transaction && !d.span) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { observer, timerange } from '../..';
import { Scenario } from '../scenario';
import { getLogger } from '../utils/get_common_services';
import { RunOptions } from '../utils/parse_run_cli_flags';
import { AgentConfigFields } from '../../lib/agent_config/agent_config_fields';

const scenario: Scenario<AgentConfigFields> = async (runOptions: RunOptions) => {
const logger = getLogger(runOptions);

return {
generate: ({ from, to }) => {
const agentConfig = observer().agentConfig();

const range = timerange(from, to);
return range
.interval('30s')
.rate(1)
.generator((timestamp) => {
const events = logger.perf('generating_agent_config_events', () => {
return agentConfig.etag('test-etag').timestamp(timestamp);
});
return events;
});
},
};
};

export default scenario;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export type AgentConfigurationIntake = t.TypeOf<
export type AgentConfiguration = {
'@timestamp': number;
applied_by_agent?: boolean;
etag?: string;
etag: string;
agent_name?: string;
} & AgentConfigurationIntake;
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,27 @@ import { AgentConfiguration } from '../../../../common/agent_configuration/confi
export function convertConfigSettingsToString(
hit: SearchHit<AgentConfiguration>
) {
const config = hit._source;
const { settings } = hit._source;

if (config.settings?.transaction_sample_rate) {
config.settings.transaction_sample_rate =
config.settings.transaction_sample_rate.toString();
}
const convertedConfigSettings = {
...settings,
...(settings?.transaction_sample_rate
? {
transaction_sample_rate: settings.transaction_sample_rate.toString(),
}
: {}),
...(settings?.transaction_max_spans
? {
transaction_max_spans: settings.transaction_max_spans.toString(),
}
: {}),
};

if (config.settings?.transaction_max_spans) {
config.settings.transaction_max_spans =
config.settings.transaction_max_spans.toString();
}

return hit;
return {
...hit,
_source: {
...hit._source,
settings: convertedConfigSettings,
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../../lib/helpers/setup_request';
import { convertConfigSettingsToString } from './convert_settings_to_string';
import { getConfigsAppliedToAgentsThroughFleet } from './get_config_applied_to_agent_through_fleet';

export async function findExactConfiguration({
service,
Expand Down Expand Up @@ -40,16 +41,27 @@ export async function findExactConfiguration({
},
};

const resp = await internalClient.search<AgentConfiguration, typeof params>(
'find_exact_agent_configuration',
params
);
const [agentConfig, configsAppliedToAgentsThroughFleet] = await Promise.all([
internalClient.search<AgentConfiguration, typeof params>(
'find_exact_agent_configuration',
params
),
getConfigsAppliedToAgentsThroughFleet({ setup }),
]);

const hit = resp.hits.hits[0] as SearchHit<AgentConfiguration> | undefined;
const hit = agentConfig.hits.hits[0] as
| SearchHit<AgentConfiguration>
| undefined;

if (!hit) {
return;
}

return convertConfigSettingsToString(hit);
return {
id: hit._id,
...convertConfigSettingsToString(hit)._source,
applied_by_agent:
hit._source.applied_by_agent ||
configsAppliedToAgentsThroughFleet.hasOwnProperty(hit._source.etag),
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 { termQuery, rangeQuery } from '@kbn/observability-plugin/server';
import datemath from '@kbn/datemath';
import { METRICSET_NAME } from '../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../../lib/helpers/setup_request';

export async function getConfigsAppliedToAgentsThroughFleet({
setup,
}: {
setup: Setup;
}) {
const { internalClient, indices } = setup;

const params = {
index: indices.metric,
size: 0,
body: {
query: {
bool: {
filter: [
...termQuery(METRICSET_NAME, 'agent_config'),
...rangeQuery(
datemath.parse('now-15m')!.valueOf(),
datemath.parse('now')!.valueOf()
),
],
},
},
aggs: {
config_by_etag: {
terms: {
field: 'labels.etag',
size: 200,
},
},
},
},
};

const response = await internalClient.search(
'get_config_applied_to_agent_through_fleet',
params
);

return (
response.aggregations?.config_by_etag.buckets.reduce(
(configsAppliedToAgentsThroughFleet, bucket) => {
configsAppliedToAgentsThroughFleet[bucket.key as string] = true;
return configsAppliedToAgentsThroughFleet;
},
{} as Record<string, true>
) ?? {}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { Setup } from '../../../lib/helpers/setup_request';
import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types';
import { convertConfigSettingsToString } from './convert_settings_to_string';
import { getConfigsAppliedToAgentsThroughFleet } from './get_config_applied_to_agent_through_fleet';

export async function listConfigurations({ setup }: { setup: Setup }) {
const { internalClient, indices } = setup;
Expand All @@ -17,12 +18,22 @@ export async function listConfigurations({ setup }: { setup: Setup }) {
size: 200,
};

const resp = await internalClient.search<AgentConfiguration>(
'list_agent_configuration',
params
);
const [agentConfigs, configsAppliedToAgentsThroughFleet] = await Promise.all([
internalClient.search<AgentConfiguration>(
'list_agent_configuration',
params
),
getConfigsAppliedToAgentsThroughFleet({ setup }),
]);

return resp.hits.hits
return agentConfigs.hits.hits
.map(convertConfigSettingsToString)
.map((hit) => hit._source);
.map((hit) => {
return {
...hit._source,
applied_by_agent:
hit._source.applied_by_agent ||
configsAppliedToAgentsThroughFleet.hasOwnProperty(hit._source.etag),
};
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ const agentConfigurationRoute = createApmServerRoute({
>;
}> => {
const setup = await setupRequest(resources);

const configurations = await listConfigurations({ setup });

return { configurations };
},
});
Expand Down Expand Up @@ -71,7 +73,7 @@ const getSingleAgentConfigurationRoute = createApmServerRoute({
throw Boom.notFound();
}

return config._source;
return config;
},
});

Expand Down Expand Up @@ -102,11 +104,11 @@ const deleteAgentConfigurationRoute = createApmServerRoute({
}

logger.info(
`Deleting config ${service.name}/${service.environment} (${config._id})`
`Deleting config ${service.name}/${service.environment} (${config.id})`
);

const deleteConfigurationResult = await deleteConfiguration({
configurationId: config._id,
configurationId: config.id,
setup,
});

Expand Down Expand Up @@ -162,7 +164,7 @@ const createOrUpdateAgentConfigurationRoute = createApmServerRoute({
);

await createOrUpdateConfiguration({
configurationId: config?._id,
configurationId: config?.id,
configurationIntake: body,
setup,
});
Expand Down
Loading

0 comments on commit fe6190f

Please sign in to comment.