lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject lucene-solr:feature/autoscaling: SOLR-11031: Implement SystemLogListener for autoscaling.
Date Wed, 19 Jul 2017 15:58:35 GMT
Repository: lucene-solr
Updated Branches:
  refs/heads/feature/autoscaling 39b904cec -> e9e9b3c21


SOLR-11031: Implement SystemLogListener for autoscaling.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/e9e9b3c2
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/e9e9b3c2
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/e9e9b3c2

Branch: refs/heads/feature/autoscaling
Commit: e9e9b3c21ac06e0eb25fe5a0013973158da18f41
Parents: 39b904c
Author: Andrzej Bialecki <ab@apache.org>
Authored: Wed Jul 19 17:20:52 2017 +0200
Committer: Andrzej Bialecki <ab@apache.org>
Committed: Wed Jul 19 17:20:52 2017 +0200

----------------------------------------------------------------------
 solr/CHANGES.txt                                |   2 +
 .../apache/solr/cloud/CreateCollectionCmd.java  |   7 +-
 .../solr/cloud/autoscaling/ActionContext.java   |  14 +-
 .../solr/cloud/autoscaling/AutoScaling.java     |   4 -
 .../cloud/autoscaling/AutoScalingHandler.java   |  32 ++-
 .../solr/cloud/autoscaling/LogPlanAction.java   |  28 ---
 .../cloud/autoscaling/LogTriggerListener.java   |  38 ---
 .../solr/cloud/autoscaling/LoggingListener.java |  38 +++
 .../cloud/autoscaling/ScheduledTriggers.java    |   4 +
 .../cloud/autoscaling/SystemLogListener.java    | 202 ++++++++++++++++
 .../org/apache/solr/core/BlobRepository.java    |  12 +-
 .../org/apache/solr/core/MemClassLoader.java    |   3 +-
 .../src/java/org/apache/solr/core/SolrCore.java |   4 +-
 .../org/apache/solr/handler/BlobHandler.java    |   1 +
 .../solr/handler/admin/CollectionsHandler.java  |  10 +-
 .../org/apache/solr/servlet/HttpSolrCall.java   |   8 +-
 .../src/java/org/apache/solr/util/SolrCLI.java  |   3 +-
 .../src/resources/SystemCollectionSchema.xml    |  27 ++-
 .../AutoAddReplicasPlanActionTest.java          |   3 +-
 .../autoscaling/AutoScalingHandlerTest.java     |  31 +--
 .../cloud/autoscaling/NodeAddedTriggerTest.java |   4 -
 .../cloud/autoscaling/NodeLostTriggerTest.java  |   4 -
 .../autoscaling/SystemLogListenerTest.java      | 239 +++++++++++++++++++
 .../solr/core/BlobRepositoryCloudTest.java      |   3 +-
 .../cloud/autoscaling/AutoScalingConfig.java    |  22 +-
 .../solrj/request/CollectionAdminRequest.java   |  20 +-
 .../common/params/CollectionAdminParams.java    |   4 +-
 .../apache/solr/common/params/CommonParams.java |   3 +
 28 files changed, 634 insertions(+), 136 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 5b1636c..3e369e2 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -63,6 +63,8 @@ New Features
 
 * SOLR-11046: Add residuals Stream Evaluator (Joel Bernstein)
 
+* SOLR-11031: Implement SystemLogListener for autoscaling (ab)
+
 Bug Fixes
 ----------------------
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
index d859170..cc1c1a1 100644
--- a/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
@@ -30,7 +30,6 @@ import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.solr.client.solrj.cloud.autoscaling.Policy;
-import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.cloud.OverseerCollectionMessageHandler.Cmd;
 import org.apache.solr.cloud.autoscaling.AutoScaling;
 import org.apache.solr.cloud.autoscaling.AutoScalingHandler;
@@ -48,18 +47,16 @@ import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.cloud.ZooKeeperException;
 import org.apache.solr.common.params.AutoScalingParams;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.CommandOperation;
-import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.handler.admin.ConfigSetsHandlerApi;
 import org.apache.solr.handler.component.ShardHandler;
 import org.apache.solr.handler.component.ShardRequest;
-import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.TimeOut;
 import org.apache.zookeeper.CreateMode;
@@ -349,7 +346,7 @@ public class CreateCollectionCmd implements Cmd {
       try {
         configNames = ocmh.zkStateReader.getZkClient().getChildren(ZkConfigManager.CONFIGS_ZKNODE, null, true);
         if (configNames.contains(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME)) {
-          if (!".system".equals(coll)) {
+          if (!CollectionAdminParams.SYSTEM_COLL.equals(coll)) {
             copyDefaultConfigSetTo(configNames, coll);
           }
           return coll;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
index ecc339c..178a972 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
@@ -17,8 +17,10 @@
 
 package org.apache.solr.cloud.autoscaling;
 
+import java.io.IOException;
 import java.util.Map;
 
+import org.apache.solr.common.MapWriter;
 import org.apache.solr.core.CoreContainer;
 
 /**
@@ -26,7 +28,7 @@ import org.apache.solr.core.CoreContainer;
  * which the action is being executed as well as helper methods to pass computed information along
  * to the next action
  */
-public class ActionContext {
+public class ActionContext implements MapWriter {
 
   private final CoreContainer coreContainer;
   private final AutoScaling.Trigger source;
@@ -53,4 +55,14 @@ public class ActionContext {
   public Object getProperty(String name)  {
     return properties != null ? properties.get(name) : null;
   }
+
+  @Override
+  public void writeMap(EntryWriter ew) throws IOException {
+    ew.put("source", source.getName());
+    if (properties != null) {
+      for (Map.Entry<String, Object> entry : properties.entrySet()) {
+        ew.put("properties." + entry.getKey(), entry.getValue());
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
index c25b00e..0d192d3 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
@@ -158,10 +158,6 @@ public class AutoScaling {
       "            {" +
       "                'name':'execute_plan'," +
       "                'class':'solr.ExecutePlanAction'" +
-      "            }," +
-      "            {" +
-      "                'name':'log_plan'," +
-      "                'class':'solr.LogPlanAction'" +
       "            }" +
       "        ]" +
       "    }" +

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
index 83d8663..837f7fd 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -48,6 +49,8 @@ import org.apache.solr.client.solrj.impl.SolrClientDataProvider;
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.AutoScalingParams;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.util.CommandOperation;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
@@ -93,10 +96,6 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
     map.put(NAME, "execute_plan");
     map.put(CLASS, "solr.ExecutePlanAction");
     DEFAULT_ACTIONS.add(map);
-    map = new HashMap<>(2);
-    map.put(NAME, "log_plan");
-    map.put(CLASS, "solr.LogPlanAction");
-    DEFAULT_ACTIONS.add(map);
   }
 
   @Override
@@ -508,7 +507,30 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
     }
     AutoScalingConfig.TriggerConfig trigger = new AutoScalingConfig.TriggerConfig(triggerName, op.getValuesExcluding("name"));
     currentConfig = currentConfig.withTriggerConfig(trigger);
-    return currentConfig;
+    // check that there's a default SystemLogListener, unless user specified another one
+    return withSystemLogListener(currentConfig, triggerName);
+  }
+
+  private static String fullName = SystemLogListener.class.getName();
+  private static String solrName = "solr." + SystemLogListener.class.getSimpleName();
+
+  private static AutoScalingConfig withSystemLogListener(AutoScalingConfig autoScalingConfig, String triggerName) {
+    Map<String, AutoScalingConfig.TriggerListenerConfig> configs = autoScalingConfig.getTriggerListenerConfigs();
+    for (AutoScalingConfig.TriggerListenerConfig cfg : configs.values()) {
+      if (triggerName.equals(cfg.trigger)) {
+        // already has some listener config
+        return autoScalingConfig;
+      }
+    }
+    // need to add
+    Map<String, Object> properties = new HashMap<>();
+    properties.put(AutoScalingParams.CLASS, SystemLogListener.class.getName());
+    properties.put(AutoScalingParams.TRIGGER, triggerName);
+    properties.put(AutoScalingParams.STAGE, EnumSet.allOf(TriggerEventProcessorStage.class));
+    AutoScalingConfig.TriggerListenerConfig listener =
+        new AutoScalingConfig.TriggerListenerConfig(CollectionAdminParams.SYSTEM_COLL, properties);
+    autoScalingConfig = autoScalingConfig.withTriggerListenerConfig(listener);
+    return autoScalingConfig;
   }
 
   private int parseHumanTime(String timeStr) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogPlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogPlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogPlanAction.java
deleted file mode 100644
index 45107c1..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogPlanAction.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.solr.cloud.autoscaling;
-
-/**
- * todo nocommit
- */
-public class LogPlanAction extends TriggerActionBase {
-  @Override
-  public void process(TriggerEvent event, ActionContext actionContext) {
-
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogTriggerListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogTriggerListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogTriggerListener.java
deleted file mode 100644
index 736d946..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/LogTriggerListener.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.solr.cloud.autoscaling;
-
-import java.lang.invoke.MethodHandles;
-
-import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Implementation of {@link TriggerListener} that reports
- * events to a log.
- */
-public class LogTriggerListener extends TriggerListenerBase {
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  @Override
-  public void onEvent(TriggerEvent event, TriggerEventProcessorStage stage, String actionName, ActionContext context,
-                      Throwable error, String message) {
-    LOG.info("{}: stage={}, actionName={}, event={}, error={}, messsage={}", config.name, stage, actionName, event, error, message);
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/LoggingListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/LoggingListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/LoggingListener.java
new file mode 100644
index 0000000..bfda572
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/LoggingListener.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.autoscaling;
+
+import java.lang.invoke.MethodHandles;
+
+import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of {@link TriggerListener} that reports
+ * events to a log.
+ */
+public class LoggingListener extends TriggerListenerBase {
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  @Override
+  public void onEvent(TriggerEvent event, TriggerEventProcessorStage stage, String actionName, ActionContext context,
+                      Throwable error, String message) {
+    LOG.info("{}: stage={}, actionName={}, event={}, error={}, messsage={}", config.name, stage, actionName, event, error, message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
index 255efb8..1158d01 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
@@ -184,6 +184,8 @@ public class ScheduledTriggers implements Closeable {
               actionThrottle.markAttemptingAction();
               ActionContext actionContext = new ActionContext(coreContainer, newTrigger, new HashMap<>());
               for (TriggerAction action : actions) {
+                List<String> beforeActions = (List<String>)actionContext.getProperties().computeIfAbsent(TriggerEventProcessorStage.BEFORE_ACTION.toString(), k -> new ArrayList<String>());
+                beforeActions.add(action.getName());
                 listeners.fireListeners(event.getSource(), event, TriggerEventProcessorStage.BEFORE_ACTION, action.getName(), actionContext);
                 try {
                   action.process(event, actionContext);
@@ -192,6 +194,8 @@ public class ScheduledTriggers implements Closeable {
                   log.error("Error executing action: " + action.getName() + " for trigger event: " + event, e);
                   throw e;
                 }
+                List<String> afterActions = (List<String>)actionContext.getProperties().computeIfAbsent(TriggerEventProcessorStage.AFTER_ACTION.toString(), k -> new ArrayList<String>());
+                afterActions.add(action.getName());
                 listeners.fireListeners(event.getSource(), event, TriggerEventProcessorStage.AFTER_ACTION, action.getName(), actionContext);
               }
               if (enqueued) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
new file mode 100644
index 0000000..099f6b6
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud.autoscaling;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
+import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.util.IdUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This listener saves events to the {@link CollectionAdminParams#SYSTEM_COLL} collection.
+ * <p>Configuration properties:</p>
+ * <ul>
+ *   <li>collection - optional string, specifies what collection should be used for storing events. Default value
+ *   is {@link CollectionAdminParams#SYSTEM_COLL}.</li>
+ * </ul>
+ */
+public class SystemLogListener extends TriggerListenerBase {
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  public static final String SOURCE_FIELD = "source_s";
+  public static final String SOURCE = SystemLogListener.class.getSimpleName();
+  public static final String DOC_TYPE = "autoscaling_event";
+
+  private String collection = CollectionAdminParams.SYSTEM_COLL;
+  private boolean enabled = true;
+
+  @Override
+  public void init(CoreContainer coreContainer, AutoScalingConfig.TriggerListenerConfig config) {
+    super.init(coreContainer, config);
+    collection = (String)config.properties.getOrDefault(CollectionAdminParams.COLLECTION, CollectionAdminParams.SYSTEM_COLL);
+    enabled = Boolean.parseBoolean(String.valueOf(config.properties.getOrDefault("enabled", true)));
+  }
+
+  @Override
+  public void onEvent(TriggerEvent event, TriggerEventProcessorStage stage, String actionName, ActionContext context,
+               Throwable error, String message) throws Exception {
+    if (!enabled) {
+      return;
+    }
+    try (CloudSolrClient cloudSolrClient = new CloudSolrClient.Builder()
+        .withZkHost(coreContainer.getZkController().getZkServerAddress())
+        .withHttpClient(coreContainer.getUpdateShardHandler().getHttpClient())
+        .build()) {
+      SolrInputDocument doc = new SolrInputDocument();
+      doc.addField(CommonParams.TYPE, DOC_TYPE);
+      doc.addField(SOURCE_FIELD, SOURCE);
+      doc.addField("id", IdUtils.timeRandomId());
+      doc.addField("event.id_s", event.getId());
+      doc.addField("event.type_s", event.getEventType().toString());
+      doc.addField("event.source_s", event.getSource());
+      doc.addField("event.time_l", event.getEventTime());
+      doc.addField("timestamp", new Date());
+      addMap("event.property.", doc, event.getProperties());
+      doc.addField("stage_s", stage.toString());
+      if (actionName != null) {
+        doc.addField("action_s", actionName);
+      }
+      if (message != null) {
+        doc.addField("message_t", message);
+      }
+      addError(doc, error);
+      // add JSON versions of event and context
+      String eventJson = Utils.toJSONString(event);
+      doc.addField("event_str", eventJson);
+      if (context != null) {
+        // capture specifics of operations after compute_plan action
+        addOperations(doc, (List<SolrRequest>)context.getProperties().get("operations"));
+        // capture specifics of responses after execute_plan action
+        addResponses(doc, (List<NamedList<Object>>)context.getProperties().get("responses"));
+        addActions("before", doc, (List<String>)context.getProperties().get(TriggerEventProcessorStage.BEFORE_ACTION.toString()));
+        addActions("after", doc, (List<String>)context.getProperties().get(TriggerEventProcessorStage.AFTER_ACTION.toString()));
+        String contextJson = Utils.toJSONString(context);
+        doc.addField("context_str", contextJson);
+      }
+      UpdateRequest req = new UpdateRequest();
+      req.add(doc);
+      cloudSolrClient.request(req, collection);
+    } catch (Exception e) {
+      if ((e instanceof SolrException) && e.getMessage().contains("Collection not found")) {
+        // relatively benign
+        log.info("Collection " + collection + " does not exist, disabling logging.");
+        enabled = false;
+      } else {
+        log.warn("Exception sending event to collection " + collection, e);
+      }
+    }
+  }
+
+  private void addActions(String prefix, SolrInputDocument doc, List<String> actions) {
+    if (actions == null) {
+      return;
+    }
+    actions.forEach(a -> doc.addField(prefix + ".actions_ss", a));
+  }
+
+  private void addMap(String prefix, SolrInputDocument doc, Map<String, Object> map) {
+    map.forEach((k, v) -> {
+      if (v instanceof Collection) {
+        for (Object o : (Collection)v) {
+          doc.addField(prefix + k + "_ss", String.valueOf(o));
+        }
+      } else {
+        doc.addField(prefix + k + "_s", String.valueOf(v));
+      }
+    });
+  }
+
+  private void addOperations(SolrInputDocument doc, List<SolrRequest> operations) {
+    if (operations == null || operations.isEmpty()) {
+      return;
+    }
+    for (SolrRequest req : operations) {
+      SolrParams params = req.getParams();
+      if (params == null) {
+        continue;
+      }
+      // build a whitespace-separated param string
+      StringJoiner paramJoiner = new StringJoiner(" ");
+      paramJoiner.setEmptyValue("");
+      for (Iterator<String> it = params.getParameterNamesIterator(); it.hasNext(); ) {
+        final String name = it.next();
+        final String [] values = params.getParams(name);
+        for (String value : values) {
+          paramJoiner.add(name + "=" + value);
+        }
+      }
+      String paramString = paramJoiner.toString();
+      if (!paramString.isEmpty()) {
+        doc.addField("operations.params_ts", paramString);
+      }
+    }
+  }
+
+  private void addResponses(SolrInputDocument doc, List<NamedList<Object>> responses) {
+    if (responses == null || responses.isEmpty()) {
+      return;
+    }
+    for (NamedList<Object> rsp : responses) {
+      Object o = rsp.get("success");
+      if (o != null) {
+        doc.addField("responses_ts", "success " + o);
+      } else {
+        o = rsp.get("failure");
+        if (o != null) {
+          doc.addField("responses_ts", "failure " + o);
+        } else { // something else
+          doc.addField("responses_ts", Utils.toJSONString(rsp));
+        }
+      }
+    }
+  }
+
+  private void addError(SolrInputDocument doc, Throwable error) {
+    if (error == null) {
+      return;
+    }
+    StringWriter sw = new StringWriter();
+    PrintWriter pw = new PrintWriter(sw);
+    error.printStackTrace(pw);
+    pw.flush(); pw.close();
+    doc.addField("error.message_t", error.getMessage());
+    doc.addField("error.details_t", sw.toString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/core/BlobRepository.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/BlobRepository.java b/solr/core/src/java/org/apache/solr/core/BlobRepository.java
index bbe7c62..e4d5e04 100644
--- a/solr/core/src/java/org/apache/solr/core/BlobRepository.java
+++ b/solr/core/src/java/org/apache/solr/core/BlobRepository.java
@@ -42,7 +42,7 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.handler.admin.CollectionsHandler;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.util.SimplePostTool;
 import org.apache.zookeeper.server.ByteBufferInputStream;
 import org.slf4j.Logger;
@@ -153,7 +153,7 @@ public class BlobRepository {
    */
   ByteBuffer fetchBlob(String key) {
     Replica replica = getSystemCollReplica();
-    String url = replica.getStr(BASE_URL_PROP) + "/.system/blob/" + key + "?wt=filestream";
+    String url = replica.getStr(BASE_URL_PROP) + "/" + CollectionAdminParams.SYSTEM_COLL + "/blob/" + key + "?wt=filestream";
 
     HttpClient httpClient = coreContainer.getUpdateShardHandler().getHttpClient();
     HttpGet httpGet = new HttpGet(url);
@@ -180,10 +180,10 @@ public class BlobRepository {
   private Replica getSystemCollReplica() {
     ZkStateReader zkStateReader = this.coreContainer.getZkController().getZkStateReader();
     ClusterState cs = zkStateReader.getClusterState();
-    DocCollection coll = cs.getCollectionOrNull(CollectionsHandler.SYSTEM_COLL);
-    if (coll == null) throw new SolrException(SERVICE_UNAVAILABLE, ".system collection not available");
+    DocCollection coll = cs.getCollectionOrNull(CollectionAdminParams.SYSTEM_COLL);
+    if (coll == null) throw new SolrException(SERVICE_UNAVAILABLE, CollectionAdminParams.SYSTEM_COLL + " collection not available");
     ArrayList<Slice> slices = new ArrayList<>(coll.getActiveSlices());
-    if (slices.isEmpty()) throw new SolrException(SERVICE_UNAVAILABLE, "No active slices for .system collection");
+    if (slices.isEmpty()) throw new SolrException(SERVICE_UNAVAILABLE, "No active slices for " + CollectionAdminParams.SYSTEM_COLL + " collection");
     Collections.shuffle(slices, RANDOM); //do load balancing
 
     Replica replica = null;
@@ -202,7 +202,7 @@ public class BlobRepository {
       }
     }
     if (replica == null) {
-      throw new SolrException(SERVICE_UNAVAILABLE, ".no active replica available for .system collection");
+      throw new SolrException(SERVICE_UNAVAILABLE, "No active replica available for " + CollectionAdminParams.SYSTEM_COLL + " collection");
     }
     return replica;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/MemClassLoader.java b/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
index 4df0a8b..e4f561f 100644
--- a/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/MemClassLoader.java
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.lucene.analysis.util.ResourceLoader;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -92,7 +93,7 @@ public class MemClassLoader extends ClassLoader implements AutoCloseable, Resour
     ProtectionDomain defaultDomain = null;
     //using the default protection domain, with no permissions
     try {
-      defaultDomain = new ProtectionDomain(new CodeSource(new URL("http://localhost/.system/blob/" + jarName.get()), (Certificate[]) null),
+      defaultDomain = new ProtectionDomain(new CodeSource(new URL("http://localhost/" + CollectionAdminParams.SYSTEM_COLL + "/blob/" + jarName.get()), (Certificate[]) null),
           null);
     } catch (MalformedURLException mue) {
       throw new ClassNotFoundException("Unexpected exception ", mue);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/core/SolrCore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 5319881..7ff1a52 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -82,6 +82,7 @@ import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.CommonParams.EchoParamStyle;
 import org.apache.solr.common.params.SolrParams;
@@ -3035,7 +3036,8 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
    * processing. The Decoder will only run on the first invocations, subsequent invocations will return the 
    * cached object. 
    * 
-   * @param key A key in the format of name/version for a blob stored in the .system blob store via the Blob Store API
+   * @param key A key in the format of name/version for a blob stored in the
+   *            {@link CollectionAdminParams#SYSTEM_COLL} blob store via the Blob Store API
    * @param decoder a decoder with which to convert the blob into a Java Object representation (first time only)
    * @return a reference to the blob that has already cached the decoded version.
    */

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/BlobHandler.java b/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
index 725a0ea..e3097fc 100644
--- a/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
@@ -137,6 +137,7 @@ public class BlobHandler extends RequestHandlerBase implements PluginInfoInitial
         String id = blobName + "/" + version;
         Map<String, Object> doc = makeMap(
             ID, id,
+            CommonParams.TYPE, "blob",
             "md5", md5,
             "blobName", blobName,
             VERSION, version,

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index 3afad2f..586ee0d 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -348,20 +348,18 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
     return Category.ADMIN;
   }
 
-  public static final String SYSTEM_COLL = ".system";
-
   private static void createSysConfigSet(CoreContainer coreContainer) throws KeeperException, InterruptedException {
     SolrZkClient zk = coreContainer.getZkController().getZkStateReader().getZkClient();
     ZkCmdExecutor cmdExecutor = new ZkCmdExecutor(zk.getZkClientTimeout());
     cmdExecutor.ensureExists(ZkStateReader.CONFIGS_ZKNODE, zk);
-    cmdExecutor.ensureExists(ZkStateReader.CONFIGS_ZKNODE + "/" + SYSTEM_COLL, zk);
+    cmdExecutor.ensureExists(ZkStateReader.CONFIGS_ZKNODE + "/" + CollectionAdminParams.SYSTEM_COLL, zk);
 
     try {
-      String path = ZkStateReader.CONFIGS_ZKNODE + "/" + SYSTEM_COLL + "/schema.xml";
+      String path = ZkStateReader.CONFIGS_ZKNODE + "/" + CollectionAdminParams.SYSTEM_COLL + "/schema.xml";
       byte[] data = IOUtils.toByteArray(CollectionsHandler.class.getResourceAsStream("/SystemCollectionSchema.xml"));
       assert data != null && data.length > 0;
       cmdExecutor.ensureExists(path, data, CreateMode.PERSISTENT, zk);
-      path = ZkStateReader.CONFIGS_ZKNODE + "/" + SYSTEM_COLL + "/solrconfig.xml";
+      path = ZkStateReader.CONFIGS_ZKNODE + "/" + CollectionAdminParams.SYSTEM_COLL + "/solrconfig.xml";
       data = IOUtils.toByteArray(CollectionsHandler.class.getResourceAsStream("/SystemCollectionSolrConfig.xml"));
       assert data != null && data.length > 0;
       cmdExecutor.ensureExists(path, data, CreateMode.PERSISTENT, zk);
@@ -418,7 +416,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
       if (StringUtils.isNotEmpty(shardsParam)) {
         verifyShardsParam(shardsParam);
       }
-      if (SYSTEM_COLL.equals(collectionName)) {
+      if (CollectionAdminParams.SYSTEM_COLL.equals(collectionName)) {
         //We must always create a .system collection with only a single shard
         props.put(NUM_SLICES, 1);
         props.remove(SHARDS_PROP);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index a548c05..e5ec720 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -119,7 +119,7 @@ import static org.apache.solr.common.params.CollectionParams.CollectionAction.DE
 import static org.apache.solr.common.params.CollectionParams.CollectionAction.RELOAD;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.common.params.CoreAdminParams.ACTION;
-import static org.apache.solr.handler.admin.CollectionsHandler.SYSTEM_COLL;
+import static org.apache.solr.common.params.CollectionAdminParams.SYSTEM_COLL;
 import static org.apache.solr.servlet.SolrDispatchFilter.Action.ADMIN;
 import static org.apache.solr.servlet.SolrDispatchFilter.Action.FORWARD;
 import static org.apache.solr.servlet.SolrDispatchFilter.Action.PASSTHROUGH;
@@ -347,7 +347,7 @@ public class HttpSolrCall {
         SYSTEM_COLL.equals(corename) &&
         "POST".equals(req.getMethod()) &&
         !cores.getZkController().getClusterState().hasCollection(SYSTEM_COLL)) {
-      log.info("Going to auto-create .system collection");
+      log.info("Going to auto-create " + SYSTEM_COLL + " collection");
       SolrQueryResponse rsp = new SolrQueryResponse();
       String repFactor = String.valueOf(Math.min(3, cores.getZkController().getClusterState().getLiveNodes().size()));
       cores.getCollectionsHandler().handleRequestBody(new LocalSolrQueryRequest(null,
@@ -356,7 +356,7 @@ public class HttpSolrCall {
               .add( NAME, SYSTEM_COLL)
               .add(REPLICATION_FACTOR, repFactor)), rsp);
       if (rsp.getValues().get("success") == null) {
-        throw new SolrException(ErrorCode.SERVER_ERROR, "Could not auto-create .system collection: "+ Utils.toJSONString(rsp.getValues()));
+        throw new SolrException(ErrorCode.SERVER_ERROR, "Could not auto-create " + SYSTEM_COLL + " collection: "+ Utils.toJSONString(rsp.getValues()));
       }
       TimeOut timeOut = new TimeOut(3, TimeUnit.SECONDS);
       for (; ; ) {
@@ -364,7 +364,7 @@ public class HttpSolrCall {
           break;
         } else {
           if (timeOut.hasTimedOut()) {
-            throw new SolrException(ErrorCode.SERVER_ERROR, "Could not find .system collection even after 3 seconds");
+            throw new SolrException(ErrorCode.SERVER_ERROR, "Could not find " + SYSTEM_COLL + " collection even after 3 seconds");
           }
           Thread.sleep(50);
         }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/java/org/apache/solr/util/SolrCLI.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/SolrCLI.java b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
index 657b402..a4b4fdd 100644
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -112,6 +112,7 @@ import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkConfigManager;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.ContentStreamBase;
@@ -1512,7 +1513,7 @@ public class SolrCLI {
       boolean configExistsInZk = confname != null && !"".equals(confname.trim()) &&
           cloudSolrClient.getZkStateReader().getZkClient().exists("/configs/" + confname, true);
 
-      if (".system".equals(collectionName)) {
+      if (CollectionAdminParams.SYSTEM_COLL.equals(collectionName)) {
         //do nothing
       } else if (configExistsInZk) {
         echo("Re-using existing configuration directory "+confname);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/resources/SystemCollectionSchema.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/resources/SystemCollectionSchema.xml b/solr/core/src/resources/SystemCollectionSchema.xml
index d491480..2077b36 100644
--- a/solr/core/src/resources/SystemCollectionSchema.xml
+++ b/solr/core/src/resources/SystemCollectionSchema.xml
@@ -2,16 +2,37 @@
 <schema name="_system collection or core" version="1.1">
   <fieldtype name="string"  class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
   <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
+  <fieldType name="double" class="solr.TrieDoubleField" positionIncrementGap="0" precisionStep="0"/>
   <fieldType name="bytes" class="solr.BinaryField"/>
   <fieldType name="date" class="solr.TrieDateField"/>
+  <fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
+    <analyzer>
+      <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+    </analyzer>
+  </fieldType>
+  <uniqueKey>id</uniqueKey>
   <field name="id"   type="string"   indexed="true"  stored="true"  multiValued="false" required="true"/>
-  <field name="md5"   type="string"   indexed="true"  stored="true"  multiValued="false" required="true"/>
+  <field name="_version_" type="long"     indexed="true"  stored="true"/>
+  <field name="type"   type="string"   indexed="true"  stored="true"  multiValued="false" required="true"/>
+  <!-- blob repository fields -->
+  <field name="md5"   type="string"   indexed="true"  stored="true"  multiValued="false"/>
   <field name="blob"      type="bytes"   indexed="false" stored="true"  multiValued="false" />
   <field name="size"      type="long"   indexed="true" stored="true"  multiValued="false" />
   <field name="version"   type="long"     indexed="true"  stored="true"  multiValued="false" />
   <field name="timestamp"   type="date"   indexed="true"  stored="true"  multiValued="false" />
   <field name="blobName"      type="string"   indexed="true"  stored="true"  multiValued="false" />
-  <field name="_version_" type="long"     indexed="true"  stored="true"/>
+
+  <!-- general purpose fields -->
   <dynamicField name="*_s"  type="string"  indexed="true"  stored="true" />
-  <uniqueKey>id</uniqueKey>
+  <dynamicField name="*_ss"  type="string"  indexed="true"  multiValued="true"  stored="true" />
+  <dynamicField name="*_str"  type="string"  indexed="false" stored="true" />
+  <dynamicField name="*_strs"  type="string"  indexed="false"  multiValued="true" stored="true" />
+  <dynamicField name="*_bin"  type="bytes"  indexed="false"  multiValued="false" stored="true" />
+  <dynamicField name="*_t"  type="text_ws"  indexed="true"  stored="true" />
+  <dynamicField name="*_ts"  type="text_ws"  indexed="true"  multiValued="true" stored="true" />
+  <dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
+  <dynamicField name="*_l" type="long" indexed="true" stored="true"/>
+  <dynamicField name="*_ls" type="long" multiValued="true" indexed="true" stored="true"/>
+  <dynamicField name="*_d" type="double" indexed="true" stored="true"/>
+  <dynamicField name="*_ds" type="double" multiValued="true" indexed="true" stored="true"/>
 </schema>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanActionTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanActionTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanActionTest.java
index 460cc80..2937b4a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanActionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanActionTest.java
@@ -75,7 +75,8 @@ public class AutoAddReplicasPlanActionTest extends SolrCloudTestCase{
     // we remove the implicit created trigger, so the replicas won't be moved
     String removeTriggerCommand = "{" +
         "'remove-trigger' : {" +
-        "'name' : '.auto_add_replicas'" +
+        "'name' : '.auto_add_replicas'," +
+        "'removeListeners': true" +
         "}" +
         "}";
     SolrRequest req = createAutoScalingRequest(SolrRequest.METHOD.POST, removeTriggerCommand);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
index b953218..9130b15 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
@@ -86,7 +86,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertNotNull(autoAddReplicasTrigger);
     List<Map<String, Object>> actions = (List<Map<String, Object>>) autoAddReplicasTrigger.get("actions");
     assertNotNull(actions);
-    assertEquals(3, actions.size());
+    assertEquals(2, actions.size());
     assertEquals("auto_add_replicas_plan", actions.get(0).get("name").toString());
     assertEquals("solr.AutoAddReplicasPlanAction", actions.get(0).get("class").toString());
 
@@ -124,7 +124,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertNotNull(autoAddReplicasTrigger);
     actions = (List<Map<String, Object>>) autoAddReplicasTrigger.get("actions");
     assertNotNull(actions);
-    assertEquals(3, actions.size());
+    assertEquals(2, actions.size());
     assertEquals("auto_add_replicas_plan", actions.get(0).get("name").toString());
     assertEquals("solr.AutoAddReplicasPlanAction", actions.get(0).get("class").toString());
 
@@ -306,11 +306,6 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
         "{" +
         "'name' : 'compute_plan'," +
         "'class' : 'solr.ComputePlanAction'" +
-        "}," +
-        "{" +
-        "'name' : 'log_plan'," +
-        "'class' : 'solr.LogPlanAction'," +
-        "'collection' : '.system'" +
         "}]}}";
     SolrRequest req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
 
@@ -327,7 +322,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertEquals(4, nodeLostTrigger.size());
     List<Map<String, String>> actions = (List<Map<String, String>>) nodeLostTrigger.get("actions");
     assertNotNull(actions);
-    assertEquals(2, actions.size());
+    assertEquals(1, actions.size());
     assertEquals("600", nodeLostTrigger.get("waitFor").toString());
 
     setTriggerCommand = "{" +
@@ -352,7 +347,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertEquals("false", nodeLostTrigger.get("enabled").toString());
     actions = (List<Map<String, String>>) nodeLostTrigger.get("actions");
     assertNotNull(actions);
-    assertEquals(3, actions.size());
+    assertEquals(2, actions.size());
 
     String setListenerCommand = "{" +
         "'set-listener' : " +
@@ -372,7 +367,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     loaded = ZkNodeProps.load(data);
     Map<String, Object> listeners = (Map<String, Object>) loaded.get("listeners");
     assertNotNull(listeners);
-    assertEquals(1, listeners.size());
+    assertEquals(2, listeners.size());
     assertTrue(listeners.containsKey("xyz"));
     Map<String, Object> xyzListener = (Map<String, Object>) listeners.get("xyz");
     assertEquals(6, xyzListener.size());
@@ -387,10 +382,10 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     try {
       response = solrClient.request(req);
       String errorMsg = (String) ((NamedList)response.get("error")).get("msg");
-      assertTrue(errorMsg.contains("Cannot remove trigger: node_lost_trigger because it has active listeners: [xyz]"));
+      assertTrue(errorMsg.contains("Cannot remove trigger: node_lost_trigger because it has active listeners: ["));
     } catch (HttpSolrClient.RemoteSolrException e) {
       // expected
-      assertTrue(e.getMessage().contains("Cannot remove trigger: node_lost_trigger because it has active listeners: [xyz]"));
+      assertTrue(e.getMessage().contains("Cannot remove trigger: node_lost_trigger because it has active listeners: ["));
     }
 
     String removeListenerCommand = "{\n" +
@@ -398,9 +393,17 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
         "\t\t\"name\" : \"xyz\"\n" +
         "\t}\n" +
         "}";
+    String removeListenerCommand1 = "{\n" +
+        "\t\"remove-listener\" : {\n" +
+        "\t\t\"name\" : \".system\"\n" +
+        "\t}\n" +
+        "}";
     req = createAutoScalingRequest(SolrRequest.METHOD.POST, removeListenerCommand);
     response = solrClient.request(req);
     assertEquals(response.get("result").toString(), "success");
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, removeListenerCommand1);
+    response = solrClient.request(req);
+    assertEquals(response.get("result").toString(), "success");
     data = zkClient().getData(SOLR_AUTOSCALING_CONF_PATH, null, null, true);
     loaded = ZkNodeProps.load(data);
     listeners = (Map<String, Object>) loaded.get("listeners");
@@ -620,7 +623,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertEquals(4, node_added_trigger1.size());
     assertEquals(0L, node_added_trigger1.get("waitFor"));
     assertEquals(true, node_added_trigger1.get("enabled"));
-    assertEquals(3, ((List)node_added_trigger1.get("actions")).size());
+    assertEquals(2, ((List)node_added_trigger1.get("actions")).size());
 
     List<Map> clusterPrefs = (List<Map>) response.get("cluster-preferences");
     assertNotNull(clusterPrefs);
@@ -759,7 +762,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertEquals(4, node_added_trigger1.size());
     assertEquals(0L, node_added_trigger1.get("waitFor"));
     assertEquals(true, node_added_trigger1.get("enabled"));
-    assertEquals(3, ((List)node_added_trigger1.get("actions")).size());
+    assertEquals(2, ((List)node_added_trigger1.get("actions")).size());
 
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
index 29bfb59..daa9213 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
@@ -297,10 +297,6 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
     map.put("name", "execute_plan");
     map.put("class", "solr.ExecutePlanAction");
     actions.add(map);
-    map = new HashMap<>(2);
-    map.put("name", "log_plan");
-    map.put("class", "solr.LogPlanAction");
-    actions.add(map);
     props.put("actions", actions);
     return props;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
index e501c64..f1d6545 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
@@ -335,10 +335,6 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
     map.put("name", "execute_plan");
     map.put("class", "solr.ExecutePlanAction");
     actions.add(map);
-    map = new HashMap<>(2);
-    map.put("name", "log_plan");
-    map.put("class", "solr.LogPlanAction");
-    actions.add(map);
     props.put("actions", actions);
     return props;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/cloud/autoscaling/SystemLogListenerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/SystemLogListenerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SystemLogListenerTest.java
new file mode 100644
index 0000000..c5536de
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SystemLogListenerTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.autoscaling;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.embedded.JettySolrRunner;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.util.LogLevel;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.solr.cloud.autoscaling.AutoScalingHandlerTest.createAutoScalingRequest;
+
+/**
+ * Test for {@link SystemLogListener}
+ */
+@LogLevel("org.apache.solr.cloud.autoscaling=DEBUG")
+public class SystemLogListenerTest extends SolrCloudTestCase {
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  private static final AtomicBoolean fired = new AtomicBoolean(false);
+  private static final int NODE_COUNT = 3;
+  private static CountDownLatch triggerFiredLatch = new CountDownLatch(1);
+  private static final AtomicReference<Map> actionContextPropsRef = new AtomicReference<>();
+  private static final AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
+
+  public static class AssertingTriggerAction extends TriggerActionBase {
+    @Override
+    public void process(TriggerEvent event, ActionContext context) {
+      if (fired.compareAndSet(false, true)) {
+        eventRef.set(event);
+        actionContextPropsRef.set(context.getProperties());
+        triggerFiredLatch.countDown();
+      }
+    }
+  }
+
+  public static class ErrorTriggerAction extends TriggerActionBase {
+    @Override
+    public void process(TriggerEvent event, ActionContext context) {
+      throw new RuntimeException("failure from ErrorTriggerAction");
+    }
+  }
+
+  @BeforeClass
+  public static void setupCluster() throws Exception {
+    configureCluster(NODE_COUNT)
+        .addConfig("conf", configset("cloud-minimal"))
+        .configure();
+    CollectionAdminRequest.createCollection(CollectionAdminParams.SYSTEM_COLL, null, 1, 3)
+        .process(cluster.getSolrClient());
+  }
+
+  @Test
+  public void test() throws Exception {
+    CloudSolrClient solrClient = cluster.getSolrClient();
+    String setTriggerCommand = "{" +
+        "'set-trigger' : {" +
+        "'name' : 'node_lost_trigger'," +
+        "'event' : 'nodeLost'," +
+        "'waitFor' : '1s'," +
+        "'enabled' : true," +
+        "'actions' : [{'name':'compute_plan', 'class' : 'solr.ComputePlanAction'}," +
+        "{'name':'execute_plan','class':'solr.ExecutePlanAction'}," +
+        "{'name':'test','class':'" + AssertingTriggerAction.class.getName() + "'}," +
+        "{'name':'error','class':'" + ErrorTriggerAction.class.getName() + "'}]" +
+        "}}";
+    SolrRequest req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
+    NamedList<Object> response = solrClient.request(req);
+    assertEquals(response.get("result").toString(), "success");
+
+    // remove default listener
+    String removeListenerCommand = "{\n" +
+        "\t\"remove-listener\" : {\n" +
+        "\t\t\"name\" : \".system\"\n" +
+        "\t}\n" +
+        "}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, removeListenerCommand);
+    response = solrClient.request(req);
+    assertEquals(response.get("result").toString(), "success");
+
+    CollectionAdminRequest.Create create = CollectionAdminRequest.createCollection("test",
+        "conf",3, 2);
+    create.setMaxShardsPerNode(3);
+    create.process(solrClient);
+
+    waitForState("Timed out waiting for replicas of new collection to be active",
+        "test", clusterShape(3, 2));
+
+    String setListenerCommand = "{" +
+        "'set-listener' : " +
+        "{" +
+        "'name' : 'foo'," +
+        "'trigger' : 'node_lost_trigger'," +
+        "'stage' : ['STARTED','ABORTED','SUCCEEDED', 'FAILED']," +
+        "'beforeAction' : ['compute_plan','execute_plan','test','error']," +
+        "'afterAction' : ['compute_plan','execute_plan','test','error']," +
+        "'class' : '" + SystemLogListener.class.getName() + "'" +
+        "}" +
+        "}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, setListenerCommand);
+    response = solrClient.request(req);
+    assertEquals(response.get("result").toString(), "success");
+
+    // stop non-overseer node
+    NamedList<Object> overSeerStatus = cluster.getSolrClient().request(CollectionAdminRequest.getOverseerStatus());
+    String overseerLeader = (String) overSeerStatus.get("leader");
+    int nonOverseerLeaderIndex = 0;
+    for (int i = 0; i < cluster.getJettySolrRunners().size(); i++) {
+      JettySolrRunner jetty = cluster.getJettySolrRunner(i);
+      if (!jetty.getNodeName().equals(overseerLeader)) {
+        nonOverseerLeaderIndex = i;
+      }
+    }
+    cluster.stopJettySolrRunner(nonOverseerLeaderIndex);
+    cluster.waitForAllNodes(30);
+    assertTrue("Trigger was not fired even after 5 seconds", triggerFiredLatch.await(5, TimeUnit.SECONDS));
+    assertTrue(fired.get());
+    Map context = actionContextPropsRef.get();
+    assertNotNull(context);
+
+    // make sure the event docs are replicated and committed
+    Thread.sleep(5000);
+    cluster.getSolrClient().commit(CollectionAdminParams.SYSTEM_COLL, true, true);
+
+    ModifiableSolrParams query = new ModifiableSolrParams();
+    query.add(CommonParams.Q, "type:" + SystemLogListener.DOC_TYPE);
+    query.add(CommonParams.SORT, "id asc");
+    QueryResponse resp = cluster.getSolrClient().query(CollectionAdminParams.SYSTEM_COLL, query);
+    SolrDocumentList docs = resp.getResults();
+    assertNotNull(docs);
+    assertEquals("wrong number of events added to .system", 9, docs.size());
+    docs.forEach(doc -> assertCommonFields(doc));
+
+    // STARTED
+    SolrDocument doc = docs.get(0);
+    assertEquals("STARTED", doc.getFieldValue("stage_s"));
+
+    // BEFORE_ACTION compute_plan
+    doc = docs.get(1);
+    assertEquals("BEFORE_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("compute_plan", doc.getFieldValue("action_s"));
+
+    // AFTER_ACTION compute_plan
+    doc = docs.get(2);
+    assertEquals("AFTER_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("compute_plan", doc.getFieldValue("action_s"));
+    Collection<Object> vals = doc.getFieldValues("operations.params_ts");
+    assertEquals(3, vals.size());
+    for (Object val : vals) {
+      assertTrue(val.toString(), String.valueOf(val).contains("action=MOVEREPLICA"));
+    }
+
+    // BEFORE_ACTION execute_plan
+    doc = docs.get(3);
+    assertEquals("BEFORE_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("execute_plan", doc.getFieldValue("action_s"));
+    vals = doc.getFieldValues("operations.params_ts");
+    assertEquals(3, vals.size());
+
+    // AFTER_ACTION execute_plan
+    doc = docs.get(4);
+    assertEquals("AFTER_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("execute_plan", doc.getFieldValue("action_s"));
+    vals = doc.getFieldValues("operations.params_ts");
+    assertNotNull(vals);
+    assertEquals(3, vals.size());
+    vals = doc.getFieldValues("responses_ts");
+    assertNotNull(vals);
+    assertEquals(3, vals.size());
+    vals.forEach(s -> assertTrue(s.toString(), s.toString().startsWith("success MOVEREPLICA action completed successfully")));
+
+    // BEFORE_ACTION test
+    doc = docs.get(5);
+    assertEquals("BEFORE_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("test", doc.getFieldValue("action_s"));
+
+    // AFTER_ACTION test
+    doc = docs.get(6);
+    assertEquals("AFTER_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("test", doc.getFieldValue("action_s"));
+
+    // BEFORE_ACTION error
+    doc = docs.get(7);
+    assertEquals("BEFORE_ACTION", doc.getFieldValue("stage_s"));
+    assertEquals("error", doc.getFieldValue("action_s"));
+
+    // FAILED error
+    doc = docs.get(8);
+    assertEquals("FAILED", doc.getFieldValue("stage_s"));
+    assertEquals("error", doc.getFieldValue("action_s"));
+    assertEquals("failure from ErrorTriggerAction", doc.getFieldValue("error.message_t"));
+    assertTrue(doc.getFieldValue("error.details_t").toString().contains("RuntimeException"));
+  }
+
+  private void assertCommonFields(SolrDocument doc) {
+    assertEquals(SystemLogListener.class.getSimpleName(), doc.getFieldValue(SystemLogListener.SOURCE_FIELD));
+    assertEquals(SystemLogListener.DOC_TYPE, doc.getFieldValue(CommonParams.TYPE));
+    assertEquals("node_lost_trigger", doc.getFieldValue("event.source_s"));
+    assertNotNull(doc.getFieldValue("event.time_l"));
+    assertNotNull(doc.getFieldValue("timestamp"));
+    assertNotNull(doc.getFieldValue("event.property.nodeName_s"));
+    assertNotNull(doc.getFieldValue("event_str"));
+    assertEquals("NODELOST", doc.getFieldValue("event.type_s"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/core/src/test/org/apache/solr/core/BlobRepositoryCloudTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/core/BlobRepositoryCloudTest.java b/solr/core/src/test/org/apache/solr/core/BlobRepositoryCloudTest.java
index ad3c8db..efa8e11 100644
--- a/solr/core/src/test/org/apache/solr/core/BlobRepositoryCloudTest.java
+++ b/solr/core/src/test/org/apache/solr/core/BlobRepositoryCloudTest.java
@@ -31,6 +31,7 @@ import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.handler.TestBlobHandler;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -46,7 +47,7 @@ public class BlobRepositoryCloudTest extends SolrCloudTestCase {
         .configure();
 //    Thread.sleep(2000);
     HashMap<String, String> params = new HashMap<>();
-    CollectionAdminRequest.createCollection(".system", null, 1, 1)
+    CollectionAdminRequest.createCollection(CollectionAdminParams.SYSTEM_COLL, null, 1, 1)
         .process(cluster.getSolrClient());
     // test component will fail if it cant' find a blob with this data by this name
     TestBlobHandler.postData(cluster.getSolrClient(), findLiveNodeURI(), "testResource", ByteBuffer.wrap("foo,bar\nbaz,bam".getBytes(StandardCharsets.UTF_8)));

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/autoscaling/AutoScalingConfig.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/autoscaling/AutoScalingConfig.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/autoscaling/AutoScalingConfig.java
index 06cfac3..51e8f42 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/autoscaling/AutoScalingConfig.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/autoscaling/AutoScalingConfig.java
@@ -18,6 +18,8 @@ package org.apache.solr.client.solrj.cloud.autoscaling;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
@@ -72,18 +74,22 @@ public class AutoScalingConfig implements MapWriter {
         this.properties = Collections.unmodifiableMap(new HashMap<>(properties));
       }
       trigger = (String)this.properties.get(AutoScalingParams.TRIGGER);
-      List<String> stageNames = getList(AutoScalingParams.STAGE, this.properties);
-      for (String stageName : stageNames) {
+      List<Object> stageNames = getList(AutoScalingParams.STAGE, this.properties);
+      for (Object stageName : stageNames) {
         try {
-          TriggerEventProcessorStage stage = TriggerEventProcessorStage.valueOf(stageName.toUpperCase(Locale.ROOT));
+          TriggerEventProcessorStage stage = TriggerEventProcessorStage.valueOf(String.valueOf(stageName).toUpperCase(Locale.ROOT));
           stages.add(stage);
         } catch (Exception e) {
           LOG.warn("Invalid stage name '" + name + "' in listener config, skipping: " + properties);
         }
       }
       listenerClass = (String)this.properties.get(AutoScalingParams.CLASS);
-      beforeActions = Collections.unmodifiableSet(new HashSet<>(getList(AutoScalingParams.BEFORE_ACTION, this.properties)));
-      afterActions = Collections.unmodifiableSet(new HashSet<>(getList(AutoScalingParams.AFTER_ACTION, this.properties)));
+      Set<String> bActions = new HashSet<>();
+      getList(AutoScalingParams.BEFORE_ACTION, this.properties).forEach(o -> bActions.add(String.valueOf(o)));
+      beforeActions = Collections.unmodifiableSet(bActions);
+      Set<String> aActions = new HashSet<>();
+      getList(AutoScalingParams.AFTER_ACTION, this.properties).forEach(o -> aActions.add(String.valueOf(o)));
+      afterActions = Collections.unmodifiableSet(aActions);
     }
 
     @Override
@@ -501,11 +507,11 @@ public class AutoScalingConfig implements MapWriter {
     return listeners.equals(that.listeners);
   }
 
-  private static List<String> getList(String key, Map<String, Object> properties) {
+  private static List<Object> getList(String key, Map<String, Object> properties) {
     return getList(key, properties, null);
   }
 
-  private static List<String> getList(String key, Map<String, Object> properties, List<String> defaultList) {
+  private static List<Object> getList(String key, Map<String, Object> properties, List<Object> defaultList) {
     if (defaultList == null) {
       defaultList = Collections.emptyList();
     }
@@ -515,6 +521,8 @@ public class AutoScalingConfig implements MapWriter {
     }
     if (o instanceof List) {
       return (List)o;
+    } else if (o instanceof Collection) {
+      return new ArrayList<>((Collection) o);
     } else {
       return Collections.singletonList(String.valueOf(o));
     }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
index 16f2e2e..b394364 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
@@ -18,6 +18,7 @@ package org.apache.solr.client.solrj.request;
 
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
@@ -32,6 +33,7 @@ import org.apache.solr.client.solrj.V2RequestSupport;
 import org.apache.solr.client.solrj.response.CollectionAdminResponse;
 import org.apache.solr.client.solrj.response.RequestStatusState;
 import org.apache.solr.client.solrj.util.SolrIdentifierValidator;
+import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.ImplicitDocRouter;
 import org.apache.solr.common.cloud.Replica;
@@ -57,7 +59,7 @@ import static org.apache.solr.common.params.CollectionAdminParams.CREATE_NODE_SE
  *
  * @since solr 4.5
  */
-public abstract class CollectionAdminRequest<T extends CollectionAdminResponse> extends SolrRequest<T> implements V2RequestSupport {
+public abstract class CollectionAdminRequest<T extends CollectionAdminResponse> extends SolrRequest<T> implements V2RequestSupport, MapWriter {
 
   protected final CollectionAction action;
 
@@ -97,6 +99,22 @@ public abstract class CollectionAdminRequest<T extends CollectionAdminResponse>
     }
   }
 
+  @Override
+  public void writeMap(EntryWriter ew) throws IOException {
+    ew.put("class", this.getClass().getName());
+    ew.put("method", getMethod().toString());
+    SolrParams params = getParams();
+    if (params != null) {
+      for (Iterator<String> it = params.getParameterNamesIterator(); it.hasNext(); ) {
+        final String name = it.next();
+        final String [] values = params.getParams(name);
+        for (String value : values) {
+          ew.put("params." + name, value);
+        }
+      }
+    }
+  }
+
   /**
    * Base class for asynchronous collection admin requests
    */

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/solrj/src/java/org/apache/solr/common/params/CollectionAdminParams.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/common/params/CollectionAdminParams.java b/solr/solrj/src/java/org/apache/solr/common/params/CollectionAdminParams.java
index ffc373b..b5f23e2 100644
--- a/solr/solrj/src/java/org/apache/solr/common/params/CollectionAdminParams.java
+++ b/solr/solrj/src/java/org/apache/solr/common/params/CollectionAdminParams.java
@@ -28,6 +28,9 @@ public interface CollectionAdminParams {
 
   String COUNT_PROP = "count";
 
+  /** Predefined system collection name. */
+  String SYSTEM_COLL = ".system";
+
   /**
    * A parameter to specify list of Solr nodes to be used (e.g. for collection creation or restore operation).
    */
@@ -59,5 +62,4 @@ public interface CollectionAdminParams {
    */
   public static final Collection<String> INDEX_BACKUP_STRATEGIES =
       Arrays.asList(COPY_FILES_STRATEGY, NO_INDEX_BACKUP_STRATEGY);
-
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e9e9b3c2/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
index 3b24f22..d260281 100644
--- a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
+++ b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
@@ -233,6 +233,9 @@ public interface CommonParams {
   String TRUE = Boolean.TRUE.toString();
   String FALSE = Boolean.FALSE.toString();
 
+  /** document type in {@link CollectionAdminParams#SYSTEM_COLL} collection. **/
+  String TYPE = "type";
+
   /** Used as a local parameter on queries.  cache=false means don't check any query or filter caches.
    * cache=true is the default.
    */


Mime
View raw message