Repository: metron Updated Branches: refs/heads/master c73c7af1d -> 8ef18d31a
METRON-1138 Improve Error Message with Bad Profile Expression (nickwallen) closes apache/metron#721 Project: http://git-wip-us.apache.org/repos/asf/metron/repo Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/8ef18d31 Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/8ef18d31 Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/8ef18d31 Branch: refs/heads/master Commit: 8ef18d31ab927acad7798c6c32252ca27c8e8b46 Parents: c73c7af Author: nickwallen <[email protected]> Authored: Thu Aug 31 10:51:53 2017 -0400 Committer: nickallen <[email protected]> Committed: Thu Aug 31 10:51:53 2017 -0400 ---------------------------------------------------------------------- .../metron/profiler/DefaultProfileBuilder.java | 53 ++++++++++++++------ .../profiler/DefaultProfileBuilderTest.java | 2 +- metron-analytics/metron-profiler/README.md | 1 + 3 files changed, 40 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metron/blob/8ef18d31/metron-analytics/metron-profiler-common/src/main/java/org/apache/metron/profiler/DefaultProfileBuilder.java ---------------------------------------------------------------------- diff --git a/metron-analytics/metron-profiler-common/src/main/java/org/apache/metron/profiler/DefaultProfileBuilder.java b/metron-analytics/metron-profiler-common/src/main/java/org/apache/metron/profiler/DefaultProfileBuilder.java index 1f352d0..2e34160 100644 --- a/metron-analytics/metron-profiler-common/src/main/java/org/apache/metron/profiler/DefaultProfileBuilder.java +++ b/metron-analytics/metron-profiler-common/src/main/java/org/apache/metron/profiler/DefaultProfileBuilder.java @@ -27,9 +27,11 @@ import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.commons.collections4.ListUtils; @@ -245,17 +247,28 @@ public class DefaultProfileBuilder implements ProfileBuilder, Serializable { * @param expressionType The type of expression; init, update, result. Provides additional context if expression execution fails. */ private void assign(Map<String, String> expressions, Map<String, Object> transientState, String expressionType) { - try { - // execute each of the 'update' expressions - MapUtils.emptyIfNull(expressions) - .forEach((var, expr) -> executor.assign(var, expr, transientState)); + // for each expression... + for(Map.Entry<String, String> entry : MapUtils.emptyIfNull(expressions).entrySet()) { + String var = entry.getKey(); + String expr = entry.getValue(); + + try { + // assign the result of the expression to the variable + executor.assign(var, expr, transientState); - } catch(ParseException e) { + } catch (Throwable e) { - // make it brilliantly clear that one of the 'update' expressions is bad - String msg = format("Bad '%s' expression: error=%s, profile=%s, entity=%s", expressionType, e.getMessage(), profileName, entity); - throw new ParseException(msg, e); + // in-scope variables = persistent state maintained by the profiler + the transient state + Set<String> variablesInScope = new HashSet<>(); + variablesInScope.addAll(transientState.keySet()); + variablesInScope.addAll(executor.getState().keySet()); + + String msg = format("Bad '%s' expression: error='%s', expr='%s', profile='%s', entity='%s', variables-available='%s'", + expressionType, e.getMessage(), expr, profileName, entity, variablesInScope); + LOG.error(msg, e); + throw new ParseException(msg, e); + } } } @@ -269,14 +282,24 @@ public class DefaultProfileBuilder implements ProfileBuilder, Serializable { private List<Object> execute(List<String> expressions, Map<String, Object> transientState, String expressionType) { List<Object> results = new ArrayList<>(); - try { - ListUtils.emptyIfNull(expressions) - .forEach((expr) -> results.add(executor.execute(expr, transientState, Object.class))); + for(String expr: ListUtils.emptyIfNull(expressions)) { + try { + // execute an expression + Object result = executor.execute(expr, transientState, Object.class); + results.add(result); + + } catch (Throwable e) { - } catch (Throwable e) { - String msg = format("Bad '%s' expression: error=%s, profile=%s, entity=%s", expressionType, e.getMessage(), profileName, entity); - LOG.error(msg, e); - throw new ParseException(msg, e); + // in-scope variables = persistent state maintained by the profiler + the transient state + Set<String> variablesInScope = new HashSet<>(); + variablesInScope.addAll(transientState.keySet()); + variablesInScope.addAll(executor.getState().keySet()); + + String msg = format("Bad '%s' expression: error='%s', expr='%s', profile='%s', entity='%s', variables-available='%s'", + expressionType, e.getMessage(), expr, profileName, entity, variablesInScope); + LOG.error(msg, e); + throw new ParseException(msg, e); + } } return results; http://git-wip-us.apache.org/repos/asf/metron/blob/8ef18d31/metron-analytics/metron-profiler-common/src/test/java/org/apache/metron/profiler/DefaultProfileBuilderTest.java ---------------------------------------------------------------------- diff --git a/metron-analytics/metron-profiler-common/src/test/java/org/apache/metron/profiler/DefaultProfileBuilderTest.java b/metron-analytics/metron-profiler-common/src/test/java/org/apache/metron/profiler/DefaultProfileBuilderTest.java index 71ef982..d25b7ff 100644 --- a/metron-analytics/metron-profiler-common/src/test/java/org/apache/metron/profiler/DefaultProfileBuilderTest.java +++ b/metron-analytics/metron-profiler-common/src/test/java/org/apache/metron/profiler/DefaultProfileBuilderTest.java @@ -600,7 +600,7 @@ public class DefaultProfileBuilderTest { * "init": { "x": "0" }, * "update": { "x": "x + 1" }, * "result": "x", - * "groupBy": ["2 / 0"] + * "groupBy": ["nonexistant"] * } */ @Multiline http://git-wip-us.apache.org/repos/asf/metron/blob/8ef18d31/metron-analytics/metron-profiler/README.md ---------------------------------------------------------------------- diff --git a/metron-analytics/metron-profiler/README.md b/metron-analytics/metron-profiler/README.md index b7aed55..9b908f6 100644 --- a/metron-analytics/metron-profiler/README.md +++ b/metron-analytics/metron-profiler/README.md @@ -200,6 +200,7 @@ A common use case would be grouping by day of week. This allows a contiguous sc ``` The expression can reference any of these variables. +* Any variable defined by the profile in its `init` or `update` expressions. * `profile` The name of the profile. * `entity` The name of the entity being profiled. * `start` The start time of the profile period in epoch milliseconds.
