Prepare APM agent configuration for production use (#78697)

This commit is contained in:
Josh Dover 2020-10-05 15:01:04 -06:00 committed by GitHub
parent 6a173ba19d
commit c3076a8011
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 60 additions and 24 deletions

View file

@ -42,12 +42,13 @@ describe('ApmConfiguration', () => {
resetAllMocks();
});
it('sets the correct service name', () => {
it('sets the correct service name and version', () => {
packageMock.raw = {
version: '9.2.1',
};
const config = new ApmConfiguration(mockedRootDir, {}, false);
expect(config.getConfig('myservice').serviceName).toBe('myservice-9_2_1');
expect(config.getConfig('myservice').serviceName).toBe('myservice');
expect(config.getConfig('myservice').serviceVersion).toBe('9.2.1');
});
it('sets the git revision from `git rev-parse` command in non distribution mode', () => {

View file

@ -30,8 +30,15 @@ const getDefaultConfig = (isDistributable: boolean): ApmAgentConfig => {
return {
active: false,
globalLabels: {},
// Do not use a centralized controlled config
centralConfig: false,
// Capture all exceptions that are not caught
logUncaughtExceptions: true,
// Can be performance intensive, disabling by default
breakdownMetrics: false,
};
}
return {
active: false,
serverUrl: 'https://f1542b814f674090afd914960583265f.apm.us-central1.gcp.cloud.es.io:443',
@ -60,14 +67,14 @@ export class ApmConfiguration {
) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { version, build } = require(join(this.rootDir, 'package.json'));
this.kibanaVersion = version.replace(/\./g, '_');
this.kibanaVersion = version;
this.pkgBuild = build;
}
public getConfig(serviceName: string): ApmAgentConfig {
return {
...this.getBaseConfig(),
serviceName: `${serviceName}-${this.kibanaVersion}`,
serviceName,
};
}
@ -76,7 +83,8 @@ export class ApmConfiguration {
const apmConfig = merge(
getDefaultConfig(this.isDistributable),
this.getConfigFromKibanaConfig(),
this.getDevConfig()
this.getDevConfig(),
this.getDistConfig()
);
const rev = this.getGitRev();
@ -88,6 +96,8 @@ export class ApmConfiguration {
if (uuid) {
apmConfig.globalLabels.kibana_uuid = uuid;
}
apmConfig.serviceVersion = this.kibanaVersion;
this.baseConfig = apmConfig;
}
@ -123,6 +133,19 @@ export class ApmConfiguration {
}
}
/** Config keys that cannot be overridden in production builds */
private getDistConfig(): ApmAgentConfig {
if (!this.isDistributable) {
return {};
}
return {
// Headers & body may contain sensitive info
captureHeaders: false,
captureBody: 'off',
};
}
private getGitRev() {
if (this.isDistributable) {
return this.pkgBuild.sha;

View file

@ -36,7 +36,22 @@ module.exports = function (serviceName = name) {
apmConfig = loadConfiguration(process.argv, ROOT_DIR, isKibanaDistributable);
const conf = apmConfig.getConfig(serviceName);
require('elastic-apm-node').start(conf);
const apm = require('elastic-apm-node');
// Filter out all user PII
apm.addFilter((payload) => {
try {
if (payload.context && payload.context.user && typeof payload.context.user === 'object') {
Object.keys(payload.context.user).forEach((key) => {
payload.context.user[key] = '[REDACTED]';
});
}
} finally {
return payload;
}
});
apm.start(conf);
};
module.exports.getConfig = (serviceName) => {
@ -50,4 +65,3 @@ module.exports.getConfig = (serviceName) => {
}
return {};
};
module.exports.isKibanaDistributable = isKibanaDistributable;

View file

@ -110,6 +110,7 @@ export class ClusterManager {
type: 'server',
log: this.log,
argv: serverArgv,
apmServiceName: 'kibana',
})),
];

View file

@ -49,6 +49,7 @@ interface WorkerOptions {
title?: string;
watch?: boolean;
baseArgv?: string[];
apmServiceName?: string;
}
export class Worker extends EventEmitter {
@ -89,6 +90,7 @@ export class Worker extends EventEmitter {
NODE_OPTIONS: process.env.NODE_OPTIONS || '',
kbnWorkerType: this.type,
kbnWorkerArgv: JSON.stringify([...(opts.baseArgv || baseArgv), ...(opts.argv || [])]),
ELASTIC_APM_SERVICE_NAME: opts.apmServiceName || '',
};
}

View file

@ -17,6 +17,6 @@
* under the License.
*/
require('../apm')(process.env.ELASTIC_APM_PROXY_SERVICE_NAME || 'kibana-proxy');
require('../apm')(process.env.ELASTIC_APM_SERVICE_NAME || 'kibana-proxy');
require('../setup_node_env');
require('./cli');

View file

@ -28,6 +28,7 @@ import type { InternalApplicationStart } from './application';
interface ApmConfig {
// AgentConfigOptions is not exported from @elastic/apm-rum
active?: boolean;
globalLabels?: Record<string, string>;
}
@ -39,10 +40,10 @@ export class ApmSystem {
private readonly enabled: boolean;
/**
* `apmConfig` would be populated with relevant APM RUM agent
* configuration if server is started with `ELASTIC_APM_ACTIVE=true`
* configuration if server is started with elastic.apm.* config.
*/
constructor(private readonly apmConfig?: ApmConfig) {
this.enabled = process.env.IS_KIBANA_DISTRIBUTABLE !== 'true' && apmConfig != null;
this.enabled = apmConfig != null && !!apmConfig.active;
}
async setup() {

View file

@ -25,6 +25,10 @@ const HANDLED_IN_NEW_PLATFORM = Joi.any().description(
);
export default () =>
Joi.object({
elastic: Joi.object({
apm: HANDLED_IN_NEW_PLATFORM,
}).default(),
pkg: Joi.object({
version: Joi.string().default(Joi.ref('$version')),
branch: Joi.string().default(Joi.ref('$branch')),

View file

@ -17,18 +17,10 @@
* under the License.
*/
import { getConfig, isKibanaDistributable } from '../../../apm';
import { getConfig } from '../../../apm';
import agent from 'elastic-apm-node';
const apmEnabled = !isKibanaDistributable && process.env.ELASTIC_APM_ACTIVE === 'true';
export function apmImport() {
return apmEnabled ? 'import { init } from "@elastic/apm-rum"' : '';
}
export function apmInit(config) {
return apmEnabled ? `init(${config})` : '';
}
const apmEnabled = getConfig()?.active;
export function getApmConfig(requestPath) {
if (!apmEnabled) {
@ -36,11 +28,9 @@ export function getApmConfig(requestPath) {
}
const config = {
...getConfig('kibana-frontend'),
...{
active: true,
pageLoadTransactionName: requestPath,
},
pageLoadTransactionName: requestPath,
};
/**
* Get current active backend transaction to make distrubuted tracing
* work for rendering the app