diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts b/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts index 07379b2a3002d..e9b89fa4739d0 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/apm_fields.ts @@ -57,6 +57,7 @@ export type ApmFields = Fields & 'error.grouping_name': string; 'error.grouping_key': string; 'host.name': string; + 'host.architecture': string; 'host.hostname': string; 'http.request.method': string; 'http.response.status_code': number; diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts b/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts index c8287066cc273..433acf42ba6ba 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/serverless_function.ts @@ -26,11 +26,13 @@ export function serverlessFunction({ serviceName, environment, agentName, + architecture = 'arm', }: { functionName: string; environment: string; agentName: string; serviceName?: string; + architecture?: string; }) { const faasId = `arn:aws:lambda:us-west-2:001:function:${functionName}`; return new ServerlessFunction({ @@ -40,5 +42,6 @@ export function serverlessFunction({ 'service.environment': environment, 'agent.name': agentName, 'service.runtime.name': 'AWS_lambda', + 'host.architecture': architecture, }); } diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 22b2a5de751f5..0aa6830adf867 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -442,6 +442,14 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'observability:apmAWSLambdaPriceFactor': { + type: 'text', + _meta: { description: 'Non-default value of setting.' }, + }, + 'observability:apmAWSLambdaRequestCostPerMillion': { + type: 'integer', + _meta: { description: 'Non-default value of setting.' }, + }, 'banners:placement': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 6957323103545..88220ed367886 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -43,6 +43,8 @@ export interface UsageStats { 'observability:enableComparisonByDefault': boolean; 'observability:enableServiceGroups': boolean; 'observability:apmEnableServiceMetrics': boolean; + 'observability:apmAWSLambdaPriceFactor': string; + 'observability:apmAWSLambdaRequestCostPerMillion': number; 'observability:enableInfrastructureHostsView': boolean; 'visualize:enableLabs': boolean; 'visualization:heatmap:maxBuckets': number; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 43dc28b3e9e61..7ad52ecb20d25 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -8785,6 +8785,18 @@ "description": "Non-default value of setting." } }, + "observability:apmAWSLambdaPriceFactor": { + "type": "text", + "_meta": { + "description": "Non-default value of setting." + } + }, + "observability:apmAWSLambdaRequestCostPerMillion": { + "type": "integer", + "_meta": { + "description": "Non-default value of setting." + } + }, "banners:placement": { "type": "keyword", "_meta": { diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 8a1ae899ddd3b..10c42bd763da6 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -85,6 +85,8 @@ Object { } `; +exports[`Error HOST_ARCHITECTURE 1`] = `undefined`; + exports[`Error HOST_HOSTNAME 1`] = `"my hostname"`; exports[`Error HOST_NAME 1`] = `undefined`; @@ -338,6 +340,8 @@ exports[`Span FAAS_TRIGGER_TYPE 1`] = `undefined`; exports[`Span HOST 1`] = `undefined`; +exports[`Span HOST_ARCHITECTURE 1`] = `undefined`; + exports[`Span HOST_HOSTNAME 1`] = `undefined`; exports[`Span HOST_NAME 1`] = `undefined`; @@ -595,6 +599,8 @@ Object { } `; +exports[`Transaction HOST_ARCHITECTURE 1`] = `undefined`; + exports[`Transaction HOST_HOSTNAME 1`] = `"my hostname"`; exports[`Transaction HOST_NAME 1`] = `undefined`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index 6fa3625c7ff78..4915dff2da4f3 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -123,6 +123,7 @@ export const HOST = 'host'; export const HOST_HOSTNAME = 'host.hostname'; // Do not use. Please use `HOST_NAME` instead. export const HOST_NAME = 'host.name'; export const HOST_OS_PLATFORM = 'host.os.platform'; +export const HOST_ARCHITECTURE = 'host.architecture'; export const HOST_OS_VERSION = 'host.os.version'; export const CONTAINER_ID = 'container.id'; export const CONTAINER = 'container'; diff --git a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx index f6d93cb9cd809..365937c8c48a2 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/serverless_metrics/serverless_summary.tsx @@ -163,6 +163,20 @@ export function ServerlessSummary({ serverlessId }: Props) { /> {showVerticalRule && } + {data?.estimatedCost && ( + + + + )} ); diff --git a/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx b/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx index 2faad60fb8b81..564cddd1af89c 100644 --- a/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx @@ -16,6 +16,8 @@ import { defaultApmServiceEnvironment, enableComparisonByDefault, enableInspectEsQueries, + apmAWSLambdaPriceFactor, + apmAWSLambdaRequestCostPerMillion, } from '@kbn/observability-plugin/common'; import { isEmpty } from 'lodash'; import React from 'react'; @@ -30,6 +32,8 @@ const apmSettingsKeys = [ apmServiceGroupMaxNumberOfServices, enableInspectEsQueries, apmLabsButton, + apmAWSLambdaPriceFactor, + apmAWSLambdaRequestCostPerMillion, ]; export function GeneralSettings() { diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/serverless_details.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/serverless_details.tsx index 5d6e3f5df0b66..2c6fabc72c037 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/serverless_details.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/serverless_details.tsx @@ -72,5 +72,17 @@ export function ServerlessDetails({ serverless }: Props) { }); } + if (serverless.hostArchitecture) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.cloud.architecture', + { defaultMessage: 'Architecture' } + ), + description: ( + {serverless.hostArchitecture} + ), + }); + } + return ; } diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts index d3f292a11b872..1b35e8fd22ed3 100644 --- a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts @@ -14,14 +14,65 @@ import { FAAS_BILLED_DURATION, FAAS_DURATION, FAAS_ID, + HOST_ARCHITECTURE, METRICSET_NAME, METRIC_SYSTEM_FREE_MEMORY, METRIC_SYSTEM_TOTAL_MEMORY, SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { environmentQuery } from '../../../../common/utils/environment_query'; -import { calcMemoryUsedRate } from './helper'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { calcEstimatedCost, calcMemoryUsedRate } from './helper'; + +export type AwsLambdaArchitecture = 'arm' | 'x86_64'; + +export type AWSLambdaPriceFactor = Record; + +async function getServerlessTransactionThroughput({ + end, + environment, + kuery, + serviceName, + start, + serverlessId, + apmEventClient, +}: { + environment: string; + kuery: string; + serviceName: string; + start: number; + end: number; + serverlessId?: string; + apmEventClient: APMEventClient; +}) { + const params = { + apm: { + events: [ProcessorEvent.transaction], + }, + body: { + track_total_hits: true, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(SERVICE_NAME, serviceName), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...termQuery(FAAS_ID, serverlessId), + ], + }, + }, + }, + }; + + const response = await apmEventClient.search( + 'get_serverless_transaction_throughout', + params + ); + + return response.hits.total.value; +} export async function getServerlessSummary({ end, @@ -31,6 +82,8 @@ export async function getServerlessSummary({ start, serverlessId, apmEventClient, + awsLambdaPriceFactor, + awsLambdaRequestCostPerMillion, }: { environment: string; kuery: string; @@ -39,6 +92,8 @@ export async function getServerlessSummary({ end: number; serverlessId?: string; apmEventClient: APMEventClient; + awsLambdaPriceFactor?: AWSLambdaPriceFactor; + awsLambdaRequestCostPerMillion?: number; }) { const params = { apm: { @@ -65,14 +120,28 @@ export async function getServerlessSummary({ faasBilledDurationAvg: { avg: { field: FAAS_BILLED_DURATION } }, avgTotalMemory: { avg: { field: METRIC_SYSTEM_TOTAL_MEMORY } }, avgFreeMemory: { avg: { field: METRIC_SYSTEM_FREE_MEMORY } }, + sample: { + top_metrics: { + metrics: [{ field: HOST_ARCHITECTURE }], + sort: [{ '@timestamp': { order: 'desc' as const } }], + }, + }, }, }, }; - const response = await apmEventClient.search( - 'ger_serverless_summary', - params - ); + const [response, transactionThroughput] = await Promise.all([ + apmEventClient.search('get_serverless_summary', params), + getServerlessTransactionThroughput({ + end, + environment, + kuery, + serviceName, + apmEventClient, + start, + serverlessId, + }), + ]); return { memoryUsageAvgRate: calcMemoryUsedRate({ @@ -82,5 +151,15 @@ export async function getServerlessSummary({ serverlessFunctionsTotal: response.aggregations?.totalFunctions?.value, serverlessDurationAvg: response.aggregations?.faasDurationAvg?.value, billedDurationAvg: response.aggregations?.faasBilledDurationAvg?.value, + estimatedCost: calcEstimatedCost({ + awsLambdaPriceFactor, + awsLambdaRequestCostPerMillion, + architecture: response.aggregations?.sample?.top?.[0]?.metrics?.[ + HOST_ARCHITECTURE + ] as AwsLambdaArchitecture | undefined, + transactionThroughput, + billedDuration: response.aggregations?.faasBilledDurationAvg.value, + totalMemory: response.aggregations?.avgTotalMemory.value, + }), }; } diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts index c6927f36a8eb9..d92b7edece8dc 100644 --- a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.test.ts @@ -4,7 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { calcMemoryUsed, calcMemoryUsedRate } from './helper'; +import { + calcMemoryUsed, + calcMemoryUsedRate, + calcEstimatedCost, +} from './helper'; describe('calcMemoryUsed', () => { it('returns undefined when memory values are no a number', () => { [ @@ -38,3 +42,85 @@ describe('calcMemoryUsedRate', () => { expect(calcMemoryUsedRate({ memoryFree: 50, memoryTotal: 100 })).toBe(0.5); }); }); + +const AWS_LAMBDA_PRICE_FACTOR = { + x86_64: 0.0000166667, + arm: 0.0000133334, +}; + +describe('calcEstimatedCost', () => { + it('returns undefined when price factor is not defined', () => { + expect( + calcEstimatedCost({ + totalMemory: 1, + billedDuration: 1, + transactionThroughput: 1, + architecture: 'arm', + }) + ).toBeUndefined(); + }); + + it('returns undefined when architecture is not defined', () => { + expect( + calcEstimatedCost({ + totalMemory: 1, + billedDuration: 1, + transactionThroughput: 1, + awsLambdaPriceFactor: AWS_LAMBDA_PRICE_FACTOR, + }) + ).toBeUndefined(); + }); + + it('returns undefined when compute usage is not defined', () => { + expect( + calcEstimatedCost({ + transactionThroughput: 1, + awsLambdaPriceFactor: AWS_LAMBDA_PRICE_FACTOR, + architecture: 'arm', + }) + ).toBeUndefined(); + }); + + it('returns undefined when request cost per million is not defined', () => { + expect( + calcEstimatedCost({ + totalMemory: 1, + billedDuration: 1, + transactionThroughput: 1, + awsLambdaPriceFactor: AWS_LAMBDA_PRICE_FACTOR, + architecture: 'arm', + }) + ).toBeUndefined(); + }); + + describe('x86_64 architecture', () => { + const architecture = 'x86_64'; + it('returns correct cost', () => { + expect( + calcEstimatedCost({ + awsLambdaPriceFactor: AWS_LAMBDA_PRICE_FACTOR, + architecture, + billedDuration: 4000, + totalMemory: 536870912, // 0.5gb + transactionThroughput: 100000, + awsLambdaRequestCostPerMillion: 0.2, + }) + ).toEqual(0.03); + }); + }); + describe('arm architecture', () => { + const architecture = 'arm'; + it('returns correct cost', () => { + expect( + calcEstimatedCost({ + awsLambdaPriceFactor: AWS_LAMBDA_PRICE_FACTOR, + architecture, + billedDuration: 8000, + totalMemory: 536870912, // 0.5gb + transactionThroughput: 200000, + awsLambdaRequestCostPerMillion: 0.2, + }) + ).toEqual(0.05); + }); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts index 0c16ee101c735..2026cc9990a7b 100644 --- a/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/helper.ts @@ -5,6 +5,10 @@ * 2.0. */ import { isFiniteNumber } from '../../../../common/utils/is_finite_number'; +import { + AwsLambdaArchitecture, + AWSLambdaPriceFactor, +} from './get_serverless_summary'; export function calcMemoryUsedRate({ memoryFree, @@ -33,3 +37,68 @@ export function calcMemoryUsed({ return memoryTotal - memoryFree; } + +const GB = 1024 ** 3; +/** + * To calculate the compute usage we need to multiply the "system.memory.total" by "faas.billed_duration". + * But the result of this calculation is in Bytes-milliseconds, as the "system.memory.total" is stored in bytes and the "faas.billed_duration" is stored in milliseconds. + * But to calculate the overall cost AWS uses GB-second, so we need to convert the result to this unit. + */ +export function calcComputeUsageGBSeconds({ + billedDuration, + totalMemory, +}: { + billedDuration?: number | null; + totalMemory?: number | null; +}) { + if (!isFiniteNumber(billedDuration) || !isFiniteNumber(totalMemory)) { + return undefined; + } + + const totalMemoryGB = totalMemory / GB; + const billedDurationSec = billedDuration / 1000; + return totalMemoryGB * billedDurationSec; +} + +export function calcEstimatedCost({ + awsLambdaPriceFactor, + architecture, + transactionThroughput, + billedDuration, + totalMemory, + awsLambdaRequestCostPerMillion, +}: { + awsLambdaPriceFactor?: AWSLambdaPriceFactor; + architecture?: AwsLambdaArchitecture; + transactionThroughput: number; + billedDuration?: number | null; + totalMemory?: number | null; + awsLambdaRequestCostPerMillion?: number; +}) { + try { + const computeUsage = calcComputeUsageGBSeconds({ + billedDuration, + totalMemory, + }); + if ( + !awsLambdaPriceFactor || + !architecture || + !isFiniteNumber(awsLambdaRequestCostPerMillion) || + !isFiniteNumber(awsLambdaPriceFactor?.[architecture]) || + !isFiniteNumber(computeUsage) + ) { + return undefined; + } + + const priceFactor = awsLambdaPriceFactor?.[architecture]; + + const estimatedCost = + computeUsage * priceFactor + + transactionThroughput * (awsLambdaRequestCostPerMillion / 1000000); + + // Rounds up the decimals + return Math.ceil(estimatedCost * 100) / 100; + } catch (e) { + return undefined; + } +} diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts index af2a0aa0834f7..7fdf4dca1e2cd 100644 --- a/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/route.ts @@ -6,13 +6,20 @@ */ import * as t from 'io-ts'; +import { + apmAWSLambdaPriceFactor, + apmAWSLambdaRequestCostPerMillion, +} from '@kbn/observability-plugin/common'; import { setupRequest } from '../../../lib/helpers/setup_request'; import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; import { environmentRt, kueryRt, rangeRt } from '../../default_api_types'; import { getServerlessAgentMetricsCharts } from './get_serverless_agent_metrics_chart'; import { getServerlessActiveInstancesOverview } from './get_active_instances_overview'; import { getServerlessFunctionsOverview } from './get_serverless_functions_overview'; -import { getServerlessSummary } from './get_serverless_summary'; +import { + AWSLambdaPriceFactor, + getServerlessSummary, +} from './get_serverless_summary'; import { getActiveInstancesTimeseries } from './get_active_instances_timeseries'; import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; @@ -163,8 +170,25 @@ const serverlessMetricsSummaryRoute = createApmServerRoute({ handler: async ( resources ): Promise>> => { - const { params } = resources; - const apmEventClient = await getApmEventClient(resources); + const { params, context } = resources; + const { + uiSettings: { client: uiSettingsClient }, + } = await context.core; + + const [ + apmEventClient, + awsLambdaPriceFactor, + awsLambdaRequestCostPerMillion, + ] = await Promise.all([ + getApmEventClient(resources), + uiSettingsClient + .get(apmAWSLambdaPriceFactor) + .then( + (value): AWSLambdaPriceFactor => + JSON.parse(value) as AWSLambdaPriceFactor + ), + uiSettingsClient.get(apmAWSLambdaRequestCostPerMillion), + ]); const { serviceName } = params.path; const { environment, kuery, start, end, serverlessId } = params.query; @@ -177,6 +201,8 @@ const serverlessMetricsSummaryRoute = createApmServerRoute({ apmEventClient, serviceName, serverlessId, + awsLambdaPriceFactor, + awsLambdaRequestCostPerMillion, }); }, }); diff --git a/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts b/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts index 40e48101784c4..dfe482325035b 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_metadata_details.ts @@ -59,6 +59,7 @@ export interface ServiceMetadataDetails { type?: string; functionNames?: string[]; faasTriggerTypes?: string[]; + hostArchitecture?: string; }; cloud?: { provider?: string; @@ -102,6 +103,7 @@ export async function getServiceMetadataDetails({ ProcessorEvent.metric, ], }, + sort: [{ '@timestamp': { order: 'desc' as const } }], body: { track_total_hits: 1, size: 1, @@ -212,6 +214,7 @@ export async function getServiceMetadataDetails({ faasTriggerTypes: response.aggregations?.faasTriggerTypes.buckets.map( (bucket) => bucket.key as string ), + hostArchitecture: host?.architecture, } : undefined; diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts index 7a2100e15225a..a8332262eda94 100644 --- a/x-pack/plugins/observability/common/index.ts +++ b/x-pack/plugins/observability/common/index.ts @@ -26,6 +26,8 @@ export { enableInfrastructureHostsView, enableServiceMetrics, enableAwsLambdaMetrics, + apmAWSLambdaPriceFactor, + apmAWSLambdaRequestCostPerMillion, enableCriticalPath, } from './ui_settings_keys'; diff --git a/x-pack/plugins/observability/common/ui_settings_keys.ts b/x-pack/plugins/observability/common/ui_settings_keys.ts index 7de867608bfcb..52258c5711d1c 100644 --- a/x-pack/plugins/observability/common/ui_settings_keys.ts +++ b/x-pack/plugins/observability/common/ui_settings_keys.ts @@ -21,4 +21,6 @@ export const apmLabsButton = 'observability:apmLabsButton'; export const enableInfrastructureHostsView = 'observability:enableInfrastructureHostsView'; export const enableAwsLambdaMetrics = 'observability:enableAwsLambdaMetrics'; export const enableServiceMetrics = 'observability:apmEnableServiceMetrics'; +export const apmAWSLambdaPriceFactor = 'observability:apmAWSLambdaPriceFactor'; +export const apmAWSLambdaRequestCostPerMillion = 'observability:apmAWSLambdaRequestCostPerMillion'; export const enableCriticalPath = 'observability:apmEnableCriticalPath'; diff --git a/x-pack/plugins/observability/server/ui_settings.ts b/x-pack/plugins/observability/server/ui_settings.ts index a2bc38727e53e..6f2bfb27a1613 100644 --- a/x-pack/plugins/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability/server/ui_settings.ts @@ -24,6 +24,8 @@ import { enableInfrastructureHostsView, enableServiceMetrics, enableAwsLambdaMetrics, + apmAWSLambdaPriceFactor, + apmAWSLambdaRequestCostPerMillion, enableCriticalPath, } from '../common/ui_settings_keys'; @@ -39,7 +41,7 @@ function feedbackLink({ href }: { href: string }) { )}`; } -type UiSettings = UiSettingsParams & { showInLabs?: boolean }; +type UiSettings = UiSettingsParams & { showInLabs?: boolean }; /** * uiSettings definitions for Observability. @@ -291,6 +293,29 @@ export const uiSettings: Record = { type: 'boolean', showInLabs: true, }, + [apmAWSLambdaPriceFactor]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.apmAWSLambdaPricePerGbSeconds', { + defaultMessage: 'AWS lambda price factor', + }), + type: 'json', + value: JSON.stringify({ x86_64: 0.0000166667, arm: 0.0000133334 }, null, 2), + description: i18n.translate('xpack.observability.apmAWSLambdaPricePerGbSecondsDescription', { + defaultMessage: 'Price per Gb-second.', + }), + schema: schema.object({ + arm: schema.number(), + x86_64: schema.number(), + }), + }, + [apmAWSLambdaRequestCostPerMillion]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.apmAWSLambdaRequestCostPerMillion', { + defaultMessage: 'AWS lambda price per 1M requests', + }), + value: 0.2, + schema: schema.number({ min: 0 }), + }, [enableCriticalPath]: { category: [observabilityFeatureId], name: i18n.translate('xpack.observability.enableCriticalPath', { diff --git a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts index eff5e11278018..223e7a448df4c 100644 --- a/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts +++ b/x-pack/test/apm_api_integration/tests/metrics/serverless/serverless_summary.spec.ts @@ -57,7 +57,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { await generateData({ start, end, synthtraceEsClient }); }); - // after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); describe('Python service', () => { let serverlessSummary: APIReturnType<'GET /internal/apm/services/{serviceName}/metrics/serverless/summary'>;