[APM Tracing config] Allow per-service overrides (#166184)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alejandro Fernández Haro 2023-09-19 12:49:37 +02:00 committed by GitHub
parent ab073a6d3d
commit 639d9547a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 7 deletions

View file

@ -6,14 +6,22 @@
* Side Public License, v 1.
*/
import { schema } from '@kbn/config-schema';
import { schema, TypeOf } from '@kbn/config-schema';
export const apmConfigSchema = schema.object(
export type ApmConfigSchema = TypeOf<typeof apmConfigSchema>;
const apmReusableConfigSchema = schema.object(
{
active: schema.maybe(schema.boolean()),
serverUrl: schema.maybe(schema.uri()),
secretToken: schema.maybe(schema.string()),
globalLabels: schema.object({}, { unknowns: 'allow' }),
apiKey: schema.maybe(schema.string()),
environment: schema.maybe(schema.string()),
globalLabels: schema.maybe(schema.object({}, { unknowns: 'allow' })),
},
{ unknowns: 'allow' }
);
export const apmConfigSchema = apmReusableConfigSchema.extends({
servicesOverrides: schema.maybe(schema.recordOf(schema.string(), apmReusableConfigSchema)),
});

View file

@ -359,5 +359,50 @@ describe('ApmConfiguration', () => {
})
);
});
it('allows overriding some services settings', () => {
const kibanaConfig = {
elastic: {
apm: {
active: true,
serverUrl: 'http://an.internal.apm.server:port/',
transactionSampleRate: 0.1,
servicesOverrides: {
externalServiceName: {
active: false,
serverUrl: 'http://a.public.apm.server:port/',
disableSend: true, // just adding an extra field to prove merging works
},
},
},
},
};
const internalService = new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig(
'internalServiceName'
);
expect(internalService).toEqual(
expect.objectContaining({
active: true,
serverUrl: 'http://an.internal.apm.server:port/',
transactionSampleRate: 0.1,
serviceName: 'internalServiceName',
})
);
expect(internalService).not.toHaveProperty('disableSend');
expect(internalService).not.toHaveProperty('servicesOverrides'); // We don't want to leak this to the client's config
expect(
new ApmConfiguration(mockedRootDir, kibanaConfig, true).getConfig('externalServiceName')
).toEqual(
expect.objectContaining({
active: false,
serverUrl: 'http://a.public.apm.server:port/',
transactionSampleRate: 0.1,
disableSend: true,
serviceName: 'externalServiceName',
})
);
});
});
});

View file

@ -14,6 +14,7 @@ import { getDataPath } from '@kbn/utils';
import { readFileSync } from 'fs';
import type { AgentConfigOptions } from 'elastic-apm-node';
import type { AgentConfigOptions as RUMAgentConfigOptions } from '@elastic/apm-rum';
import type { ApmConfigSchema } from './apm_config';
// https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html
const DEFAULT_CONFIG: AgentConfigOptions = {
@ -49,6 +50,18 @@ const CENTRALIZED_SERVICE_DIST_CONFIG: AgentConfigOptions = {
transactionSampleRate: 0.1,
};
interface KibanaRawConfig {
elastic?: {
apm?: ApmConfigSchema;
};
path?: {
data?: string;
};
server?: {
uuid?: string;
};
}
export class ApmConfiguration {
private baseConfig?: AgentConfigOptions;
private kibanaVersion: string;
@ -56,7 +69,7 @@ export class ApmConfiguration {
constructor(
private readonly rootDir: string,
private readonly rawKibanaConfig: Record<string, any>,
private readonly rawKibanaConfig: KibanaRawConfig,
private readonly isDistributable: boolean
) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
@ -66,10 +79,19 @@ export class ApmConfiguration {
}
public getConfig(serviceName: string): AgentConfigOptions {
return {
const { servicesOverrides = {} } = this.getConfigFromKibanaConfig();
let baseConfig = {
...this.getBaseConfig(),
serviceName,
};
const serviceOverride = servicesOverrides[serviceName];
if (serviceOverride) {
baseConfig = merge({}, baseConfig, serviceOverride);
}
return baseConfig;
}
private getBaseConfig() {
@ -166,7 +188,7 @@ export class ApmConfiguration {
* Get the elastic.apm configuration from the --config file, supersedes the
* default config.
*/
private getConfigFromKibanaConfig(): AgentConfigOptions {
private getConfigFromKibanaConfig(): ApmConfigSchema {
return this.rawKibanaConfig?.elastic?.apm ?? {};
}
@ -266,7 +288,7 @@ export class ApmConfiguration {
* Reads APM configuration from different sources and merges them together.
*/
private getConfigFromAllSources(): AgentConfigOptions {
const configFromKibanaConfig = this.getConfigFromKibanaConfig();
const { servicesOverrides, ...configFromKibanaConfig } = this.getConfigFromKibanaConfig();
const configFromEnv = this.getConfigFromEnv(configFromKibanaConfig);
const config = merge({}, configFromKibanaConfig, configFromEnv);