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.

Reply via email to