"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.queryTopNCommon = queryTopNCommon; exports.registerTraceEventsTopNContainersSearchRoute = registerTraceEventsTopNContainersSearchRoute; exports.registerTraceEventsTopNDeploymentsSearchRoute = registerTraceEventsTopNDeploymentsSearchRoute; exports.registerTraceEventsTopNHostsSearchRoute = registerTraceEventsTopNHostsSearchRoute; exports.registerTraceEventsTopNStackTracesSearchRoute = registerTraceEventsTopNStackTracesSearchRoute; exports.registerTraceEventsTopNThreadsSearchRoute = registerTraceEventsTopNThreadsSearchRoute; exports.topNElasticSearchQuery = topNElasticSearchQuery; var _configSchema = require("@kbn/config-schema"); var _common = require("../../common"); var _elasticsearch = require("../../common/elasticsearch"); var _histogram = require("../../common/histogram"); var _profiling = require("../../common/profiling"); var _stack_traces = require("../../common/stack_traces"); var _topn = require("../../common/topn"); var _handle_route_error_handler = require("../utils/handle_route_error_handler"); var _with_profiling_span = require("../utils/with_profiling_span"); var _compat = require("./compat"); var _downsampling = require("./downsampling"); var _query = require("./query"); var _search_stacktraces = require("./search_stacktraces"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ async function topNElasticSearchQuery({ client, logger, timeFrom, timeTo, searchField, highCardinality, kuery }) { var _aggregations$group_b, _aggregations$total_c; const filter = (0, _query.createCommonFilter)({ timeFrom, timeTo, kuery }); const targetSampleSize = 20000; // minimum number of samples to get statistically sound results const bucketWidth = (0, _histogram.computeBucketWidthFromTimeRangeAndBucketCount)(timeFrom, timeTo, 50); const eventsIndex = await (0, _downsampling.findDownsampledIndex)({ logger, client, index: _common.INDEX_EVENTS, filter, sampleSize: targetSampleSize }); const resEvents = await client.search('get_topn_histogram', { index: eventsIndex.name, size: 0, query: filter, aggs: (0, _topn.getTopNAggregationRequest)({ searchField, highCardinality, fixedInterval: `${bucketWidth}s` }), // Adrien and Dario found out this is a work-around for some bug in 8.1. // It reduces the query time by avoiding unneeded searches. pre_filter_shard_size: 1 }); const { aggregations } = resEvents; if (!aggregations) { return { TotalCount: 0, TopN: [], Metadata: {}, Labels: {} }; } // Creating top N samples requires the time range and bucket width to // be in milliseconds, not seconds const topN = (0, _topn.createTopNSamples)(aggregations, timeFrom * 1000, timeTo * 1000, bucketWidth * 1000); for (let i = 0; i < topN.length; i++) { var _topN$i$Count; topN[i].Count = ((_topN$i$Count = topN[i].Count) !== null && _topN$i$Count !== void 0 ? _topN$i$Count : 0) / eventsIndex.sampleRate; } const groupByBuckets = (_aggregations$group_b = aggregations.group_by.buckets) !== null && _aggregations$group_b !== void 0 ? _aggregations$group_b : []; const labels = {}; for (const bucket of groupByBuckets) { var _bucket$sample; if ((_bucket$sample = bucket.sample) !== null && _bucket$sample !== void 0 && _bucket$sample.top[0]) { labels[String(bucket.key)] = String(bucket.sample.top[0].metrics[_elasticsearch.ProfilingESField.HostName] || bucket.sample.top[0].metrics[_elasticsearch.ProfilingESField.HostIP] || ''); } } let totalSampledStackTraces = (_aggregations$total_c = aggregations.total_count.value) !== null && _aggregations$total_c !== void 0 ? _aggregations$total_c : 0; totalSampledStackTraces = Math.floor(totalSampledStackTraces / eventsIndex.sampleRate); if (searchField !== _elasticsearch.ProfilingESField.StacktraceID) { return { TotalCount: totalSampledStackTraces, TopN: topN, Metadata: {}, Labels: labels }; } const { stackTraces, executables, stackFrames } = await (0, _with_profiling_span.withProfilingSpan)('search_stacktraces', async () => { const stackTraceIDs = new Set(); for (let i = 0; i < groupByBuckets.length; i++) { stackTraceIDs.add(String(groupByBuckets[i].key)); } const stackTraceKuery = [...stackTraceIDs].join(' or '); const stackTraceFilter = (0, _query.createCommonFilter)({ timeFrom, timeTo, kuery: stackTraceKuery }); return (0, _search_stacktraces.searchStackTraces)({ client, filter: stackTraceFilter, sampleSize: targetSampleSize }); }); const metadata = await (0, _with_profiling_span.withProfilingSpan)('collect_stackframe_metadata', async () => { return (0, _profiling.groupStackFrameMetadataByStackTrace)(stackTraces, stackFrames, executables); }); return { TotalCount: totalSampledStackTraces, TopN: topN, Metadata: metadata, Labels: labels }; } function queryTopNCommon({ logger, router, services: { createProfilingEsClient }, pathName, searchField, highCardinality }) { router.get({ path: pathName, options: { tags: ['access:profiling'] }, validate: { query: _configSchema.schema.object({ timeFrom: _configSchema.schema.number(), timeTo: _configSchema.schema.number(), kuery: _configSchema.schema.string() }) } }, async (context, request, response) => { const { timeFrom, timeTo, kuery } = request.query; const client = await (0, _compat.getClient)(context); try { return response.ok({ body: await topNElasticSearchQuery({ client: createProfilingEsClient({ request, esClient: client }), logger, timeFrom, timeTo, searchField, highCardinality, kuery }) }); } catch (error) { return (0, _handle_route_error_handler.handleRouteHandlerError)({ error, logger, response, message: 'Error while fetching TopN functions' }); } }); } function registerTraceEventsTopNContainersSearchRoute(parameters) { const paths = (0, _common.getRoutePaths)(); return queryTopNCommon({ ...parameters, pathName: paths.TopNContainers, searchField: (0, _stack_traces.getFieldNameForTopNType)(_stack_traces.TopNType.Containers), highCardinality: false }); } function registerTraceEventsTopNDeploymentsSearchRoute(parameters) { const paths = (0, _common.getRoutePaths)(); return queryTopNCommon({ ...parameters, pathName: paths.TopNDeployments, searchField: (0, _stack_traces.getFieldNameForTopNType)(_stack_traces.TopNType.Deployments), highCardinality: false }); } function registerTraceEventsTopNHostsSearchRoute(parameters) { const paths = (0, _common.getRoutePaths)(); return queryTopNCommon({ ...parameters, pathName: paths.TopNHosts, searchField: (0, _stack_traces.getFieldNameForTopNType)(_stack_traces.TopNType.Hosts), highCardinality: false }); } function registerTraceEventsTopNStackTracesSearchRoute(parameters) { const paths = (0, _common.getRoutePaths)(); return queryTopNCommon({ ...parameters, pathName: paths.TopNTraces, searchField: (0, _stack_traces.getFieldNameForTopNType)(_stack_traces.TopNType.Traces), highCardinality: false }); } function registerTraceEventsTopNThreadsSearchRoute(parameters) { const paths = (0, _common.getRoutePaths)(); return queryTopNCommon({ ...parameters, pathName: paths.TopNThreads, searchField: (0, _stack_traces.getFieldNameForTopNType)(_stack_traces.TopNType.Threads), highCardinality: true }); }