Skip to content

ES|QL query log #124094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
dca56b5
ES|QL slow log
luigidellaquila Mar 5, 2025
e725e07
[CI] Auto commit changes from spotless
elasticsearchmachine Mar 5, 2025
4746cd4
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 7, 2025
d4ed58f
First round of reviews
luigidellaquila Mar 7, 2025
8957918
Fix test
luigidellaquila Mar 7, 2025
6e0b9c5
Add slowlog for failing queries
luigidellaquila Mar 7, 2025
4d25aaa
Cleanup
luigidellaquila Mar 7, 2025
45764f4
Cleanup
luigidellaquila Mar 7, 2025
b2ae5ef
Update docs/changelog/124094.yaml
luigidellaquila Mar 7, 2025
2eb589a
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 10, 2025
cbfcf2c
Add unit tests
luigidellaquila Mar 10, 2025
51820c9
Merge remote-tracking branch 'luigidellaquila/esql/slowlog' into esql…
luigidellaquila Mar 10, 2025
d2bd672
Add user name to slow log; some refactoring
luigidellaquila Mar 10, 2025
b74ea91
Implement review suggestions
luigidellaquila Mar 11, 2025
30d07d4
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 11, 2025
4e1838b
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 11, 2025
af3366f
Refactor to use SlowLogFieldProviders
luigidellaquila Mar 14, 2025
95c76d7
Merge remote-tracking branch 'luigidellaquila/esql/slowlog' into esql…
luigidellaquila Mar 14, 2025
bbfa89b
[CI] Auto commit changes from spotless
elasticsearchmachine Mar 14, 2025
bbc11c5
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 14, 2025
e390232
Merge log field providers
luigidellaquila Mar 14, 2025
694ff2e
Merge remote-tracking branch 'luigidellaquila/esql/slowlog' into esql…
luigidellaquila Mar 14, 2025
cec182e
[CI] Auto commit changes from spotless
elasticsearchmachine Mar 14, 2025
44ea6fc
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 14, 2025
df788db
Fix tests
luigidellaquila Mar 14, 2025
a970fc5
Merge remote-tracking branch 'luigidellaquila/esql/slowlog' into esql…
luigidellaquila Mar 14, 2025
e4202af
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 17, 2025
01d4c66
Rename as QueryLog
luigidellaquila Mar 17, 2025
fd85f06
Simplify cluster settings
luigidellaquila Mar 17, 2025
03dbacd
fix log4j config
luigidellaquila Mar 18, 2025
6cdb1b3
Merge branch 'main' into esql/slowlog
luigidellaquila Mar 18, 2025
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
23 changes: 23 additions & 0 deletions distribution/src/config/log4j2.properties
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,26 @@ logger.index_indexing_slowlog.name = index.indexing.slowlog.index
logger.index_indexing_slowlog.level = trace
logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling
logger.index_indexing_slowlog.additivity = false


######## ES|QL query log JSON ####################
appender.esql_querylog_rolling.type = RollingFile
appender.esql_querylog_rolling.name = esql_querylog_rolling
appender.esql_querylog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs\
.cluster_name}_esql_querylog.json
appender.esql_querylog_rolling.layout.type = ECSJsonLayout
appender.esql_querylog_rolling.layout.dataset = elasticsearch.esql_querylog

appender.esql_querylog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs\
.cluster_name}_esql_querylog-%i.json.gz
appender.esql_querylog_rolling.policies.type = Policies
appender.esql_querylog_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.esql_querylog_rolling.policies.size.size = 1GB
appender.esql_querylog_rolling.strategy.type = DefaultRolloverStrategy
appender.esql_querylog_rolling.strategy.max = 4
#################################################

logger.esql_querylog_rolling.name = esql.querylog
logger.esql_querylog_rolling.level = trace
logger.esql_querylog_rolling.appenderRef.esql_querylog_rolling.ref = esql_querylog_rolling
logger.esql_querylog_rolling.additivity = false
5 changes: 5 additions & 0 deletions docs/changelog/124094.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 124094
summary: ES|QL slow log
area: ES|QL
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ public interface SlowLogFieldProvider {
* @param indexSettings settings for the index
*/
SlowLogFields create(IndexSettings indexSettings);

/**
* Create a field provider without index level settings
*/
SlowLogFields create();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@ public interface SlowLogFields {
* @return map of field name to value
*/
Map<String, String> searchFields();

/**
* Slow log fields for query
* @return map of field name to value
*/
default Map<String, String> queryFields() {
return Map.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public class IndicesServiceBuilder {
QueryRewriteInterceptor queryRewriteInterceptor = null;
SlowLogFieldProvider slowLogFieldProvider = new SlowLogFieldProvider() {
@Override
public SlowLogFields create(IndexSettings indexSettings) {
public SlowLogFields create() {
return new SlowLogFields() {
@Override
public Map<String, String> indexFields() {
Expand All @@ -96,6 +96,12 @@ public Map<String, String> searchFields() {
}
};
}

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

};

public IndicesServiceBuilder settings(Settings settings) {
Expand Down
77 changes: 59 additions & 18 deletions server/src/main/java/org/elasticsearch/node/NodeConstruction.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
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.SlowLogFieldProvider;
import org.elasticsearch.index.SlowLogFields;
Expand Down Expand Up @@ -806,26 +807,65 @@ private void construct(
List<? extends SlowLogFieldProvider> slowLogFieldProviders = pluginsService.loadServiceProviders(SlowLogFieldProvider.class);
// 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 = 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));
SlowLogFieldProvider slowLogFieldProvider = new SlowLogFieldProvider() {
Copy link
Contributor

Choose a reason for hiding this comment

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

The point of this is that it will merge all field providers provided by the plugins into one (in practice I think that's only the one in the security plugin). So this should ideally have an implementation for merging queryFields too and then this instance should be passed to the PluginService (instead of the list of providers).

If you don't want to implement the merge for indexFields and searchFields in the provider without index settings you could add an empty default implementation in the interface in the same way you did for queryFields.

public SlowLogFields create() {
final List<SlowLogFields> fields = new ArrayList<>();
for (var provider : slowLogFieldProviders) {
fields.add(provider.create());
}
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));
}
};
}

@Override
public Map<String, String> searchFields() {
return fields.stream()
.flatMap(f -> f.searchFields().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 Expand Up @@ -914,7 +954,8 @@ public Map<String, String> searchFields() {
dataStreamGlobalRetentionSettings,
documentParsingProvider,
taskManager,
projectResolver
projectResolver,
slowLogFieldProvider
);

Collection<?> pluginComponents = pluginsService.flatMap(plugin -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.features.FeatureService;
import org.elasticsearch.index.SlowLogFieldProvider;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.indices.SystemIndices;
import org.elasticsearch.plugins.Plugin;
Expand Down Expand Up @@ -53,5 +54,6 @@ public record PluginServiceInstances(
DataStreamGlobalRetentionSettings dataStreamGlobalRetentionSettings,
DocumentParsingProvider documentParsingProvider,
TaskManager taskManager,
ProjectResolver projectResolver
ProjectResolver projectResolver,
SlowLogFieldProvider slowLogFieldProvider
) implements Plugin.PluginServices {}
6 changes: 6 additions & 0 deletions server/src/main/java/org/elasticsearch/plugins/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.elasticsearch.features.FeatureService;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.index.IndexSettingProvider;
import org.elasticsearch.index.SlowLogFieldProvider;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.indices.SystemIndices;
import org.elasticsearch.plugins.internal.DocumentParsingProvider;
Expand Down Expand Up @@ -180,6 +181,11 @@ public interface PluginServices {
* The project resolver for the cluster. This should be used to determine the active project against which a request should execute
*/
ProjectResolver projectResolver();

/**
* Provider for additional SlowLog fields
*/
SlowLogFieldProvider slowLogFieldProvider();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ static void setFields(Map<String, String> fields) {
}

@Override
public SlowLogFields create(IndexSettings indexSettings) {
public SlowLogFields create() {
return new SlowLogFields() {
@Override
public Map<String, String> indexFields() {
Expand All @@ -226,6 +226,12 @@ public Map<String, String> searchFields() {
}
};
}

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

}

public static class TestAnotherSlowLogFieldProvider implements SlowLogFieldProvider {
Expand All @@ -237,7 +243,7 @@ static void setFields(Map<String, String> fields) {
}

@Override
public SlowLogFields create(IndexSettings indexSettings) {
public SlowLogFields create() {
return new SlowLogFields() {
@Override
public Map<String, String> indexFields() {
Expand All @@ -250,6 +256,11 @@ public Map<String, String> searchFields() {
}
};
}

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

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum LogType {
AUDIT("%s_audit.json"),
SEARCH_SLOW("%s_index_search_slowlog.json"),
INDEXING_SLOW("%s_index_indexing_slowlog.json"),
ESQL_SLOW("%s_esql_slowlog.json"),
DEPRECATION("%s_deprecation.json");

private final String filenameFormat;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.
*/

package org.elasticsearch.xpack.esql;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.filter.RegexFilter;
import org.apache.logging.log4j.message.Message;

public class MockAppender extends AbstractAppender {
public LogEvent lastEvent;

public MockAppender(final String name) throws IllegalAccessException {
super(name, RegexFilter.createFilter(".*(\n.*)*", new String[0], false, null, null), null, false);
}

@Override
public void append(LogEvent event) {
lastEvent = event.toImmutable();
}

public Message lastMessage() {
return lastEvent.getMessage();
}

public LogEvent lastEvent() {
return lastEvent;
}

public LogEvent getLastEventAndReset() {
LogEvent toReturn = lastEvent;
lastEvent = null;
return toReturn;
}
}
Loading
Loading