Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions server/src/main/java/org/elasticsearch/index/IndexModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,8 @@ public IndexModule(
this.engineFactory = Objects.requireNonNull(engineFactory);
// Need to have a mutable arraylist for plugins to add listeners to it
this.searchOperationListeners = new ArrayList<>(searchOperationListeners);
SlowLogFields slowLogFields = slowLogFieldProvider.create(indexSettings);
this.searchOperationListeners.add(new SearchSlowLog(indexSettings, slowLogFields));
this.indexOperationListeners.add(new IndexingSlowLog(indexSettings, slowLogFields));
this.searchOperationListeners.add(new SearchSlowLog(indexSettings, slowLogFieldProvider));
this.indexOperationListeners.add(new IndexingSlowLog(indexSettings, slowLogFieldProvider));
this.directoryFactories = Collections.unmodifiableMap(directoryFactories);
this.allowExpensiveQueries = allowExpensiveQueries;
this.expressionResolver = expressionResolver;
Expand Down
34 changes: 20 additions & 14 deletions server/src/main/java/org/elasticsearch/index/IndexingSlowLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public final class IndexingSlowLog implements IndexingOperationListener {
public static final String INDEX_INDEXING_SLOWLOG_PREFIX = "index.indexing.slowlog";
Expand Down Expand Up @@ -125,10 +126,15 @@ public final class IndexingSlowLog implements IndexingOperationListener {
Property.IndexScope
);

IndexingSlowLog(IndexSettings indexSettings, SlowLogFields slowLogFields) {
this.slowLogFields = slowLogFields;
IndexingSlowLog(IndexSettings indexSettings, SlowLogFieldProvider slowLogFieldsProvider) {
this.index = indexSettings.getIndex();

SlowLogContext logContext = new SlowLogContext(indexSettings.getValue(INDEX_INDEXING_SLOWLOG_INCLUDE_USER_SETTING));
indexSettings.getScopedSettings()
.addSettingsUpdateConsumer(INDEX_INDEXING_SLOWLOG_INCLUDE_USER_SETTING, logContext::setIncludeUserInformation);

this.slowLogFields = slowLogFieldsProvider.create(logContext);

indexSettings.getScopedSettings().addSettingsUpdateConsumer(INDEX_INDEXING_SLOWLOG_REFORMAT_SETTING, this::setReformat);
this.reformat = indexSettings.getValue(INDEX_INDEXING_SLOWLOG_REFORMAT_SETTING);
indexSettings.getScopedSettings()
Expand Down Expand Up @@ -177,22 +183,22 @@ public void postIndex(ShardId shardId, Engine.Index indexOperation, Engine.Index
if (result.getResultType() == Engine.Result.Type.SUCCESS) {
final ParsedDocument doc = indexOperation.parsedDoc();
final long tookInNanos = result.getTook();
Supplier<ESLogMessage> messageProducer = () -> IndexingSlowLogMessage.of(
slowLogFields.logFields(),
index,
doc,
tookInNanos,
reformat,
maxSourceCharsToLog
);
if (indexWarnThreshold >= 0 && tookInNanos > indexWarnThreshold) {
indexLogger.warn(
IndexingSlowLogMessage.of(this.slowLogFields.indexFields(), index, doc, tookInNanos, reformat, maxSourceCharsToLog)
);
indexLogger.warn(messageProducer.get());
} else if (indexInfoThreshold >= 0 && tookInNanos > indexInfoThreshold) {
indexLogger.info(
IndexingSlowLogMessage.of(this.slowLogFields.indexFields(), index, doc, tookInNanos, reformat, maxSourceCharsToLog)
);
indexLogger.info(messageProducer.get());
} else if (indexDebugThreshold >= 0 && tookInNanos > indexDebugThreshold) {
indexLogger.debug(
IndexingSlowLogMessage.of(this.slowLogFields.indexFields(), index, doc, tookInNanos, reformat, maxSourceCharsToLog)
);
indexLogger.debug(messageProducer.get());
} else if (indexTraceThreshold >= 0 && tookInNanos > indexTraceThreshold) {
indexLogger.trace(
IndexingSlowLogMessage.of(this.slowLogFields.indexFields(), index, doc, tookInNanos, reformat, maxSourceCharsToLog)
);
indexLogger.trace(messageProducer.get());
}
}
}
Expand Down
26 changes: 16 additions & 10 deletions server/src/main/java/org/elasticsearch/index/SearchSlowLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Stream;

public final class SearchSlowLog implements SearchOperationListener {
Expand Down Expand Up @@ -126,8 +127,11 @@ public final class SearchSlowLog implements SearchOperationListener {

private static final ToXContent.Params FORMAT_PARAMS = new ToXContent.MapParams(Collections.singletonMap("pretty", "false"));

public SearchSlowLog(IndexSettings indexSettings, SlowLogFields slowLogFields) {
this.slowLogFields = slowLogFields;
public SearchSlowLog(IndexSettings indexSettings, SlowLogFieldProvider slowLogFieldsProvider) {
SlowLogContext logContext = new SlowLogContext(indexSettings.getValue(INDEX_SEARCH_SLOWLOG_INCLUDE_USER_SETTING));
this.slowLogFields = slowLogFieldsProvider.create(logContext);
indexSettings.getScopedSettings()
.addSettingsUpdateConsumer(INDEX_SEARCH_SLOWLOG_INCLUDE_USER_SETTING, logContext::setIncludeUserInformation);
indexSettings.getScopedSettings()
.addSettingsUpdateConsumer(INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING, this::setQueryWarnThreshold);
this.queryWarnThreshold = indexSettings.getValue(INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING).nanos();
Expand Down Expand Up @@ -157,27 +161,29 @@ public SearchSlowLog(IndexSettings indexSettings, SlowLogFields slowLogFields) {

@Override
public void onQueryPhase(SearchContext context, long tookInNanos) {
Supplier<ESLogMessage> messageProducer = () -> SearchSlowLogMessage.of(slowLogFields.logFields(), context, tookInNanos);
if (queryWarnThreshold >= 0 && tookInNanos > queryWarnThreshold) {
queryLogger.warn(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
queryLogger.warn(messageProducer.get());
} else if (queryInfoThreshold >= 0 && tookInNanos > queryInfoThreshold) {
queryLogger.info(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
queryLogger.info(messageProducer.get());
} else if (queryDebugThreshold >= 0 && tookInNanos > queryDebugThreshold) {
queryLogger.debug(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
queryLogger.debug(messageProducer.get());
} else if (queryTraceThreshold >= 0 && tookInNanos > queryTraceThreshold) {
queryLogger.trace(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
queryLogger.trace(messageProducer.get());
}
}

@Override
public void onFetchPhase(SearchContext context, long tookInNanos) {
Supplier<ESLogMessage> messageProducer = () -> SearchSlowLogMessage.of(slowLogFields.logFields(), context, tookInNanos);
if (fetchWarnThreshold >= 0 && tookInNanos > fetchWarnThreshold) {
fetchLogger.warn(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
fetchLogger.warn(messageProducer.get());
} else if (fetchInfoThreshold >= 0 && tookInNanos > fetchInfoThreshold) {
fetchLogger.info(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
fetchLogger.info(messageProducer.get());
} else if (fetchDebugThreshold >= 0 && tookInNanos > fetchDebugThreshold) {
fetchLogger.debug(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
fetchLogger.debug(messageProducer.get());
} else if (fetchTraceThreshold >= 0 && tookInNanos > fetchTraceThreshold) {
fetchLogger.trace(SearchSlowLogMessage.of(this.slowLogFields.searchFields(), context, tookInNanos));
fetchLogger.trace(messageProducer.get());
}
}

Expand Down
36 changes: 36 additions & 0 deletions server/src/main/java/org/elasticsearch/index/SlowLogContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index;

/**
* Context for log fields generation - includes options that can influence how the fields are generated.
*/
public class SlowLogContext {
/**
* Do we want any user authentication context?
*/
private volatile boolean includeUserInformation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's really necessary to mark this volatile. Settings updates are by nature async, so this being somewhat eventually consistent is fine IMO and probably not worth the perf hit on reading this field on every log entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the cluster state changes would be updating this variable, I am concerned the checks may get an old value... probably not likely to matter that much in real scenario, but might make some tests flaky. I can drop it and see if anything breaks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I hadn't considered test stability. You might be right. In production it doesn't really matter, it just means there may be some insignificant delay until the setting change actually takes hold.


public SlowLogContext() {
this(false);
}

public SlowLogContext(boolean includeUserInformation) {
this.includeUserInformation = includeUserInformation;
}

public boolean includeUserInformation() {
return includeUserInformation;
}

public void setIncludeUserInformation(boolean includeUserInformation) {
this.includeUserInformation = includeUserInformation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
*/
public interface SlowLogFieldProvider {
/**
* Create a field provider with index level settings to be able to listen for updates and set initial values
* @param indexSettings settings for the index
* Create a field provider
*/
SlowLogFields create(IndexSettings indexSettings);

/**
* Create a field provider without index level settings
*/
SlowLogFields create();
SlowLogFields create(SlowLogContext context);
}
18 changes: 6 additions & 12 deletions server/src/main/java/org/elasticsearch/index/SlowLogFields.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,19 @@
/**
* Fields for the slow log. These may be different each call depending on the state of the system.
*/
public interface SlowLogFields {
public abstract class SlowLogFields {

/**
* Slow log fields for indexing events
* @return map of field name to value
*/
Map<String, String> indexFields();
protected final SlowLogContext context;

/**
* Slow log fields for search events
* @return map of field name to value
*/
Map<String, String> searchFields();
public SlowLogFields(SlowLogContext context) {
this.context = context;
}

/**
* Slow log fields for query
* @return map of field name to value
*/
default Map<String, String> queryFields() {
public Map<String, String> logFields() {
return Map.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,7 @@ public class IndicesServiceBuilder {
MergeMetrics mergeMetrics;
List<SearchOperationListener> searchOperationListener = List.of();
QueryRewriteInterceptor queryRewriteInterceptor = null;
SlowLogFieldProvider slowLogFieldProvider = new SlowLogFieldProvider() {
@Override
public SlowLogFields create() {
return new SlowLogFields() {
@Override
public Map<String, String> indexFields() {
return Map.of();
}

@Override
public Map<String, String> searchFields() {
return Map.of();
}
};
}

@Override
public SlowLogFields create(IndexSettings indexSettings) {
return create();
}

SlowLogFieldProvider slowLogFieldProvider = (context) -> new SlowLogFields(context) {
};

public IndicesServiceBuilder settings(Settings settings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.index.IndexSettingProvider;
import org.elasticsearch.index.IndexSettingProviders;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.IndexingPressure;
import org.elasticsearch.index.SlowLogContext;
import org.elasticsearch.index.SlowLogFieldProvider;
import org.elasticsearch.index.SlowLogFields;
import org.elasticsearch.index.analysis.AnalysisRegistry;
Expand Down Expand Up @@ -872,64 +872,20 @@ private void construct(
// NOTE: the response of index/search slow log fields below must be calculated dynamically on every call
// because the responses may change dynamically at runtime
SlowLogFieldProvider slowLogFieldProvider = new SlowLogFieldProvider() {
public SlowLogFields create() {
public SlowLogFields create(SlowLogContext context) {
final List<SlowLogFields> fields = new ArrayList<>();
for (var provider : slowLogFieldProviders) {
fields.add(provider.create());
fields.add(provider.create(context));
}
return new SlowLogFields() {
return new SlowLogFields(context) {
@Override
public Map<String, String> indexFields() {
public Map<String, String> logFields() {
return fields.stream()
.flatMap(f -> f.indexFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Map<String, String> searchFields() {
return fields.stream()
.flatMap(f -> f.searchFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Map<String, String> queryFields() {
return fields.stream()
.flatMap(f -> f.queryFields().entrySet().stream())
.flatMap(f -> f.logFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
};
}

public SlowLogFields create(IndexSettings indexSettings) {
final List<SlowLogFields> fields = new ArrayList<>();
for (var provider : slowLogFieldProviders) {
fields.add(provider.create(indexSettings));
}
return new SlowLogFields() {
@Override
public Map<String, String> indexFields() {
return fields.stream()
.flatMap(f -> f.indexFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Map<String, String> searchFields() {
return fields.stream()
.flatMap(f -> f.searchFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@Override
public Map<String, String> queryFields() {
return fields.stream()
.flatMap(f -> f.queryFields().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
};
}

};

IndicesService indicesService = new IndicesServiceBuilder().settings(settings)
Expand Down
Loading