From e370cff51abf614ff474086cb566fc00974b945c Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Thu, 9 Jul 2020 13:56:53 +0300 Subject: [PATCH 1/5] Add metrics --- .../xpack/eql/analysis/Verifier.java | 118 ++++++++++++++++++ .../xpack/eql/execution/PlanExecutor.java | 9 +- .../xpack/eql/stats/FeatureMetric.java | 19 ++- .../xpack/eql/stats/Metrics.java | 64 +++++++--- .../xpack/eql/stats/QueryMetric.java | 18 +++ .../xpack/eql/analysis/VerifierTests.java | 3 +- .../xpack/eql/optimizer/OptimizerTests.java | 3 +- .../xpack/eql/optimizer/TomlFoldTests.java | 3 +- .../planner/AbstractQueryFolderTestCase.java | 3 +- 9 files changed, 218 insertions(+), 22 deletions(-) create mode 100644 x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/QueryMetric.java diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java index 0d526c4d052a9..0d4ffdaf30159 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java @@ -10,12 +10,25 @@ import org.elasticsearch.xpack.ql.common.Failure; import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.ql.plan.logical.Aggregate; +import org.elasticsearch.xpack.ql.plan.logical.Filter; +import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.plan.logical.OrderBy; +import org.elasticsearch.xpack.ql.plan.logical.Project; import org.elasticsearch.xpack.ql.tree.Node; import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.ql.util.Holder; import org.elasticsearch.xpack.ql.util.StringUtils; +import org.elasticsearch.xpack.eql.plan.logical.Head; +import org.elasticsearch.xpack.eql.plan.logical.Join; +import org.elasticsearch.xpack.eql.plan.logical.Sequence; +import org.elasticsearch.xpack.eql.plan.logical.Tail; +import org.elasticsearch.xpack.eql.stats.FeatureMetric; +import org.elasticsearch.xpack.eql.stats.Metrics; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; @@ -23,6 +36,26 @@ import java.util.Set; import static java.util.stream.Collectors.toMap; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.HEAD; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_FIVE_OR_MORE_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_FOUR_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_ONE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_THREE_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_TWO_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_FIVE_OR_MORE_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_FOUR_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_MAXSPAN; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_THREE_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_TWO_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.TAIL; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.UNTIL; import static org.elasticsearch.xpack.ql.common.Failure.fail; /** @@ -31,6 +64,12 @@ */ public class Verifier { + private final Metrics metrics; + + public Verifier(Metrics metrics) { + this.metrics = metrics; + } + public Map, String> verifyFailures(LogicalPlan plan) { Collection failures = verify(plan); return failures.stream().collect(toMap(Failure::node, Failure::message)); @@ -104,6 +143,85 @@ Collection verify(LogicalPlan plan) { failures.addAll(localFailures); }); + // gather metrics + if (failures.isEmpty()) { + BitSet b = new BitSet(FeatureMetric.values().length); + Holder isLikelyAnEventQuery = new Holder<>(false); + + plan.forEachDown(p -> { + if (p instanceof Project) { + isLikelyAnEventQuery.set(true); + } else if (p instanceof Head) { + b.set(HEAD.ordinal()); + } else if (p instanceof Tail) { + b.set(TAIL.ordinal()); + } else if (p instanceof Join) { + Join j = (Join) p; + + if (p instanceof Sequence) { + b.set(SEQUENCE.ordinal()); + Sequence s = (Sequence) p; + if (s.maxSpan().duration() > 0) { + b.set(SEQUENCE_MAXSPAN.ordinal()); + } + + int queriesCount = s.queries().size(); + switch (queriesCount) { + case 2: b.set(SEQUENCE_TWO_QUERIES.ordinal()); + break; + case 3: b.set(SEQUENCE_THREE_QUERIES.ordinal()); + break; + case 4: b.set(SEQUENCE_FOUR_QUERIES.ordinal()); + break; + default: b.set(SEQUENCE_FIVE_OR_MORE_QUERIES.ordinal()); + break; + } + } else { + b.set(FeatureMetric.JOIN.ordinal()); + int queriesCount = j.queries().size(); + switch (queriesCount) { + case 2: b.set(JOIN_TWO_QUERIES.ordinal()); + break; + case 3: b.set(JOIN_THREE_QUERIES.ordinal()); + break; + case 4: b.set(JOIN_FOUR_QUERIES.ordinal()); + break; + default: b.set(JOIN_FIVE_OR_MORE_QUERIES.ordinal()); + break; + } + } + + if (j.until().keys().isEmpty() == false) { + b.set(UNTIL.ordinal()); + } + + int joinKeysCount = j.queries().get(0).keys().size(); + switch (joinKeysCount) { + case 1: b.set(JOIN_KEYS_ONE.ordinal()); + break; + case 2: b.set(JOIN_KEYS_TWO.ordinal()); + break; + case 3: b.set(JOIN_KEYS_THREE.ordinal()); + break; + case 4: b.set(JOIN_KEYS_FOUR.ordinal()); + break; + default: if (joinKeysCount >= 5) { + b.set(JOIN_KEYS_FIVE_OR_MORE.ordinal()); + } + break; + } + } + }); + + if (isLikelyAnEventQuery.get() && b.get(SEQUENCE.ordinal()) == false && b.get(JOIN.ordinal()) == false) { + b.set(EVENT.ordinal()); + } + + for (int i = b.nextSetBit(0); i >= 0; i = b.nextSetBit(i + 1)) { + metrics.inc(FeatureMetric.values()[i]); + } + } + return failures; } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/execution/PlanExecutor.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/execution/PlanExecutor.java index e6c30be535533..d899b701f1aa0 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/execution/PlanExecutor.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/execution/PlanExecutor.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.eql.session.EqlSession; import org.elasticsearch.xpack.eql.session.Results; import org.elasticsearch.xpack.eql.stats.Metrics; +import org.elasticsearch.xpack.eql.stats.QueryMetric; import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; import org.elasticsearch.xpack.ql.index.IndexResolver; @@ -49,7 +50,7 @@ public PlanExecutor(Client client, IndexResolver indexResolver, NamedWriteableRe this.metrics = new Metrics(); this.preAnalyzer = new PreAnalyzer(); - this.verifier = new Verifier(); + this.verifier = new Verifier(metrics); this.optimizer = new Optimizer(); this.planner = new Planner(); } @@ -59,7 +60,11 @@ private EqlSession newSession(EqlConfiguration cfg) { } public void eql(EqlConfiguration cfg, String eql, ParserParams parserParams, ActionListener listener) { - newSession(cfg).eql(eql, parserParams, wrap(listener::onResponse, listener::onFailure)); + metrics.total(QueryMetric.ALL); + newSession(cfg).eql(eql, parserParams, wrap(listener::onResponse, ex -> { + metrics.failed(QueryMetric.ALL); + listener.onFailure(ex); + })); } public Metrics metrics() { diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java index c9734214314aa..bdba32949202e 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java @@ -11,7 +11,24 @@ public enum FeatureMetric { SEQUENCE, JOIN, - PIPE; + EVENT, + UNTIL, + HEAD, + TAIL, + SEQUENCE_MAXSPAN, + SEQUENCE_TWO_QUERIES, + SEQUENCE_THREE_QUERIES, + SEQUENCE_FOUR_QUERIES, + SEQUENCE_FIVE_OR_MORE_QUERIES, + JOIN_TWO_QUERIES, + JOIN_THREE_QUERIES, + JOIN_FOUR_QUERIES, + JOIN_FIVE_OR_MORE_QUERIES, + JOIN_KEYS_ONE, + JOIN_KEYS_TWO, + JOIN_KEYS_THREE, + JOIN_KEYS_FOUR, + JOIN_KEYS_FIVE_OR_MORE; @Override public String toString() { diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java index 1dd9f2117a8a9..f64c7192610ad 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java @@ -27,20 +27,32 @@ public String toString() { return this.name().toLowerCase(Locale.ROOT); } } - - // map that holds total/failed counters for each eql "feature" (join, pipe, sequence...) - private final Map> featuresMetrics; + + // map that holds total/failed counters for all queries, atm + private final Map> opsByTypeMetrics; + // map that holds counters for each eql "feature" (join, pipe, sequence...) + private final Map featuresMetrics; + protected static String QPREFIX = "queries."; protected static String FPREFIX = "features."; + protected static String SEQUENCE_PREFIX = "sequences."; + protected static String JOIN_PREFIX = "joins."; + protected static String KEYS_PREFIX = "keys."; public Metrics() { - Map> fMap = new LinkedHashMap<>(); - for (FeatureMetric metric : FeatureMetric.values()) { + Map> qMap = new LinkedHashMap<>(); + for (QueryMetric metric : QueryMetric.values()) { Map metricsMap = new LinkedHashMap<>(OperationType.values().length); for (OperationType type : OperationType.values()) { metricsMap.put(type, new CounterMetric()); } - fMap.put(metric, Collections.unmodifiableMap(metricsMap)); + qMap.put(metric, Collections.unmodifiableMap(metricsMap)); + } + opsByTypeMetrics = Collections.unmodifiableMap(qMap); + + Map fMap = new LinkedHashMap<>(FeatureMetric.values().length); + for (FeatureMetric featureMetric : FeatureMetric.values()) { + fMap.put(featureMetric, new CounterMetric()); } featuresMetrics = Collections.unmodifiableMap(fMap); } @@ -49,37 +61,59 @@ public Metrics() { * Increments the "total" counter for a metric * This method should be called only once per query. */ - public void total(FeatureMetric metric) { + public void total(QueryMetric metric) { inc(metric, OperationType.TOTAL); } /** * Increments the "failed" counter for a metric */ - public void failed(FeatureMetric metric) { + public void failed(QueryMetric metric) { inc(metric, OperationType.FAILED); } - private void inc(FeatureMetric metric, OperationType op) { - this.featuresMetrics.get(metric).get(op).inc(); + private void inc(QueryMetric metric, OperationType op) { + this.opsByTypeMetrics.get(metric).get(op).inc(); + } + + /** + * Increments the counter for a "features" metric + */ + public void inc(FeatureMetric metric) { + this.featuresMetrics.get(metric).inc(); } public Counters stats() { Counters counters = new Counters(); - + // queries metrics - for (Entry> entry : featuresMetrics.entrySet()) { + for (Entry> entry : opsByTypeMetrics.entrySet()) { String metricName = entry.getKey().toString(); for (OperationType type : OperationType.values()) { long metricCounter = entry.getValue().get(type).count(); String operationTypeName = type.toString(); - counters.inc(FPREFIX + metricName + "." + operationTypeName, metricCounter); - counters.inc(FPREFIX + "_all." + operationTypeName, metricCounter); + counters.inc(QPREFIX + metricName + "." + operationTypeName, metricCounter); + counters.inc(QPREFIX + "_all." + operationTypeName, metricCounter); } } - + + // features metrics + for (Entry entry : featuresMetrics.entrySet()) { + String featureName = entry.getKey().toString(); + String prefix = FPREFIX; + + if (featureName.startsWith("sequence_")) { + prefix += SEQUENCE_PREFIX; + } else if (featureName.startsWith("join_k")) { + prefix += KEYS_PREFIX; + } else if (featureName.startsWith("join_")) { + prefix += JOIN_PREFIX; + } + counters.inc(prefix + featureName, entry.getValue().count()); + } + return counters; } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/QueryMetric.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/QueryMetric.java new file mode 100644 index 0000000000000..6cf487b7d490f --- /dev/null +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/QueryMetric.java @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql.stats; + +import java.util.Locale; + +public enum QueryMetric { + ALL; + + @Override + public String toString() { + return this.name().toLowerCase(Locale.ROOT); + } +} diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java index 69872bfdbe938..e84c740b3f0db 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.xpack.eql.expression.function.EqlFunctionRegistry; import org.elasticsearch.xpack.eql.parser.EqlParser; import org.elasticsearch.xpack.eql.parser.ParsingException; +import org.elasticsearch.xpack.eql.stats.Metrics; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; @@ -36,7 +37,7 @@ private IndexResolution loadIndexResolution(String name) { private LogicalPlan accept(IndexResolution resolution, String eql) { PreAnalyzer preAnalyzer = new PreAnalyzer(); - Analyzer analyzer = new Analyzer(EqlTestUtils.TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier()); + Analyzer analyzer = new Analyzer(EqlTestUtils.TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier(new Metrics())); return analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(eql), resolution)); } diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java index e1c25f3e30eca..76c92b68efa64 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.eql.plan.logical.Sequence; import org.elasticsearch.xpack.eql.plan.logical.Tail; import org.elasticsearch.xpack.eql.plan.physical.LocalRelation; +import org.elasticsearch.xpack.eql.stats.Metrics; import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.EmptyAttribute; import org.elasticsearch.xpack.ql.expression.FieldAttribute; @@ -72,7 +73,7 @@ private IndexResolution loadIndexResolution(String name) { private LogicalPlan accept(IndexResolution resolution, String eql) { PreAnalyzer preAnalyzer = new PreAnalyzer(); - Analyzer analyzer = new Analyzer(TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier()); + Analyzer analyzer = new Analyzer(TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier(new Metrics())); return optimizer.optimize(analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(eql), resolution))); } diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/TomlFoldTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/TomlFoldTests.java index 15d6ae644029f..245c87b4f9b5f 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/TomlFoldTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/TomlFoldTests.java @@ -14,6 +14,7 @@ import org.elasticsearch.xpack.eql.expression.function.EqlFunctionRegistry; import org.elasticsearch.xpack.eql.parser.EqlParser; import org.elasticsearch.xpack.eql.plan.physical.LocalRelation; +import org.elasticsearch.xpack.eql.stats.Metrics; import org.elasticsearch.xpack.ql.expression.Alias; import org.elasticsearch.xpack.ql.expression.Expression; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; @@ -38,7 +39,7 @@ public class TomlFoldTests extends ESTestCase { private static EqlParser parser = new EqlParser(); private static final EqlFunctionRegistry functionRegistry = new EqlFunctionRegistry(); - private static Verifier verifier = new Verifier(); + private static Verifier verifier = new Verifier(new Metrics()); private static Analyzer caseSensitiveAnalyzer = new Analyzer(TEST_CFG_CASE_SENSITIVE, functionRegistry, verifier); private static Analyzer caseInsensitiveAnalyzer = new Analyzer(TEST_CFG_CASE_INSENSITIVE, functionRegistry, verifier); diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/planner/AbstractQueryFolderTestCase.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/planner/AbstractQueryFolderTestCase.java index 5dd7fe20281c9..cca0f234498b3 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/planner/AbstractQueryFolderTestCase.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/planner/AbstractQueryFolderTestCase.java @@ -16,6 +16,7 @@ import org.elasticsearch.xpack.eql.parser.EqlParser; import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.eql.session.EqlConfiguration; +import org.elasticsearch.xpack.eql.stats.Metrics; import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; @@ -25,7 +26,7 @@ public abstract class AbstractQueryFolderTestCase extends ESTestCase { protected EqlParser parser = new EqlParser(); protected PreAnalyzer preAnalyzer = new PreAnalyzer(); protected EqlConfiguration configuration = EqlTestUtils.randomConfiguration(); - protected Analyzer analyzer = new Analyzer(configuration, new EqlFunctionRegistry(), new Verifier()); + protected Analyzer analyzer = new Analyzer(configuration, new EqlFunctionRegistry(), new Verifier(new Metrics())); protected Optimizer optimizer = new Optimizer(); protected Planner planner = new Planner(); From b8fdd68977e6f92e4889ad850cc802ef76bc955b Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Mon, 13 Jul 2020 16:06:28 +0300 Subject: [PATCH 2/5] Add tests --- .../elasticsearch/test/eql/DataLoader.java | 14 +- .../test/eql/stats/FeatureMetric.java | 37 ++ .../test/eql/stats/RestEqlUsageTestCase.java | 366 ++++++++++++++++++ .../elasticsearch/xpack/eql/EqlStatsIT.java | 7 + .../xpack/eql/analysis/Verifier.java | 48 ++- .../xpack/eql/stats/FeatureMetric.java | 16 +- .../xpack/eql/stats/Metrics.java | 9 +- .../xpack/eql/optimizer/OptimizerTests.java | 2 +- .../xpack/eql/stats/VerifierMetricsTests.java | 205 ++++++++++ 9 files changed, 662 insertions(+), 42 deletions(-) create mode 100644 x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java create mode 100644 x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java create mode 100644 x-pack/plugin/eql/qa/rest/src/test/java/org/elasticsearch/xpack/eql/EqlStatsIT.java create mode 100644 x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java index bab624aca724b..51b6707805f07 100644 --- a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java +++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java @@ -38,7 +38,7 @@ public class DataLoader { private static final String TEST_DATA = "/test_data.json"; private static final String MAPPING = "/mapping-default.json"; static final String indexPrefix = "endgame"; - static final String testIndexName = indexPrefix + "-1.4.0"; + public static final String testIndexName = indexPrefix + "-1.4.0"; public static void main(String[] args) throws IOException { try (RestClient client = RestClient.builder(new HttpHost("localhost", 9200)).build()) { @@ -51,15 +51,23 @@ public static void main(String[] args) throws IOException { } } - @SuppressWarnings("unchecked") - protected static void loadDatasetIntoEs(RestHighLevelClient client, + public static void loadDatasetIntoEs(RestHighLevelClient client, CheckedBiFunction p) throws IOException { + createTestIndex(client); + loadData(client, p); + } + + private static void createTestIndex(RestHighLevelClient client) throws IOException { CreateIndexRequest request = new CreateIndexRequest(testIndexName) .mapping(Streams.readFully(DataLoader.class.getResourceAsStream(MAPPING)), XContentType.JSON); client.indices().create(request, RequestOptions.DEFAULT); + } + @SuppressWarnings("unchecked") + private static void loadData(RestHighLevelClient client, CheckedBiFunction p) + throws IOException { BulkRequest bulk = new BulkRequest(); bulk.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java new file mode 100644 index 0000000000000..9787158d80dc7 --- /dev/null +++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.test.eql.stats; + +import java.util.Locale; + +public enum FeatureMetric { + SEQUENCE, + JOIN, + EVENT, + UNTIL, + HEAD, + TAIL, + SEQUENCE_MAXSPAN, + SEQUENCE_QUERIES_TWO, + SEQUENCE_QUERIES_THREE, + SEQUENCE_QUERIES_FOUR, + SEQUENCE_QUERIES_FIVE_OR_MORE, + JOIN_QUERIES_TWO, + JOIN_QUERIES_THREE, + JOIN_QUERIES_FOUR, + JOIN_QUERIES_FIVE_OR_MORE, + JOIN_KEYS_ONE, + JOIN_KEYS_TWO, + JOIN_KEYS_THREE, + JOIN_KEYS_FOUR, + JOIN_KEYS_FIVE_OR_MORE; + + @Override + public String toString() { + return this.name().toLowerCase(Locale.ROOT); + } +} diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java new file mode 100644 index 0000000000000..74a3ae4d8d819 --- /dev/null +++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java @@ -0,0 +1,366 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.test.eql.stats; + +import org.elasticsearch.Build; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.test.eql.DataLoader; +import org.elasticsearch.test.rest.ESRestTestCase; +import org.junit.Before; +import org.junit.BeforeClass; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Tests a random number of queries that increase various (most of the times, one query will "touch" multiple metrics values) metrics. + */ +public abstract class RestEqlUsageTestCase extends ESRestTestCase { + + private RestHighLevelClient highLevelClient; + private Map baseMetrics = new HashMap(); + private Integer baseAllTotalQueries = 0; + private Integer baseAllFailedQueries = 0; + + @BeforeClass + public static void checkForSnapshot() { + assumeTrue("Only works on snapshot builds for now", Build.CURRENT.isSnapshot()); + } + + /** + * This method gets the metrics' values before the test runs, in case these values + * were changed by other tests running in the same REST test cluster. The test itself + * will count the new metrics' values starting from the base values initialized here. + * These values will increase during the execution of the test with updates in {@link #assertFeatureMetric(int, Map, String)} + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Before + private void getBaseMetrics() throws UnsupportedOperationException, IOException { + Map baseStats = getStats(); + List>> nodesListStats = (List) baseStats.get("stats"); + + for (Map perNodeStats : nodesListStats) { + Map queriesMetrics = (Map) ((Map) perNodeStats.get("stats")).get("queries"); + Map featuresMetrics = getFeaturesMetrics(perNodeStats); + + for (FeatureMetric metric : FeatureMetric.values()) { + String metricName = metric.toString(); + if (baseMetrics.containsKey(metricName)) { + baseMetrics.put(metricName, baseMetrics.get(metricName) + ((Integer) featuresMetrics.get(metricName))); + } else { + baseMetrics.put(metricName, (Integer) featuresMetrics.get(metricName)); + } + } + + // initialize the "base" metric values with whatever values are already recorded on ES + baseAllTotalQueries += ((Map) queriesMetrics.get("_all")).get("total"); + baseAllFailedQueries += ((Map) queriesMetrics.get("_all")).get("failed"); + } + } + + /** + * "Flatten" the response from ES putting all the features metrics in the same Map. + * "features": { + * "head": 3, + * "joins": { + * "join_five_or_more_queries": 0, + * "join_four_queries": 0, + * "join_two_queries": 0, + * "join_three_queries": 0 + * }, + * "sequence": 3, + * "keys": { + * "join_keys_two": 0, + * "join_keys_one": 0, + * "join_keys_three": 3, + * "join_keys_five_or_more": 0, + * "join_keys_four": 0 + * }, + * "tail": 0, + * "until": 3, + * "join": 0, + * "sequences": { + * "sequence_five_or_more_queries": 0, + * "sequence_two_queries": 3, + * "sequence_three_queries": 0, + * "sequence_four_queries": 0, + * "sequence_maxspan": 0 + * }, + * "event": 0 + * } + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Map getFeaturesMetrics(Map perNodeStats) { + Map featuresMetrics = (Map) ((Map) perNodeStats.get("stats")).get("features"); + featuresMetrics.putAll((Map) featuresMetrics.get("keys")); + featuresMetrics.putAll((Map) featuresMetrics.get("sequences")); + featuresMetrics.putAll((Map) featuresMetrics.get("joins")); + return featuresMetrics; + } + + public void testEqlRestUsage() throws IOException { + DataLoader.loadDatasetIntoEs(highLevelClient(), (t, u) -> createParser(t, u)); + + // + // random event queries + // + int randomEventExecutions = randomIntBetween(1, 15); + int allTotalQueries = baseAllTotalQueries + randomEventExecutions; + + for (int i = 0; i < randomEventExecutions; i++) { + runEql("process where serial_event_id < 4 | head 3"); + } + + Map responseAsMap = getStats(); + Set metricsToCheck = Set.of("head", "event"); + assertFeaturesMetrics(randomEventExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random two sequences queries + // + int randomSequenceExecutions = randomIntBetween(1, 15); + allTotalQueries += randomSequenceExecutions; + for (int i = 0; i < randomSequenceExecutions; i++) { + runEql("sequence [process where serial_event_id = 1] [process where serial_event_id = 2]"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "head"); + assertFeaturesMetrics(randomSequenceExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random tail queries + // + int randomTailExecutions = randomIntBetween(1, 15); + allTotalQueries += randomTailExecutions; + for (int i = 0; i < randomTailExecutions; i++) { + runEql("process where serial_event_id < 4 | tail 2"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("tail", "event"); + assertFeaturesMetrics(randomTailExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random sequence with maxspan and four queries + // + int randomMaxspanExecutions = randomIntBetween(1, 15); + allTotalQueries += randomMaxspanExecutions; + for (int i = 0; i < randomMaxspanExecutions; i++) { + runEql("sequence with maxspan=1d" + + " [process where serial_event_id < 4] by exit_code" + + " [process where opcode == 1] by user" + + " [process where opcode == 2] by user" + + " [file where parent_process_name == 'file_delete_event'] by exit_code" + + " until [process where opcode=1] by ppid" + + " | head 4" + + " | tail 2"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_maxspan", "sequence_queries_four", "head", "tail", "join_keys_one", "until"); + assertFeaturesMetrics(randomMaxspanExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random sequence with three queries + // + int randomThreeQueriesSequences = randomIntBetween(1, 15); + allTotalQueries += randomThreeQueriesSequences; + for (int i = 0; i < randomThreeQueriesSequences; i++) { + runEql("sequence with maxspan=1d" + + " [process where serial_event_id < 4] by exit_code" + + " [process where opcode == 1] by user" + + " [process where opcode == 2] by user"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_queries_three", "head", "join_keys_one", "sequence_maxspan"); + assertFeaturesMetrics(randomThreeQueriesSequences, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random sequence with five queries and three join keys + // + int randomFiveQueriesSequences = randomIntBetween(1, 15); + allTotalQueries += randomFiveQueriesSequences; + for (int i = 0; i < randomFiveQueriesSequences; i++) { + runEql("sequence by user, ppid, exit_code with maxspan=1m" + + " [process where serial_event_id < 4]" + + " [process where opcode == 1]" + + " [file where parent_process_name == 'file_delete_event']" + + " [process where serial_event_id < 4]" + + " [process where opcode == 1]" + + "| tail 4"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_queries_five_or_more", "tail", "join_keys_three", "sequence_maxspan"); + assertFeaturesMetrics(randomFiveQueriesSequences, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random sequence with four join keys + // + int randomFourJoinKeysExecutions = randomIntBetween(1, 15); + allTotalQueries += randomFourJoinKeysExecutions; + for (int i = 0; i < randomFourJoinKeysExecutions; i++) { + runEql("sequence by exit_code, user, serial_event_id, pid" + + " [process where serial_event_id < 4]" + + " [process where opcode == 1]"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "head", "join_keys_four"); + assertFeaturesMetrics(randomFourJoinKeysExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random sequence with five join keys + // + int randomFiveJoinKeysExecutions = randomIntBetween(1, 15); + allTotalQueries += randomFiveJoinKeysExecutions; + for (int i = 0; i < randomFiveJoinKeysExecutions; i++) { + runEql("sequence by exit_code, user, serial_event_id, pid, ppid" + + " [process where serial_event_id < 4]" + + " [process where opcode == 1]"); + } + responseAsMap = getStats(); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "head", "join_keys_five_or_more"); + assertFeaturesMetrics(randomFiveJoinKeysExecutions, responseAsMap, metricsToCheck); + assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + + // + // random failed queries + // + int randomFailedExecutions = randomIntBetween(1, 15); + int allFailedQueries = baseAllFailedQueries + randomFailedExecutions; + allTotalQueries += randomFailedExecutions; + for (int i = 0; i < randomFailedExecutions; i++) { + // not interested in the exception type, but in the fact that the metrics are incremented when an exception is thrown + expectThrows(Exception.class, () -> { + runEql( + randomFrom( + "process where missing_field < 4 | tail 2", + "sequence abc [process where serial_event_id = 1]", + "sequence with maxspan=1x [process where serial_event_id = 1]", + "sequence by exit_code, user [process where serial_event_id < 4] by ppid", + "sequence by" + ) + ); + }); + } + responseAsMap = getStats(); + assertAllFailedQueryMetrics(allFailedQueries, responseAsMap); + assertAllQueryMetrics(allTotalQueries, responseAsMap); + } + + private void assertAllQueryMetrics(int allTotalQueries, Map responseAsMap) throws IOException { + assertAllQueryMetric(allTotalQueries, responseAsMap, "total"); + } + + private void assertAllFailedQueryMetrics(int allFailedQueries, Map responseAsMap) throws IOException { + assertAllQueryMetric(allFailedQueries, responseAsMap, "failed"); + } + + private Map getStats() throws UnsupportedOperationException, IOException { + Request request = new Request("GET", "/_eql/stats"); + Map responseAsMap; + try (InputStream content = client().performRequest(request).getEntity().getContent()) { + responseAsMap = XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false); + } + + return responseAsMap; + } + + private void runEql(String eql) throws IOException { + Request request = new Request("POST", DataLoader.testIndexName + "/_eql/search"); + request.setJsonEntity("{\"query\":\"" + eql +"\"}"); + client().performRequest(request); + } + + private void assertFeaturesMetrics(int expected, Map responseAsMap, Set metricsToCheck) throws IOException { + for(String metricName : metricsToCheck) { + assertFeatureMetric(expected, responseAsMap, metricName); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void assertFeatureMetric(int expected, Map responseAsMap, String feature) throws IOException { + List> nodesListStats = (List>) responseAsMap.get("stats"); + int actualMetricValue = 0; + for (Map perNodeStats : nodesListStats) { + Map featuresMetrics = getFeaturesMetrics(perNodeStats); + actualMetricValue += (int) featuresMetrics.get(feature); + } + assertEquals(expected + baseMetrics.get(feature), actualMetricValue); + + /* + * update the base value for future checks in {@link #assertFeaturesMetricsExcept(Set, Map)} + */ + baseMetrics.put(feature, expected + baseMetrics.get(feature)); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void assertQueryMetric(int expected, Map responseAsMap, String queryType, String metric) throws IOException { + List>> nodesListStats = (List) responseAsMap.get("stats"); + int actualMetricValue = 0; + for (Map perNodeStats : nodesListStats) { + Map queriesMetrics = (Map) ((Map) perNodeStats.get("stats")).get("queries"); + Map perTypeQueriesMetrics = (Map) queriesMetrics.get(queryType); + actualMetricValue += (int) perTypeQueriesMetrics.get(metric); + } + assertEquals(expected, actualMetricValue); + } + + private void assertAllQueryMetric(int expected, Map responseAsMap, String metric) throws IOException { + assertQueryMetric(expected, responseAsMap, "_all", metric); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void assertFeaturesMetricsExcept(Map responseAsMap, Set exceptions) { + List> nodesListStats = (List>) responseAsMap.get("stats"); + for (FeatureMetric metric : FeatureMetric.values()) { + String metricName = metric.toString(); + if (exceptions.contains(metricName) == false) { + Integer actualValue = 0; + for (Map perNodeStats : nodesListStats) { + Map featuresMetrics = getFeaturesMetrics(perNodeStats); + Integer featureMetricValue = (Integer) featuresMetrics.get(metricName); + actualValue += featureMetricValue; + } + + assertEquals(baseMetrics.get(metricName), actualValue); + } + } + } + + private RestHighLevelClient highLevelClient() { + if (highLevelClient == null) { + highLevelClient = new RestHighLevelClient( + client(), + ignore -> { + }, + Collections.emptyList()) { + }; + } + return highLevelClient; + } +} diff --git a/x-pack/plugin/eql/qa/rest/src/test/java/org/elasticsearch/xpack/eql/EqlStatsIT.java b/x-pack/plugin/eql/qa/rest/src/test/java/org/elasticsearch/xpack/eql/EqlStatsIT.java new file mode 100644 index 0000000000000..03d75a1574924 --- /dev/null +++ b/x-pack/plugin/eql/qa/rest/src/test/java/org/elasticsearch/xpack/eql/EqlStatsIT.java @@ -0,0 +1,7 @@ +package org.elasticsearch.xpack.eql; + +import org.elasticsearch.test.eql.stats.RestEqlUsageTestCase; + +public class EqlStatsIT extends RestEqlUsageTestCase { + +} diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java index 0d4ffdaf30159..83787a197d927 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java @@ -6,26 +6,22 @@ package org.elasticsearch.xpack.eql.analysis; +import org.elasticsearch.xpack.eql.plan.logical.Head; +import org.elasticsearch.xpack.eql.plan.logical.Join; +import org.elasticsearch.xpack.eql.plan.logical.Sequence; +import org.elasticsearch.xpack.eql.plan.logical.Tail; +import org.elasticsearch.xpack.eql.stats.FeatureMetric; +import org.elasticsearch.xpack.eql.stats.Metrics; import org.elasticsearch.xpack.ql.capabilities.Unresolvable; import org.elasticsearch.xpack.ql.common.Failure; import org.elasticsearch.xpack.ql.expression.Attribute; import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.plan.logical.Aggregate; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; import org.elasticsearch.xpack.ql.plan.logical.Project; import org.elasticsearch.xpack.ql.tree.Node; import org.elasticsearch.xpack.ql.type.DataTypes; import org.elasticsearch.xpack.ql.util.Holder; import org.elasticsearch.xpack.ql.util.StringUtils; -import org.elasticsearch.xpack.eql.plan.logical.Head; -import org.elasticsearch.xpack.eql.plan.logical.Join; -import org.elasticsearch.xpack.eql.plan.logical.Sequence; -import org.elasticsearch.xpack.eql.plan.logical.Tail; -import org.elasticsearch.xpack.eql.stats.FeatureMetric; -import org.elasticsearch.xpack.eql.stats.Metrics; import java.util.ArrayList; import java.util.BitSet; @@ -39,21 +35,21 @@ import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.HEAD; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_FIVE_OR_MORE_QUERIES; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_FOUR_QUERIES; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_ONE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_TWO; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_THREE_QUERIES; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_TWO_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_TWO; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_FIVE_OR_MORE_QUERIES; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_FOUR_QUERIES; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_MAXSPAN; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_THREE_QUERIES; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_TWO_QUERIES; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_TWO; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.TAIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.UNTIL; import static org.elasticsearch.xpack.ql.common.Failure.fail; @@ -167,26 +163,26 @@ Collection verify(LogicalPlan plan) { int queriesCount = s.queries().size(); switch (queriesCount) { - case 2: b.set(SEQUENCE_TWO_QUERIES.ordinal()); + case 2: b.set(SEQUENCE_QUERIES_TWO.ordinal()); break; - case 3: b.set(SEQUENCE_THREE_QUERIES.ordinal()); + case 3: b.set(SEQUENCE_QUERIES_THREE.ordinal()); break; - case 4: b.set(SEQUENCE_FOUR_QUERIES.ordinal()); + case 4: b.set(SEQUENCE_QUERIES_FOUR.ordinal()); break; - default: b.set(SEQUENCE_FIVE_OR_MORE_QUERIES.ordinal()); + default: b.set(SEQUENCE_QUERIES_FIVE_OR_MORE.ordinal()); break; } } else { b.set(FeatureMetric.JOIN.ordinal()); int queriesCount = j.queries().size(); switch (queriesCount) { - case 2: b.set(JOIN_TWO_QUERIES.ordinal()); + case 2: b.set(JOIN_QUERIES_TWO.ordinal()); break; - case 3: b.set(JOIN_THREE_QUERIES.ordinal()); + case 3: b.set(JOIN_QUERIES_THREE.ordinal()); break; - case 4: b.set(JOIN_FOUR_QUERIES.ordinal()); + case 4: b.set(JOIN_QUERIES_FOUR.ordinal()); break; - default: b.set(JOIN_FIVE_OR_MORE_QUERIES.ordinal()); + default: b.set(JOIN_QUERIES_FIVE_OR_MORE.ordinal()); break; } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java index bdba32949202e..6d12ee71b0bc3 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java @@ -16,14 +16,14 @@ public enum FeatureMetric { HEAD, TAIL, SEQUENCE_MAXSPAN, - SEQUENCE_TWO_QUERIES, - SEQUENCE_THREE_QUERIES, - SEQUENCE_FOUR_QUERIES, - SEQUENCE_FIVE_OR_MORE_QUERIES, - JOIN_TWO_QUERIES, - JOIN_THREE_QUERIES, - JOIN_FOUR_QUERIES, - JOIN_FIVE_OR_MORE_QUERIES, + SEQUENCE_QUERIES_TWO, + SEQUENCE_QUERIES_THREE, + SEQUENCE_QUERIES_FOUR, + SEQUENCE_QUERIES_FIVE_OR_MORE, + JOIN_QUERIES_TWO, + JOIN_QUERIES_THREE, + JOIN_QUERIES_FOUR, + JOIN_QUERIES_FIVE_OR_MORE, JOIN_KEYS_ONE, JOIN_KEYS_TWO, JOIN_KEYS_THREE, diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java index f64c7192610ad..6e51d2c018b5a 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java @@ -19,6 +19,7 @@ * Class encapsulating the metrics collected for EQL */ public class Metrics { + private enum OperationType { FAILED, TOTAL; @@ -37,7 +38,7 @@ public String toString() { protected static String SEQUENCE_PREFIX = "sequences."; protected static String JOIN_PREFIX = "joins."; protected static String KEYS_PREFIX = "keys."; - + public Metrics() { Map> qMap = new LinkedHashMap<>(); for (QueryMetric metric : QueryMetric.values()) { @@ -45,7 +46,7 @@ public Metrics() { for (OperationType type : OperationType.values()) { metricsMap.put(type, new CounterMetric()); } - + qMap.put(metric, Collections.unmodifiableMap(metricsMap)); } opsByTypeMetrics = Collections.unmodifiableMap(qMap); @@ -64,7 +65,7 @@ public Metrics() { public void total(QueryMetric metric) { inc(metric, OperationType.TOTAL); } - + /** * Increments the "failed" counter for a metric */ @@ -89,7 +90,7 @@ public Counters stats() { // queries metrics for (Entry> entry : opsByTypeMetrics.entrySet()) { String metricName = entry.getKey().toString(); - + for (OperationType type : OperationType.values()) { long metricCounter = entry.getValue().get(type).count(); String operationTypeName = type.toString(); diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java index 76c92b68efa64..c737ca221a720 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java @@ -67,7 +67,7 @@ private static Map loadEqlMapping(String name) { return TypesTests.loadMapping(name); } - private IndexResolution loadIndexResolution(String name) { + public static IndexResolution loadIndexResolution(String name) { return IndexResolution.valid(new EsIndex(INDEX_NAME, loadEqlMapping(name))); } diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java new file mode 100644 index 0000000000000..a79ee44f73878 --- /dev/null +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java @@ -0,0 +1,205 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql.stats; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.core.watcher.common.stats.Counters; +import org.elasticsearch.xpack.eql.EqlTestUtils; +import org.elasticsearch.xpack.eql.analysis.Analyzer; +import org.elasticsearch.xpack.eql.analysis.PreAnalyzer; +import org.elasticsearch.xpack.eql.analysis.Verifier; +import org.elasticsearch.xpack.eql.expression.function.EqlFunctionRegistry; +import org.elasticsearch.xpack.eql.optimizer.OptimizerTests; +import org.elasticsearch.xpack.eql.parser.EqlParser; +import org.elasticsearch.xpack.ql.index.IndexResolution; + +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.HEAD; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_ONE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_MAXSPAN; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FIVE_OR_MORE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FOUR; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_THREE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.TAIL; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.UNTIL; +import static org.elasticsearch.xpack.eql.stats.Metrics.FPREFIX; +import static org.elasticsearch.xpack.eql.stats.Metrics.JOIN_PREFIX; +import static org.elasticsearch.xpack.eql.stats.Metrics.KEYS_PREFIX; +import static org.elasticsearch.xpack.eql.stats.Metrics.SEQUENCE_PREFIX; + +public class VerifierMetricsTests extends ESTestCase { + + private EqlParser parser = new EqlParser(); + private PreAnalyzer preAnalyzer = new PreAnalyzer(); + private EqlFunctionRegistry eqlFunctionRegistry = new EqlFunctionRegistry(); + private IndexResolution index = OptimizerTests.loadIndexResolution("mapping-default.json"); + protected static String FEATURES_KEYS_PREFIX = FPREFIX + KEYS_PREFIX; + protected static String FEATURES_JOIN_PREFIX = FPREFIX + JOIN_PREFIX; + protected static String FEATURES_SEQUENCE_PREFIX = FPREFIX + SEQUENCE_PREFIX; + + public void testEventQuery() { + Counters c = eql("process where serial_event_id < 4"); + assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + } + + public void testSequenceQuery() { + Counters c = eql("sequence\r\n" + + " [process where serial_event_id = 1]\r\n" + + " [process where serial_event_id = 2]"); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + } + + @AwaitsFix(bugUrl = "waiting for the join implementation") + public void testJoinQuery() { + Counters c = eql("join\r\n" + + " [file where file_name=\"*.exe\"] by ppid\r\n" + + " [file where file_name=\"*.com\"] by pid\r\n" + + "until [process where opcode=1] by ppid\r\n" + + "| head 1"); + assertCounters(0, 0, 1L, 1L, 0, 0, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + } + + public void testHeadQuery() { + Counters c = eql("process where serial_event_id < 4 | head 2"); + assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + } + + public void testTailQuery() { + Counters c = eql("process where serial_event_id < 4 | tail 2"); + assertCounters(0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + } + + public void testSequenceMaxSpanQuery() { + Counters c = eql("sequence with maxspan=1d\r\n" + + " [process where serial_event_id < 4] by exit_code\r\n" + + " [process where opcode == 1] by user\r\n" + + " [process where opcode == 2] by user\r\n" + + " [file where parent_process_name == \"file_delete_event\"] by exit_code\r\n" + + "until [process where opcode=1] by ppid\r\n" + + "| head 4\r\n" + + "| tail 2"); + assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + } + + public void testSequenceWithTwoQueries() { + Counters c = eql("sequence with maxspan=1d\r\n" + + " [process where serial_event_id < 4] by exit_code\r\n" + + " [process where opcode == 1] by user\r\n" + + "until [process where opcode=1] by ppid\r\n" + + "| head 4\r\n" + + "| tail 2"); + assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + } + + public void testSequenceWithThreeQueries() { + Counters c = eql("sequence with maxspan=1d\r\n" + + " [process where serial_event_id < 4] by exit_code\r\n" + + " [process where opcode == 1] by user\r\n" + + " [file where parent_process_name == \"file_delete_event\"] by exit_code\r\n" + + "| head 4"); + assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + } + + public void testSequenceWithFiveQueries() { + Counters c = eql("sequence with maxspan=1d\r\n" + + " [process where serial_event_id < 4] by exit_code\r\n" + + " [process where opcode == 1] by user\r\n" + + " [file where parent_process_name == \"file_delete_event\"] by exit_code\r\n" + + " [process where serial_event_id < 4] by exit_code\r\n" + + " [process where opcode == 1] by user\r\n" + + "| head 4"); + assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + } + + public void testSequenceWithSevenQueries() { + Counters c = eql("sequence by exit_code, user\r\n" + + " [process where serial_event_id < 4]\r\n" + + " [process where opcode == 1]\r\n" + + " [file where parent_process_name == \"file_delete_event\"]\r\n" + + " [process where serial_event_id < 4]\r\n" + + " [process where opcode == 1]\r\n" + + " [process where true]\r\n" + + " [process where true]\r\n" + + "| tail 1"); + assertCounters(1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, c); + } + + public void testSequenceWithThreeKeys() { + Counters c = eql("sequence by exit_code, user, serial_event_id\r\n" + + " [process where serial_event_id < 4]\r\n" + + " [process where opcode == 1]\r\n"); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, c); + } + + public void testSequenceWithFourKeys() { + Counters c = eql("sequence by exit_code, user, serial_event_id, pid\r\n" + + " [process where serial_event_id < 4]\r\n" + + " [process where opcode == 1]\r\n"); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, c); + } + + public void testSequenceWithFiveKeys() { + Counters c = eql("sequence by exit_code, user, serial_event_id, pid, ppid\r\n" + + " [process where serial_event_id < 4]\r\n" + + " [process where opcode == 1]\r\n"); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, c); + } + + private void assertCounters(long sequence, long event, long join, long head, long tail, long seqMaxSpan, long until, long seqQTwo, + long seqQThree, long seqQFour, long seqQFive, long joinQTwo, long joinQThree, long joinQFour, long joingQFive, long keysOne, + long keysTwo, long keysThree, long keysFour, long keysFive, Counters c) + { + assertEquals(sequence, c.get(FPREFIX + SEQUENCE)); + assertEquals(event, c.get(FPREFIX + EVENT)); + assertEquals(join, c.get(FPREFIX + JOIN)); + assertEquals(head, c.get(FPREFIX + HEAD)); + assertEquals(tail, c.get(FPREFIX + TAIL)); + assertEquals(seqMaxSpan, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_MAXSPAN)); + assertEquals(until, c.get(FPREFIX + UNTIL)); + assertEquals(seqQTwo, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_TWO)); + assertEquals(seqQThree, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_THREE)); + assertEquals(seqQFour, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_FOUR)); + assertEquals(seqQFive, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_FIVE_OR_MORE)); + assertEquals(joinQTwo, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_TWO)); + assertEquals(joinQThree, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_THREE)); + assertEquals(joinQFour, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_FOUR)); + assertEquals(joingQFive, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_FIVE_OR_MORE)); + assertEquals(keysOne, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_ONE)); + assertEquals(keysTwo, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_TWO)); + assertEquals(keysThree, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_THREE)); + assertEquals(keysFour, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_FOUR)); + assertEquals(keysFive, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_FIVE_OR_MORE)); + } + + private Counters eql(String query) { + return eql(query, null); + } + + private Counters eql(String query, Verifier v) { + Verifier verifier = v; + Metrics metrics = null; + if (v == null) { + metrics = new Metrics(); + verifier = new Verifier(metrics); + } + Analyzer analyzer = new Analyzer(EqlTestUtils.randomConfiguration(), eqlFunctionRegistry, verifier); + analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(query), index)); + + return metrics == null ? null : metrics.stats(); + } +} \ No newline at end of file From 6abfc90926b1263aa75cea4208c0203110e3820a Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Mon, 13 Jul 2020 18:18:30 +0300 Subject: [PATCH 3/5] Create a common "pipes" section and put there head and tail Split "until" and place a join_until and sequence_until in each correspondent section --- .../test/eql/stats/FeatureMetric.java | 9 ++-- .../test/eql/stats/RestEqlUsageTestCase.java | 51 ++++++++++--------- .../xpack/eql/analysis/Verifier.java | 21 ++++---- .../xpack/eql/stats/FeatureMetric.java | 9 ++-- .../xpack/eql/stats/Metrics.java | 3 ++ .../xpack/eql/stats/VerifierMetricsTests.java | 48 +++++++++-------- 6 files changed, 79 insertions(+), 62 deletions(-) diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java index 9787158d80dc7..05d282e1a1259 100644 --- a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java +++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/FeatureMetric.java @@ -12,10 +12,8 @@ public enum FeatureMetric { SEQUENCE, JOIN, EVENT, - UNTIL, - HEAD, - TAIL, SEQUENCE_MAXSPAN, + SEQUENCE_UNTIL, SEQUENCE_QUERIES_TWO, SEQUENCE_QUERIES_THREE, SEQUENCE_QUERIES_FOUR, @@ -24,11 +22,14 @@ public enum FeatureMetric { JOIN_QUERIES_THREE, JOIN_QUERIES_FOUR, JOIN_QUERIES_FIVE_OR_MORE, + JOIN_UNTIL, JOIN_KEYS_ONE, JOIN_KEYS_TWO, JOIN_KEYS_THREE, JOIN_KEYS_FOUR, - JOIN_KEYS_FIVE_OR_MORE; + JOIN_KEYS_FIVE_OR_MORE, + PIPE_HEAD, + PIPE_TAIL; @Override public String toString() { diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java index 74a3ae4d8d819..417fbd3e9b5e9 100644 --- a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java +++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/stats/RestEqlUsageTestCase.java @@ -72,33 +72,36 @@ private void getBaseMetrics() throws UnsupportedOperationException, IOException /** * "Flatten" the response from ES putting all the features metrics in the same Map. - * "features": { - * "head": 3, + * "features": { * "joins": { - * "join_five_or_more_queries": 0, - * "join_four_queries": 0, - * "join_two_queries": 0, - * "join_three_queries": 0 + * "join_queries_three": 0, + * "join_queries_two": 0, + * "join_until": 0, + * "join_queries_five_or_more": 0, + * "join_queries_four": 0 * }, - * "sequence": 3, + * "sequence": 0, * "keys": { * "join_keys_two": 0, * "join_keys_one": 0, - * "join_keys_three": 3, + * "join_keys_three": 0, * "join_keys_five_or_more": 0, * "join_keys_four": 0 * }, - * "tail": 0, - * "until": 3, * "join": 0, * "sequences": { - * "sequence_five_or_more_queries": 0, - * "sequence_two_queries": 3, - * "sequence_three_queries": 0, - * "sequence_four_queries": 0, + * "sequence_queries_three": 0, + * "sequence_queries_four": 0, + * "sequence_queries_two": 0, + * "sequence_until": 0, + * "sequence_queries_five_or_more": 0, * "sequence_maxspan": 0 * }, - * "event": 0 + * "event": 0, + * "pipes": { + * "pipe_tail": 0, + * "pipe_head": 0 + * } * } */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -107,6 +110,7 @@ private Map getFeaturesMetrics(Map perNodeStats) { featuresMetrics.putAll((Map) featuresMetrics.get("keys")); featuresMetrics.putAll((Map) featuresMetrics.get("sequences")); featuresMetrics.putAll((Map) featuresMetrics.get("joins")); + featuresMetrics.putAll((Map) featuresMetrics.get("pipes")); return featuresMetrics; } @@ -124,7 +128,7 @@ public void testEqlRestUsage() throws IOException { } Map responseAsMap = getStats(); - Set metricsToCheck = Set.of("head", "event"); + Set metricsToCheck = Set.of("pipe_head", "event"); assertFeaturesMetrics(randomEventExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -138,7 +142,7 @@ public void testEqlRestUsage() throws IOException { runEql("sequence [process where serial_event_id = 1] [process where serial_event_id = 2]"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_queries_two", "head"); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "pipe_head"); assertFeaturesMetrics(randomSequenceExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -152,7 +156,7 @@ public void testEqlRestUsage() throws IOException { runEql("process where serial_event_id < 4 | tail 2"); } responseAsMap = getStats(); - metricsToCheck = Set.of("tail", "event"); + metricsToCheck = Set.of("pipe_tail", "event"); assertFeaturesMetrics(randomTailExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -173,7 +177,8 @@ public void testEqlRestUsage() throws IOException { " | tail 2"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_maxspan", "sequence_queries_four", "head", "tail", "join_keys_one", "until"); + metricsToCheck = Set.of("sequence", "sequence_maxspan", "sequence_queries_four", "pipe_head", "pipe_tail", "join_keys_one", + "sequence_until"); assertFeaturesMetrics(randomMaxspanExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -190,7 +195,7 @@ public void testEqlRestUsage() throws IOException { " [process where opcode == 2] by user"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_queries_three", "head", "join_keys_one", "sequence_maxspan"); + metricsToCheck = Set.of("sequence", "sequence_queries_three", "pipe_head", "join_keys_one", "sequence_maxspan"); assertFeaturesMetrics(randomThreeQueriesSequences, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -210,7 +215,7 @@ public void testEqlRestUsage() throws IOException { "| tail 4"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_queries_five_or_more", "tail", "join_keys_three", "sequence_maxspan"); + metricsToCheck = Set.of("sequence", "sequence_queries_five_or_more", "pipe_tail", "join_keys_three", "sequence_maxspan"); assertFeaturesMetrics(randomFiveQueriesSequences, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -226,7 +231,7 @@ public void testEqlRestUsage() throws IOException { " [process where opcode == 1]"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_queries_two", "head", "join_keys_four"); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "pipe_head", "join_keys_four"); assertFeaturesMetrics(randomFourJoinKeysExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); @@ -242,7 +247,7 @@ public void testEqlRestUsage() throws IOException { " [process where opcode == 1]"); } responseAsMap = getStats(); - metricsToCheck = Set.of("sequence", "sequence_queries_two", "head", "join_keys_five_or_more"); + metricsToCheck = Set.of("sequence", "sequence_queries_two", "pipe_head", "join_keys_five_or_more"); assertFeaturesMetrics(randomFiveJoinKeysExecutions, responseAsMap, metricsToCheck); assertFeaturesMetricsExcept(responseAsMap, metricsToCheck); assertAllQueryMetrics(allTotalQueries, responseAsMap); diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java index 83787a197d927..41080f788e6cf 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java @@ -33,8 +33,8 @@ import static java.util.stream.Collectors.toMap; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.HEAD; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_UNTIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_ONE; @@ -44,14 +44,15 @@ import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.PIPE_HEAD; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.PIPE_TAIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_UNTIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_MAXSPAN; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FIVE_OR_MORE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_TWO; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.TAIL; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.UNTIL; import static org.elasticsearch.xpack.ql.common.Failure.fail; /** @@ -148,9 +149,9 @@ Collection verify(LogicalPlan plan) { if (p instanceof Project) { isLikelyAnEventQuery.set(true); } else if (p instanceof Head) { - b.set(HEAD.ordinal()); + b.set(PIPE_HEAD.ordinal()); } else if (p instanceof Tail) { - b.set(TAIL.ordinal()); + b.set(PIPE_TAIL.ordinal()); } else if (p instanceof Join) { Join j = (Join) p; @@ -172,6 +173,9 @@ Collection verify(LogicalPlan plan) { default: b.set(SEQUENCE_QUERIES_FIVE_OR_MORE.ordinal()); break; } + if (j.until().keys().isEmpty() == false) { + b.set(SEQUENCE_UNTIL.ordinal()); + } } else { b.set(FeatureMetric.JOIN.ordinal()); int queriesCount = j.queries().size(); @@ -185,10 +189,9 @@ Collection verify(LogicalPlan plan) { default: b.set(JOIN_QUERIES_FIVE_OR_MORE.ordinal()); break; } - } - - if (j.until().keys().isEmpty() == false) { - b.set(UNTIL.ordinal()); + if (j.until().keys().isEmpty() == false) { + b.set(JOIN_UNTIL.ordinal()); + } } int joinKeysCount = j.queries().get(0).keys().size(); diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java index 6d12ee71b0bc3..76b44a0421c39 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java @@ -12,10 +12,8 @@ public enum FeatureMetric { SEQUENCE, JOIN, EVENT, - UNTIL, - HEAD, - TAIL, SEQUENCE_MAXSPAN, + SEQUENCE_UNTIL, SEQUENCE_QUERIES_TWO, SEQUENCE_QUERIES_THREE, SEQUENCE_QUERIES_FOUR, @@ -24,11 +22,14 @@ public enum FeatureMetric { JOIN_QUERIES_THREE, JOIN_QUERIES_FOUR, JOIN_QUERIES_FIVE_OR_MORE, + JOIN_UNTIL, JOIN_KEYS_ONE, JOIN_KEYS_TWO, JOIN_KEYS_THREE, JOIN_KEYS_FOUR, - JOIN_KEYS_FIVE_OR_MORE; + JOIN_KEYS_FIVE_OR_MORE, + PIPE_HEAD, + PIPE_TAIL; @Override public String toString() { diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java index 6e51d2c018b5a..50f00f3e5e7e8 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java @@ -38,6 +38,7 @@ public String toString() { protected static String SEQUENCE_PREFIX = "sequences."; protected static String JOIN_PREFIX = "joins."; protected static String KEYS_PREFIX = "keys."; + protected static String PIPES_PREFIX = "pipes."; public Metrics() { Map> qMap = new LinkedHashMap<>(); @@ -111,6 +112,8 @@ public Counters stats() { prefix += KEYS_PREFIX; } else if (featureName.startsWith("join_")) { prefix += JOIN_PREFIX; + } else if (featureName.startsWith("pipe_")) { + prefix += PIPES_PREFIX; } counters.inc(prefix + featureName, entry.getValue().count()); } diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java index a79ee44f73878..b52b5669fc9ee 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java @@ -18,7 +18,6 @@ import org.elasticsearch.xpack.ql.index.IndexResolution; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.HEAD; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FOUR; @@ -29,17 +28,20 @@ import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_TWO; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_UNTIL; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.PIPE_HEAD; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.PIPE_TAIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_MAXSPAN; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FIVE_OR_MORE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_FOUR; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_TWO; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.TAIL; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.UNTIL; +import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_UNTIL; import static org.elasticsearch.xpack.eql.stats.Metrics.FPREFIX; import static org.elasticsearch.xpack.eql.stats.Metrics.JOIN_PREFIX; import static org.elasticsearch.xpack.eql.stats.Metrics.KEYS_PREFIX; +import static org.elasticsearch.xpack.eql.stats.Metrics.PIPES_PREFIX; import static org.elasticsearch.xpack.eql.stats.Metrics.SEQUENCE_PREFIX; public class VerifierMetricsTests extends ESTestCase { @@ -51,17 +53,18 @@ public class VerifierMetricsTests extends ESTestCase { protected static String FEATURES_KEYS_PREFIX = FPREFIX + KEYS_PREFIX; protected static String FEATURES_JOIN_PREFIX = FPREFIX + JOIN_PREFIX; protected static String FEATURES_SEQUENCE_PREFIX = FPREFIX + SEQUENCE_PREFIX; + protected static String FEATURES_PIPES_PREFIX = FPREFIX + PIPES_PREFIX; public void testEventQuery() { Counters c = eql("process where serial_event_id < 4"); - assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); } public void testSequenceQuery() { Counters c = eql("sequence\r\n" + " [process where serial_event_id = 1]\r\n" + " [process where serial_event_id = 2]"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); } @AwaitsFix(bugUrl = "waiting for the join implementation") @@ -71,17 +74,17 @@ public void testJoinQuery() { " [file where file_name=\"*.com\"] by pid\r\n" + "until [process where opcode=1] by ppid\r\n" + "| head 1"); - assertCounters(0, 0, 1L, 1L, 0, 0, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(0, 0, 1L, 1L, 0, 0, 0, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); } public void testHeadQuery() { Counters c = eql("process where serial_event_id < 4 | head 2"); - assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); } public void testTailQuery() { Counters c = eql("process where serial_event_id < 4 | tail 2"); - assertCounters(0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); } public void testSequenceMaxSpanQuery() { @@ -93,7 +96,7 @@ public void testSequenceMaxSpanQuery() { "until [process where opcode=1] by ppid\r\n" + "| head 4\r\n" + "| tail 2"); - assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); } public void testSequenceWithTwoQueries() { @@ -103,7 +106,7 @@ public void testSequenceWithTwoQueries() { "until [process where opcode=1] by ppid\r\n" + "| head 4\r\n" + "| tail 2"); - assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); } public void testSequenceWithThreeQueries() { @@ -112,7 +115,7 @@ public void testSequenceWithThreeQueries() { " [process where opcode == 1] by user\r\n" + " [file where parent_process_name == \"file_delete_event\"] by exit_code\r\n" + "| head 4"); - assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); } public void testSequenceWithFiveQueries() { @@ -123,7 +126,7 @@ public void testSequenceWithFiveQueries() { " [process where serial_event_id < 4] by exit_code\r\n" + " [process where opcode == 1] by user\r\n" + "| head 4"); - assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); } public void testSequenceWithSevenQueries() { @@ -136,41 +139,42 @@ public void testSequenceWithSevenQueries() { " [process where true]\r\n" + " [process where true]\r\n" + "| tail 1"); - assertCounters(1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, c); + assertCounters(1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, c); } public void testSequenceWithThreeKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, c); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, c); } public void testSequenceWithFourKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id, pid\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, c); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, c); } public void testSequenceWithFiveKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id, pid, ppid\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, c); + assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, c); } - private void assertCounters(long sequence, long event, long join, long head, long tail, long seqMaxSpan, long until, long seqQTwo, - long seqQThree, long seqQFour, long seqQFive, long joinQTwo, long joinQThree, long joinQFour, long joingQFive, long keysOne, - long keysTwo, long keysThree, long keysFour, long keysFive, Counters c) + private void assertCounters(long sequence, long event, long join, long head, long tail, long seqMaxSpan, long seqUntil, long joinUntil, + long seqQTwo, long seqQThree, long seqQFour, long seqQFive, long joinQTwo, long joinQThree, long joinQFour, long joingQFive, + long keysOne, long keysTwo, long keysThree, long keysFour, long keysFive, Counters c) { assertEquals(sequence, c.get(FPREFIX + SEQUENCE)); assertEquals(event, c.get(FPREFIX + EVENT)); assertEquals(join, c.get(FPREFIX + JOIN)); - assertEquals(head, c.get(FPREFIX + HEAD)); - assertEquals(tail, c.get(FPREFIX + TAIL)); + assertEquals(head, c.get(FEATURES_PIPES_PREFIX + PIPE_HEAD)); + assertEquals(tail, c.get(FEATURES_PIPES_PREFIX + PIPE_TAIL)); assertEquals(seqMaxSpan, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_MAXSPAN)); - assertEquals(until, c.get(FPREFIX + UNTIL)); + assertEquals(seqUntil, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_UNTIL)); + assertEquals(joinUntil, c.get(FEATURES_JOIN_PREFIX + JOIN_UNTIL)); assertEquals(seqQTwo, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_TWO)); assertEquals(seqQThree, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_THREE)); assertEquals(seqQFour, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_FOUR)); From 6069444dc9986bd0d9f5b0cff3de1732ae970e36 Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Tue, 14 Jul 2020 10:52:16 +0300 Subject: [PATCH 4/5] Improve the prefix handling for FeatureMetric --- .../xpack/eql/stats/FeatureMetric.java | 22 ++++ .../xpack/eql/stats/Metrics.java | 19 +--- .../xpack/eql/stats/VerifierMetricsTests.java | 101 +++++++++--------- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java index 76b44a0421c39..e035b5b8076a2 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/FeatureMetric.java @@ -31,8 +31,30 @@ public enum FeatureMetric { PIPE_HEAD, PIPE_TAIL; + private final String prefix; + + FeatureMetric() { + String featureName = this.toString(); + String prefix = "features."; + + if (featureName.startsWith("sequence_")) { + prefix += "sequences."; + } else if (featureName.startsWith("join_k")) { + prefix += "keys."; + } else if (featureName.startsWith("join_")) { + prefix += "joins."; + } else if (featureName.startsWith("pipe_")) { + prefix += "pipes."; + } + this.prefix = prefix; + } + @Override public String toString() { return this.name().toLowerCase(Locale.ROOT); } + + public String prefixedName() { + return this.prefix + this.toString(); + } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java index 50f00f3e5e7e8..519bbb6fc1f0b 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/stats/Metrics.java @@ -34,11 +34,6 @@ public String toString() { // map that holds counters for each eql "feature" (join, pipe, sequence...) private final Map featuresMetrics; protected static String QPREFIX = "queries."; - protected static String FPREFIX = "features."; - protected static String SEQUENCE_PREFIX = "sequences."; - protected static String JOIN_PREFIX = "joins."; - protected static String KEYS_PREFIX = "keys."; - protected static String PIPES_PREFIX = "pipes."; public Metrics() { Map> qMap = new LinkedHashMap<>(); @@ -103,19 +98,7 @@ public Counters stats() { // features metrics for (Entry entry : featuresMetrics.entrySet()) { - String featureName = entry.getKey().toString(); - String prefix = FPREFIX; - - if (featureName.startsWith("sequence_")) { - prefix += SEQUENCE_PREFIX; - } else if (featureName.startsWith("join_k")) { - prefix += KEYS_PREFIX; - } else if (featureName.startsWith("join_")) { - prefix += JOIN_PREFIX; - } else if (featureName.startsWith("pipe_")) { - prefix += PIPES_PREFIX; - } - counters.inc(prefix + featureName, entry.getValue().count()); + counters.inc(entry.getKey().prefixedName(), entry.getValue().count()); } return counters; diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java index b52b5669fc9ee..e48a58c7e6488 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/stats/VerifierMetricsTests.java @@ -17,6 +17,8 @@ import org.elasticsearch.xpack.eql.parser.EqlParser; import org.elasticsearch.xpack.ql.index.IndexResolution; +import java.util.Set; + import static org.elasticsearch.xpack.eql.stats.FeatureMetric.EVENT; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_FIVE_OR_MORE; @@ -24,9 +26,6 @@ import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_ONE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_KEYS_TWO; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FIVE_OR_MORE; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_FOUR; -import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_QUERIES_TWO; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.JOIN_UNTIL; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.PIPE_HEAD; @@ -38,11 +37,6 @@ import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_THREE; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_QUERIES_TWO; import static org.elasticsearch.xpack.eql.stats.FeatureMetric.SEQUENCE_UNTIL; -import static org.elasticsearch.xpack.eql.stats.Metrics.FPREFIX; -import static org.elasticsearch.xpack.eql.stats.Metrics.JOIN_PREFIX; -import static org.elasticsearch.xpack.eql.stats.Metrics.KEYS_PREFIX; -import static org.elasticsearch.xpack.eql.stats.Metrics.PIPES_PREFIX; -import static org.elasticsearch.xpack.eql.stats.Metrics.SEQUENCE_PREFIX; public class VerifierMetricsTests extends ESTestCase { @@ -50,21 +44,17 @@ public class VerifierMetricsTests extends ESTestCase { private PreAnalyzer preAnalyzer = new PreAnalyzer(); private EqlFunctionRegistry eqlFunctionRegistry = new EqlFunctionRegistry(); private IndexResolution index = OptimizerTests.loadIndexResolution("mapping-default.json"); - protected static String FEATURES_KEYS_PREFIX = FPREFIX + KEYS_PREFIX; - protected static String FEATURES_JOIN_PREFIX = FPREFIX + JOIN_PREFIX; - protected static String FEATURES_SEQUENCE_PREFIX = FPREFIX + SEQUENCE_PREFIX; - protected static String FEATURES_PIPES_PREFIX = FPREFIX + PIPES_PREFIX; public void testEventQuery() { Counters c = eql("process where serial_event_id < 4"); - assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(c, Set.of(EVENT, PIPE_HEAD)); } public void testSequenceQuery() { Counters c = eql("sequence\r\n" + " [process where serial_event_id = 1]\r\n" + " [process where serial_event_id = 2]"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_QUERIES_TWO)); } @AwaitsFix(bugUrl = "waiting for the join implementation") @@ -74,17 +64,17 @@ public void testJoinQuery() { " [file where file_name=\"*.com\"] by pid\r\n" + "until [process where opcode=1] by ppid\r\n" + "| head 1"); - assertCounters(0, 0, 1L, 1L, 0, 0, 0, 1L, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(c, Set.of(JOIN, PIPE_HEAD, JOIN_UNTIL, JOIN_QUERIES_TWO, JOIN_KEYS_ONE)); } public void testHeadQuery() { Counters c = eql("process where serial_event_id < 4 | head 2"); - assertCounters(0, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(c, Set.of(EVENT, PIPE_HEAD)); } public void testTailQuery() { Counters c = eql("process where serial_event_id < 4 | tail 2"); - assertCounters(0, 1L, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c); + assertCounters(c, Set.of(EVENT, PIPE_TAIL)); } public void testSequenceMaxSpanQuery() { @@ -96,7 +86,7 @@ public void testSequenceMaxSpanQuery() { "until [process where opcode=1] by ppid\r\n" + "| head 4\r\n" + "| tail 2"); - assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, PIPE_TAIL, SEQUENCE_MAXSPAN, SEQUENCE_UNTIL, SEQUENCE_QUERIES_FOUR, JOIN_KEYS_ONE)); } public void testSequenceWithTwoQueries() { @@ -106,7 +96,7 @@ public void testSequenceWithTwoQueries() { "until [process where opcode=1] by ppid\r\n" + "| head 4\r\n" + "| tail 2"); - assertCounters(1L, 0, 0, 1L, 1L, 1L, 1L, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, PIPE_TAIL, SEQUENCE_MAXSPAN, SEQUENCE_UNTIL, SEQUENCE_QUERIES_TWO, JOIN_KEYS_ONE)); } public void testSequenceWithThreeQueries() { @@ -115,7 +105,7 @@ public void testSequenceWithThreeQueries() { " [process where opcode == 1] by user\r\n" + " [file where parent_process_name == \"file_delete_event\"] by exit_code\r\n" + "| head 4"); - assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_MAXSPAN, SEQUENCE_QUERIES_THREE, JOIN_KEYS_ONE)); } public void testSequenceWithFiveQueries() { @@ -126,7 +116,7 @@ public void testSequenceWithFiveQueries() { " [process where serial_event_id < 4] by exit_code\r\n" + " [process where opcode == 1] by user\r\n" + "| head 4"); - assertCounters(1L, 0, 0, 1L, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_MAXSPAN, SEQUENCE_QUERIES_FIVE_OR_MORE, JOIN_KEYS_ONE)); } public void testSequenceWithSevenQueries() { @@ -139,55 +129,37 @@ public void testSequenceWithSevenQueries() { " [process where true]\r\n" + " [process where true]\r\n" + "| tail 1"); - assertCounters(1L, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 1L, 0, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_TAIL, SEQUENCE_QUERIES_FIVE_OR_MORE, JOIN_KEYS_TWO)); } public void testSequenceWithThreeKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_QUERIES_TWO, JOIN_KEYS_THREE)); } public void testSequenceWithFourKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id, pid\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, 0, c); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_QUERIES_TWO, JOIN_KEYS_FOUR)); } public void testSequenceWithFiveKeys() { Counters c = eql("sequence by exit_code, user, serial_event_id, pid, ppid\r\n" + " [process where serial_event_id < 4]\r\n" + " [process where opcode == 1]\r\n"); - assertCounters(1L, 0, 0, 1L, 0, 0, 0, 0, 1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1L, c); - } - - private void assertCounters(long sequence, long event, long join, long head, long tail, long seqMaxSpan, long seqUntil, long joinUntil, - long seqQTwo, long seqQThree, long seqQFour, long seqQFive, long joinQTwo, long joinQThree, long joinQFour, long joingQFive, - long keysOne, long keysTwo, long keysThree, long keysFour, long keysFive, Counters c) - { - assertEquals(sequence, c.get(FPREFIX + SEQUENCE)); - assertEquals(event, c.get(FPREFIX + EVENT)); - assertEquals(join, c.get(FPREFIX + JOIN)); - assertEquals(head, c.get(FEATURES_PIPES_PREFIX + PIPE_HEAD)); - assertEquals(tail, c.get(FEATURES_PIPES_PREFIX + PIPE_TAIL)); - assertEquals(seqMaxSpan, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_MAXSPAN)); - assertEquals(seqUntil, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_UNTIL)); - assertEquals(joinUntil, c.get(FEATURES_JOIN_PREFIX + JOIN_UNTIL)); - assertEquals(seqQTwo, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_TWO)); - assertEquals(seqQThree, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_THREE)); - assertEquals(seqQFour, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_FOUR)); - assertEquals(seqQFive, c.get(FEATURES_SEQUENCE_PREFIX + SEQUENCE_QUERIES_FIVE_OR_MORE)); - assertEquals(joinQTwo, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_TWO)); - assertEquals(joinQThree, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_THREE)); - assertEquals(joinQFour, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_FOUR)); - assertEquals(joingQFive, c.get(FEATURES_JOIN_PREFIX + JOIN_QUERIES_FIVE_OR_MORE)); - assertEquals(keysOne, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_ONE)); - assertEquals(keysTwo, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_TWO)); - assertEquals(keysThree, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_THREE)); - assertEquals(keysFour, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_FOUR)); - assertEquals(keysFive, c.get(FEATURES_KEYS_PREFIX + JOIN_KEYS_FIVE_OR_MORE)); + assertCounters(c, Set.of(SEQUENCE, PIPE_HEAD, SEQUENCE_QUERIES_TWO, JOIN_KEYS_FIVE_OR_MORE)); + } + + private void assertCounters(Counters actual, Set metrics) { + MetricsHolder expected = new MetricsHolder(); + expected.set(metrics); + + for (FeatureMetric metric : FeatureMetric.values()) { + assertEquals(expected.get(metric), actual.get(metric.prefixedName())); + } } private Counters eql(String query) { @@ -206,4 +178,29 @@ private Counters eql(String query, Verifier v) { return metrics == null ? null : metrics.stats(); } + + private class MetricsHolder { + long[] metrics; + + MetricsHolder() { + this.metrics = new long[FeatureMetric.values().length]; + for (int i = 0; i < this.metrics.length; i++) { + this.metrics[i] = 0; + } + } + + void set(Set metrics) { + for (FeatureMetric metric : metrics) { + set(metric); + } + } + + void set(FeatureMetric metric) { + this.metrics[metric.ordinal()] = 1L; + } + + long get(FeatureMetric metric) { + return this.metrics[metric.ordinal()]; + } + } } \ No newline at end of file From 5fd7c37a6749a55c9986bf4ce1bf9b9edfdb501a Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Tue, 14 Jul 2020 15:29:15 +0300 Subject: [PATCH 5/5] Bump the supported version --- .../org/elasticsearch/xpack/core/eql/EqlFeatureSetUsage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/eql/EqlFeatureSetUsage.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/eql/EqlFeatureSetUsage.java index a9c8b6dc71156..0484a2fe0bc2d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/eql/EqlFeatureSetUsage.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/eql/EqlFeatureSetUsage.java @@ -52,7 +52,7 @@ public void writeTo(StreamOutput out) throws IOException { @Override public Version getMinimalSupportedVersion() { - return Version.V_7_7_0; + return Version.V_7_9_0; } }