Skip to content

Commit

Permalink
Add an APM metric to aggregations usage (#108110)
Browse files Browse the repository at this point in the history
This wires up the "new" APM metrics integration to the existing Aggregations usage tracking system. It introduces one new metric, a LongCounter named es.search.query.aggregations.total, which has dimensions for the specific aggregation being run, and the values source type we resolved it to.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
not-napoleon and elasticmachine committed May 9, 2024
1 parent 1b7cad1 commit 6308bbf
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 5 deletions.
Expand Up @@ -257,7 +257,7 @@ static NodeConstruction prepareConstruction(
ThreadPool threadPool = constructor.createThreadPool(settings, telemetryProvider.getMeterRegistry());
SettingsModule settingsModule = constructor.validateSettings(initialEnvironment.settings(), settings, threadPool);

SearchModule searchModule = constructor.createSearchModule(settingsModule.getSettings(), threadPool);
SearchModule searchModule = constructor.createSearchModule(settingsModule.getSettings(), threadPool, telemetryProvider);
constructor.createClientAndRegistries(settingsModule.getSettings(), threadPool, searchModule);
DocumentParsingProvider documentParsingProvider = constructor.getDocumentParsingProvider();

Expand Down Expand Up @@ -525,9 +525,9 @@ private SettingsModule validateSettings(Settings envSettings, Settings settings,
return settingsModule;
}

private SearchModule createSearchModule(Settings settings, ThreadPool threadPool) {
private SearchModule createSearchModule(Settings settings, ThreadPool threadPool, TelemetryProvider telemetryProvider) {
IndexSearcher.setMaxClauseCount(SearchUtils.calculateMaxClauseValue(threadPool));
return new SearchModule(settings, pluginsService.filterPlugins(SearchPlugin.class).toList());
return new SearchModule(settings, pluginsService.filterPlugins(SearchPlugin.class).toList(), telemetryProvider);
}

/**
Expand Down
20 changes: 19 additions & 1 deletion server/src/main/java/org/elasticsearch/search/SearchModule.java
Expand Up @@ -254,6 +254,7 @@
import org.elasticsearch.search.vectors.KnnScoreDocQueryBuilder;
import org.elasticsearch.search.vectors.KnnVectorQueryBuilder;
import org.elasticsearch.search.vectors.QueryVectorBuilder;
import org.elasticsearch.telemetry.TelemetryProvider;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.ParseField;
import org.elasticsearch.xcontent.XContentParser;
Expand Down Expand Up @@ -289,6 +290,11 @@ public class SearchModule {
Setting.Property.NodeScope
);

/**
* Metric name for aggregation usage statistics
*/
private final TelemetryProvider telemetryProvider;

private final Map<String, Highlighter> highlighters;

private final List<FetchSubPhase> fetchSubPhases = new ArrayList<>();
Expand All @@ -306,7 +312,19 @@ public class SearchModule {
* @param plugins List of included {@link SearchPlugin} objects.
*/
public SearchModule(Settings settings, List<SearchPlugin> plugins) {
this(settings, plugins, TelemetryProvider.NOOP);
}

/**
* Constructs a new SearchModule object
*
* @param settings Current settings
* @param plugins List of included {@link SearchPlugin} objects.
* @param telemetryProvider
*/
public SearchModule(Settings settings, List<SearchPlugin> plugins, TelemetryProvider telemetryProvider) {
this.settings = settings;
this.telemetryProvider = telemetryProvider;
registerSuggesters(plugins);
highlighters = setupHighlighters(settings, plugins);
registerScoreFunctions(plugins);
Expand Down Expand Up @@ -352,7 +370,7 @@ public Map<String, Highlighter> getHighlighters() {
}

private ValuesSourceRegistry registerAggregations(List<SearchPlugin> plugins) {
ValuesSourceRegistry.Builder builder = new ValuesSourceRegistry.Builder();
ValuesSourceRegistry.Builder builder = new ValuesSourceRegistry.Builder(telemetryProvider.getMeterRegistry());

registerAggregation(
new AggregationSpec(AvgAggregationBuilder.NAME, AvgAggregationBuilder::new, AvgAggregationBuilder.PARSER).addResultReader(
Expand Down
Expand Up @@ -9,22 +9,35 @@
package org.elasticsearch.search.aggregations.support;

import org.elasticsearch.node.ReportingService;
import org.elasticsearch.telemetry.metric.LongCounter;
import org.elasticsearch.telemetry.metric.MeterRegistry;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.LongAdder;

public class AggregationUsageService implements ReportingService<AggregationInfo> {
private static final String ES_SEARCH_QUERY_AGGREGATIONS_TOTAL_COUNT = "es.search.query.aggregations.total";
private final String AGGREGATION_NAME_KEY = "aggregation_name";
private final String VALUES_SOURCE_KEY = "values_source";
private final LongCounter aggregationsUsageCounter;
private final Map<String, Map<String, LongAdder>> aggs;
private final AggregationInfo info;

public static final String OTHER_SUBTYPE = "other";

public static class Builder {
private final Map<String, Map<String, LongAdder>> aggs;
private final MeterRegistry meterRegistry;

public Builder() {
this(MeterRegistry.NOOP);
}

public Builder(MeterRegistry meterRegistry) {
aggs = new HashMap<>();
assert meterRegistry != null;
this.meterRegistry = meterRegistry;
}

public void registerAggregationUsage(String aggregationName) {
Expand All @@ -45,9 +58,16 @@ public AggregationUsageService build() {
}
}

// Attribute names for the metric

private AggregationUsageService(Builder builder) {
this.aggs = builder.aggs;
info = new AggregationInfo(aggs);
this.aggregationsUsageCounter = builder.meterRegistry.registerLongCounter(
ES_SEARCH_QUERY_AGGREGATIONS_TOTAL_COUNT,
"Aggregations usage",
"count"
);
}

public void incAggregationUsage(String aggregationName, String valuesSourceType) {
Expand All @@ -61,6 +81,8 @@ public void incAggregationUsage(String aggregationName, String valuesSourceType)
assert adder != null : "Unknown subtype [" + aggregationName + "][" + valuesSourceType + "]";
}
assert valuesSourceMap != null : "Unknown aggregation [" + aggregationName + "][" + valuesSourceType + "]";
// tests will have a no-op implementation here
aggregationsUsageCounter.incrementBy(1, Map.of(AGGREGATION_NAME_KEY, aggregationName, VALUES_SOURCE_KEY, valuesSourceType));
}

public Map<String, Object> getUsageStats() {
Expand Down
Expand Up @@ -10,6 +10,7 @@
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.aggregations.AggregationExecutionException;
import org.elasticsearch.telemetry.metric.MeterRegistry;

import java.util.AbstractMap;
import java.util.ArrayList;
Expand Down Expand Up @@ -58,7 +59,11 @@ public static class Builder {
private final Map<RegistryKey<?>, List<Map.Entry<ValuesSourceType, ?>>> aggregatorRegistry = new HashMap<>();

public Builder() {
this.usageServiceBuilder = new AggregationUsageService.Builder();
this(MeterRegistry.NOOP);
}

public Builder(MeterRegistry meterRegistry) {
this.usageServiceBuilder = new AggregationUsageService.Builder(meterRegistry);
}

/**
Expand Down

0 comments on commit 6308bbf

Please sign in to comment.