[7.17] chore(NA): remove prettier custom overrides across codebase (#180958) (#181077)

# Backport

This will backport the following commits from `main` to `7.17`:
- [chore(NA): remove prettier custom overrides across codebase
(#180958)](https://github.com/elastic/kibana/pull/180958)
This commit is contained in:
Tiago Costa 2024-04-17 21:00:48 +01:00 committed by GitHub
parent 531c3ac55a
commit 9d1a3745cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
780 changed files with 5278 additions and 11751 deletions

View file

@ -21,3 +21,4 @@ export DISABLE_BOOTSTRAP_VALIDATION=false
.buildkite/scripts/steps/checks/verify_notice.sh
.buildkite/scripts/steps/checks/test_projects.sh
.buildkite/scripts/steps/checks/test_hardening.sh
.buildkite/scripts/steps/checks/prettier_topology.sh

View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
source .buildkite/scripts/common/util.sh
echo --- Check Prettier Configuration Topology
node scripts/prettier_topology_check

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
require('../src/setup_node_env');
require('../src/dev/run_prettier_topology_check');

View file

@ -0,0 +1,54 @@
/*
* 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 globby from 'globby';
import path from 'path';
import { createFailError, run, REPO_ROOT } from '@kbn/dev-utils';
function listPaths(filePaths: string[]) {
return filePaths.map((filePath: string) => ` - ${filePath}`).join('\n');
}
run(async ({ log }) => {
const filePaths = await globby('**/.prettierrc*', {
cwd: REPO_ROOT,
onlyFiles: true,
gitignore: true,
ignore: [
// the gitignore: true option makes sure that we don't
// include files from node_modules in the result, but it still
// loads all of the files from node_modules before filtering
// so it's still super slow. This prevents loading the files
// and still relies on gitignore to final ignores
'**/node_modules',
],
});
// const filePaths = paths.map((path) => (new File(path)).getRelativePath());
if (!filePaths.length) {
throw createFailError(`A top level .prettierrc file should exist and no file was found.`);
}
if (filePaths.length > 1) {
throw createFailError(
`Only a single .prettierrc root file should exist and more than one were found.\n${listPaths(
filePaths
)}`
);
}
if (
filePaths.length === 1 &&
path.resolve(path.dirname(filePaths[0])) === path.resolve(REPO_ROOT)
) {
log.success('Only one .prettierrc file found at the root level.');
}
process.exit(0);
});

View file

@ -1,4 +0,0 @@
{
"singleQuote": true,
"semi": true
}

View file

@ -8,9 +8,7 @@
import t from 'io-ts';
import { agentConfigurationIntakeRt } from './runtime_types/agent_configuration_intake_rt';
export type AgentConfigurationIntake = t.TypeOf<
typeof agentConfigurationIntakeRt
>;
export type AgentConfigurationIntake = t.TypeOf<typeof agentConfigurationIntakeRt>;
export type AgentConfiguration = {
'@timestamp': number;

View file

@ -10,22 +10,20 @@ import { settingDefinitions } from '../setting_definitions';
import { SettingValidation } from '../setting_definitions/types';
// retrieve validation from config definitions settings and validate on the server
const knownSettings = settingDefinitions.reduce<
Record<string, SettingValidation>
>((acc, { key, validation }) => {
acc[key] = validation;
return acc;
}, {});
const knownSettings = settingDefinitions.reduce<Record<string, SettingValidation>>(
(acc, { key, validation }) => {
acc[key] = validation;
return acc;
},
{}
);
export const serviceRt = t.partial({
name: t.string,
environment: t.string,
});
export const settingsRt = t.intersection([
t.record(t.string, t.string),
t.partial(knownSettings),
]);
export const settingsRt = t.intersection([t.record(t.string, t.string), t.partial(knownSettings)]);
export const agentConfigurationIntakeRt = t.intersection([
t.partial({ agent_name: t.string }),

View file

@ -39,21 +39,14 @@ export function getBytesRt({ min, max }: { min?: string; max?: string }) {
'bytesRt',
t.string.is,
(input, context) => {
return either.chain(
t.string.validate(input, context),
(inputAsString) => {
const inputAsBytes = amountAndUnitToBytes(inputAsString);
return either.chain(t.string.validate(input, context), (inputAsString) => {
const inputAsBytes = amountAndUnitToBytes(inputAsString);
const isValidAmount =
inputAsBytes !== undefined &&
inputAsBytes >= minAsBytes &&
inputAsBytes <= maxAsBytes;
const isValidAmount =
inputAsBytes !== undefined && inputAsBytes >= minAsBytes && inputAsBytes <= maxAsBytes;
return isValidAmount
? t.success(inputAsString)
: t.failure(input, context, message);
}
);
return isValidAmount ? t.success(inputAsString) : t.failure(input, context, message);
});
},
t.identity
);

View file

@ -13,19 +13,7 @@ describe('getDurationRt', () => {
describe('must be at least 1m', () => {
const customDurationRt = getDurationRt({ min: '1m' });
describe('it should not accept', () => {
[
undefined,
null,
'',
0,
'foo',
true,
false,
'0m',
'-1m',
'1ms',
'1s',
].map((input) => {
[undefined, null, '', 0, 'foo', true, false, '0m', '-1m', '1ms', '1s'].map((input) => {
it(`${JSON.stringify(input)}`, () => {
expect(isRight(customDurationRt.decode(input))).toBeFalsy();
});
@ -98,13 +86,11 @@ describe('getDurationRt', () => {
const customDurationRt = getDurationRt({ max: '1m' });
describe('it should not accept', () => {
[undefined, null, '', 0, 'foo', true, false, '2m', '61s', '60001ms'].map(
(input) => {
it(`${JSON.stringify(input)}`, () => {
expect(isRight(customDurationRt.decode(input))).toBeFalsy();
});
}
);
[undefined, null, '', 0, 'foo', true, false, '2m', '61s', '60001ms'].map((input) => {
it(`${JSON.stringify(input)}`, () => {
expect(isRight(customDurationRt.decode(input))).toBeFalsy();
});
});
});
describe('it should return correct error message', () => {
['2m', '61s', '60001ms'].map((input) => {

View file

@ -33,22 +33,16 @@ export function getDurationRt({ min, max }: { min?: string; max?: string }) {
'durationRt',
t.string.is,
(input, context) => {
return either.chain(
t.string.validate(input, context),
(inputAsString) => {
const inputAsMilliseconds =
amountAndUnitToMilliseconds(inputAsString);
return either.chain(t.string.validate(input, context), (inputAsString) => {
const inputAsMilliseconds = amountAndUnitToMilliseconds(inputAsString);
const isValidAmount =
inputAsMilliseconds !== undefined &&
inputAsMilliseconds >= minAsMilliseconds &&
inputAsMilliseconds <= maxAsMilliseconds;
const isValidAmount =
inputAsMilliseconds !== undefined &&
inputAsMilliseconds >= minAsMilliseconds &&
inputAsMilliseconds <= maxAsMilliseconds;
return isValidAmount
? t.success(inputAsString)
: t.failure(input, context, message);
}
);
return isValidAmount ? t.success(inputAsString) : t.failure(input, context, message);
});
},
t.identity
);

View file

@ -14,11 +14,9 @@ export const floatRt = new t.Type<string, string, unknown>(
(input, context) => {
return either.chain(t.string.validate(input, context), (inputAsString) => {
const inputAsFloat = parseFloat(inputAsString);
const maxThreeDecimals =
parseFloat(inputAsFloat.toFixed(3)) === inputAsFloat;
const maxThreeDecimals = parseFloat(inputAsFloat.toFixed(3)) === inputAsFloat;
const isValid =
inputAsFloat >= 0 && inputAsFloat <= 1 && maxThreeDecimals;
const isValid = inputAsFloat >= 0 && inputAsFloat <= 1 && maxThreeDecimals;
return isValid
? t.success(inputAsString)

View file

@ -19,10 +19,7 @@ function getRangeType(min?: number, max?: number) {
}
}
export function getRangeTypeMessage(
min?: number | string,
max?: number | string
) {
export function getRangeTypeMessage(min?: number | string, max?: number | string) {
return i18n.translate('xpack.apm.agentConfig.range.errorText', {
defaultMessage: `{rangeType, select,
between {Must be between {min} and {max}}

View file

@ -17,13 +17,11 @@ describe('getIntegerRt', () => {
});
describe('it should not accept', () => {
[NaN, undefined, null, '', 'foo', 0, 55, '-1', '-55', '33000'].map(
(input) => {
it(`${JSON.stringify(input)}`, () => {
expect(isRight(integerRt.decode(input))).toBe(false);
});
}
);
[NaN, undefined, null, '', 'foo', 0, 55, '-1', '-55', '33000'].map((input) => {
it(`${JSON.stringify(input)}`, () => {
expect(isRight(integerRt.decode(input))).toBe(false);
});
});
});
describe('it should return correct error message', () => {

View file

@ -22,16 +22,11 @@ export function getIntegerRt({
'integerRt',
t.string.is,
(input, context) => {
return either.chain(
t.string.validate(input, context),
(inputAsString) => {
const inputAsInt = parseInt(inputAsString, 10);
const isValid = inputAsInt >= min && inputAsInt <= max;
return isValid
? t.success(inputAsString)
: t.failure(input, context, message);
}
);
return either.chain(t.string.validate(input, context), (inputAsString) => {
const inputAsInt = parseInt(inputAsString, 10);
const isValid = inputAsInt >= min && inputAsInt <= max;
return isValid ? t.success(inputAsString) : t.failure(input, context, message);
});
},
t.identity
);

View file

@ -19,13 +19,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.apiRequestSize.label', {
defaultMessage: 'API Request Size',
}),
description: i18n.translate(
'xpack.apm.agentConfig.apiRequestSize.description',
{
defaultMessage:
'The maximum total compressed size of the request body which is sent to the APM Server intake api via a chunked encoding (HTTP streaming).\nNote that a small overshoot is possible.\n\nAllowed byte units are `b`, `kb` and `mb`. `1kb` is equal to `1024b`.',
}
),
description: i18n.translate('xpack.apm.agentConfig.apiRequestSize.description', {
defaultMessage:
'The maximum total compressed size of the request body which is sent to the APM Server intake api via a chunked encoding (HTTP streaming).\nNote that a small overshoot is possible.\n\nAllowed byte units are `b`, `kb` and `mb`. `1kb` is equal to `1024b`.',
}),
excludeAgents: ['js-base', 'rum-js', 'dotnet', 'go', 'nodejs', 'php'],
},
@ -37,13 +34,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.apiRequestTime.label', {
defaultMessage: 'API Request Time',
}),
description: i18n.translate(
'xpack.apm.agentConfig.apiRequestTime.description',
{
defaultMessage:
"Maximum time to keep an HTTP request to the APM Server open for.\n\nNOTE: This value has to be lower than the APM Server's `read_timeout` setting.",
}
),
description: i18n.translate('xpack.apm.agentConfig.apiRequestTime.description', {
defaultMessage:
"Maximum time to keep an HTTP request to the APM Server open for.\n\nNOTE: This value has to be lower than the APM Server's `read_timeout` setting.",
}),
excludeAgents: ['js-base', 'rum-js', 'dotnet', 'go', 'nodejs', 'php'],
},
@ -56,13 +50,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.captureBody.label', {
defaultMessage: 'Capture body',
}),
description: i18n.translate(
'xpack.apm.agentConfig.captureBody.description',
{
defaultMessage:
'For transactions that are HTTP requests, the agent can optionally capture the request body (e.g. POST variables).\nFor transactions that are initiated by receiving a message from a message broker, the agent can capture the textual message body.',
}
),
description: i18n.translate('xpack.apm.agentConfig.captureBody.description', {
defaultMessage:
'For transactions that are HTTP requests, the agent can optionally capture the request body (e.g. POST variables).\nFor transactions that are initiated by receiving a message from a message broker, the agent can capture the textual message body.',
}),
options: [
{ text: 'off', value: 'off' },
{ text: 'errors', value: 'errors' },
@ -80,13 +71,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.captureHeaders.label', {
defaultMessage: 'Capture Headers',
}),
description: i18n.translate(
'xpack.apm.agentConfig.captureHeaders.description',
{
defaultMessage:
'If set to `true`, the agent will capture HTTP request and response headers (including cookies), as well as message headers/properties when using messaging frameworks (like Kafka).\n\nNOTE: Setting this to `false` reduces network bandwidth, disk space and object allocations.',
}
),
description: i18n.translate('xpack.apm.agentConfig.captureHeaders.description', {
defaultMessage:
'If set to `true`, the agent will capture HTTP request and response headers (including cookies), as well as message headers/properties when using messaging frameworks (like Kafka).\n\nNOTE: Setting this to `false` reduces network bandwidth, disk space and object allocations.',
}),
excludeAgents: ['js-base', 'rum-js', 'nodejs', 'php'],
},
@ -137,13 +125,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.serverTimeout.label', {
defaultMessage: 'Server Timeout',
}),
description: i18n.translate(
'xpack.apm.agentConfig.serverTimeout.description',
{
defaultMessage:
'If a request to the APM Server takes longer than the configured timeout,\nthe request is cancelled and the event (exception or transaction) is discarded.\nSet to 0 to disable timeouts.\n\nWARNING: If timeouts are disabled or set to a high value, your app could experience memory issues if the APM Server times out.',
}
),
description: i18n.translate('xpack.apm.agentConfig.serverTimeout.description', {
defaultMessage:
'If a request to the APM Server takes longer than the configured timeout,\nthe request is cancelled and the event (exception or transaction) is discarded.\nSet to 0 to disable timeouts.\n\nWARNING: If timeouts are disabled or set to a high value, your app could experience memory issues if the APM Server times out.',
}),
includeAgents: ['java'],
},
@ -156,13 +141,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.spanFramesMinDuration.label', {
defaultMessage: 'Span frames minimum duration',
}),
description: i18n.translate(
'xpack.apm.agentConfig.spanFramesMinDuration.description',
{
defaultMessage:
'In its default settings, the APM agent will collect a stack trace with every recorded span.\nWhile this is very helpful to find the exact place in your code that causes the span, collecting this stack trace does have some overhead. \nWhen setting this option to a negative value, like `-1ms`, stack traces will be collected for all spans. Setting it to a positive value, e.g. `5ms`, will limit stack trace collection to spans with durations equal to or longer than the given value, e.g. 5 milliseconds.\n\nTo disable stack trace collection for spans completely, set the value to `0ms`.',
}
),
description: i18n.translate('xpack.apm.agentConfig.spanFramesMinDuration.description', {
defaultMessage:
'In its default settings, the APM agent will collect a stack trace with every recorded span.\nWhile this is very helpful to find the exact place in your code that causes the span, collecting this stack trace does have some overhead. \nWhen setting this option to a negative value, like `-1ms`, stack traces will be collected for all spans. Setting it to a positive value, e.g. `5ms`, will limit stack trace collection to spans with durations equal to or longer than the given value, e.g. 5 milliseconds.\n\nTo disable stack trace collection for spans completely, set the value to `0ms`.',
}),
excludeAgents: ['js-base', 'rum-js', 'nodejs', 'php'],
},
@ -174,13 +156,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.stackTraceLimit.label', {
defaultMessage: 'Stack trace limit',
}),
description: i18n.translate(
'xpack.apm.agentConfig.stackTraceLimit.description',
{
defaultMessage:
'Setting it to 0 will disable stack trace collection. Any positive integer value will be used as the maximum number of frames to collect. Setting it -1 means that all frames will be collected.',
}
),
description: i18n.translate('xpack.apm.agentConfig.stackTraceLimit.description', {
defaultMessage:
'Setting it to 0 will disable stack trace collection. Any positive integer value will be used as the maximum number of frames to collect. Setting it -1 means that all frames will be collected.',
}),
includeAgents: ['java', 'dotnet', 'go'],
},
@ -193,13 +172,9 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.transactionMaxSpans.label', {
defaultMessage: 'Transaction max spans',
}),
description: i18n.translate(
'xpack.apm.agentConfig.transactionMaxSpans.description',
{
defaultMessage:
'Limits the amount of spans that are recorded per transaction.',
}
),
description: i18n.translate('xpack.apm.agentConfig.transactionMaxSpans.description', {
defaultMessage: 'Limits the amount of spans that are recorded per transaction.',
}),
excludeAgents: ['js-base', 'rum-js'],
},
@ -211,13 +186,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.transactionSampleRate.label', {
defaultMessage: 'Transaction sample rate',
}),
description: i18n.translate(
'xpack.apm.agentConfig.transactionSampleRate.description',
{
defaultMessage:
'By default, the agent will sample every transaction (e.g. request to your service). To reduce overhead and storage requirements, you can set the sample rate to a value between 0.0 and 1.0. We still record overall time and the result for unsampled transactions, but not context information, labels, or spans.',
}
),
description: i18n.translate('xpack.apm.agentConfig.transactionSampleRate.description', {
defaultMessage:
'By default, the agent will sample every transaction (e.g. request to your service). To reduce overhead and storage requirements, you can set the sample rate to a value between 0.0 and 1.0. We still record overall time and the result for unsampled transactions, but not context information, labels, or spans.',
}),
},
// Sanitize field names
@ -229,13 +201,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.sanitizeFiledNames.label', {
defaultMessage: 'Sanitize field names',
}),
description: i18n.translate(
'xpack.apm.agentConfig.sanitizeFiledNames.description',
{
defaultMessage:
'Sometimes it is necessary to sanitize, i.e., remove, sensitive data sent to Elastic APM. This config accepts a list of wildcard patterns of field names which should be sanitized. These apply to HTTP headers (including cookies) and `application/x-www-form-urlencoded` data (POST form fields). The query string and the captured request body (such as `application/json` data) will not get sanitized.',
}
),
description: i18n.translate('xpack.apm.agentConfig.sanitizeFiledNames.description', {
defaultMessage:
'Sometimes it is necessary to sanitize, i.e., remove, sensitive data sent to Elastic APM. This config accepts a list of wildcard patterns of field names which should be sanitized. These apply to HTTP headers (including cookies) and `application/x-www-form-urlencoded` data (POST form fields). The query string and the captured request body (such as `application/json` data) will not get sanitized.',
}),
includeAgents: ['java', 'python', 'go', 'dotnet', 'nodejs', 'ruby'],
},
@ -248,13 +217,10 @@ export const generalSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.transactionIgnoreUrl.label', {
defaultMessage: 'Ignore transactions based on URLs',
}),
description: i18n.translate(
'xpack.apm.agentConfig.transactionIgnoreUrl.description',
{
defaultMessage:
'Used to restrict requests to certain URLs from being instrumented. This config accepts a comma-separated list of wildcard patterns of URL paths that should be ignored. When an incoming HTTP request is detected, its request path will be tested against each element in this list. For example, adding `/home/index` to this list would match and remove instrumentation from `http://localhost/home/index` as well as `http://whatever.com/home/index?value1=123`',
}
),
description: i18n.translate('xpack.apm.agentConfig.transactionIgnoreUrl.description', {
defaultMessage:
'Used to restrict requests to certain URLs from being instrumented. This config accepts a comma-separated list of wildcard patterns of URL paths that should be ignored. When an incoming HTTP request is detected, its request path will be tested against each element in this list. For example, adding `/home/index` to this list would match and remove instrumentation from `http://localhost/home/index` as well as `http://whatever.com/home/index?value1=123`',
}),
includeAgents: ['java', 'nodejs', 'python', 'dotnet', 'ruby', 'go'],
},
];

View file

@ -88,15 +88,11 @@ describe('filterByAgent', () => {
});
it('js-base', () => {
expect(getSettingKeysForAgent('js-base')).toEqual([
'transaction_sample_rate',
]);
expect(getSettingKeysForAgent('js-base')).toEqual(['transaction_sample_rate']);
});
it('rum-js', () => {
expect(getSettingKeysForAgent('rum-js')).toEqual([
'transaction_sample_rate',
]);
expect(getSettingKeysForAgent('rum-js')).toEqual(['transaction_sample_rate']);
});
it('nodejs', () => {

View file

@ -17,13 +17,10 @@ export const javaSettings: RawSettingDefinition[] = [
label: i18n.translate('xpack.apm.agentConfig.enableLogCorrelation.label', {
defaultMessage: 'Enable log correlation',
}),
description: i18n.translate(
'xpack.apm.agentConfig.enableLogCorrelation.description',
{
defaultMessage:
"A boolean specifying if the agent should integrate into SLF4J's MDC to enable trace-log correlation. If set to `true`, the agent will set the `trace.id` and `transaction.id` for the currently active spans and transactions to the MDC. Since Java agent version 1.16.0, the agent also adds `error.id` of captured error to the MDC just before the error message is logged. NOTE: While it's allowed to enable this setting at runtime, you can't disable it without a restart.",
}
),
description: i18n.translate('xpack.apm.agentConfig.enableLogCorrelation.description', {
defaultMessage:
"A boolean specifying if the agent should integrate into SLF4J's MDC to enable trace-log correlation. If set to `true`, the agent will set the `trace.id` and `transaction.id` for the currently active spans and transactions to the MDC. Since Java agent version 1.16.0, the agent also adds `error.id` of captured error to the MDC just before the error message is logged. NOTE: While it's allowed to enable this setting at runtime, you can't disable it without a restart.",
}),
includeAgents: ['java'],
},
@ -38,21 +35,17 @@ export const javaSettings: RawSettingDefinition[] = [
type: 'boolean',
category: 'Circuit-Breaker',
defaultValue: 'false',
description: i18n.translate(
'xpack.apm.agentConfig.circuitBreakerEnabled.description',
{
defaultMessage:
'A boolean specifying whether the circuit breaker should be enabled or not. When enabled, the agent periodically polls stress monitors to detect system/process/JVM stress state. If ANY of the monitors detects a stress indication, the agent will pause, as if the `recording` configuration option has been set to `false`, thus reducing resource consumption to a minimum. When paused, the agent continues polling the same monitors in order to detect whether the stress state has been relieved. If ALL monitors approve that the system/process/JVM is not under stress anymore, the agent will resume and become fully functional.',
}
),
description: i18n.translate('xpack.apm.agentConfig.circuitBreakerEnabled.description', {
defaultMessage:
'A boolean specifying whether the circuit breaker should be enabled or not. When enabled, the agent periodically polls stress monitors to detect system/process/JVM stress state. If ANY of the monitors detects a stress indication, the agent will pause, as if the `recording` configuration option has been set to `false`, thus reducing resource consumption to a minimum. When paused, the agent continues polling the same monitors in order to detect whether the stress state has been relieved. If ALL monitors approve that the system/process/JVM is not under stress anymore, the agent will resume and become fully functional.',
}),
includeAgents: ['java'],
},
{
key: 'stress_monitor_gc_stress_threshold',
label: i18n.translate(
'xpack.apm.agentConfig.stressMonitorGcStressThreshold.label',
{ defaultMessage: 'Stress monitor gc stress threshold' }
),
label: i18n.translate('xpack.apm.agentConfig.stressMonitorGcStressThreshold.label', {
defaultMessage: 'Stress monitor gc stress threshold',
}),
type: 'float',
category: 'Circuit-Breaker',
defaultValue: '0.95',
@ -67,10 +60,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'stress_monitor_gc_relief_threshold',
label: i18n.translate(
'xpack.apm.agentConfig.stressMonitorGcReliefThreshold.label',
{ defaultMessage: 'Stress monitor gc relief threshold' }
),
label: i18n.translate('xpack.apm.agentConfig.stressMonitorGcReliefThreshold.label', {
defaultMessage: 'Stress monitor gc relief threshold',
}),
type: 'float',
category: 'Circuit-Breaker',
@ -86,10 +78,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'stress_monitor_cpu_duration_threshold',
label: i18n.translate(
'xpack.apm.agentConfig.stressMonitorCpuDurationThreshold.label',
{ defaultMessage: 'Stress monitor cpu duration threshold' }
),
label: i18n.translate('xpack.apm.agentConfig.stressMonitorCpuDurationThreshold.label', {
defaultMessage: 'Stress monitor cpu duration threshold',
}),
type: 'duration',
category: 'Circuit-Breaker',
defaultValue: '1m',
@ -105,10 +96,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'stress_monitor_system_cpu_stress_threshold',
label: i18n.translate(
'xpack.apm.agentConfig.stressMonitorSystemCpuStressThreshold.label',
{ defaultMessage: 'Stress monitor system cpu stress threshold' }
),
label: i18n.translate('xpack.apm.agentConfig.stressMonitorSystemCpuStressThreshold.label', {
defaultMessage: 'Stress monitor system cpu stress threshold',
}),
type: 'float',
category: 'Circuit-Breaker',
defaultValue: '0.95',
@ -123,10 +113,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'stress_monitor_system_cpu_relief_threshold',
label: i18n.translate(
'xpack.apm.agentConfig.stressMonitorSystemCpuReliefThreshold.label',
{ defaultMessage: 'Stress monitor system cpu relief threshold' }
),
label: i18n.translate('xpack.apm.agentConfig.stressMonitorSystemCpuReliefThreshold.label', {
defaultMessage: 'Stress monitor system cpu relief threshold',
}),
type: 'float',
category: 'Circuit-Breaker',
defaultValue: '0.8',
@ -146,28 +135,23 @@ export const javaSettings: RawSettingDefinition[] = [
{
key: 'profiling_inferred_spans_enabled',
label: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansEnabled.label',
{ defaultMessage: 'Profiling inferred spans enabled' }
),
label: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansEnabled.label', {
defaultMessage: 'Profiling inferred spans enabled',
}),
type: 'boolean',
category: 'Profiling',
defaultValue: 'false',
description: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansEnabled.description',
{
defaultMessage:
'Set to `true` to make the agent create spans for method executions based on async-profiler, a sampling aka statistical profiler. Due to the nature of how sampling profilers work, the duration of the inferred spans are not exact, but only estimations. The `profiling_inferred_spans_sampling_interval` lets you fine tune the trade-off between accuracy and overhead. The inferred spans are created after a profiling session has ended. This means there is a delay between the regular and the inferred spans being visible in the UI. NOTE: This feature is not available on Windows.',
}
),
description: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansEnabled.description', {
defaultMessage:
'Set to `true` to make the agent create spans for method executions based on async-profiler, a sampling aka statistical profiler. Due to the nature of how sampling profilers work, the duration of the inferred spans are not exact, but only estimations. The `profiling_inferred_spans_sampling_interval` lets you fine tune the trade-off between accuracy and overhead. The inferred spans are created after a profiling session has ended. This means there is a delay between the regular and the inferred spans being visible in the UI. NOTE: This feature is not available on Windows.',
}),
includeAgents: ['java'],
},
{
key: 'profiling_inferred_spans_sampling_interval',
label: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansSamplingInterval.label',
{ defaultMessage: 'Profiling inferred spans sampling interval' }
),
label: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansSamplingInterval.label', {
defaultMessage: 'Profiling inferred spans sampling interval',
}),
type: 'duration',
category: 'Profiling',
defaultValue: '50ms',
@ -184,10 +168,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'profiling_inferred_spans_min_duration',
label: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansMinDuration.label',
{ defaultMessage: 'Profiling inferred spans min duration' }
),
label: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansMinDuration.label', {
defaultMessage: 'Profiling inferred spans min duration',
}),
type: 'duration',
category: 'Profiling',
defaultValue: '0ms',
@ -203,10 +186,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'profiling_inferred_spans_included_classes',
label: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansIncludedClasses.label',
{ defaultMessage: 'Profiling inferred spans included classes' }
),
label: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansIncludedClasses.label', {
defaultMessage: 'Profiling inferred spans included classes',
}),
type: 'text',
category: 'Profiling',
defaultValue: '*',
@ -221,10 +203,9 @@ export const javaSettings: RawSettingDefinition[] = [
},
{
key: 'profiling_inferred_spans_excluded_classes',
label: i18n.translate(
'xpack.apm.agentConfig.profilingInferredSpansExcludedClasses.label',
{ defaultMessage: 'Profiling inferred spans excluded classes' }
),
label: i18n.translate('xpack.apm.agentConfig.profilingInferredSpansExcludedClasses.label', {
defaultMessage: 'Profiling inferred spans excluded classes',
}),
type: 'text',
category: 'Profiling',
defaultValue:

View file

@ -46,17 +46,11 @@ export const AGENT_NAMES: AgentName[] = [
export const JAVA_AGENT_NAMES: AgentName[] = ['java', 'opentelemetry/java'];
export function isJavaAgentName(
agentName?: string
): agentName is 'java' | 'opentelemetry/java' {
export function isJavaAgentName(agentName?: string): agentName is 'java' | 'opentelemetry/java' {
return JAVA_AGENT_NAMES.includes(agentName! as AgentName);
}
export const RUM_AGENT_NAMES: AgentName[] = [
'js-base',
'rum-js',
'opentelemetry/webjs',
];
export const RUM_AGENT_NAMES: AgentName[] = ['js-base', 'rum-js', 'opentelemetry/webjs'];
export function isRumAgentName(
agentName?: string
@ -64,9 +58,7 @@ export function isRumAgentName(
return RUM_AGENT_NAMES.includes(agentName! as AgentName);
}
export function normalizeAgentName<T extends string | undefined>(
agentName: T
): T | string {
export function normalizeAgentName<T extends string | undefined>(agentName: T): T | string {
if (isRumAgentName(agentName)) {
return 'rum-js';
}

View file

@ -99,17 +99,14 @@ export function formatTransactionDurationAnomalyReason({
severityLevel: string;
measured: number;
}) {
return i18n.translate(
'xpack.apm.alertTypes.transactionDurationAnomaly.reason',
{
defaultMessage: `{severityLevel} anomaly detected for {serviceName} (score was {measured})`,
values: {
serviceName,
severityLevel,
measured,
},
}
);
return i18n.translate('xpack.apm.alertTypes.transactionDurationAnomaly.reason', {
defaultMessage: `{severityLevel} anomaly detected for {serviceName} (score was {measured})`,
values: {
serviceName,
severityLevel,
measured,
},
});
}
export const ALERT_TYPES_CONFIG: Record<
@ -196,9 +193,7 @@ export const ANOMALY_ALERT_SEVERITY_TYPES = [
},
] as const;
export type AnomalyAlertSeverityType = ValuesType<
typeof ANOMALY_ALERT_SEVERITY_TYPES
>['type'];
export type AnomalyAlertSeverityType = ValuesType<typeof ANOMALY_ALERT_SEVERITY_TYPES>['type'];
// Server side registrations
// x-pack/plugins/apm/server/lib/alerts/<alert>.ts

View file

@ -7,10 +7,7 @@
import { i18n } from '@kbn/i18n';
import { ANOMALY_SEVERITY } from './ml_constants';
import {
getSeverityType,
getSeverityColor as mlGetSeverityColor,
} from '../../ml/common';
import { getSeverityType, getSeverityColor as mlGetSeverityColor } from '../../ml/common';
import { ServiceHealthStatus } from './service_health_status';
export interface ServiceAnomalyStats {
@ -34,12 +31,9 @@ export function getSeverityColor(score: number) {
}
export const ML_ERRORS = {
INVALID_LICENSE: i18n.translate(
'xpack.apm.anomaly_detection.error.invalid_license',
{
defaultMessage: `To use anomaly detection, you must be subscribed to an Elastic Platinum license. With it, you'll be able to monitor your services with the aid of machine learning.`,
}
),
INVALID_LICENSE: i18n.translate('xpack.apm.anomaly_detection.error.invalid_license', {
defaultMessage: `To use anomaly detection, you must be subscribed to an Elastic Platinum license. With it, you'll be able to monitor your services with the aid of machine learning.`,
}),
MISSING_READ_PRIVILEGES: i18n.translate(
'xpack.apm.anomaly_detection.error.missing_read_privileges',
{
@ -54,12 +48,9 @@ export const ML_ERRORS = {
'You must have "write" privileges to Machine Learning and APM in order to create Anomaly Detection jobs',
}
),
ML_NOT_AVAILABLE: i18n.translate(
'xpack.apm.anomaly_detection.error.not_available',
{
defaultMessage: 'Machine learning is not available',
}
),
ML_NOT_AVAILABLE: i18n.translate('xpack.apm.anomaly_detection.error.not_available', {
defaultMessage: 'Machine learning is not available',
}),
ML_NOT_AVAILABLE_IN_SPACE: i18n.translate(
'xpack.apm.anomaly_detection.error.not_available_in_space',
{

View file

@ -7,10 +7,7 @@
type Method = 'get' | 'post' | 'put' | 'delete';
export function parseEndpoint(
endpoint: string,
pathParams: Record<string, any> = {}
) {
export function parseEndpoint(endpoint: string, pathParams: Record<string, any> = {}) {
const [method, rawPathname] = endpoint.split(' ');
// replace template variables with path params

View file

@ -5,10 +5,7 @@
* 2.0.
*/
import {
getApmTelemetryMapping,
mergeApmTelemetryMapping,
} from './apm_telemetry';
import { getApmTelemetryMapping, mergeApmTelemetryMapping } from './apm_telemetry';
// Add this snapshot serializer for this test. The default snapshot serializer
// prints "Object" next to objects in the JSON output, but we want to be able to
@ -80,8 +77,8 @@ describe('APM telemetry helpers', () => {
};
expect(
mergeApmTelemetryMapping(validTelemetryMapping)?.mappings.properties
.stack_stats.properties.kibana.properties.plugins.properties.apm
mergeApmTelemetryMapping(validTelemetryMapping)?.mappings.properties.stack_stats
.properties.kibana.properties.plugins.properties.apm
).toEqual(getApmTelemetryMapping());
});
});

View file

@ -24,10 +24,7 @@ function schemaToMapping(schemaLeaf: any): any {
return {
...acc,
[key]:
typeof propMapping.type === 'string'
? propMapping
: { properties: propMapping },
[key]: typeof propMapping.type === 'string' ? propMapping : { properties: propMapping },
};
}, {});
}
@ -45,9 +42,7 @@ export function getApmTelemetryMapping() {
* Merge a telemetry mapping object (from https://github.com/elastic/telemetry/blob/master/config/templates/xpack-phone-home.json)
* with the output from `getApmTelemetryMapping`.
*/
export function mergeApmTelemetryMapping(
xpackPhoneHomeMapping: Record<string, any>
) {
export function mergeApmTelemetryMapping(xpackPhoneHomeMapping: Record<string, any>) {
return produce(xpackPhoneHomeMapping, (draft: Record<string, any>) => {
draft.mappings.properties.stack_stats.properties.kibana.properties.plugins.properties.apm =
getApmTelemetryMapping();

View file

@ -7,18 +7,12 @@
import { i18n } from '@kbn/i18n';
import { ProcessorEvent } from './processor_event';
import {
PROCESSOR_EVENT,
SPAN_DESTINATION_SERVICE_RESOURCE,
} from './elasticsearch_fieldnames';
import { PROCESSOR_EVENT, SPAN_DESTINATION_SERVICE_RESOURCE } from './elasticsearch_fieldnames';
import { environmentQuery } from './utils/environment_query';
export const kueryBarPlaceholder = i18n.translate(
'xpack.apm.dependencies.kueryBarPlaceholder',
{
defaultMessage: `Search dependency metrics (e.g. span.destination.service.resource:elasticsearch)`,
}
);
export const kueryBarPlaceholder = i18n.translate('xpack.apm.dependencies.kueryBarPlaceholder', {
defaultMessage: `Search dependency metrics (e.g. span.destination.service.resource:elasticsearch)`,
});
export const getKueryBarBoolFilter = ({
backendName,
@ -30,9 +24,7 @@ export const getKueryBarBoolFilter = ({
return [
{ term: { [PROCESSOR_EVENT]: ProcessorEvent.metric } },
{ exists: { field: SPAN_DESTINATION_SERVICE_RESOURCE } },
...(backendName
? [{ term: { [SPAN_DESTINATION_SERVICE_RESOURCE]: backendName } }]
: []),
...(backendName ? [{ term: { [SPAN_DESTINATION_SERVICE_RESOURCE]: backendName } }] : []),
...environmentQuery(environment),
];
};

View file

@ -61,11 +61,7 @@ export const FIELDS_TO_ADD_AS_CANDIDATE = new Set([
'process.args',
'http.response.status_code',
]);
export const FIELD_PREFIX_TO_ADD_AS_CANDIDATE = [
'cloud.',
'labels.',
'user_agent.',
];
export const FIELD_PREFIX_TO_ADD_AS_CANDIDATE = ['cloud.', 'labels.', 'user_agent.'];
/**
* Other constants

View file

@ -8,22 +8,13 @@
import { i18n } from '@kbn/i18n';
export const FAILED_TRANSACTIONS_IMPACT_THRESHOLD = {
HIGH: i18n.translate(
'xpack.apm.correlations.failedTransactions.highImpactText',
{
defaultMessage: 'High',
}
),
MEDIUM: i18n.translate(
'xpack.apm.correlations.failedTransactions.mediumImpactText',
{
defaultMessage: 'Medium',
}
),
LOW: i18n.translate(
'xpack.apm.correlations.failedTransactions.lowImpactText',
{
defaultMessage: 'Low',
}
),
HIGH: i18n.translate('xpack.apm.correlations.failedTransactions.highImpactText', {
defaultMessage: 'High',
}),
MEDIUM: i18n.translate('xpack.apm.correlations.failedTransactions.mediumImpactText', {
defaultMessage: 'Medium',
}),
LOW: i18n.translate('xpack.apm.correlations.failedTransactions.lowImpactText', {
defaultMessage: 'Low',
}),
} as const;

View file

@ -51,7 +51,4 @@ export interface BooleanFieldStats {
[key: string]: number | string;
}
export type FieldStats =
| NumericFieldStats
| KeywordFieldStats
| BooleanFieldStats;
export type FieldStats = NumericFieldStats | KeywordFieldStats | BooleanFieldStats;

View file

@ -41,5 +41,4 @@ export interface CorrelationsServerParams {
includeFrozen?: boolean;
}
export type CorrelationsParams = CorrelationsClientParams &
CorrelationsServerParams;
export type CorrelationsParams = CorrelationsClientParams & CorrelationsServerParams;

View file

@ -14,8 +14,7 @@ describe('correlations', () => {
{ fieldName: 'the-field-1', fieldValue: 'the-value-1' },
{ fieldName: 'the-field-2', fieldValue: 'the-value-2' },
];
const prioritziedFieldValuePairs =
getPrioritizedFieldValuePairs(fieldValuePairs);
const prioritziedFieldValuePairs = getPrioritizedFieldValuePairs(fieldValuePairs);
expect(prioritziedFieldValuePairs.map((d) => d.fieldName)).toEqual([
'the-field-1',
'the-field-2',
@ -27,8 +26,7 @@ describe('correlations', () => {
{ fieldName: 'service.version', fieldValue: 'the-value-1' },
{ fieldName: 'the-field-2', fieldValue: 'the-value-2' },
];
const prioritziedFieldValuePairs =
getPrioritizedFieldValuePairs(fieldValuePairs);
const prioritziedFieldValuePairs = getPrioritizedFieldValuePairs(fieldValuePairs);
expect(prioritziedFieldValuePairs.map((d) => d.fieldName)).toEqual([
'service.version',
'the-field-2',
@ -40,8 +38,7 @@ describe('correlations', () => {
{ fieldName: 'the-field-1', fieldValue: 'the-value-1' },
{ fieldName: 'service.version', fieldValue: 'the-value-2' },
];
const prioritziedFieldValuePairs =
getPrioritizedFieldValuePairs(fieldValuePairs);
const prioritziedFieldValuePairs = getPrioritizedFieldValuePairs(fieldValuePairs);
expect(prioritziedFieldValuePairs.map((d) => d.fieldName)).toEqual([
'service.version',
'the-field-1',
@ -54,8 +51,7 @@ describe('correlations', () => {
{ fieldName: 'service.version', fieldValue: 'the-value-2' },
{ fieldName: 'cloud.the-field-3', fieldValue: 'the-value-3' },
];
const prioritziedFieldValuePairs =
getPrioritizedFieldValuePairs(fieldValuePairs);
const prioritziedFieldValuePairs = getPrioritizedFieldValuePairs(fieldValuePairs);
expect(prioritziedFieldValuePairs.map((d) => d.fieldName)).toEqual([
'service.version',
'cloud.the-field-3',

View file

@ -10,9 +10,7 @@ import { hasPrefixToInclude } from './has_prefix_to_include';
import type { FieldValuePair } from '../types';
export const getPrioritizedFieldValuePairs = (
fieldValuePairs: FieldValuePair[]
) => {
export const getPrioritizedFieldValuePairs = (fieldValuePairs: FieldValuePair[]) => {
const prioritizedFields = [...FIELDS_TO_ADD_AS_CANDIDATE];
return fieldValuePairs.sort((a, b) => {

View file

@ -18,9 +18,7 @@ describe('aggregation utils', () => {
});
it('returns false if the prefix is included', async () => {
FIELD_PREFIX_TO_ADD_AS_CANDIDATE.forEach((prefix) => {
expect(
hasPrefixToInclude(`unknown-prefix-.${prefix}the-field-name`)
).toBe(false);
expect(hasPrefixToInclude(`unknown-prefix-.${prefix}the-field-name`)).toBe(false);
expect(hasPrefixToInclude('the-field-name')).toBe(false);
});
});

View file

@ -8,7 +8,5 @@
import { FIELD_PREFIX_TO_ADD_AS_CANDIDATE } from '../constants';
export const hasPrefixToInclude = (fieldName: string) => {
return FIELD_PREFIX_TO_ADD_AS_CANDIDATE.some((prefix) =>
fieldName.startsWith(prefix)
);
return FIELD_PREFIX_TO_ADD_AS_CANDIDATE.some((prefix) => fieldName.startsWith(prefix));
};

View file

@ -18,7 +18,6 @@ export const INVALID_LICENSE = i18n.translate(
export const NO_PERMISSION_LABEL = i18n.translate(
'xpack.apm.settings.customizeUI.customLink.noPermissionTooltipLabel',
{
defaultMessage:
"Your user role doesn't have permissions to create custom links",
defaultMessage: "Your user role doesn't have permissions to create custom links",
}
);

View file

@ -67,8 +67,7 @@ export const SPAN_SELF_TIME_SUM = 'span.self_time.sum.us';
export const SPAN_ACTION = 'span.action';
export const SPAN_NAME = 'span.name';
export const SPAN_ID = 'span.id';
export const SPAN_DESTINATION_SERVICE_RESOURCE =
'span.destination.service.resource';
export const SPAN_DESTINATION_SERVICE_RESOURCE = 'span.destination.service.resource';
export const SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT =
'span.destination.service.response_time.count';
@ -93,17 +92,14 @@ export const METRIC_SYSTEM_FREE_MEMORY = 'system.memory.actual.free';
export const METRIC_SYSTEM_TOTAL_MEMORY = 'system.memory.total';
export const METRIC_SYSTEM_CPU_PERCENT = 'system.cpu.total.norm.pct';
export const METRIC_PROCESS_CPU_PERCENT = 'system.process.cpu.total.norm.pct';
export const METRIC_CGROUP_MEMORY_LIMIT_BYTES =
'system.process.cgroup.memory.mem.limit.bytes';
export const METRIC_CGROUP_MEMORY_USAGE_BYTES =
'system.process.cgroup.memory.mem.usage.bytes';
export const METRIC_CGROUP_MEMORY_LIMIT_BYTES = 'system.process.cgroup.memory.mem.limit.bytes';
export const METRIC_CGROUP_MEMORY_USAGE_BYTES = 'system.process.cgroup.memory.mem.usage.bytes';
export const METRIC_JAVA_HEAP_MEMORY_MAX = 'jvm.memory.heap.max';
export const METRIC_JAVA_HEAP_MEMORY_COMMITTED = 'jvm.memory.heap.committed';
export const METRIC_JAVA_HEAP_MEMORY_USED = 'jvm.memory.heap.used';
export const METRIC_JAVA_NON_HEAP_MEMORY_MAX = 'jvm.memory.non_heap.max';
export const METRIC_JAVA_NON_HEAP_MEMORY_COMMITTED =
'jvm.memory.non_heap.committed';
export const METRIC_JAVA_NON_HEAP_MEMORY_COMMITTED = 'jvm.memory.non_heap.committed';
export const METRIC_JAVA_NON_HEAP_MEMORY_USED = 'jvm.memory.non_heap.used';
export const METRIC_JAVA_THREAD_COUNT = 'jvm.thread.count';
export const METRIC_JAVA_GC_COUNT = 'jvm.gc.count';
@ -129,10 +125,8 @@ export const CLIENT_GEO = 'client.geo';
export const USER_AGENT_DEVICE = 'user_agent.device.name';
export const USER_AGENT_OS = 'user_agent.os.name';
export const TRANSACTION_TIME_TO_FIRST_BYTE =
'transaction.marks.agent.timeToFirstByte';
export const TRANSACTION_DOM_INTERACTIVE =
'transaction.marks.agent.domInteractive';
export const TRANSACTION_TIME_TO_FIRST_BYTE = 'transaction.marks.agent.timeToFirstByte';
export const TRANSACTION_DOM_INTERACTIVE = 'transaction.marks.agent.domInteractive';
export const FCP_FIELD = 'transaction.marks.agent.firstContentfulPaint';
export const LCP_FIELD = 'transaction.marks.agent.largestContentfulPaint';

View file

@ -62,10 +62,8 @@ export function getNextEnvironmentUrlParam({
requestedEnvironment?: string;
currentEnvironmentUrlParam: Environment;
}) {
const normalizedRequestedEnvironment =
requestedEnvironment || ENVIRONMENT_NOT_DEFINED.value;
const normalizedQueryEnvironment =
currentEnvironmentUrlParam || ENVIRONMENT_ALL.value;
const normalizedRequestedEnvironment = requestedEnvironment || ENVIRONMENT_NOT_DEFINED.value;
const normalizedQueryEnvironment = currentEnvironmentUrlParam || ENVIRONMENT_ALL.value;
if (normalizedRequestedEnvironment === normalizedQueryEnvironment) {
return currentEnvironmentUrlParam || ENVIRONMENT_ALL.value;

View file

@ -6,10 +6,7 @@
*/
import * as t from 'io-ts';
import { nonEmptyStringRt } from '@kbn/io-ts-utils/non_empty_string_rt';
import {
ENVIRONMENT_ALL,
ENVIRONMENT_NOT_DEFINED,
} from './environment_filter_values';
import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED } from './environment_filter_values';
export const environmentRt = t.type({
environment: t.union([

View file

@ -7,9 +7,6 @@
import { i18n } from '@kbn/i18n';
export const NOT_AVAILABLE_LABEL = i18n.translate(
'xpack.apm.notAvailableLabel',
{
defaultMessage: 'N/A',
}
);
export const NOT_AVAILABLE_LABEL = i18n.translate('xpack.apm.notAvailableLabel', {
defaultMessage: 'N/A',
});

View file

@ -43,12 +43,9 @@ export interface ProfileNode {
const config = {
[ProfilingValueType.wallTime]: {
unit: ProfilingValueTypeUnit.us,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.wallTime',
{
defaultMessage: 'Wall',
}
),
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.wallTime', {
defaultMessage: 'Wall',
}),
field: PROFILE_WALL_US,
},
[ProfilingValueType.cpuTime]: {
@ -67,42 +64,30 @@ const config = {
},
[ProfilingValueType.allocObjects]: {
unit: ProfilingValueTypeUnit.count,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.allocObjects',
{
defaultMessage: 'Alloc. objects',
}
),
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.allocObjects', {
defaultMessage: 'Alloc. objects',
}),
field: PROFILE_ALLOC_OBJECTS,
},
[ProfilingValueType.allocSpace]: {
unit: ProfilingValueTypeUnit.bytes,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.allocSpace',
{
defaultMessage: 'Alloc. space',
}
),
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.allocSpace', {
defaultMessage: 'Alloc. space',
}),
field: PROFILE_ALLOC_SPACE,
},
[ProfilingValueType.inuseObjects]: {
unit: ProfilingValueTypeUnit.count,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.inuseObjects',
{
defaultMessage: 'In-use objects',
}
),
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.inuseObjects', {
defaultMessage: 'In-use objects',
}),
field: PROFILE_INUSE_OBJECTS,
},
[ProfilingValueType.inuseSpace]: {
unit: ProfilingValueTypeUnit.bytes,
label: i18n.translate(
'xpack.apm.serviceProfiling.valueTypeLabel.inuseSpace',
{
defaultMessage: 'In-use space',
}
),
label: i18n.translate('xpack.apm.serviceProfiling.valueTypeLabel.inuseSpace', {
defaultMessage: 'In-use space',
}),
field: PROFILE_INUSE_SPACE,
},
};

View file

@ -12,10 +12,6 @@ export enum TimeRangeComparisonEnum {
PeriodBefore = 'period',
}
export const comparisonTypeRt = t.union([
t.literal('day'),
t.literal('week'),
t.literal('period'),
]);
export const comparisonTypeRt = t.union([t.literal('day'), t.literal('week'), t.literal('period')]);
export type TimeRangeComparisonType = t.TypeOf<typeof comparisonTypeRt>;

View file

@ -16,11 +16,7 @@ export enum ServiceHealthStatus {
unknown = 'unknown',
}
export function getServiceHealthStatus({
severity,
}: {
severity: ANOMALY_SEVERITY;
}) {
export function getServiceHealthStatus({ severity }: { severity: ANOMALY_SEVERITY }) {
switch (severity) {
case ANOMALY_SEVERITY.CRITICAL:
case ANOMALY_SEVERITY.MAJOR:
@ -38,10 +34,7 @@ export function getServiceHealthStatus({
}
}
export function getServiceHealthStatusColor(
theme: EuiTheme,
status: ServiceHealthStatus
) {
export function getServiceHealthStatusColor(theme: EuiTheme, status: ServiceHealthStatus) {
switch (status) {
case ServiceHealthStatus.healthy:
return theme.eui.euiColorVis0;
@ -54,10 +47,7 @@ export function getServiceHealthStatusColor(
}
}
export function getServiceHealthStatusBadgeColor(
theme: EuiTheme,
status: ServiceHealthStatus
) {
export function getServiceHealthStatusBadgeColor(theme: EuiTheme, status: ServiceHealthStatus) {
switch (status) {
case ServiceHealthStatus.healthy:
return theme.eui.euiColorVis0_behindText;

View file

@ -68,13 +68,10 @@ export interface NodeStats {
avgErrorRate: number | null;
}
export const invalidLicenseMessage = i18n.translate(
'xpack.apm.serviceMap.invalidLicenseMessage',
{
defaultMessage:
"In order to access Service Maps, you must be subscribed to an Elastic Platinum license. With it, you'll have the ability to visualize your entire application stack along with your APM data.",
}
);
export const invalidLicenseMessage = i18n.translate('xpack.apm.serviceMap.invalidLicenseMessage', {
defaultMessage:
"In order to access Service Maps, you must be subscribed to an Elastic Platinum license. With it, you'll have the ability to visualize your entire application stack along with your APM data.",
});
const NONGROUPED_SPANS: Record<string, string[]> = {
aws: ['servicename'],
@ -90,8 +87,7 @@ export function isSpanGroupingSupported(type?: string, subtype?: string) {
return true;
}
return !NONGROUPED_SPANS[type].some(
(nongroupedSubType) =>
nongroupedSubType === 'all' || nongroupedSubType === subtype
(nongroupedSubType) => nongroupedSubType === 'all' || nongroupedSubType === subtype
);
}

View file

@ -9,12 +9,9 @@ import { i18n } from '@kbn/i18n';
export const SERVICE_NODE_NAME_MISSING = '_service_node_name_missing_';
const UNIDENTIFIED_SERVICE_NODES_LABEL = i18n.translate(
'xpack.apm.serviceNodeNameMissing',
{
defaultMessage: '(Empty)',
}
);
const UNIDENTIFIED_SERVICE_NODES_LABEL = i18n.translate('xpack.apm.serviceNodeNameMissing', {
defaultMessage: '(Empty)',
});
export function getServiceNodeName(serviceNodeName?: string) {
return serviceNodeName === SERVICE_NODE_NAME_MISSING || !serviceNodeName

View file

@ -7,17 +7,13 @@
import { i18n } from '@kbn/i18n';
export const createNodeAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createNodeAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.nodeClient.install.title', {
defaultMessage: 'Install the APM agent',
}),
textPre: i18n.translate('xpack.apm.tutorial.nodeClient.install.textPre', {
defaultMessage:
'Install the APM agent for Node.js as a dependency to your application.',
defaultMessage: 'Install the APM agent for Node.js as a dependency to your application.',
}),
commands: ['npm install elastic-apm-node --save'],
},
@ -32,27 +28,20 @@ APM services are created programmatically based on the `serviceName`. \
This agent supports a variety of frameworks but can also be used with your custom stack.',
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.nodeClient.configure.textPost',
{
defaultMessage:
'See [the documentation]({documentationLink}) for advanced usage, including how to use with \
textPost: i18n.translate('xpack.apm.tutorial.nodeClient.configure.textPost', {
defaultMessage:
'See [the documentation]({documentationLink}) for advanced usage, including how to use with \
[Babel/ES Modules]({babelEsModulesLink}).',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html',
babelEsModulesLink:
'{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules',
},
}
),
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html',
babelEsModulesLink:
'{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules',
},
}),
},
];
export const createDjangoAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createDjangoAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.djangoClient.install.title', {
defaultMessage: 'Install the APM agent',
@ -66,33 +55,23 @@ export const createDjangoAgentInstructions = (
title: i18n.translate('xpack.apm.tutorial.djangoClient.configure.title', {
defaultMessage: 'Configure the agent',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.djangoClient.configure.textPre',
{
defaultMessage:
'Agents are libraries that run inside of your application process. \
textPre: i18n.translate('xpack.apm.tutorial.djangoClient.configure.textPre', {
defaultMessage:
'Agents are libraries that run inside of your application process. \
APM services are created programmatically based on the `SERVICE_NAME`.',
}
),
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.djangoClient.configure.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for advanced usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.djangoClient.configure.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html',
},
}),
},
];
export const createFlaskAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createFlaskAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.flaskClient.install.title', {
defaultMessage: 'Install the APM agent',
@ -106,33 +85,23 @@ export const createFlaskAgentInstructions = (
title: i18n.translate('xpack.apm.tutorial.flaskClient.configure.title', {
defaultMessage: 'Configure the agent',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.flaskClient.configure.textPre',
{
defaultMessage:
'Agents are libraries that run inside of your application process. \
textPre: i18n.translate('xpack.apm.tutorial.flaskClient.configure.textPre', {
defaultMessage:
'Agents are libraries that run inside of your application process. \
APM services are created programmatically based on the `SERVICE_NAME`.',
}
),
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.flaskClient.configure.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for advanced usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.flaskClient.configure.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html',
},
}),
},
];
export const createRailsAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createRailsAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.railsClient.install.title', {
defaultMessage: 'Install the APM agent',
@ -146,33 +115,23 @@ export const createRailsAgentInstructions = (
title: i18n.translate('xpack.apm.tutorial.railsClient.configure.title', {
defaultMessage: 'Configure the agent',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.railsClient.configure.textPre',
{
defaultMessage:
'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}',
values: { configFile: '`config/elastic_apm.yml`' },
}
),
textPre: i18n.translate('xpack.apm.tutorial.railsClient.configure.textPre', {
defaultMessage:
'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}',
values: { configFile: '`config/elastic_apm.yml`' },
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.railsClient.configure.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.railsClient.configure.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html',
},
}),
},
];
export const createRackAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createRackAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.rackClient.install.title', {
defaultMessage: 'Install the APM agent',
@ -222,78 +181,56 @@ export const createRackAgentInstructions = (
title: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.title', {
defaultMessage: 'Create config file',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.rackClient.createConfig.textPre',
{
defaultMessage: 'Create a config file {configFile}:',
values: { configFile: '`config/elastic_apm.yml`' },
}
),
textPre: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.textPre', {
defaultMessage: 'Create a config file {configFile}:',
values: { configFile: '`config/elastic_apm.yml`' },
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.rackClient.createConfig.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html',
},
}),
},
];
export const createJsAgentInstructions = (apmServerUrl = '') => [
{
title: i18n.translate(
'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title',
{
defaultMessage: 'Enable Real User Monitoring support in APM Server',
}
),
textPre: i18n.translate(
'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre',
{
defaultMessage:
'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \
title: i18n.translate('xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title', {
defaultMessage: 'Enable Real User Monitoring support in APM Server',
}),
textPre: i18n.translate('xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre', {
defaultMessage:
'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \
for details on how to enable RUM support.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html',
},
}
),
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html',
},
}),
},
{
title: i18n.translate(
'xpack.apm.tutorial.jsClient.installDependency.title',
{
defaultMessage: 'Set up the Agent as a dependency',
}
),
textPre: i18n.translate(
'xpack.apm.tutorial.jsClient.installDependency.textPre',
{
defaultMessage:
'You can install the Agent as a dependency to your application with \
title: i18n.translate('xpack.apm.tutorial.jsClient.installDependency.title', {
defaultMessage: 'Set up the Agent as a dependency',
}),
textPre: i18n.translate('xpack.apm.tutorial.jsClient.installDependency.textPre', {
defaultMessage:
'You can install the Agent as a dependency to your application with \
`npm install @elastic/apm-rum --save`.\n\n\
The Agent can then be initialized and configured in your application like this:',
}
),
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.jsClient.installDependency.textPost',
{
defaultMessage:
'Framework integrations, like React or Angular, have custom dependencies. \
textPost: i18n.translate('xpack.apm.tutorial.jsClient.installDependency.textPost', {
defaultMessage:
'Framework integrations, like React or Angular, have custom dependencies. \
See the [integration documentation]({docLink}) for more information.',
values: {
docLink:
'{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html',
},
}
),
values: {
docLink:
'{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html',
},
}),
},
{
title: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.title', {
@ -306,20 +243,15 @@ Add a `<script>` tag to the HTML page and use the `elasticApm` global object to
Don't forget to download the latest version of the RUM Agent from [GitHub]({GitHubLink}) or [UNPKG]({UnpkgLink}), \
and host the file on your Server/CDN before deploying to production.",
values: {
GitHubLink:
'https://github.com/elastic/apm-agent-rum-js/releases/latest',
UnpkgLink:
'https://unpkg.com/@elastic/apm-rum/dist/bundles/elastic-apm-rum.umd.min.js',
GitHubLink: 'https://github.com/elastic/apm-agent-rum-js/releases/latest',
UnpkgLink: 'https://unpkg.com/@elastic/apm-rum/dist/bundles/elastic-apm-rum.umd.min.js',
},
}),
customComponentName: 'TutorialConfigAgentRumScript',
},
];
export const createGoAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createGoAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.goClient.install.title', {
defaultMessage: 'Install the APM agent',
@ -341,11 +273,9 @@ file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.',
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate('xpack.apm.tutorial.goClient.configure.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for advanced configuration.',
defaultMessage: 'See the [documentation]({documentationLink}) for advanced configuration.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html',
documentationLink: '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html',
},
}),
},
@ -371,25 +301,19 @@ func main() {curlyOpen}
http.ListenAndServe(":8080", apmhttp.Wrap(mux))
{curlyClose}
`.split('\n'),
textPost: i18n.translate(
'xpack.apm.tutorial.goClient.instrument.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for a detailed \
textPost: i18n.translate('xpack.apm.tutorial.goClient.instrument.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for a detailed \
guide to instrumenting Go source code.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html',
},
}
),
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html',
},
}),
},
];
export const createJavaAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createJavaAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.javaClient.download.title', {
defaultMessage: 'Download the APM agent',
@ -399,94 +323,68 @@ export const createJavaAgentInstructions = (
'Download the agent jar from [Maven Central]({mavenCentralLink}). \
Do **not** add the agent as a dependency to your application.',
values: {
mavenCentralLink:
'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent',
mavenCentralLink: 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent',
},
}),
},
{
title: i18n.translate(
'xpack.apm.tutorial.javaClient.startApplication.title',
{
defaultMessage: 'Start your application with the javaagent flag',
}
),
textPre: i18n.translate(
'xpack.apm.tutorial.javaClient.startApplication.textPre',
{
defaultMessage:
'Add the `-javaagent` flag and configure the agent with system properties.\n\n \
title: i18n.translate('xpack.apm.tutorial.javaClient.startApplication.title', {
defaultMessage: 'Start your application with the javaagent flag',
}),
textPre: i18n.translate('xpack.apm.tutorial.javaClient.startApplication.textPre', {
defaultMessage:
'Add the `-javaagent` flag and configure the agent with system properties.\n\n \
* Set the required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \
* Set the custom APM Server URL (default: {customApmServerUrl})\n \
* Set the APM Server secret token\n \
* Set the service environment\n \
* Set the base package of your application',
values: { customApmServerUrl: 'http://localhost:8200' },
}
),
values: { customApmServerUrl: 'http://localhost:8200' },
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.javaClient.startApplication.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced \
textPost: i18n.translate('xpack.apm.tutorial.javaClient.startApplication.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced \
usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/java/current/index.html',
},
}
),
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/java/current/index.html',
},
}),
},
];
export const createDotNetAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createDotNetAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.dotNetClient.download.title', {
defaultMessage: 'Download the APM agent',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.dotNetClient.download.textPre',
{
defaultMessage:
'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \
textPre: i18n.translate('xpack.apm.tutorial.dotNetClient.download.textPre', {
defaultMessage:
'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \
NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \
Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \
agent component to your application. \n\n In case you would like to minimize the dependencies, you can use the \
[Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \
ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n In \
case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.',
values: {
allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm',
netCoreAllApmPackageLink:
'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll',
aspNetCorePackageLink:
'https://www.nuget.org/packages/Elastic.Apm.AspNetCore',
efCorePackageLink:
'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore',
elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm',
},
}
),
values: {
allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm',
netCoreAllApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll',
aspNetCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore',
efCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore',
elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm',
},
}),
},
{
title: i18n.translate(
'xpack.apm.tutorial.dotNetClient.configureApplication.title',
{
defaultMessage: 'Add the agent to the application',
}
),
textPre: i18n.translate(
'xpack.apm.tutorial.dotNetClient.configureApplication.textPre',
{
defaultMessage:
'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \
title: i18n.translate('xpack.apm.tutorial.dotNetClient.configureApplication.title', {
defaultMessage: 'Add the agent to the application',
}),
textPre: i18n.translate('xpack.apm.tutorial.dotNetClient.configureApplication.textPre', {
defaultMessage:
'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \
method in the `Configure` method within the `Startup.cs` file.',
}
),
}),
commands: `public class Startup
{curlyOpen}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
@ -496,43 +394,31 @@ export const createDotNetAgentInstructions = (
{curlyClose}
//…rest of the class
{curlyClose}`.split('\n'),
textPost: i18n.translate(
'xpack.apm.tutorial.dotNetClient.configureApplication.textPost',
{
defaultMessage:
'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \
textPost: i18n.translate('xpack.apm.tutorial.dotNetClient.configureApplication.textPost', {
defaultMessage:
'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \
`IConfiguration` instance (e.g. from the `appsettings.json` file).',
}
),
}),
},
{
title: i18n.translate(
'xpack.apm.tutorial.dotNetClient.configureAgent.title',
{
defaultMessage: 'Sample appsettings.json file:',
}
),
title: i18n.translate('xpack.apm.tutorial.dotNetClient.configureAgent.title', {
defaultMessage: 'Sample appsettings.json file:',
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.dotNetClient.configureAgent.textPost',
{
defaultMessage:
'In case you dont pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \
textPost: i18n.translate('xpack.apm.tutorial.dotNetClient.configureAgent.textPost', {
defaultMessage:
'In case you dont pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \
you can also configure the agent through environment variables. \n \
See [the documentation]({documentationLink}) for advanced usage.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html',
},
}
),
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html',
},
}),
},
];
export const createPhpAgentInstructions = (
apmServerUrl = '',
secretToken = ''
) => [
export const createPhpAgentInstructions = (apmServerUrl = '', secretToken = '') => [
{
title: i18n.translate('xpack.apm.tutorial.phpClient.download.title', {
defaultMessage: 'Download the APM agent',
@ -549,47 +435,34 @@ export const createPhpAgentInstructions = (
title: i18n.translate('xpack.apm.tutorial.phpClient.installPackage.title', {
defaultMessage: 'Install the downloaded package',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.phpClient.installPackage.textPre',
{
defaultMessage: 'For example on Alpine Linux using APK package:',
}
),
textPre: i18n.translate('xpack.apm.tutorial.phpClient.installPackage.textPre', {
defaultMessage: 'For example on Alpine Linux using APK package:',
}),
commands: ['apk add --allow-untrusted <package-file>.apk'],
textPost: i18n.translate(
'xpack.apm.tutorial.phpClient.installPackage.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/php/current/setup.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.phpClient.installPackage.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.',
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/php/current/setup.html',
},
}),
},
{
title: i18n.translate('xpack.apm.tutorial.phpClient.configureAgent.title', {
defaultMessage: 'Configure the agent',
}),
textPre: i18n.translate(
'xpack.apm.tutorial.phpClient.configureAgent.textPre',
{
defaultMessage:
'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:',
}
),
textPre: i18n.translate('xpack.apm.tutorial.phpClient.configureAgent.textPre', {
defaultMessage:
'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:',
}),
customComponentName: 'TutorialConfigAgent',
textPost: i18n.translate(
'xpack.apm.tutorial.phpClient.configure.textPost',
{
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html',
},
}
),
textPost: i18n.translate('xpack.apm.tutorial.phpClient.configure.textPost', {
defaultMessage:
'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: {
documentationLink:
'{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html',
},
}),
},
];

View file

@ -75,8 +75,7 @@ export const createDownloadServerDeb = () => ({
'sudo dpkg -i apm-server-{config.kibana.version}-amd64.deb',
],
textPost: i18n.translate('xpack.apm.tutorial.downloadServerTitle', {
defaultMessage:
'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).',
defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).',
values: {
downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server',
},
@ -90,8 +89,7 @@ export const createDownloadServerRpm = () => ({
'sudo rpm -vi apm-server-{config.kibana.version}-x86_64.rpm',
],
textPost: i18n.translate('xpack.apm.tutorial.downloadServerRpm', {
defaultMessage:
'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).',
defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).',
values: {
downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server',
},
@ -104,41 +102,32 @@ export function createWindowsServerInstructions() {
return [
{
title: createDownloadServerTitle(),
textPre: i18n.translate(
'xpack.apm.tutorial.windowsServerInstructions.textPre',
{
defaultMessage:
'1. Download the APM Server Windows zip file from the \
textPre: i18n.translate('xpack.apm.tutorial.windowsServerInstructions.textPre', {
defaultMessage:
'1. Download the APM Server Windows zip file from the \
[Download page]({downloadPageLink}).\n2. Extract the contents of \
the zip file into {zipFileExtractFolder}.\n3. Rename the {apmServerDirectory} \
directory to `APM-Server`.\n4. Open a PowerShell prompt as an Administrator \
(right-click the PowerShell icon and select \
**Run As Administrator**). If you are running Windows XP, you might need to download and install \
PowerShell.\n5. From the PowerShell prompt, run the following commands to install APM Server as a Windows service:',
values: {
downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server',
zipFileExtractFolder: '`C:\\Program Files`',
apmServerDirectory: '`apm-server-{config.kibana.version}-windows`',
},
}
),
commands: [
`cd 'C:\\Program Files\\APM-Server'`,
`.\\install-service-apm-server.ps1`,
],
textPost: i18n.translate(
'xpack.apm.tutorial.windowsServerInstructions.textPost',
{
defaultMessage:
'Note: If script execution is disabled on your system, \
values: {
downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server',
zipFileExtractFolder: '`C:\\Program Files`',
apmServerDirectory: '`apm-server-{config.kibana.version}-windows`',
},
}),
commands: [`cd 'C:\\Program Files\\APM-Server'`, `.\\install-service-apm-server.ps1`],
textPost: i18n.translate('xpack.apm.tutorial.windowsServerInstructions.textPost', {
defaultMessage:
'Note: If script execution is disabled on your system, \
you need to set the execution policy for the current session \
to allow the script to run. For example: {command}.',
values: {
command:
'`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`',
},
}
),
values: {
command:
'`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`',
},
}),
},
createEditConfig(),
{

View file

@ -9,8 +9,6 @@ import { ValuesType } from 'utility-types';
// work around a TypeScript limitation described in https://stackoverflow.com/posts/49511416
export const arrayUnionToCallable = <T extends any[]>(
array: T
): Array<ValuesType<T>> => {
export const arrayUnionToCallable = <T extends any[]>(array: T): Array<ValuesType<T>> => {
return array;
};

View file

@ -7,14 +7,9 @@
import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types';
import { SERVICE_ENVIRONMENT } from '../elasticsearch_fieldnames';
import {
ENVIRONMENT_ALL,
ENVIRONMENT_NOT_DEFINED,
} from '../environment_filter_values';
import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED } from '../environment_filter_values';
export function environmentQuery(
environment: string
): QueryDslQueryContainer[] {
export function environmentQuery(environment: string): QueryDslQueryContainer[] {
if (!environment || environment === ENVIRONMENT_ALL.value) {
return [];
}

View file

@ -6,11 +6,7 @@
*/
import moment from 'moment-timezone';
import {
asRelativeDateTimeRange,
asAbsoluteDateTime,
getDateDifference,
} from './datetime';
import { asRelativeDateTimeRange, asAbsoluteDateTime, getDateDifference } from './datetime';
describe('date time formatters', () => {
beforeAll(() => {
@ -18,8 +14,7 @@ describe('date time formatters', () => {
});
afterAll(() => moment.tz.setDefault(''));
describe('asRelativeDateTimeRange', () => {
const formatDateToTimezone = (dateTimeString: string) =>
moment(dateTimeString).valueOf();
const formatDateToTimezone = (dateTimeString: string) => moment(dateTimeString).valueOf();
describe('YYYY - YYYY', () => {
it('range: 10 years', () => {
const start = formatDateToTimezone('2000-01-01 10:01:01');
@ -113,17 +108,13 @@ describe('date time formatters', () => {
const start = formatDateToTimezone('2019-10-29 10:01:01.001');
const end = formatDateToTimezone('2019-10-29 10:01:10.002');
const dateRange = asRelativeDateTimeRange(start, end);
expect(dateRange).toEqual(
'Oct 29, 2019, 10:01:01.001 - 10:01:10.002 (UTC+1)'
);
expect(dateRange).toEqual('Oct 29, 2019, 10:01:01.001 - 10:01:10.002 (UTC+1)');
});
it('range: 1 second', () => {
const start = formatDateToTimezone('2019-10-29 10:01:01.001');
const end = formatDateToTimezone('2019-10-29 10:01:02.002');
const dateRange = asRelativeDateTimeRange(start, end);
expect(dateRange).toEqual(
'Oct 29, 2019, 10:01:01.001 - 10:01:02.002 (UTC+1)'
);
expect(dateRange).toEqual('Oct 29, 2019, 10:01:01.001 - 10:01:02.002 (UTC+1)');
});
});
});
@ -133,23 +124,17 @@ describe('date time formatters', () => {
it('should add a leading plus for timezones with positive UTC offset', () => {
moment.tz.setDefault('Europe/Copenhagen');
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe(
'Jun 1, 2019, 14:00 (UTC+2)'
);
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe('Jun 1, 2019, 14:00 (UTC+2)');
});
it('should add a leading minus for timezones with negative UTC offset', () => {
moment.tz.setDefault('America/Los_Angeles');
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe(
'Jun 1, 2019, 05:00 (UTC-7)'
);
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe('Jun 1, 2019, 05:00 (UTC-7)');
});
it('should use default UTC offset formatting when offset contains minutes', () => {
moment.tz.setDefault('Canada/Newfoundland');
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe(
'Jun 1, 2019, 09:30 (UTC-02:30)'
);
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe('Jun 1, 2019, 09:30 (UTC-02:30)');
});
it('should respect DST', () => {
@ -157,13 +142,9 @@ describe('date time formatters', () => {
const timeWithDST = 1559390400000; // Jun 1, 2019
const timeWithoutDST = 1575201600000; // Dec 1, 2019
expect(asAbsoluteDateTime(timeWithDST)).toBe(
'Jun 1, 2019, 14:00:00.000 (UTC+2)'
);
expect(asAbsoluteDateTime(timeWithDST)).toBe('Jun 1, 2019, 14:00:00.000 (UTC+2)');
expect(asAbsoluteDateTime(timeWithoutDST)).toBe(
'Dec 1, 2019, 13:00:00.000 (UTC+1)'
);
expect(asAbsoluteDateTime(timeWithoutDST)).toBe('Dec 1, 2019, 13:00:00.000 (UTC+1)');
});
it('milliseconds', () => {
@ -175,46 +156,34 @@ describe('date time formatters', () => {
it('seconds', () => {
moment.tz.setDefault('Europe/Copenhagen');
expect(asAbsoluteDateTime(1559390400000, 'seconds')).toBe(
'Jun 1, 2019, 14:00:00 (UTC+2)'
);
expect(asAbsoluteDateTime(1559390400000, 'seconds')).toBe('Jun 1, 2019, 14:00:00 (UTC+2)');
});
it('minutes', () => {
moment.tz.setDefault('Europe/Copenhagen');
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe(
'Jun 1, 2019, 14:00 (UTC+2)'
);
expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe('Jun 1, 2019, 14:00 (UTC+2)');
});
it('hours', () => {
moment.tz.setDefault('Europe/Copenhagen');
expect(asAbsoluteDateTime(1559390400000, 'hours')).toBe(
'Jun 1, 2019, 14 (UTC+2)'
);
expect(asAbsoluteDateTime(1559390400000, 'hours')).toBe('Jun 1, 2019, 14 (UTC+2)');
});
});
describe('getDateDifference', () => {
it('milliseconds', () => {
const start = moment('2019-10-29 08:00:00.001');
const end = moment('2019-10-29 08:00:00.005');
expect(
getDateDifference({ start, end, unitOfTime: 'milliseconds' })
).toEqual(4);
expect(getDateDifference({ start, end, unitOfTime: 'milliseconds' })).toEqual(4);
});
it('seconds', () => {
const start = moment('2019-10-29 08:00:00');
const end = moment('2019-10-29 08:00:10');
expect(getDateDifference({ start, end, unitOfTime: 'seconds' })).toEqual(
10
);
expect(getDateDifference({ start, end, unitOfTime: 'seconds' })).toEqual(10);
});
it('minutes', () => {
const start = moment('2019-10-29 08:00:00');
const end = moment('2019-10-29 08:15:00');
expect(getDateDifference({ start, end, unitOfTime: 'minutes' })).toEqual(
15
);
expect(getDateDifference({ start, end, unitOfTime: 'minutes' })).toEqual(15);
});
it('hours', () => {
const start = moment('2019-10-29 08:00:00');
@ -229,9 +198,7 @@ describe('date time formatters', () => {
it('months', () => {
const start = moment('2019-10-29 08:00:00');
const end = moment('2019-12-29 08:00:00');
expect(getDateDifference({ start, end, unitOfTime: 'months' })).toEqual(
2
);
expect(getDateDifference({ start, end, unitOfTime: 'months' })).toEqual(2);
});
it('years', () => {
const start = moment('2019-10-29 08:00:00');
@ -241,9 +208,9 @@ describe('date time formatters', () => {
it('precise days', () => {
const start = moment('2019-10-29 08:00:00');
const end = moment('2019-10-30 10:00:00');
expect(
getDateDifference({ start, end, unitOfTime: 'days', precise: true })
).toEqual(1.0833333333333333);
expect(getDateDifference({ start, end, unitOfTime: 'days', precise: true })).toEqual(
1.0833333333333333
);
});
});
});

View file

@ -18,8 +18,7 @@ function formatTimezone(momentTime: moment.Moment) {
const utcOffsetHours = momentTime.utcOffset() / 60;
const customTimezoneFormat =
utcOffsetHours > 0 ? `+${utcOffsetHours}` : utcOffsetHours;
const customTimezoneFormat = utcOffsetHours > 0 ? `+${utcOffsetHours}` : utcOffsetHours;
const utcOffsetFormatted = Number.isInteger(utcOffsetHours)
? customTimezoneFormat
@ -70,10 +69,7 @@ export const getDateDifference = ({
precise?: boolean;
}) => end.diff(start, unitOfTime, precise);
function getFormatsAccordingToDateDifference(
start: moment.Moment,
end: moment.Moment
) {
function getFormatsAccordingToDateDifference(start: moment.Moment, end: moment.Moment) {
if (getDateDifference({ start, end, unitOfTime: 'years' }) >= 5) {
return { dateFormat: getDateFormat('years') };
}
@ -117,9 +113,7 @@ export function asAbsoluteDateTime(
const momentTime = moment(time);
const formattedTz = formatTimezone(momentTime);
return momentTime.format(
`${getDateFormat('days')}, ${getTimeFormat(timeUnit)} ${formattedTz}`
);
return momentTime.format(`${getDateFormat('days')}, ${getTimeFormat(timeUnit)} ${formattedTz}`);
}
/**
@ -148,9 +142,7 @@ export function asRelativeDateTimeRange(start: number, end: number) {
);
if (timeFormat) {
const startFormatted = momentStartTime.format(
`${dateFormat}, ${timeFormat}`
);
const startFormatted = momentStartTime.format(`${dateFormat}, ${timeFormat}`);
const endFormatted = momentEndTime.format(timeFormat);
const formattedTz = formatTimezone(momentStartTime);
return `${startFormatted} - ${endFormatted} ${formattedTz}`;

View file

@ -20,12 +20,8 @@ describe('duration formatters', () => {
expect(asDuration(0)).toEqual('0 μs');
expect(asDuration(1)).toEqual('1 μs');
expect(asDuration(toMicroseconds(1, 'milliseconds'))).toEqual('1,000 μs');
expect(asDuration(toMicroseconds(1000, 'milliseconds'))).toEqual(
'1,000 ms'
);
expect(asDuration(toMicroseconds(10000, 'milliseconds'))).toEqual(
'10,000 ms'
);
expect(asDuration(toMicroseconds(1000, 'milliseconds'))).toEqual('1,000 ms');
expect(asDuration(toMicroseconds(10000, 'milliseconds'))).toEqual('10,000 ms');
expect(asDuration(toMicroseconds(20, 'seconds'))).toEqual('20 s');
expect(asDuration(toMicroseconds(10, 'minutes'))).toEqual('600 s');
expect(asDuration(toMicroseconds(11, 'minutes'))).toEqual('11 min');
@ -44,43 +40,21 @@ describe('duration formatters', () => {
// Formatting with a default threshold of 10 for more detail for single values
it('formats correctly with defaults', () => {
expect(getDurationFormatter(987654)(987654).formatted).toEqual('988 ms');
expect(getDurationFormatter(1000000)(1000000).formatted).toEqual(
'1,000 ms'
);
expect(getDurationFormatter(1234567)(1234567).formatted).toEqual(
'1,235 ms'
);
expect(getDurationFormatter(9876543)(9876543).formatted).toEqual(
'9,877 ms'
);
expect(getDurationFormatter(10000000)(10000000).formatted).toEqual(
'10,000 ms'
);
expect(getDurationFormatter(12345678)(12345678).formatted).toEqual(
'12 s'
);
expect(getDurationFormatter(1000000)(1000000).formatted).toEqual('1,000 ms');
expect(getDurationFormatter(1234567)(1234567).formatted).toEqual('1,235 ms');
expect(getDurationFormatter(9876543)(9876543).formatted).toEqual('9,877 ms');
expect(getDurationFormatter(10000000)(10000000).formatted).toEqual('10,000 ms');
expect(getDurationFormatter(12345678)(12345678).formatted).toEqual('12 s');
});
// Formatting useful for axis ticks with a lower threshold where less detail is sufficient
it('formats correctly with a threshold of 0.9999', () => {
expect(getDurationFormatter(987654, 0.9999)(987654).formatted).toEqual(
'988 ms'
);
expect(getDurationFormatter(1000000, 0.9999)(1000000).formatted).toEqual(
'1 s'
);
expect(getDurationFormatter(1234567, 0.9999)(1234567).formatted).toEqual(
'1 s'
);
expect(getDurationFormatter(9876543, 0.9999)(9876543).formatted).toEqual(
'10 s'
);
expect(
getDurationFormatter(10000000, 0.9999)(10000000).formatted
).toEqual('10 s');
expect(
getDurationFormatter(12345678, 0.9999)(12345678).formatted
).toEqual('12 s');
expect(getDurationFormatter(987654, 0.9999)(987654).formatted).toEqual('988 ms');
expect(getDurationFormatter(1000000, 0.9999)(1000000).formatted).toEqual('1 s');
expect(getDurationFormatter(1234567, 0.9999)(1234567).formatted).toEqual('1 s');
expect(getDurationFormatter(9876543, 0.9999)(9876543).formatted).toEqual('10 s');
expect(getDurationFormatter(10000000, 0.9999)(10000000).formatted).toEqual('10 s');
expect(getDurationFormatter(12345678, 0.9999)(12345678).formatted).toEqual('12 s');
});
});

View file

@ -26,10 +26,7 @@ interface ConvertedDuration {
formatted: string;
}
export type TimeFormatter = (
value: Maybe<number>,
options?: FormatterOptions
) => ConvertedDuration;
export type TimeFormatter = (value: Maybe<number>, options?: FormatterOptions) => ConvertedDuration;
type TimeFormatterBuilder = (max: number, threshold?: number) => TimeFormatter;
@ -47,10 +44,7 @@ function getUnitLabelAndConvertedValue(
unitLabel: i18n.translate('xpack.apm.formatters.hoursTimeUnitLabel', {
defaultMessage: 'h',
}),
convertedValue: asDecimalOrInteger(
moment.duration(ms).asHours(),
threshold
),
convertedValue: asDecimalOrInteger(moment.duration(ms).asHours(), threshold),
};
}
case 'minutes': {
@ -58,10 +52,7 @@ function getUnitLabelAndConvertedValue(
unitLabel: i18n.translate('xpack.apm.formatters.minutesTimeUnitLabel', {
defaultMessage: 'min',
}),
convertedValue: asDecimalOrInteger(
moment.duration(ms).asMinutes(),
threshold
),
convertedValue: asDecimalOrInteger(moment.duration(ms).asMinutes(), threshold),
};
}
case 'seconds': {
@ -69,10 +60,7 @@ function getUnitLabelAndConvertedValue(
unitLabel: i18n.translate('xpack.apm.formatters.secondsTimeUnitLabel', {
defaultMessage: 's',
}),
convertedValue: asDecimalOrInteger(
moment.duration(ms).asSeconds(),
threshold
),
convertedValue: asDecimalOrInteger(moment.duration(ms).asSeconds(), threshold),
};
}
case 'milliseconds': {
@ -80,10 +68,7 @@ function getUnitLabelAndConvertedValue(
unitLabel: i18n.translate('xpack.apm.formatters.millisTimeUnitLabel', {
defaultMessage: 'ms',
}),
convertedValue: asDecimalOrInteger(
moment.duration(ms).asMilliseconds(),
threshold
),
convertedValue: asDecimalOrInteger(moment.duration(ms).asMilliseconds(), threshold),
};
}
case 'microseconds': {

View file

@ -132,9 +132,11 @@ describe('joinByKey', () => {
})
);
expect(
joined.find((item) => item.serviceName === 'opbeans-node')?.values
).toEqual(['a', 'b', 'c']);
expect(joined.find((item) => item.serviceName === 'opbeans-node')?.values).toEqual([
'a',
'b',
'c',
]);
});
it('deeply merges objects', () => {

View file

@ -24,10 +24,7 @@ import { isEqual, pull, merge, castArray } from 'lodash';
);
*/
type JoinedReturnType<
T extends Record<string, any>,
U extends UnionToIntersection<T>
> = Array<
type JoinedReturnType<T extends Record<string, any>, U extends UnionToIntersection<T>> = Array<
Partial<U> & {
[k in keyof T]: T[k];
}
@ -52,14 +49,11 @@ export function joinByKey<
export function joinByKey(
items: Array<Record<string, any>>,
key: string | string[],
mergeFn: Function = (a: Record<string, any>, b: Record<string, any>) =>
merge({}, a, b)
mergeFn: Function = (a: Record<string, any>, b: Record<string, any>) => merge({}, a, b)
) {
const keys = castArray(key);
return items.reduce<Array<Record<string, any>>>((prev, current) => {
let item = prev.find((prevItem) =>
keys.every((k) => isEqual(prevItem[k], current[k]))
);
let item = prev.find((prevItem) => keys.every((k) => isEqual(prevItem[k], current[k])));
if (!item) {
item = { ...current };

View file

@ -103,9 +103,7 @@ type UxLocalUIFilterMap = {
[key in UxLocalUIFilterName]: UxLocalUIFilter;
};
export const uxLocalUIFilterNames = Object.keys(
uxFiltersByName
) as UxLocalUIFilterName[];
export const uxLocalUIFilterNames = Object.keys(uxFiltersByName) as UxLocalUIFilterName[];
export const uxLocalUIFilters = uxLocalUIFilterNames.reduce((acc, key) => {
const field = uxFiltersByName[key];

View file

@ -29,10 +29,8 @@ function deleteAllRules() {
describe('Rules', () => {
describe('Error count', () => {
const ruleName = 'Error count threshold';
const comboBoxInputSelector =
'.euiPopover__panel-isOpen [data-test-subj=comboBoxSearchInput]';
const confirmModalButtonSelector =
'.euiModal button[data-test-subj=confirmModalConfirmButton]';
const comboBoxInputSelector = '.euiPopover__panel-isOpen [data-test-subj=comboBoxSearchInput]';
const confirmModalButtonSelector = '.euiModal button[data-test-subj=confirmModalConfirmButton]';
describe('when created from APM', () => {
describe('when created from Service Inventory', () => {

View file

@ -48,11 +48,7 @@ describe('Dependencies', () => {
describe('service overview page', () => {
it('shows dependency information and you can navigate to a page for a dependency', () => {
cy.visit(
`/app/apm/services/opbeans-python/overview?${new URLSearchParams(
timeRange
)}`
);
cy.visit(`/app/apm/services/opbeans-python/overview?${new URLSearchParams(timeRange)}`);
cy.contains('postgresql').click({ force: true });
@ -62,11 +58,7 @@ describe('Dependencies', () => {
describe('service dependencies tab', () => {
it('shows dependency information and you can navigate to a page for a dependency', () => {
cy.visit(
`/app/apm/services/opbeans-python/overview?${new URLSearchParams(
timeRange
)}`
);
cy.visit(`/app/apm/services/opbeans-python/overview?${new URLSearchParams(timeRange)}`);
cy.contains('a[role="tab"]', 'Dependencies').click();

View file

@ -34,16 +34,11 @@ describe('Home page', () => {
it('Redirects to service page with rangeFrom and rangeTo added to the URL', () => {
cy.visit('/app/apm');
cy.url().should(
'include',
'app/apm/services?rangeFrom=now-15m&rangeTo=now'
);
cy.url().should('include', 'app/apm/services?rangeFrom=now-15m&rangeTo=now');
});
it('includes services with only metric documents', () => {
cy.visit(
`${serviceInventoryHref}&kuery=not%20(processor.event%3A%22transaction%22)`
);
cy.visit(`${serviceInventoryHref}&kuery=not%20(processor.event%3A%22transaction%22)`);
cy.contains('opbeans-python');
cy.contains('opbeans-java');
cy.contains('opbeans-node');
@ -62,10 +57,7 @@ describe('Home page', () => {
cy.get('[data-test-subj="serviceLink_rum-js"]').then((element) => {
element[0].click();
});
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'page-load'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'page-load');
});
});
});

View file

@ -16,8 +16,7 @@ const serviceOverviewHref = url.format({
const apisToIntercept = [
{
endpoint:
'/internal/apm/services/opbeans-node/transactions/charts/latency?*',
endpoint: '/internal/apm/services/opbeans-node/transactions/charts/latency?*',
name: 'latencyChartRequest',
},
{
@ -25,13 +24,11 @@ const apisToIntercept = [
name: 'throughputChartRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/transactions/charts/error_rate?*',
endpoint: '/internal/apm/services/opbeans-node/transactions/charts/error_rate?*',
name: 'errorRateChartRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/transactions/groups/detailed_statistics?*',
endpoint: '/internal/apm/services/opbeans-node/transactions/groups/detailed_statistics?*',
name: 'transactionGroupsDetailedRequest',
},
{
@ -40,23 +37,19 @@ const apisToIntercept = [
name: 'instancesDetailedRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/service_overview_instances/main_statistics?*',
endpoint: '/internal/apm/services/opbeans-node/service_overview_instances/main_statistics?*',
name: 'instancesMainStatisticsRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/error_groups/main_statistics?*',
endpoint: '/internal/apm/services/opbeans-node/error_groups/main_statistics?*',
name: 'errorGroupsMainStatisticsRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/transaction/charts/breakdown?*',
endpoint: '/internal/apm/services/opbeans-node/transaction/charts/breakdown?*',
name: 'transactonBreakdownRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-node/transactions/groups/main_statistics?*',
endpoint: '/internal/apm/services/opbeans-node/transactions/groups/main_statistics?*',
name: 'transactionsGroupsMainStatisticsRequest',
},
];
@ -71,16 +64,10 @@ describe('Service overview - header filters', () => {
cy.visit(serviceOverviewHref);
cy.contains('opbeans-node');
cy.url().should('not.include', 'transactionType');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'request');
cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker');
cy.url().should('include', 'transactionType=Worker');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
});
it('calls APIs with correct transaction type', () => {
@ -89,10 +76,7 @@ describe('Service overview - header filters', () => {
});
cy.visit(serviceOverviewHref);
cy.contains('opbeans-node');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'request');
cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: apisToIntercept.map(({ name }) => `@${name}`),
@ -101,10 +85,7 @@ describe('Service overview - header filters', () => {
cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker');
cy.url().should('include', 'transactionType=Worker');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: apisToIntercept.map(({ name }) => `@${name}`),
value: 'transactionType=Worker',
@ -123,15 +104,9 @@ describe('Service overview - header filters', () => {
cy.contains('opbeans-java');
cy.get('[data-test-subj="headerFilterKuerybar"]').type('transaction.n');
cy.contains('transaction.name');
cy.get('[data-test-subj="suggestionContainer"]')
.find('li')
.first()
.click();
cy.get('[data-test-subj="suggestionContainer"]').find('li').first().click();
cy.get('[data-test-subj="headerFilterKuerybar"]').type(':');
cy.get('[data-test-subj="suggestionContainer"]')
.find('li')
.first()
.click();
cy.get('[data-test-subj="suggestionContainer"]').find('li').first().click();
cy.get('[data-test-subj="suggestionContainer"]').realPress('{enter}');
cy.url().should('include', '&kuery=transaction.name');
});

View file

@ -17,8 +17,7 @@ const serviceOverviewHref = url.format({
const apisToIntercept = [
{
endpoint:
'/internal/apm/services/opbeans-java/service_overview_instances/main_statistics?*',
endpoint: '/internal/apm/services/opbeans-java/service_overview_instances/main_statistics?*',
name: 'instancesMainRequest',
},
{
@ -49,8 +48,7 @@ describe('Instances table', () => {
// });
describe('when data is loaded', () => {
const serviceNodeName =
'31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad';
const serviceNodeName = '31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad';
it('has data in the table', () => {
cy.visit(serviceOverviewHref);
@ -69,9 +67,7 @@ describe('Instances table', () => {
cy.contains(serviceNodeName);
cy.wait('@instancesDetailsRequest');
cy.get(
`[data-test-subj="instanceDetailsButton_${serviceNodeName}"]`
).realClick();
cy.get(`[data-test-subj="instanceDetailsButton_${serviceNodeName}"]`).realClick();
cy.get('[data-test-subj="loadingSpinner"]').should('be.visible');
cy.wait('@instanceDetailsRequest').then(() => {
cy.contains('Service');
@ -89,9 +85,7 @@ describe('Instances table', () => {
cy.contains(serviceNodeName);
cy.wait('@instancesDetailsRequest');
cy.get(
`[data-test-subj="instanceActionsButton_${serviceNodeName}"]`
).realClick();
cy.get(`[data-test-subj="instanceActionsButton_${serviceNodeName}"]`).realClick();
cy.contains('Pod logs');
cy.contains('Pod metrics');
cy.contains('Container logs');

View file

@ -23,45 +23,25 @@ describe('Service Overview', () => {
it('persists transaction type selected when clicking on Transactions tab', () => {
cy.visit(baseUrl);
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'request');
cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
cy.contains('Transactions').click();
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
});
it('persists transaction type selected when clicking on View Transactions link', () => {
cy.visit(baseUrl);
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'request');
cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
cy.contains('View transactions').click();
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
});
it('hides dependency tab when RUM service', () => {
cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as(
'agentRequest'
);
cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as('agentRequest');
cy.visit(
url.format({
pathname: '/app/apm/services/opbeans-rum/overview',

View file

@ -18,8 +18,7 @@ const serviceOverviewHref = url.format({
const apisToIntercept = [
{
endpoint:
'/internal/apm/services/opbeans-java/transactions/charts/latency?*',
endpoint: '/internal/apm/services/opbeans-java/transactions/charts/latency?*',
name: 'latencyChartRequest',
},
{
@ -27,18 +26,15 @@ const apisToIntercept = [
name: 'throughputChartRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-java/transactions/charts/error_rate?*',
endpoint: '/internal/apm/services/opbeans-java/transactions/charts/error_rate?*',
name: 'errorRateChartRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics?*',
endpoint: '/internal/apm/services/opbeans-java/transactions/groups/detailed_statistics?*',
name: 'transactionGroupsDetailedRequest',
},
{
endpoint:
'/internal/apm/services/opbeans-java/error_groups/detailed_statistics?*',
endpoint: '/internal/apm/services/opbeans-java/error_groups/detailed_statistics?*',
name: 'errorGroupsDetailedRequest',
},
{
@ -82,25 +78,21 @@ describe('Service overview: Time Comparison', () => {
const comparisonStartEnd =
'comparisonStart=2021-08-02T06%3A50%3A00.000Z&comparisonEnd=2021-08-02T07%3A20%3A15.910Z';
// When the page loads it fetches all APIs with comparison time range
cy.wait(apisToIntercept.map(({ name }) => `@${name}`)).then(
(interceptions) => {
interceptions.map((interception) => {
expect(interception.request.url).include(comparisonStartEnd);
});
}
);
cy.wait(apisToIntercept.map(({ name }) => `@${name}`)).then((interceptions) => {
interceptions.map((interception) => {
expect(interception.request.url).include(comparisonStartEnd);
});
});
// toggles off comparison
cy.contains('Comparison').click();
cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled');
// When comparison is disabled APIs are called withou comparison time range
cy.wait(apisToIntercept.map(({ name }) => `@${name}`)).then(
(interceptions) => {
interceptions.map((interception) => {
expect(interception.request.url).not.include(comparisonStartEnd);
});
}
);
cy.wait(apisToIntercept.map(({ name }) => `@${name}`)).then((interceptions) => {
interceptions.map((interception) => {
expect(interception.request.url).not.include(comparisonStartEnd);
});
});
});
});
@ -137,29 +129,14 @@ describe('Service overview: Time Comparison', () => {
cy.changeTimeRange('Last 7 days');
cy.get('[data-test-subj="comparisonSelect"]').should('have.value', 'week');
cy.get('[data-test-subj="comparisonSelect"]').should(
'contain.text',
'Week before'
);
cy.get('[data-test-subj="comparisonSelect"]').should(
'not.contain.text',
'Day before'
);
cy.get('[data-test-subj="comparisonSelect"]').should('contain.text', 'Week before');
cy.get('[data-test-subj="comparisonSelect"]').should('not.contain.text', 'Day before');
cy.contains('Week before');
cy.changeTimeRange('Last 30 days');
cy.get('[data-test-subj="comparisonSelect"]').should(
'have.value',
'period'
);
cy.get('[data-test-subj="comparisonSelect"]').should(
'not.contain.text',
'Day before'
);
cy.get('[data-test-subj="comparisonSelect"]').should(
'not.contain.text',
'Week before'
);
cy.get('[data-test-subj="comparisonSelect"]').should('have.value', 'period');
cy.get('[data-test-subj="comparisonSelect"]').should('not.contain.text', 'Day before');
cy.get('[data-test-subj="comparisonSelect"]').should('not.contain.text', 'Week before');
});
it('hovers over throughput chart shows previous and current period', () => {

View file

@ -22,19 +22,10 @@ describe('Transactions Overview', () => {
it('persists transaction type selected when navigating to Overview tab', () => {
cy.visit(serviceOverviewHref);
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'request');
cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
cy.get('a[href*="/app/apm/services/opbeans-node/overview"]').click();
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'Worker'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').should('have.value', 'Worker');
});
});

View file

@ -48,13 +48,7 @@ Cypress.Commands.add('changeTimeRange', (value: string) => {
Cypress.Commands.add(
'expectAPIsToHaveBeenCalledWith',
({
apisIntercepted,
value,
}: {
apisIntercepted: string[];
value: string;
}) => {
({ apisIntercepted, value }: { apisIntercepted: string[]; value: string }) => {
cy.wait(apisIntercepted).then((interceptions) => {
if (Array.isArray(interceptions)) {
interceptions.map((interception) => {

View file

@ -11,9 +11,6 @@ declare namespace Cypress {
loginAsPowerUser(): void;
loginAs(params: { username: string; password: string }): void;
changeTimeRange(value: string): void;
expectAPIsToHaveBeenCalledWith(params: {
apisIntercepted: string[];
value: string;
}): void;
expectAPIsToHaveBeenCalledWith(params: { apisIntercepted: string[]; value: string }): void;
}
}

View file

@ -19,8 +19,7 @@ export function cypressRunTests(spec?: string) {
const result = await cypressStart(getService, cypress.run, spec);
if (
(result as CypressCommandLine.CypressFailedRunResult)?.status ===
'failed' ||
(result as CypressCommandLine.CypressFailedRunResult)?.status === 'failed' ||
(result as CypressCommandLine.CypressRunResult)?.totalFailed
) {
throw new Error(`APM Cypress tests failed`);

View file

@ -113,15 +113,13 @@ describe.skip('renderApp (APM)', () => {
jest.spyOn(window, 'scrollTo').mockReturnValueOnce(undefined);
createCallApmApi(coreStart);
jest
.spyOn(window.console, 'warn')
.mockImplementationOnce((message: string) => {
if (message.startsWith('[Elastic APM')) {
return;
} else {
console.warn(message); // eslint-disable-line no-console
}
});
jest.spyOn(window.console, 'warn').mockImplementationOnce((message: string) => {
if (message.startsWith('[Elastic APM')) {
return;
} else {
console.warn(message); // eslint-disable-line no-console
}
});
return {
coreStart,
@ -155,14 +153,10 @@ describe('renderUxApp', () => {
const wrapper = mount(<UXAppRoot {...(uxMountProps as any)} />);
wrapper
.find(RumHome)
.simulateError(new Error('Oh no, an unexpected error!'));
wrapper.find(RumHome).simulateError(new Error('Oh no, an unexpected error!'));
expect(wrapper.find(RumHome)).toHaveLength(0);
expect(wrapper.find(EuiErrorBoundary)).toHaveLength(1);
expect(wrapper.find(EuiErrorBoundary).text()).toMatch(
/Error: Oh no, an unexpected error!/
);
expect(wrapper.find(EuiErrorBoundary).text()).toMatch(/Error: Oh no, an unexpected error!/);
});
});

View file

@ -9,11 +9,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import type { ObservabilityRuleTypeRegistry } from '../../../observability/public';
import { ConfigSchema } from '../';
import {
AppMountParameters,
CoreStart,
APP_WRAPPER_CLASS,
} from '../../../../../src/core/public';
import { AppMountParameters, CoreStart, APP_WRAPPER_CLASS } from '../../../../../src/core/public';
import { ApmPluginSetupDeps, ApmPluginStartDeps } from '../plugin';
import { createCallApmApi } from '../services/rest/createCallApmApi';
import { createStaticIndexPattern } from '../services/rest/index_pattern';
@ -67,10 +63,7 @@ export const renderApp = ({
element.classList.add(APP_WRAPPER_CLASS);
ReactDOM.render(
<ApmAppRoot
apmPluginContextValue={apmPluginContextValue}
pluginsStart={pluginsStart}
/>,
<ApmAppRoot apmPluginContextValue={apmPluginContextValue} pluginsStart={pluginsStart} />,
element
);
return () => {

View file

@ -7,10 +7,7 @@
import { RouteComponentProps, RouteProps } from 'react-router-dom';
export type BreadcrumbTitle<T = {}> =
| string
| ((props: RouteComponentProps<T>) => string)
| null;
export type BreadcrumbTitle<T = {}> = string | ((props: RouteComponentProps<T>) => string) | null;
export interface APMRouteDefinition<T = any> extends RouteProps {
breadcrumb: BreadcrumbTitle<T>;

View file

@ -22,10 +22,7 @@ import {
} from '../../../../../src/plugins/kibana_react/public';
import { APMRouteDefinition } from '../application/routes';
import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange';
import {
RumHome,
DASHBOARD_LABEL,
} from '../components/app/RumDashboard/RumHome';
import { RumHome, DASHBOARD_LABEL } from '../components/app/RumDashboard/RumHome';
import { ApmPluginContext } from '../context/apm_plugin/apm_plugin_context';
import { UrlParamsProvider } from '../context/url_params_context/url_params_context';
import { ConfigSchema } from '../index';
@ -34,10 +31,7 @@ import { createCallApmApi } from '../services/rest/createCallApmApi';
import { createStaticIndexPattern } from '../services/rest/index_pattern';
import { UXActionMenu } from '../components/app/RumDashboard/ActionMenu';
import { redirectTo } from '../components/routing/redirect_to';
import {
InspectorContextProvider,
useBreadcrumbs,
} from '../../../observability/public';
import { InspectorContextProvider, useBreadcrumbs } from '../../../observability/public';
import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context';
import { APP_WRAPPER_CLASS } from '../../../../../src/core/public';
@ -78,11 +72,7 @@ function UxApp() {
darkMode,
})}
>
<div
className={APP_WRAPPER_CLASS}
data-test-subj="csmMainContainer"
role="main"
>
<div className={APP_WRAPPER_CLASS} data-test-subj="csmMainContainer" role="main">
<ReactRouterRoute component={ScrollToTopOnPathChange} />
<RumHome />
</div>
@ -121,14 +111,9 @@ export function UXAppRoot({
};
return (
<RedirectAppLinks
className={APP_WRAPPER_CLASS}
application={core.application}
>
<RedirectAppLinks className={APP_WRAPPER_CLASS} application={core.application}>
<ApmPluginContext.Provider value={apmPluginContextValue}>
<KibanaContextProvider
services={{ ...core, ...plugins, embeddable, data }}
>
<KibanaContextProvider services={{ ...core, ...plugins, embeddable, data }}>
<i18nCore.Context>
<RouterProvider history={history} router={uxRouter}>
<InspectorContextProvider>

View file

@ -7,10 +7,7 @@
import React, { useCallback, useMemo } from 'react';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import {
AlertType,
APM_SERVER_FEATURE_ID,
} from '../../../../common/alert_types';
import { AlertType, APM_SERVER_FEATURE_ID } from '../../../../common/alert_types';
import { getInitialAlertValues } from '../get_initial_alert_values';
import { ApmPluginStartDeps } from '../../../plugin';
import { useServiceName } from '../../../hooks/use_service_name';
@ -36,10 +33,8 @@ export function AlertingFlyout(props: Props) {
const { start, end } = useTimeRange({ rangeFrom, rangeTo, optional: true });
const environment =
'environment' in query ? query.environment : ENVIRONMENT_ALL.value;
const transactionType =
'transactionType' in query ? query.transactionType : undefined;
const environment = 'environment' in query ? query.environment : ENVIRONMENT_ALL.value;
const transactionType = 'transactionType' in query ? query.transactionType : undefined;
const { services } = useKibana<ApmPluginStartDeps>();
const initialValues = getInitialAlertValues(alertType, serviceName);

View file

@ -33,12 +33,7 @@ interface ChartPreviewProps {
uiSettings?: IUiSettingsClient;
}
export function ChartPreview({
data = [],
yTickFormat,
threshold,
uiSettings,
}: ChartPreviewProps) {
export function ChartPreview({ data = [], yTickFormat, threshold, uiSettings }: ChartPreviewProps) {
const theme = useTheme();
const thresholdOpacity = 0.3;
const timestamps = data.map((d) => d.x);

View file

@ -47,10 +47,7 @@ const stories: Meta<{}> = {
};
export default stories;
export const CreatingInApmFromInventory: Story<Args> = ({
alertParams,
metadata,
}) => {
export const CreatingInApmFromInventory: Story<Args> = ({ alertParams, metadata }) => {
const [params, setParams] = useState<AlertParams>(alertParams);
function setAlertParams(property: string, value: any) {
@ -76,10 +73,7 @@ CreatingInApmFromInventory.args = {
},
};
export const CreatingInApmFromService: Story<Args> = ({
alertParams,
metadata,
}) => {
export const CreatingInApmFromService: Story<Args> = ({ alertParams, metadata }) => {
const [params, setParams] = useState<AlertParams>(alertParams);
function setAlertParams(property: string, value: any) {
@ -105,10 +99,7 @@ CreatingInApmFromService.args = {
},
};
export const EditingInStackManagement: Story<Args> = ({
alertParams,
metadata,
}) => {
export const EditingInStackManagement: Story<Args> = ({ alertParams, metadata }) => {
const [params, setParams] = useState<AlertParams>(alertParams);
function setAlertParams(property: string, value: any) {
@ -135,10 +126,7 @@ EditingInStackManagement.args = {
metadata: undefined,
};
export const CreatingInStackManagement: Story<Args> = ({
alertParams,
metadata,
}) => {
export const CreatingInStackManagement: Story<Args> = ({ alertParams, metadata }) => {
const [params, setParams] = useState<AlertParams>(alertParams);
function setAlertParams(property: string, value: any) {

View file

@ -61,8 +61,7 @@ export function ErrorCountAlertTrigger(props: Props) {
});
if (interval && start && end) {
return callApmApi({
endpoint:
'GET /internal/apm/alerts/chart_preview/transaction_error_count',
endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_count',
params: {
query: {
environment: params.environment,
@ -75,12 +74,7 @@ export function ErrorCountAlertTrigger(props: Props) {
});
}
},
[
params.windowSize,
params.windowUnit,
params.environment,
params.serviceName,
]
[params.windowSize, params.windowUnit, params.environment, params.serviceName]
);
const fields = [
@ -100,12 +94,8 @@ export function ErrorCountAlertTrigger(props: Props) {
onChange={(value) => setAlertParams('threshold', value || 0)}
/>,
<ForLastExpression
onChangeWindowSize={(timeWindowSize) =>
setAlertParams('windowSize', timeWindowSize || '')
}
onChangeWindowUnit={(timeWindowUnit) =>
setAlertParams('windowUnit', timeWindowUnit)
}
onChangeWindowSize={(timeWindowSize) => setAlertParams('windowSize', timeWindowSize || '')}
onChangeWindowUnit={(timeWindowUnit) => setAlertParams('windowUnit', timeWindowUnit)}
timeWindowSize={params.windowSize}
timeWindowUnit={params.windowUnit}
errors={{

View file

@ -13,9 +13,7 @@ import { expectTextsInDocument } from '../../utils/testHelpers';
describe('alerting fields', () => {
describe('Service Field', () => {
it('renders with value', () => {
const component = render(
<ServiceField currentValue="foo" onChange={() => {}} />
);
const component = render(<ServiceField currentValue="foo" onChange={() => {}} />);
expectTextsInDocument(component, ['foo']);
});
it('renders with All when value is not defined', () => {
@ -26,16 +24,12 @@ describe('alerting fields', () => {
describe('TransactionTypeField', () => {
it('renders', () => {
const component = render(
<TransactionTypeField currentValue="Bar" onChange={() => {}} />
);
const component = render(<TransactionTypeField currentValue="Bar" onChange={() => {}} />);
expectTextsInDocument(component, ['Bar']);
});
it('renders current value when available', () => {
const component = render(
<TransactionTypeField currentValue="foo" onChange={() => {}} />
);
const component = render(<TransactionTypeField currentValue="foo" onChange={() => {}} />);
expectTextsInDocument(component, ['foo']);
});
});

View file

@ -13,10 +13,7 @@ import {
SERVICE_NAME,
TRANSACTION_TYPE,
} from '../../../common/elasticsearch_fieldnames';
import {
ENVIRONMENT_ALL,
getEnvironmentLabel,
} from '../../../common/environment_filter_values';
import { ENVIRONMENT_ALL, getEnvironmentLabel } from '../../../common/environment_filter_values';
import { SuggestionsSelect } from '../shared/suggestions_select';
import { PopoverExpression } from './service_alert_trigger/popover_expression';
@ -50,12 +47,9 @@ export function ServiceField({
>
<SuggestionsSelect
allOption={allowAll ? allOption : undefined}
customOptionText={i18n.translate(
'xpack.apm.serviceNamesSelectCustomOptionText',
{
defaultMessage: 'Add \\{searchValue\\} as a new service name',
}
)}
customOptionText={i18n.translate('xpack.apm.serviceNamesSelectCustomOptionText', {
defaultMessage: 'Add \\{searchValue\\} as a new service name',
})}
defaultValue={currentValue}
field={SERVICE_NAME}
onChange={onChange}
@ -83,12 +77,9 @@ export function EnvironmentField({
>
<SuggestionsSelect
allOption={environmentAllOption}
customOptionText={i18n.translate(
'xpack.apm.environmentsSelectCustomOptionText',
{
defaultMessage: 'Add \\{searchValue\\} as a new environment',
}
)}
customOptionText={i18n.translate('xpack.apm.environmentsSelectCustomOptionText', {
defaultMessage: 'Add \\{searchValue\\} as a new environment',
})}
defaultValue={getEnvironmentLabel(currentValue)}
field={SERVICE_ENVIRONMENT}
onChange={onChange}
@ -114,21 +105,15 @@ export function TransactionTypeField({
<PopoverExpression value={currentValue || allOption.value} title={label}>
<SuggestionsSelect
allOption={allOption}
customOptionText={i18n.translate(
'xpack.apm.transactionTypesSelectCustomOptionText',
{
defaultMessage: 'Add \\{searchValue\\} as a new transaction type',
}
)}
customOptionText={i18n.translate('xpack.apm.transactionTypesSelectCustomOptionText', {
defaultMessage: 'Add \\{searchValue\\} as a new transaction type',
})}
defaultValue={currentValue}
field={TRANSACTION_TYPE}
onChange={onChange}
placeholder={i18n.translate(
'xpack.apm.transactionTypesSelectPlaceholder',
{
defaultMessage: 'Select transaction type',
}
)}
placeholder={i18n.translate('xpack.apm.transactionTypesSelectPlaceholder', {
defaultMessage: 'Select transaction type',
})}
/>
</PopoverExpression>
);
@ -148,10 +133,9 @@ export function IsAboveField({
return (
<PopoverExpression
value={value ? `${value.toString()}${unit}` : ''}
title={i18n.translate(
'xpack.apm.transactionErrorRateAlertTrigger.isAbove',
{ defaultMessage: 'is above' }
)}
title={i18n.translate('xpack.apm.transactionErrorRateAlertTrigger.isAbove', {
defaultMessage: 'is above',
})}
>
<EuiFieldNumber
value={value ?? ''}

View file

@ -13,10 +13,8 @@ describe('getAlertingCapabilities', () => {
describe('when the alerting plugin is not enabled', () => {
it('returns isAlertingAvailable = false', () => {
expect(
getAlertingCapabilities(
{} as ApmPluginSetupDeps,
{ apm: {} } as unknown as Capabilities
).isAlertingAvailable
getAlertingCapabilities({} as ApmPluginSetupDeps, { apm: {} } as unknown as Capabilities)
.isAlertingAvailable
).toEqual(false);
});
});

View file

@ -15,8 +15,7 @@ export const getAlertingCapabilities = (
const canReadAlerts = !!capabilities.apm['alerting:show'];
const canSaveAlerts = !!capabilities.apm['alerting:save'];
const isAlertingPluginEnabled = !!plugins.alerting;
const isAlertingAvailable =
isAlertingPluginEnabled && (canReadAlerts || canSaveAlerts);
const isAlertingAvailable = isAlertingPluginEnabled && (canReadAlerts || canSaveAlerts);
const isMlPluginEnabled = 'ml' in plugins;
const canReadAnomalies = !!(
isMlPluginEnabled &&

View file

@ -11,9 +11,7 @@ export function getInitialAlertValues(
alertType: AlertType | null,
serviceName: string | undefined
) {
const alertTypeName = alertType
? ALERT_TYPES_CONFIG[alertType].name
: undefined;
const alertTypeName = alertType ? ALERT_TYPES_CONFIG[alertType].name : undefined;
const alertName = alertTypeName
? serviceName
? `${alertTypeName} | ${serviceName}`

View file

@ -26,9 +26,7 @@ export function getIntervalAndTimeRange({
windowUnit: TimeUnit;
}) {
const end = Date.now();
const start =
end -
moment.duration(windowSize, windowUnit).asMilliseconds() * BUCKET_SIZE;
const start = end - moment.duration(windowSize, windowUnit).asMilliseconds() * BUCKET_SIZE;
return {
interval: `${windowSize}${windowUnit}`,

View file

@ -28,24 +28,15 @@ const SERVICE_ENVIRONMENT = 'service.environment';
const SERVICE_NAME = 'service.name';
const TRANSACTION_TYPE = 'transaction.type';
const format = ({
pathname,
query,
}: {
pathname: string;
query: Record<string, any>;
}): string => {
const format = ({ pathname, query }: { pathname: string; query: Record<string, any> }): string => {
return `${pathname}?${stringify(query)}`;
};
export function registerApmAlerts(
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry
) {
export function registerApmAlerts(observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry) {
observabilityRuleTypeRegistry.register({
id: AlertType.ErrorCount,
description: i18n.translate('xpack.apm.alertTypes.errorCount.description', {
defaultMessage:
'Alert when the number of errors in a service exceeds a defined threshold.',
defaultMessage: 'Alert when the number of errors in a service exceeds a defined threshold.',
}),
format: ({ fields }) => {
return {
@ -55,9 +46,7 @@ export function registerApmAlerts(
serviceName: String(fields[SERVICE_NAME][0]),
}),
link: format({
pathname: `/app/apm/services/${String(
fields[SERVICE_NAME][0]
)}/errors`,
pathname: `/app/apm/services/${String(fields[SERVICE_NAME][0])}/errors`,
query: {
...(fields[SERVICE_ENVIRONMENT]?.[0]
? { environment: String(fields[SERVICE_ENVIRONMENT][0]) }
@ -75,28 +64,22 @@ export function registerApmAlerts(
errors: [],
}),
requiresAppContext: false,
defaultActionMessage: i18n.translate(
'xpack.apm.alertTypes.errorCount.defaultActionMessage',
{
defaultMessage: `\\{\\{alertName\\}\\} alert is firing because of the following conditions:
defaultActionMessage: i18n.translate('xpack.apm.alertTypes.errorCount.defaultActionMessage', {
defaultMessage: `\\{\\{alertName\\}\\} alert is firing because of the following conditions:
- Service name: \\{\\{context.serviceName\\}\\}
- Environment: \\{\\{context.environment\\}\\}
- Threshold: \\{\\{context.threshold\\}\\} errors
- Triggered value: \\{\\{context.triggerValue\\}\\} errors over the last \\{\\{context.interval\\}\\}`,
}
),
}),
});
observabilityRuleTypeRegistry.register({
id: AlertType.TransactionDuration,
description: i18n.translate(
'xpack.apm.alertTypes.transactionDuration.description',
{
defaultMessage:
'Alert when the latency of a specific transaction type in a service exceeds a defined threshold.',
}
),
description: i18n.translate('xpack.apm.alertTypes.transactionDuration.description', {
defaultMessage:
'Alert when the latency of a specific transaction type in a service exceeds a defined threshold.',
}),
format: ({ fields, formatters: { asDuration } }) => ({
reason: formatTransactionDurationReason({
threshold: fields[ALERT_EVALUATION_THRESHOLD]!,
@ -118,9 +101,7 @@ export function registerApmAlerts(
documentationUrl(docLinks) {
return `${docLinks.links.alerting.apmRules}`;
},
alertParamsExpression: lazy(
() => import('./transaction_duration_alert_trigger')
),
alertParamsExpression: lazy(() => import('./transaction_duration_alert_trigger')),
validate: () => ({
errors: [],
}),
@ -141,13 +122,10 @@ export function registerApmAlerts(
observabilityRuleTypeRegistry.register({
id: AlertType.TransactionErrorRate,
description: i18n.translate(
'xpack.apm.alertTypes.transactionErrorRate.description',
{
defaultMessage:
'Alert when the rate of transaction errors in a service exceeds a defined threshold.',
}
),
description: i18n.translate('xpack.apm.alertTypes.transactionErrorRate.description', {
defaultMessage:
'Alert when the rate of transaction errors in a service exceeds a defined threshold.',
}),
format: ({ fields, formatters: { asPercent } }) => ({
reason: formatTransactionErrorRateReason({
threshold: fields[ALERT_EVALUATION_THRESHOLD]!,
@ -169,9 +147,7 @@ export function registerApmAlerts(
documentationUrl(docLinks) {
return `${docLinks.links.alerting.apmRules}`;
},
alertParamsExpression: lazy(
() => import('./transaction_error_rate_alert_trigger')
),
alertParamsExpression: lazy(() => import('./transaction_error_rate_alert_trigger')),
validate: () => ({
errors: [],
}),
@ -192,12 +168,9 @@ export function registerApmAlerts(
observabilityRuleTypeRegistry.register({
id: AlertType.TransactionDurationAnomaly,
description: i18n.translate(
'xpack.apm.alertTypes.transactionDurationAnomaly.description',
{
defaultMessage: 'Alert when the latency of a service is abnormal.',
}
),
description: i18n.translate('xpack.apm.alertTypes.transactionDurationAnomaly.description', {
defaultMessage: 'Alert when the latency of a service is abnormal.',
}),
format: ({ fields }) => ({
reason: formatTransactionDurationAnomalyReason({
serviceName: String(fields[SERVICE_NAME][0]),
@ -218,9 +191,7 @@ export function registerApmAlerts(
documentationUrl(docLinks) {
return `${docLinks.links.alerting.apmRules}`;
},
alertParamsExpression: lazy(
() => import('./transaction_duration_anomaly_alert_trigger')
),
alertParamsExpression: lazy(() => import('./transaction_duration_anomaly_alert_trigger')),
validate: () => ({
errors: [],
}),

View file

@ -21,12 +21,7 @@ import {
getResponseTimeTickFormatter,
} from '../../shared/charts/transaction_charts/helper';
import { ChartPreview } from '../chart_preview';
import {
EnvironmentField,
IsAboveField,
ServiceField,
TransactionTypeField,
} from '../fields';
import { EnvironmentField, IsAboveField, ServiceField, TransactionTypeField } from '../fields';
import { AlertMetadata, getIntervalAndTimeRange, TimeUnit } from '../helper';
import { ServiceAlertTrigger } from '../service_alert_trigger';
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
@ -42,24 +37,15 @@ export interface AlertParams {
}
const TRANSACTION_ALERT_AGGREGATION_TYPES = {
avg: i18n.translate(
'xpack.apm.transactionDurationAlert.aggregationType.avg',
{
defaultMessage: 'Average',
}
),
'95th': i18n.translate(
'xpack.apm.transactionDurationAlert.aggregationType.95th',
{
defaultMessage: '95th percentile',
}
),
'99th': i18n.translate(
'xpack.apm.transactionDurationAlert.aggregationType.99th',
{
defaultMessage: '99th percentile',
}
),
avg: i18n.translate('xpack.apm.transactionDurationAlert.aggregationType.avg', {
defaultMessage: 'Average',
}),
'95th': i18n.translate('xpack.apm.transactionDurationAlert.aggregationType.95th', {
defaultMessage: '95th percentile',
}),
'99th': i18n.translate('xpack.apm.transactionDurationAlert.aggregationType.99th', {
defaultMessage: '99th percentile',
}),
};
interface Props {
@ -99,8 +85,7 @@ export function TransactionDurationAlertTrigger(props: Props) {
});
if (interval && start && end) {
return callApmApi({
endpoint:
'GET /internal/apm/alerts/chart_preview/transaction_duration',
endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_duration',
params: {
query: {
aggregationType: params.aggregationType,
@ -183,12 +168,8 @@ export function TransactionDurationAlertTrigger(props: Props) {
onChange={(value) => setAlertParams('threshold', value || 0)}
/>,
<ForLastExpression
onChangeWindowSize={(timeWindowSize) =>
setAlertParams('windowSize', timeWindowSize || '')
}
onChangeWindowUnit={(timeWindowUnit) =>
setAlertParams('windowUnit', timeWindowUnit)
}
onChangeWindowSize={(timeWindowSize) => setAlertParams('windowSize', timeWindowSize || '')}
onChangeWindowUnit={(timeWindowUnit) => setAlertParams('windowUnit', timeWindowUnit)}
timeWindowSize={params.windowSize}
timeWindowUnit={params.windowUnit}
errors={{

View file

@ -13,18 +13,11 @@ import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
import { ANOMALY_SEVERITY } from '../../../../common/ml_constants';
import { createCallApmApi } from '../../../services/rest/createCallApmApi';
import {
EnvironmentField,
ServiceField,
TransactionTypeField,
} from '../fields';
import { EnvironmentField, ServiceField, TransactionTypeField } from '../fields';
import { AlertMetadata } from '../helper';
import { ServiceAlertTrigger } from '../service_alert_trigger';
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
import {
AnomalySeverity,
SelectAnomalySeverity,
} from './select_anomaly_severity';
import { AnomalySeverity, SelectAnomalySeverity } from './select_anomaly_severity';
interface AlertParams {
anomalySeverityType?:
@ -82,12 +75,9 @@ export function TransactionDurationAnomalyAlertTrigger(props: Props) {
/>,
<PopoverExpression
value={<AnomalySeverity type={params.anomalySeverityType} />}
title={i18n.translate(
'xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity',
{
defaultMessage: 'Has anomaly with severity',
}
)}
title={i18n.translate('xpack.apm.transactionDurationAnomalyAlertTrigger.anomalySeverity', {
defaultMessage: 'Has anomaly with severity',
})}
>
<SelectAnomalySeverity
value={params.anomalySeverityType}

View file

@ -18,23 +18,16 @@ function Wrapper({ children }: { children?: ReactNode }) {
describe('SelectAnomalySeverity', () => {
it('shows the correct text for each item', async () => {
const result = render(
<SelectAnomalySeverity
onChange={() => {}}
value={ANOMALY_SEVERITY.CRITICAL}
/>,
<SelectAnomalySeverity onChange={() => {}} value={ANOMALY_SEVERITY.CRITICAL} />,
{ wrapper: Wrapper }
);
const button = (await result.findAllByText('critical'))[1];
button.click();
const options = await result.findAllByTestId(
'SelectAnomalySeverity option text'
);
const options = await result.findAllByTestId('SelectAnomalySeverity option text');
expect(
options.map((option) => (option.firstChild as HTMLElement)?.innerHTML)
).toEqual([
expect(options.map((option) => (option.firstChild as HTMLElement)?.innerHTML)).toEqual([
'score critical ', // Trailing space is intentional here, to keep the i18n simple
'score major and above',
'score minor and above',

View file

@ -15,14 +15,9 @@ import {
} from '../../../../common/alert_types';
export function AnomalySeverity({ type }: { type: AnomalyAlertSeverityType }) {
const selectedOption = ANOMALY_ALERT_SEVERITY_TYPES.find(
(option) => option.type === type
)!;
const selectedOption = ANOMALY_ALERT_SEVERITY_TYPES.find((option) => option.type === type)!;
return (
<EuiHealth
color={getSeverityColor(selectedOption.threshold)}
style={{ lineHeight: 'inherit' }}
>
<EuiHealth color={getSeverityColor(selectedOption.threshold)} style={{ lineHeight: 'inherit' }}>
{selectedOption.label}
</EuiHealth>
);

View file

@ -15,12 +15,7 @@ import { asPercent } from '../../../../common/utils/formatters';
import { useFetcher } from '../../../hooks/use_fetcher';
import { createCallApmApi } from '../../../services/rest/createCallApmApi';
import { ChartPreview } from '../chart_preview';
import {
EnvironmentField,
IsAboveField,
ServiceField,
TransactionTypeField,
} from '../fields';
import { EnvironmentField, IsAboveField, ServiceField, TransactionTypeField } from '../fields';
import { AlertMetadata, getIntervalAndTimeRange, TimeUnit } from '../helper';
import { ServiceAlertTrigger } from '../service_alert_trigger';
@ -68,8 +63,7 @@ export function TransactionErrorRateAlertTrigger(props: Props) {
});
if (interval && start && end) {
return callApmApi({
endpoint:
'GET /internal/apm/alerts/chart_preview/transaction_error_rate',
endpoint: 'GET /internal/apm/alerts/chart_preview/transaction_error_rate',
params: {
query: {
environment: params.environment,
@ -111,12 +105,8 @@ export function TransactionErrorRateAlertTrigger(props: Props) {
onChange={(value) => setAlertParams('threshold', value || 0)}
/>,
<ForLastExpression
onChangeWindowSize={(timeWindowSize) =>
setAlertParams('windowSize', timeWindowSize || '')
}
onChangeWindowUnit={(timeWindowUnit) =>
setAlertParams('windowUnit', timeWindowUnit)
}
onChangeWindowSize={(timeWindowSize) => setAlertParams('windowSize', timeWindowSize || '')}
onChangeWindowUnit={(timeWindowUnit) => setAlertParams('windowUnit', timeWindowUnit)}
timeWindowSize={params.windowSize}
timeWindowUnit={params.windowUnit}
errors={{

View file

@ -8,10 +8,7 @@
import React from 'react';
import { EuiHeaderLinks, EuiHeaderLink, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
createExploratoryViewUrl,
HeaderMenuPortal,
} from '../../../../../../observability/public';
import { createExploratoryViewUrl, HeaderMenuPortal } from '../../../../../../observability/public';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
import { AppMountParameters } from '../../../../../../../../src/core/public';
@ -22,19 +19,12 @@ const ANALYZE_DATA = i18n.translate('xpack.apm.analyzeDataButtonLabel', {
defaultMessage: 'Explore data',
});
const ANALYZE_MESSAGE = i18n.translate(
'xpack.apm.analyzeDataButtonLabel.message',
{
defaultMessage:
'Explore Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.',
}
);
const ANALYZE_MESSAGE = i18n.translate('xpack.apm.analyzeDataButtonLabel.message', {
defaultMessage:
'Explore Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.',
});
export function UXActionMenu({
appMountParameters,
}: {
appMountParameters: AppMountParameters;
}) {
export function UXActionMenu({ appMountParameters }: { appMountParameters: AppMountParameters }) {
const {
services: { http },
} = useKibana();
@ -62,9 +52,7 @@ export function UXActionMenu({
const kibana = useKibana();
return (
<HeaderMenuPortal
setHeaderActionMenu={appMountParameters.setHeaderActionMenu}
>
<HeaderMenuPortal setHeaderActionMenu={appMountParameters.setHeaderActionMenu}>
<EuiHeaderLinks gutterSize="xs">
<EuiToolTip position="top" content={<p>{ANALYZE_MESSAGE}</p>}>
<EuiHeaderLink
@ -80,9 +68,7 @@ export function UXActionMenu({
color="primary"
iconType="indexOpen"
iconSide="left"
href={kibana.services?.application?.getUrlForApp(
'/home#/tutorial/apm'
)}
href={kibana.services?.application?.getUrlForApp('/home#/tutorial/apm')}
>
{i18n.translate('xpack.apm.addDataButtonLabel', {
defaultMessage: 'Add data',

View file

@ -22,11 +22,7 @@ interface Props {
dataTestSubj: string;
}
export function BreakdownFilter({
selectedBreakdown,
onBreakdownChange,
dataTestSubj,
}: Props) {
export function BreakdownFilter({ selectedBreakdown, onBreakdownChange, dataTestSubj }: Props) {
const NO_BREAKDOWN = 'noBreakdown';
const items: BreakdownItem[] = [

View file

@ -6,12 +6,7 @@
*/
import React, { HTMLAttributes, ReactNode } from 'react';
import {
EuiErrorBoundary,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingChart,
} from '@elastic/eui';
import { EuiErrorBoundary, EuiFlexGroup, EuiFlexItem, EuiLoadingChart } from '@elastic/eui';
interface Props {
children?: ReactNode;

View file

@ -23,10 +23,7 @@ import {
Fit,
Position,
} from '@elastic/charts';
import {
EUI_CHARTS_THEME_DARK,
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme';
import styled from 'styled-components';
import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations';
import { I18LABELS } from '../translations';
@ -89,9 +86,7 @@ export function PageLoadDistChart({
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
const euiChartTheme = darkMode ? EUI_CHARTS_THEME_DARK : EUI_CHARTS_THEME_LIGHT;
return (
<ChartWrapper loading={loading || breakdownLoading} height="250px">
@ -105,11 +100,7 @@ export function PageLoadDistChart({
showLegend
/>
<PercentileAnnotations percentiles={data?.percentiles} />
<Axis
id="bottom"
title={I18LABELS.pageLoadTime}
position={Position.Bottom}
/>
<Axis id="bottom" title={I18LABELS.pageLoadTime} position={Position.Bottom} />
<Axis
id="left"
title={I18LABELS.percPageLoaded}

View file

@ -19,10 +19,7 @@ import {
timeFormatter,
Position,
} from '@elastic/charts';
import {
EUI_CHARTS_THEME_DARK,
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme';
import numeral from '@elastic/numeral';
import moment from 'moment';
import React from 'react';
@ -46,10 +43,7 @@ export function PageViewsChart({ data, loading }: Props) {
const { urlParams } = useUrlParams();
const { start, end } = urlParams;
const diffInDays = moment(new Date(end as string)).diff(
moment(new Date(start as string)),
'day'
);
const diffInDays = moment(new Date(end as string)).diff(moment(new Date(start as string)), 'day');
const formatter = timeFormatter(niceTimeFormatByDay(diffInDays > 1 ? 2 : 1));
@ -86,9 +80,7 @@ export function PageViewsChart({ data, loading }: Props) {
return yAccessor;
};
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
const euiChartTheme = darkMode ? EUI_CHARTS_THEME_DARK : EUI_CHARTS_THEME_LIGHT;
return (
<ChartWrapper loading={loading} height="250px">
@ -104,11 +96,7 @@ export function PageViewsChart({ data, loading }: Props) {
max: new Date(end as string).valueOf(),
}}
/>
<Axis
id="date_time"
position={Position.Bottom}
tickFormat={formatter}
/>
<Axis id="date_time" position={Position.Bottom} tickFormat={formatter} />
<Axis
id="page_views"
title={I18LABELS.pageViews}
@ -125,11 +113,7 @@ export function PageViewsChart({ data, loading }: Props) {
stackAccessors={['x']}
data={data?.items ?? []}
name={customSeriesNaming}
color={
!hasBreakdowns
? euiChartTheme.theme.colors?.vizColors?.[1]
: undefined
}
color={!hasBreakdowns ? euiChartTheme.theme.colors?.vizColors?.[1] : undefined}
/>
</Chart>
)}

View file

@ -17,10 +17,7 @@ import {
Settings,
} from '@elastic/charts';
import styled from 'styled-components';
import {
EUI_CHARTS_THEME_DARK,
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme';
import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public';
import { ChartWrapper } from '../ChartWrapper';
import { I18LABELS } from '../translations';
@ -46,35 +43,24 @@ const theme: PartialTheme = {
export function VisitorBreakdownChart({ loading, options }: Props) {
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
const euiChartTheme = darkMode ? EUI_CHARTS_THEME_DARK : EUI_CHARTS_THEME_LIGHT;
return (
<ChartWrapper loading={loading} height="245px" maxWidth="430px">
<StyleChart>
<Chart>
<Settings
showLegend
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
theme={theme}
/>
<Settings showLegend baseTheme={darkMode ? DARK_THEME : LIGHT_THEME} theme={theme} />
<Partition
id="spec_1"
data={
options?.length ? options : [{ count: 1, name: I18LABELS.noData }]
}
data={options?.length ? options : [{ count: 1, name: I18LABELS.noData }]}
valueAccessor={(d: Datum) => d.count as number}
valueGetter="percent"
percentFormatter={(d: number) =>
`${Math.round((d + Number.EPSILON) * 100) / 100}%`
}
percentFormatter={(d: number) => `${Math.round((d + Number.EPSILON) * 100) / 100}%`}
layers={[
{
groupByRollup: (d: Datum) => d.name,
shape: {
fillColor: (d) =>
euiChartTheme.theme.colors?.vizColors?.[d.sortIndex]!,
fillColor: (d) => euiChartTheme.theme.colors?.vizColors?.[d.sortIndex]!,
},
},
]}

View file

@ -9,13 +9,7 @@ import * as React from 'react';
import numeral from '@elastic/numeral';
import styled from 'styled-components';
import { useContext, useEffect } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiStat,
EuiToolTip,
EuiIconTip,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiToolTip, EuiIconTip } from '@elastic/eui';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { I18LABELS } from '../translations';
import { useUxQuery } from '../hooks/useUxQuery';
@ -85,10 +79,7 @@ export function Metrics() {
description={
<>
{I18LABELS.totalPageLoad}
<EuiIconTip
content={I18LABELS.totalPageLoadTooltip}
type="questionInCircle"
/>
<EuiIconTip content={I18LABELS.totalPageLoadTooltip} type="questionInCircle" />
</>
}
isLoading={status !== 'success'}
@ -101,10 +92,7 @@ export function Metrics() {
description={
<>
{I18LABELS.backEnd}
<EuiIconTip
content={I18LABELS.backEndTooltip}
type="questionInCircle"
/>
<EuiIconTip content={I18LABELS.backEndTooltip} type="questionInCircle" />
</>
}
isLoading={status !== 'success'}
@ -117,10 +105,7 @@ export function Metrics() {
description={
<>
{I18LABELS.frontEnd}
<EuiIconTip
content={I18LABELS.frontEndTooltip}
type="questionInCircle"
/>
<EuiIconTip content={I18LABELS.frontEndTooltip} type="questionInCircle" />
</>
}
isLoading={status !== 'success'}

View file

@ -6,13 +6,7 @@
*/
import * as React from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
EuiTitle,
EuiSpacer,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui';
import { I18LABELS } from '../translations';
import { getPercentileLabel } from '../UXMetrics/translations';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';

View file

@ -19,19 +19,13 @@ interface Index {
const defaultContext: Index = {
sharedData: { totalPageViews: 0 },
setSharedData: (d) => {
throw new Error(
'setSharedData was not initialized, set it when you invoke the context'
);
throw new Error('setSharedData was not initialized, set it when you invoke the context');
},
};
export const CsmSharedContext = createContext(defaultContext);
export function CsmSharedContextProvider({
children,
}: {
children: JSX.Element;
}) {
export function CsmSharedContextProvider({ children }: { children: JSX.Element }) {
const [newData, setNewData] = useState<SharedData>({ totalPageViews: 0 });
const setSharedData = React.useCallback((data: SharedData) => {

View file

@ -68,10 +68,7 @@ export function JSErrors() {
field: 'errorMessage',
name: I18LABELS.errorMessage,
render: (errorMessage: string, item: JSErrorItem) => (
<ErrorDetailLink
serviceName={serviceName!}
errorGroupId={item.errorGroupId as string}
>
<ErrorDetailLink serviceName={serviceName!} errorGroupId={item.errorGroupId as string}>
{errorMessage}
</ErrorDetailLink>
),
@ -92,11 +89,7 @@ export function JSErrors() {
},
];
const onTableChange = ({
page,
}: {
page: { size: number; index: number };
}) => {
const onTableChange = ({ page }: { page: { size: number; index: number } }) => {
setPagination({
pageIndex: page.index,
pageSize: page.size,

View file

@ -57,18 +57,14 @@ export function SelectedFilters({
removeFilter={() => {
onChange(
name,
(uxUiFilters?.[name] as string[]).filter(
(valT) => valT !== value
)
(uxUiFilters?.[name] as string[]).filter((valT) => valT !== value)
);
}}
invertFilter={({ negate }) => {
invertFilter(name, value, negate);
}}
field={fieldName}
value={
name === 'transactionUrl' ? formatUrlValue(value) : value
}
value={name === 'transactionUrl' ? formatUrlValue(value) : value}
negate={!!excluded}
label={title}
/>
@ -78,12 +74,7 @@ export function SelectedFilters({
))}
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="xs"
iconType="cross"
onClick={clearValues}
data-cy="clearFilters"
>
<EuiButtonEmpty size="xs" iconType="cross" onClick={clearValues} data-cy="clearFilters">
{i18n.translate('xpack.apm.clearFilters', {
defaultMessage: 'Clear filters',
})}

View file

@ -26,30 +26,20 @@ import { useBreakpoints } from '../../../../hooks/use_breakpoints';
import { FieldValueSuggestions } from '../../../../../../observability/public';
import { URLFilter } from '../URLFilter';
import { SelectedFilters } from './SelectedFilters';
import {
SERVICE_NAME,
TRANSACTION_TYPE,
} from '../../../../../common/elasticsearch_fieldnames';
import { SERVICE_NAME, TRANSACTION_TYPE } from '../../../../../common/elasticsearch_fieldnames';
import { TRANSACTION_PAGE_LOAD } from '../../../../../common/transaction_types';
import { useIndexPattern } from './use_index_pattern';
import { environmentQuery } from './queries';
import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values';
import { useUxUrlParams } from '../../../../context/url_params_context/use_ux_url_params';
const filterNames: UxLocalUIFilterName[] = [
'location',
'device',
'os',
'browser',
];
const filterNames: UxLocalUIFilterName[] = ['location', 'device', 'os', 'browser'];
export const getExcludedName = (filterName: string) => {
return `${filterName}Excluded` as UxLocalUIFilterName;
};
const RUM_DATA_FILTERS = [
{ term: { [TRANSACTION_TYPE]: TRANSACTION_PAGE_LOAD } },
];
const RUM_DATA_FILTERS = [{ term: { [TRANSACTION_TYPE]: TRANSACTION_PAGE_LOAD } }];
function LocalUIFilters() {
const { indexPatternTitle, indexPattern } = useIndexPattern();
@ -60,9 +50,7 @@ function LocalUIFilters() {
invertFilter,
clearValues,
} = useLocalUIFilters({
filterNames: uxLocalUIFilterNames.filter(
(name) => !['serviceName'].includes(name)
),
filterNames: uxLocalUIFilterNames.filter((name) => !['serviceName'].includes(name)),
});
const {
@ -111,23 +99,15 @@ function LocalUIFilters() {
indexPatternTitle={indexPatternTitle}
label={uxFiltersByName[filterName].title}
asCombobox={false}
selectedValue={
filters.find((ft) => ft.name === filterName && !ft.excluded)
?.value
}
selectedValue={filters.find((ft) => ft.name === filterName && !ft.excluded)?.value}
excludedValue={
filters.find(
(ft) =>
ft.name === getExcludedName(filterName) && ft.excluded
)?.value
filters.find((ft) => ft.name === getExcludedName(filterName) && ft.excluded)
?.value
}
asFilterButton={true}
onChange={(values, excludedValues) => {
setFilterValue(filterName, values || []);
setFilterValue(
getExcludedName(filterName),
excludedValues || []
);
setFilterValue(getExcludedName(filterName), excludedValues || []);
}}
filters={getFilters}
time={{ from: start!, to: end! }}

View file

@ -14,9 +14,7 @@ import {
type QueryDslQueryContainer = ESFilter;
export function environmentQuery(
environment: string
): QueryDslQueryContainer[] {
export function environmentQuery(environment: string): QueryDslQueryContainer[] {
if (!environment || environment === ENVIRONMENT_ALL.value) {
return [];
}

View file

@ -30,9 +30,7 @@ describe('useIndexPattern', () => {
const { waitForNextUpdate } = renderHook(() => useIndexPattern(), {
wrapper: ({ children }) => (
<MockApmPluginContextWrapper>
<KibanaContextProvider services={mockDataService}>
{children}
</KibanaContextProvider>
<KibanaContextProvider services={mockDataService}>{children}</KibanaContextProvider>
</MockApmPluginContextWrapper>
),
});

View file

@ -8,10 +8,7 @@
import { CurveType, Fit, LineSeries, ScaleType } from '@elastic/charts';
import React, { useEffect } from 'react';
import numeral from '@elastic/numeral';
import {
EUI_CHARTS_THEME_DARK,
EUI_CHARTS_THEME_LIGHT,
} from '@elastic/eui/dist/eui_charts_theme';
import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme';
import { PercentileRange } from './index';
import { useBreakdowns } from './use_breakdowns';
import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public';
@ -23,17 +20,10 @@ interface Props {
onLoadingChange: (loading: boolean) => void;
}
export function BreakdownSeries({
field,
value,
percentileRange,
onLoadingChange,
}: Props) {
export function BreakdownSeries({ field, value, percentileRange, onLoadingChange }: Props) {
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
const euiChartTheme = darkMode
? EUI_CHARTS_THEME_DARK
: EUI_CHARTS_THEME_LIGHT;
const euiChartTheme = darkMode ? EUI_CHARTS_THEME_DARK : EUI_CHARTS_THEME_LIGHT;
const { breakdowns, status } = useBreakdowns({
field,
@ -60,11 +50,7 @@ export function BreakdownSeries({
data={seriesData ?? []}
lineSeriesStyle={{ point: { visible: false } }}
fit={Fit.Linear}
color={
euiChartTheme.theme.colors?.vizColors?.[
sortIndex === 0 ? 0 : sortIndex + 1
]
}
color={euiChartTheme.theme.colors?.vizColors?.[sortIndex === 0 ? 0 : sortIndex + 1]}
tickFormat={(d) => numeral(d).format('0.0') + ' %'}
/>
))}

View file

@ -20,9 +20,7 @@ interface Props {
percentiles?: Record<string, number | null>;
}
function generateAnnotationData(
values?: Record<string, number | null>
): LineAnnotationDatum[] {
function generateAnnotationData(values?: Record<string, number | null>): LineAnnotationDatum[] {
return Object.entries(values ?? {}).map((value) => ({
dataValue: value[1],
details: `${(+value[0]).toFixed(0)}`,
@ -40,16 +38,8 @@ export function PercentileAnnotations({ percentiles }: Props) {
},
};
function PercentileTooltip({
annotation,
}: {
annotation: LineAnnotationDatum;
}) {
return (
<span data-cy="percentileTooltipTitle">
{annotation.details}th Percentile
</span>
);
function PercentileTooltip({ annotation }: { annotation: LineAnnotationDatum }) {
return <span data-cy="percentileTooltipTitle">{annotation.details}th Percentile</span>;
}
return (
@ -67,9 +57,7 @@ export function PercentileAnnotations({ percentiles }: Props) {
<span data-cy="percentile-markers">
<EuiToolTip
title={<PercentileTooltip annotation={annotation} />}
content={
<span>Pages loaded: {Math.round(annotation.dataValue)}</span>
}
content={<span>Pages loaded: {Math.round(annotation.dataValue)}</span>}
>
<>{annotation.details}th</>
</EuiToolTip>

Some files were not shown because too many files have changed in this diff Show more